diff --git a/example/example-dev.html b/example/example-dev.html
index 6a69c428..1ab3f672 100644
--- a/example/example-dev.html
+++ b/example/example-dev.html
@@ -27,6 +27,11 @@
+
+
+ Hey. Meet the new Editor. On this page you can see it in action — try to edit this text. Source code of the page contains the example of connection and configuration.
+
+
No core bundle file found. Run yarn build
@@ -68,8 +73,7 @@
-
-
+
@@ -132,7 +136,7 @@
image: SimpleImage,
list: {
- class: NestedList,
+ class: List,
inlineToolbar: true,
shortcut: 'CMD+SHIFT+L'
},
@@ -223,18 +227,9 @@
id: "SSBSguGvP7",
data : {
items : [
- {
- content: 'It is a block-styled editor',
- items: []
- },
- {
- content: 'It returns clean data output in JSON',
- items: []
- },
- {
- content: 'Designed to be extendable and pluggable with a simple API',
- items: []
- }
+ 'It is a block-styled editor',
+ 'It returns clean data output in JSON',
+ 'Designed to be extendable and pluggable with a simple API',
],
style: 'unordered'
}
@@ -317,6 +312,10 @@
},
onReady: function(){
saveButton.click();
+
+ const textarea = document.getElementById('it-test');
+
+ editor.inlineToolbar.bind(textarea, ['link', 'italic', 'marker']);
},
onChange: function(api, block) {
console.log('something changed', block);
diff --git a/src/components/block/index.ts b/src/components/block/index.ts
index 85771882..7fe30476 100644
--- a/src/components/block/index.ts
+++ b/src/components/block/index.ts
@@ -19,6 +19,7 @@ import BlockTune from '../tools/tune';
import { BlockTuneData } from '../../../types/block-tunes/block-tune-data';
import ToolsCollection from '../tools/collection';
import EventsDispatcher from '../utils/events';
+import InlineToolbar from "../utils/inlineToolbar";
/**
* Interface describes Block class constructor argument
@@ -93,6 +94,7 @@ type BlockEvents = 'didMutated';
* @property {HTMLElement} pluginsContent - HTML content that returns by Tool's render function
*/
export default class Block extends EventsDispatcher {
+ private inlineToolbar: InlineToolbar;
/**
* CSS classes for the Block
*
@@ -272,6 +274,8 @@ export default class Block extends EventsDispatcher {
this.composeTunes(tunesData);
this.holder = this.compose();
+
+ this.prepareInlineToolbar();
}
/**
@@ -761,6 +765,14 @@ export default class Block extends EventsDispatcher {
return wrapper;
}
+ private prepareInlineToolbar(){
+ this.inlineToolbar = new InlineToolbar({
+ element: this.holder,
+ isRtl: false, // todo
+ tools: this.tool.inlineTools,
+ });
+ }
+
/**
* Instantiate Block Tunes
*
diff --git a/src/components/modules/api/inlineToolbar.ts b/src/components/modules/api/inlineToolbar.ts
index dca74ca9..cb23002d 100644
--- a/src/components/modules/api/inlineToolbar.ts
+++ b/src/components/modules/api/inlineToolbar.ts
@@ -1,6 +1,10 @@
import { InlineToolbar } from '../../../../types/api/inline-toolbar';
import Module from '../../__module';
+import Toolbar from './../../utils/inlineToolbar';
+import ToolsCollection from "../../tools/collection";
+import InlineTool from "../../tools/inline";
+
/**
* @class InlineToolbarAPI
* Provides methods for working with the Inline Toolbar
@@ -15,6 +19,7 @@ export default class InlineToolbarAPI extends Module {
return {
close: (): void => this.close(),
open: (): void => this.open(),
+ bind: (element, tools): void => this.bind(element, tools),
};
}
@@ -31,4 +36,24 @@ export default class InlineToolbarAPI extends Module {
public close(): void {
this.Editor.InlineToolbar.close();
}
+
+ public bind(element: Element, tools: string[]): void {
+ /**
+ * Filter available tools to passed names list
+ */
+ const toolsList = new ToolsCollection(
+ Array.from(this.Editor.Tools.inlineTools.entries())
+ .filter(([, tool]) => tools ? tools.includes(tool.name) : true) as [string, InlineTool][]
+ );
+
+ const toolbar = new Toolbar({
+ element,
+ editorWrapper: this.Editor.UI.nodes.wrapper,
+ editorContentRect: this.Editor.UI.contentRect,
+ isRtl: this.isRtl,
+ tools: toolsList,
+ });
+
+ // Toolbar.bind(element);
+ }
}
diff --git a/src/components/utils/inlineToolbar.ts b/src/components/utils/inlineToolbar.ts
new file mode 100644
index 00000000..3b64a522
--- /dev/null
+++ b/src/components/utils/inlineToolbar.ts
@@ -0,0 +1,728 @@
+import $ from '../dom';
+import SelectionUtils from '../selection';
+import * as _ from '../utils';
+import { InlineTool as IInlineTool, EditorConfig } from '../../../types';
+import Flipper from '../flipper';
+import I18n from '../i18n';
+import { I18nInternalNS } from '../i18n/namespace-internal';
+import Shortcuts from '../utils/shortcuts';
+import Tooltip from '../utils/tooltip';
+import { ModuleConfig } from '../../types-internal/module-config';
+import InlineTool from '../tools/inline';
+import { CommonInternalSettings } from '../tools/base';
+import ToolsCollection from '../tools/collection';
+import Selection from '../selection';
+import Block from '../block';
+
+/**
+ * Inline Toolbar elements
+ */
+interface InlineToolbarNodes {
+ wrapper: HTMLElement;
+ togglerAndButtonsWrapper: HTMLElement;
+ buttons: HTMLElement;
+ /**
+ * Zone below the buttons where Tools can create additional actions by 'renderActions()' method
+ * For example, input for the 'link' tool or textarea for the 'comment' tool
+ */
+ actions: HTMLElement;
+}
+
+let created = false;
+
+const nodes: InlineToolbarNodes = {
+ wrapper: undefined,
+ buttons: undefined,
+ togglerAndButtonsWrapper: undefined,
+ actions: undefined,
+};
+
+document.addEventListener('selectionchange', (event: Event) => {
+ document.dispatchEvent(new CustomEvent('ch', {
+ detail: {
+ activeElement: document.activeElement,
+ },
+ }));
+ // this.selectionChanged(event, this.ownerElement);
+}, true);
+
+/**
+ * Inline toolbar with actions that modifies selected text fragment
+ *
+ * |¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|
+ * | B i [link] [mark] |
+ * |________________________|
+ */
+export default class InlineToolbar {
+ /**
+ * CSS styles
+ */
+ public CSS = {
+ inlineToolbar: 'ce-inline-toolbar',
+ inlineToolbarShowed: 'ce-inline-toolbar--showed',
+ inlineToolbarLeftOriented: 'ce-inline-toolbar--left-oriented',
+ inlineToolbarRightOriented: 'ce-inline-toolbar--right-oriented',
+ inlineToolbarShortcut: 'ce-inline-toolbar__shortcut',
+ buttonsWrapper: 'ce-inline-toolbar__buttons',
+ actionsWrapper: 'ce-inline-toolbar__actions',
+ inlineToolButton: 'ce-inline-tool',
+ inputField: 'cdx-input',
+ focusedButton: 'ce-inline-tool--focused',
+ conversionToggler: 'ce-inline-toolbar__dropdown',
+ conversionTogglerHidden: 'ce-inline-toolbar__dropdown--hidden',
+ conversionTogglerContent: 'ce-inline-toolbar__dropdown-content',
+ togglerAndButtonsWrapper: 'ce-inline-toolbar__toggler-and-button-wrapper',
+ };
+
+ /**
+ * State of inline toolbar
+ *
+ * @type {boolean}
+ */
+ public opened = false;
+
+ /**
+ * Margin above/below the Toolbar
+ */
+ private readonly toolbarVerticalMargin: number = 5;
+
+ /**
+ * TODO: Get rid of this
+ *
+ * Currently visible tools instances
+ */
+ private toolsInstances: Map;
+
+ /**
+ * Buttons List
+ *
+ * @type {NodeList}
+ */
+ private buttonsList: NodeList = null;
+
+ /**
+ * Cache for Inline Toolbar width
+ *
+ * @type {number}
+ */
+ private width = 0;
+
+ /**
+ * Instance of class that responses for leafing buttons by arrows/tab
+ */
+ private flipper: Flipper = null;
+
+ /**
+ * Tooltip utility Instance
+ */
+ private tooltip: Tooltip;
+ private ownerElement: Element;
+
+ private isRtl = false;
+ private tools: ToolsCollection;
+
+ /**
+ * @class
+ */
+ constructor({ element, isRtl, tools }) {
+ this.ownerElement = element;
+ this.isRtl = isRtl;
+ this.tools = tools;
+
+ /**
+ * @todo check on multiple instances
+ */
+ this.tooltip = new Tooltip();
+
+ document.addEventListener('ch', (event) => {
+ this.selectionChanged(event)
+ })
+
+ /**
+ * Allow to leaf buttons by arrows / tab
+ * Buttons will be filled on opening
+ */
+ this.enableFlipper();
+
+
+ if (created) {
+ return;
+ }
+
+ this.make();
+
+ document.addEventListener('selectionchange', (event: Event) => {
+ document.dispatchEvent(new CustomEvent('ch', {
+ detail: {
+ activeElement: document.activeElement,
+ },
+ }));
+ // this.selectionChanged(event, this.ownerElement);
+ }, true);
+
+ created = true;
+ }
+
+ /**
+ * Toggles read-only mode
+ *
+ * @param {boolean} readOnlyEnabled - read-only mode
+ */
+ public toggleReadOnly(readOnlyEnabled: boolean): void {
+ if (!readOnlyEnabled) {
+ this.make();
+ } else {
+ this.destroy();
+ /**
+ * @todo add ConversionToolbar support
+ */
+ // this.Editor.ConversionToolbar.destroy();
+ }
+ }
+
+ /**
+ * Moving / appearance
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+ /**
+ * Shows Inline Toolbar if something is selected
+ *
+ * @param [needToClose] - pass true to close toolbar if it is not allowed.
+ * Avoid to use it just for closing IT, better call .close() clearly.
+ * @param [needToShowConversionToolbar] - pass false to not to show Conversion Toolbar
+ */
+ public tryToShow(needToClose = false, needToShowConversionToolbar = true): void {
+ const allowedToShow = this.allowedToShow();
+
+ if (!allowedToShow) {
+ if (needToClose) {
+ this.close();
+ }
+
+ return;
+ }
+
+ this.move();
+ this.open();
+ /**
+ * @todo move it to onOpen callback
+ */
+ // this.Editor.Toolbar.close();
+ }
+
+ /**
+ * Move Toolbar to the selected text
+ */
+ public move(): void {
+ const selectionRect = SelectionUtils.rect as DOMRect;
+ const wrapperOffset = this.ownerElement.getBoundingClientRect();
+
+ const newCoords = {
+ x: selectionRect.x,
+ y: selectionRect.y +
+ selectionRect.height + // -
+ window.scrollY +
+ // wrapperOffset.top +
+ -100 + // tmp
+ this.toolbarVerticalMargin,
+ };
+
+ /**
+ * If we know selections width, place InlineToolbar to center
+ */
+ // if (selectionRect.width) {
+ // newCoords.x += Math.floor(selectionRect.width / 2);
+ // }
+ //
+ // /**
+ // * Inline Toolbar has -50% translateX, so we need to check real coords to prevent overflowing
+ // */
+ // const realLeftCoord = newCoords.x - this.width / 2;
+ // const realRightCoord = newCoords.x + this.width / 2;
+ //
+ // /**
+ // * By default, Inline Toolbar has top-corner at the center
+ // * We are adding a modifiers for to move corner to the left or right
+ // */
+ // nodes.wrapper.classList.toggle(
+ // this.CSS.inlineToolbarLeftOriented,
+ // realLeftCoord < this.editorContentRect.left
+ // );
+ //
+ // nodes.wrapper.classList.toggle(
+ // this.CSS.inlineToolbarRightOriented,
+ // realRightCoord > this.editorContentRect.right
+ // );
+
+ nodes.wrapper.style.left = Math.floor(newCoords.x) + 'px';
+ nodes.wrapper.style.top = Math.floor(newCoords.y) + 'px';
+ }
+
+ /**
+ * Hides Inline Toolbar
+ */
+ public close(): void {
+ if (!this.opened) {
+ return;
+ }
+
+ /**
+ * @todo check Readonly work
+ */
+ // if (this.Editor.ReadOnly.isEnabled) {
+ // return;
+ // }
+
+ nodes.wrapper.classList.remove(this.CSS.inlineToolbarShowed);
+ Array.from(this.toolsInstances.entries()).forEach(([name, toolInstance]) => {
+ const shortcut = this.getToolShortcut(name);
+
+ /**
+ * @todo check shortucts removing
+ */
+ if (shortcut) {
+ // Shortcuts.remove(this.Editor.UI.nodes.redactor, shortcut);
+ }
+
+ /**
+ * @todo replace 'clear' with 'destroy'
+ */
+ if (_.isFunction(toolInstance.clear)) {
+ toolInstance.clear();
+ }
+ });
+
+ this.opened = false;
+
+ this.flipper.deactivate();
+ /**
+ * @todo check
+ */
+ // this.Editor.ConversionToolbar.close();
+ }
+
+ /**
+ * Shows Inline Toolbar
+ */
+ public open(): void {
+ if (this.opened) {
+ return;
+ }
+ /**
+ * Filter inline-tools and show only allowed by Block's Tool
+ */
+ this.addToolsFiltered();
+
+ /**
+ * Show Inline Toolbar
+ */
+ nodes.wrapper.classList.add(this.CSS.inlineToolbarShowed);
+
+ this.buttonsList = nodes.buttons.querySelectorAll(`.${this.CSS.inlineToolButton}`);
+ this.opened = true;
+
+ /**
+ * @todo check ConversionToolbar
+ */
+ // if (needToShowConversionToolbar && this.Editor.ConversionToolbar.hasTools()) {
+ // /**
+ // * Change Conversion Dropdown content for current tool
+ // */
+ // this.setConversionTogglerContent();
+ // } else {
+ // /**
+ // * hide Conversion Dropdown with there are no tools
+ // */
+ // nodes.conversionToggler.hidden = true;
+ // }
+
+ /**
+ * Get currently visible buttons to pass it to the Flipper
+ */
+ let visibleTools = Array.from(this.buttonsList);
+
+ /**
+ * @todo ConversionToolbar
+ */
+ // visibleTools.unshift(nodes.conversionToggler);
+ visibleTools = visibleTools.filter((tool) => !(tool as HTMLElement).hidden);
+
+ this.flipper.activate(visibleTools as HTMLElement[]);
+ }
+
+ /**
+ * Check if node is contained by Inline Toolbar
+ *
+ * @param {Node} node — node to chcek
+ */
+ public containsNode(node: Node): boolean {
+ return nodes.wrapper.contains(node);
+ }
+
+ /**
+ * Removes UI and its components
+ */
+ public destroy(): void {
+ /**
+ * Sometimes (in read-only mode) there is no Flipper
+ */
+ if (this.flipper) {
+ this.flipper.deactivate();
+ this.flipper = null;
+ }
+
+ this.removeAllNodes();
+ this.tooltip.destroy();
+ }
+
+ /**
+ * Remove memorized nodes
+ */
+ public removeAllNodes(): void {
+ for (const key in nodes) {
+ const node = nodes[key];
+
+ if (node instanceof HTMLElement) {
+ node.remove();
+ }
+ }
+ }
+
+ private selectionChanged(event: Event): void {
+ const activeElement = event.detail.activeElement;
+ const ownerSelected = activeElement === this.ownerElement;
+ const ownerContainsSelection = this.ownerElement.contains(activeElement);
+
+ if (ownerSelected || ownerContainsSelection) {
+ this.tryToShow(true);
+ }
+ }
+
+ /**
+ * Making DOM
+ */
+ private make(): void {
+ if (nodes.wrapper) {
+ console.log('already created');
+
+ return;
+ }
+
+ nodes.wrapper = $.make('div', [
+ this.CSS.inlineToolbar,
+ /**
+ * @todo Add RTL fix
+ */
+ // ...(this.isRtl ? [ this.Editor.UI.CSS.editorRtlFix ] : []),
+ ]);
+ /**
+ * Creates a different wrapper for toggler and buttons.
+ */
+ nodes.togglerAndButtonsWrapper = $.make('div', this.CSS.togglerAndButtonsWrapper);
+ nodes.buttons = $.make('div', this.CSS.buttonsWrapper);
+ nodes.actions = $.make('div', this.CSS.actionsWrapper);
+
+ // To prevent reset of a selection when click on the wrapper
+ // @todo check this case
+ // this.listeners.on(nodes.wrapper, 'mousedown', (event) => {
+ // const isClickedOnActionsWrapper = (event.target as Element).closest(`.${this.CSS.actionsWrapper}`);
+ //
+ // // If click is on actions wrapper,
+ // // do not prevent default behaviour because actions might include interactive elements
+ // if (!isClickedOnActionsWrapper) {
+ // event.preventDefault();
+ // }
+ // });
+
+ /**
+ * Append the intermediary wrapper which contains toggler and buttons and button actions.
+ */
+ $.append(nodes.wrapper, [nodes.togglerAndButtonsWrapper, nodes.actions]);
+ /**
+ * Append the inline toolbar to the editor.
+ */
+ /**
+ * @todo check
+ */
+ // $.append(this.Editor.UI.nodes.wrapper, nodes.wrapper);
+ $.append(document.body, nodes.wrapper);
+
+ /**
+ * Wrapper for the inline tools
+ * Will be appended after the Conversion Toolbar toggler
+ */
+ $.append(nodes.togglerAndButtonsWrapper, nodes.buttons);
+
+ /**
+ * Recalculate initial width with all buttons
+ */
+ this.recalculateWidth();
+ }
+
+ /**
+ * Need to show Inline Toolbar or not
+ */
+ private allowedToShow(): boolean {
+ /**
+ * Tags conflicts with window.selection function.
+ * Ex. IMG tag returns null (Firefox) or Redactors wrapper (Chrome)
+ */
+ const tagsConflictsWithSelection = ['IMG', 'INPUT'];
+ const currentSelection = SelectionUtils.get();
+ const selectedText = SelectionUtils.text;
+
+ // old browsers
+ if (!currentSelection || !currentSelection.anchorNode) {
+ return false;
+ }
+
+ // empty selection
+ if (currentSelection.isCollapsed || selectedText.length < 1) {
+ return false;
+ }
+
+ const target = !$.isElement(currentSelection.anchorNode)
+ ? currentSelection.anchorNode.parentElement
+ : currentSelection.anchorNode;
+
+ if (currentSelection && tagsConflictsWithSelection.includes(target.tagName)) {
+ return false;
+ }
+
+ // is enabled by current Block's Tool
+
+ /**
+ * @todo check
+ */
+ // const currentBlock = this.Editor.BlockManager.getBlock(currentSelection.anchorNode as HTMLElement);
+ //
+ // if (!currentBlock) {
+ // return false;
+ // }
+
+ // return currentBlock.tool.inlineTools.size !== 0;
+
+ return true;
+ }
+
+ /**
+ * Recalculate inline toolbar width
+ */
+ private recalculateWidth(): void {
+ this.width = nodes.wrapper.offsetWidth;
+ }
+
+ /**
+ * Working with Tools
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+ /**
+ * Append only allowed Tools
+ */
+ private addToolsFiltered(): void {
+ const currentSelection = SelectionUtils.get();
+ // const currentBlock = this.Editor.BlockManager.getBlock(currentSelection.anchorNode as HTMLElement);
+
+ /**
+ * Clear buttons list
+ */
+ nodes.buttons.innerHTML = '';
+ nodes.actions.innerHTML = '';
+ this.toolsInstances = new Map();
+
+ Array.from(this.tools.values()).forEach(tool => {
+ this.addTool(tool);
+ });
+
+ /**
+ * Recalculate width because some buttons can be hidden
+ */
+ this.recalculateWidth();
+ }
+
+ /**
+ * Add tool button and activate clicks
+ *
+ * @param {InlineTool} tool - InlineTool object
+ */
+ private addTool(tool: InlineTool): void {
+ const instance = tool.create();
+ const button = instance.render();
+
+ if (!button) {
+ _.log('Render method must return an instance of Node', 'warn', tool.name);
+
+ return;
+ }
+
+ button.dataset.tool = tool.name;
+ nodes.buttons.appendChild(button);
+ this.toolsInstances.set(tool.name, instance);
+
+ if (_.isFunction(instance.renderActions)) {
+ const actions = instance.renderActions();
+
+ nodes.actions.appendChild(actions);
+ }
+
+ /**
+ * @todo check
+ */
+ // this.listeners.on(button, 'click', (event) => {
+ button.addEventListener('click', (event) => {
+ this.toolClicked(instance);
+ event.preventDefault();
+ });
+
+ const shortcut = this.getToolShortcut(tool.name);
+
+ if (shortcut) {
+ try {
+ this.enableShortcuts(instance, shortcut);
+ } catch (e) {}
+ }
+
+ /**
+ * Enable tooltip module on button
+ */
+ const tooltipContent = $.make('div');
+ const toolTitle = I18n.t(
+ I18nInternalNS.toolNames,
+ tool.title || _.capitalize(tool.name)
+ );
+
+ tooltipContent.appendChild($.text(toolTitle));
+
+ if (shortcut) {
+ tooltipContent.appendChild($.make('div', this.CSS.inlineToolbarShortcut, {
+ textContent: _.beautifyShortcut(shortcut),
+ }));
+ }
+
+ this.tooltip.onHover(button, tooltipContent, {
+ placement: 'top',
+ hidingDelay: 100,
+ });
+
+ instance.checkState(SelectionUtils.get());
+ }
+
+ /**
+ * Get shortcut name for tool
+ *
+ * @param toolName — Tool name
+ */
+ private getToolShortcut(toolName): string | void {
+ /**
+ * Enable shortcuts
+ * Ignore tool that doesn't have shortcut or empty string
+ */
+ const tool = this.tools.get(toolName);
+
+ /**
+ * @todo check
+ */
+ // /**
+ // * 1) For internal tools, check public getter 'shortcut'
+ // * 2) For external tools, check tool's settings
+ // * 3) If shortcut is not set in settings, check Tool's public property
+ // */
+ // const internalTools = Tools.internal.inlineTools;
+ //
+ // if (Array.from(internalTools.keys()).includes(toolName)) {
+ // return this.inlineTools[toolName][CommonInternalSettings.Shortcut];
+ // }
+
+ return tool.shortcut;
+ }
+
+ /**
+ * Enable Tool shortcut with Editor Shortcuts Module
+ *
+ * @param {InlineTool} tool - Tool instance
+ * @param {string} shortcut - shortcut according to the ShortcutData Module format
+ */
+ private enableShortcuts(tool: IInlineTool, shortcut: string): void {
+ Shortcuts.add({
+ name: shortcut,
+ handler: (event) => {
+ /**
+ * @todo check
+ */
+ // const { currentBlock } = this.Editor.BlockManager;
+ //
+ // /**
+ // * Editor is not focused
+ // */
+ // if (!currentBlock) {
+ // return;
+ // }
+
+ /**
+ * @todo check
+ */
+ // if (!currentBlock.tool.enabledInlineTools) {
+ // return;
+ // }
+
+ event.preventDefault();
+ this.toolClicked(tool);
+ },
+ /**
+ * @todo check
+ */
+ on: this.ownerElement as HTMLElement,
+ // on: this.Editor.UI.nodes.redactor,
+ });
+ }
+
+ /**
+ * Inline Tool button clicks
+ *
+ * @param {InlineTool} tool - Tool's instance
+ */
+ private toolClicked(tool: IInlineTool): void {
+ const range = SelectionUtils.range;
+
+ tool.surround(range);
+ this.checkToolsState();
+ }
+
+ /**
+ * Check Tools` state by selection
+ */
+ private checkToolsState(): void {
+ this.toolsInstances.forEach((toolInstance) => {
+ toolInstance.checkState(SelectionUtils.get());
+ });
+ }
+
+ /**
+ * Get inline tools tools
+ * Tools that has isInline is true
+ */
+ private get inlineTools(): { [name: string]: IInlineTool } {
+ const result = {};
+
+ Array
+ .from(this.tools.entries())
+ .forEach(([name, tool]) => {
+ result[name] = tool.create();
+ });
+
+ return result;
+ }
+
+ /**
+ * Allow to leaf buttons by arrows / tab
+ * Buttons will be filled on opening
+ */
+ private enableFlipper(): void {
+ this.flipper = new Flipper({
+ focusedItemClass: this.CSS.focusedButton,
+ allowArrows: false,
+ });
+ }
+}
diff --git a/types/api/inline-toolbar.d.ts b/types/api/inline-toolbar.d.ts
index 5b49db54..aad3d95b 100644
--- a/types/api/inline-toolbar.d.ts
+++ b/types/api/inline-toolbar.d.ts
@@ -6,10 +6,11 @@ export interface InlineToolbar {
* Closes InlineToolbar
*/
close(): void;
-
+
/**
* Opens InlineToolbar
*/
open(): void;
+
+ bind(element, tools): void;
}
-
\ No newline at end of file