diff --git a/src/components/flipper.ts b/src/components/flipper.ts index a97216a6..b770a871 100644 --- a/src/components/flipper.ts +++ b/src/components/flipper.ts @@ -120,15 +120,6 @@ export default class Flipper { document.removeEventListener('keydown', this.onKeyDown); } - /** - * Return current focused button - * - * @returns {HTMLElement|null} - */ - public get currentItem(): HTMLElement|null { - return this.iterator.currentItem; - } - /** * Focus first item */ @@ -142,6 +133,7 @@ export default class Flipper { */ public flipLeft(): void { this.iterator.previous(); + this.flipCallback(); } /** @@ -149,6 +141,14 @@ export default class Flipper { */ public flipRight(): void { this.iterator.next(); + this.flipCallback(); + } + + /** + * Return true if some button is focused + */ + public hasFocus(): boolean { + return !!this.iterator.currentItem; } /** @@ -266,4 +266,15 @@ export default class Flipper { event.preventDefault(); event.stopPropagation(); } + + /** + * Fired after flipping in any direction + */ + private flipCallback(): void { + if (this.iterator.currentItem) { + // eslint-disable-next-line @typescript-eslint/ban-ts-ignore + // @ts-ignore + this.iterator.currentItem.scrollIntoViewIfNeeded(); + } + } } diff --git a/src/components/modules/blockManager.ts b/src/components/modules/blockManager.ts index 9ac893bc..098f5aee 100644 --- a/src/components/modules/blockManager.ts +++ b/src/components/modules/blockManager.ts @@ -309,6 +309,10 @@ export default class BlockManager extends Module { }); } + /** + * @todo emit beforeInsert + */ + this._blocks.insert(newIndex, block, replace); /** diff --git a/src/components/modules/toolbar/index.ts b/src/components/modules/toolbar/index.ts index d60ffea1..150ceeb4 100644 --- a/src/components/modules/toolbar/index.ts +++ b/src/components/modules/toolbar/index.ts @@ -182,7 +182,7 @@ export default class Toolbar extends Module { close: () => void; open: () => void; toggle: () => void; - flipperHasFocus: boolean; + hasFocus: () => boolean; } { return { opened: this.toolboxInstance.opened, @@ -196,7 +196,7 @@ export default class Toolbar extends Module { this.toolboxInstance.open(); }, toggle: (): void => this.toolboxInstance.toggle(), - flipperHasFocus: this.toolboxInstance.flipperHasFocus, + hasFocus: (): boolean => this.toolboxInstance.hasFocus(), }; } diff --git a/src/components/modules/ui.ts b/src/components/modules/ui.ts index aecd6de5..788e2d44 100644 --- a/src/components/modules/ui.ts +++ b/src/components/modules/ui.ts @@ -231,7 +231,7 @@ export default class UI extends Module { * Toolbar has internal module (Toolbox) that has own Flipper, * so we check it manually */ - if (this.Editor.Toolbar.toolbox.flipperHasFocus) { + if (this.Editor.Toolbar.toolbox.hasFocus()) { return true; } @@ -239,7 +239,7 @@ export default class UI extends Module { return moduleClass.flipper instanceof Flipper; }) .some(([moduleName, moduleClass]) => { - return moduleClass.flipper.currentItem; + return moduleClass.flipper.hasFocus(); }); } diff --git a/src/components/polyfills.ts b/src/components/polyfills.ts index cfa9af74..beceff9b 100644 --- a/src/components/polyfills.ts +++ b/src/components/polyfills.ts @@ -96,3 +96,40 @@ if (!Element.prototype.prepend) { this.insertBefore(docFrag, this.firstChild); }; } + +/** + * ScrollIntoViewIfNeeded polyfill by KilianSSL (forked from hsablonniere) + * + * @see {@link https://gist.github.com/KilianSSL/774297b76378566588f02538631c3137} + */ +// eslint-disable-next-line @typescript-eslint/ban-ts-ignore +// @ts-ignore +if (!Element.prototype.scrollIntoViewIfNeeded) { + // eslint-disable-next-line @typescript-eslint/ban-ts-ignore + // @ts-ignore + Element.prototype.scrollIntoViewIfNeeded = function (centerIfNeeded): void { + centerIfNeeded = arguments.length === 0 ? true : !!centerIfNeeded; + + const parent = this.parentNode, + parentComputedStyle = window.getComputedStyle(parent, null), + parentBorderTopWidth = parseInt(parentComputedStyle.getPropertyValue('border-top-width')), + parentBorderLeftWidth = parseInt(parentComputedStyle.getPropertyValue('border-left-width')), + overTop = this.offsetTop - parent.offsetTop < parent.scrollTop, + overBottom = (this.offsetTop - parent.offsetTop + this.clientHeight - parentBorderTopWidth) > (parent.scrollTop + parent.clientHeight), + overLeft = this.offsetLeft - parent.offsetLeft < parent.scrollLeft, + overRight = (this.offsetLeft - parent.offsetLeft + this.clientWidth - parentBorderLeftWidth) > (parent.scrollLeft + parent.clientWidth), + alignWithTop = overTop && !overBottom; + + if ((overTop || overBottom) && centerIfNeeded) { + parent.scrollTop = this.offsetTop - parent.offsetTop - parent.clientHeight / 2 - parentBorderTopWidth + this.clientHeight / 2; + } + + if ((overLeft || overRight) && centerIfNeeded) { + parent.scrollLeft = this.offsetLeft - parent.offsetLeft - parent.clientWidth / 2 - parentBorderLeftWidth + this.clientWidth / 2; + } + + if ((overTop || overBottom || overLeft || overRight) && !centerIfNeeded) { + this.scrollIntoView(alignWithTop); + } + }; +} diff --git a/src/components/ui/toolbox.ts b/src/components/ui/toolbox.ts index 2c813caf..ae345a0a 100644 --- a/src/components/ui/toolbox.ts +++ b/src/components/ui/toolbox.ts @@ -1,15 +1,20 @@ -import $ from '../dom'; import * as _ from '../utils'; -import Flipper from '../flipper'; import { BlockToolAPI } from '../block'; -import I18n from '../i18n'; -import { I18nInternalNS } from '../i18n/namespace-internal'; import Shortcuts from '../utils/shortcuts'; -import Tooltip from '../utils/tooltip'; import BlockTool from '../tools/block'; import ToolsCollection from '../tools/collection'; import { API } from '../../../types'; import EventsDispatcher from '../utils/events'; +import Popover from '../utils/popover'; + +/** + * @todo check small tools number — there should not be a scroll + * @todo add search in popover + * @todo hide toolbar after some toolbox item clicked (and the new block inserted) + * @todo do not show Block Tunes Toggler near only-one block + * @todo Plus Button should be appeared near all blocks (even non-empty) + * @todo the first Tab on the Block — focus Plus Button, the second — focus Block Tunes Toggler, the third — focus next Block + */ /** * Event that can be triggered by the Toolbox @@ -45,7 +50,7 @@ export default class Toolbox extends EventsDispatcher { * @returns {boolean} */ public get isEmpty(): boolean { - return this.displayedToolsCount === 0; + return this.toolsToBeDisplayed.length === 0; } /** @@ -60,6 +65,11 @@ export default class Toolbox extends EventsDispatcher { */ private api: API; + /** + * Popover instance. There is a util for vertical lists. + */ + private popover: Popover; + /** * List of Tools available. Some of them will be shown in the Toolbox */ @@ -70,11 +80,9 @@ export default class Toolbox extends EventsDispatcher { */ private nodes: { toolbox: HTMLElement; - buttons: HTMLElement[]; } = { toolbox: null, - buttons: [], - } + }; /** * CSS styles @@ -84,34 +92,9 @@ export default class Toolbox extends EventsDispatcher { private static get CSS(): { [name: string]: string } { return { toolbox: 'ce-toolbox', - toolboxButton: 'ce-toolbox__button', - toolboxButtonActive: 'ce-toolbox__button--active', - toolboxOpened: 'ce-toolbox--opened', - - buttonTooltip: 'ce-toolbox-button-tooltip', - buttonShortcut: 'ce-toolbox-button-tooltip__shortcut', }; } - /** - * How many tools displayed in Toolbox - * - * @type {number} - */ - private displayedToolsCount = 0; - - /** - * Instance of class that responses for leafing buttons by arrows/tab - * - * @type {Flipper|null} - */ - private flipper: Flipper = null; - - /** - * Tooltip utility Instance - */ - private tooltip: Tooltip; - /** * Id of listener added used to remove it on destroy() */ @@ -129,62 +112,65 @@ export default class Toolbox extends EventsDispatcher { this.api = api; this.tools = tools; - - this.tooltip = new Tooltip(); - } - - /** - * Returns true if the Toolbox has the Flipper activated and the Flipper has selected button - */ - public get flipperHasFocus(): boolean { - return this.flipper && this.flipper.currentItem !== null; } /** * Makes the Toolbox */ public make(): Element { - this.nodes.toolbox = $.make('div', Toolbox.CSS.toolbox); + this.popover = new Popover({ + className: Toolbox.CSS.toolbox, + items: this.toolsToBeDisplayed.map(tool => { + return { + icon: tool.toolbox.icon, + label: tool.toolbox.title, + onClick: (item): void => { + this.toolButtonActivated(tool.name); + }, + secondaryLabel: tool.shortcut ? _.beautifyShortcut(tool.shortcut) : '', + }; + }), + }); - this.addTools(); - this.enableFlipper(); + /** + * Enable tools shortcuts + */ + this.enableShortcuts(); + + this.nodes.toolbox = this.popover.getElement(); return this.nodes.toolbox; } + /** + * Returns true if the Toolbox has the Flipper activated and the Flipper has selected button + */ + public hasFocus(): boolean { + return this.popover.hasFocus(); + } + /** * Destroy Module */ public destroy(): void { super.destroy(); - /** - * Sometimes (in read-only mode) there is no Flipper - */ - if (this.flipper) { - this.flipper.deactivate(); - this.flipper = null; - } - if (this.nodes && this.nodes.toolbox) { this.nodes.toolbox.remove(); this.nodes.toolbox = null; - this.nodes.buttons = []; } this.api.listeners.offById(this.clickListenerId); this.removeAllShortcuts(); - this.tooltip.destroy(); } /** * Toolbox Tool's button click handler * - * @param {MouseEvent|KeyboardEvent} event - event that activates toolbox button - * @param {string} toolName - button to activate + * @param toolName - tool type to be activated */ - public toolButtonActivate(event: MouseEvent|KeyboardEvent, toolName: string): void { + public toolButtonActivated(toolName: string): void { this.insertNewBlock(toolName); } @@ -196,24 +182,20 @@ export default class Toolbox extends EventsDispatcher { return; } - this.emit(ToolboxEvent.Opened); - - this.nodes.toolbox.classList.add(Toolbox.CSS.toolboxOpened); + this.popover.show(); this.opened = true; - this.flipper.activate(); + this.emit(ToolboxEvent.Opened); } /** * Close Toolbox */ public close(): void { - this.emit(ToolboxEvent.Closed); - - this.nodes.toolbox.classList.remove(Toolbox.CSS.toolboxOpened); + this.popover.hide(); this.opened = false; - this.flipper.deactivate(); + this.emit(ToolboxEvent.Closed); } /** @@ -228,106 +210,43 @@ export default class Toolbox extends EventsDispatcher { } /** - * Iterates available tools and appends them to the Toolbox + * Returns list of tools that enables the Toolbox (by specifying the 'toolbox' getter) */ - private addTools(): void { - Array + @_.cacheable + private get toolsToBeDisplayed(): BlockTool[] { + return Array .from(this.tools.values()) - .forEach((tool) => this.addTool(tool)); + .filter(tool => { + const toolToolboxSettings = tool.toolbox; + + /** + * Skip tools that don't pass 'toolbox' property + */ + if (!toolToolboxSettings) { + return false; + } + + if (toolToolboxSettings && !toolToolboxSettings.icon) { + _.log('Toolbar icon is missed. Tool %o skipped', 'warn', tool.name); + + return false; + } + + return true; + }); } /** - * Append Tool to the Toolbox - * - * @param {BlockToolConstructable} tool - BlockTool object + * Iterate all tools and enable theirs shortcuts if specified */ - private addTool(tool: BlockTool): void { - const toolToolboxSettings = tool.toolbox; + private enableShortcuts(): void { + this.toolsToBeDisplayed.forEach((tool: BlockTool) => { + const shortcut = tool.shortcut; - /** - * Skip tools that don't pass 'toolbox' property - */ - if (!toolToolboxSettings) { - return; - } - - if (toolToolboxSettings && !toolToolboxSettings.icon) { - _.log('Toolbar icon is missed. Tool %o skipped', 'warn', tool.name); - - return; - } - - /** - * @todo Add checkup for the render method - */ - // if (typeof tool.render !== 'function') { - // _.log('render method missed. Tool %o skipped', 'warn', tool); - // return; - // } - - const button = $.make('li', [ Toolbox.CSS.toolboxButton ]); - - button.dataset.tool = tool.name; - button.innerHTML = toolToolboxSettings.icon; - - $.append(this.nodes.toolbox, button); - - this.nodes.toolbox.appendChild(button); - this.nodes.buttons.push(button); - - /** - * Add click listener - */ - this.clickListenerId = this.api.listeners.on(button, 'click', (event: KeyboardEvent|MouseEvent) => { - this.toolButtonActivate(event, tool.name); + if (shortcut) { + this.enableShortcutForTool(tool.name, shortcut); + } }); - - /** - * Add listeners to show/hide toolbox tooltip - */ - const tooltipContent = this.drawTooltip(tool); - - this.tooltip.onHover(button, tooltipContent, { - placement: 'bottom', - hidingDelay: 200, - }); - - const shortcut = tool.shortcut; - - if (shortcut) { - this.enableShortcut(tool.name, shortcut); - } - - /** Increment Tools count */ - this.displayedToolsCount++; - } - - /** - * Draw tooltip for toolbox tools - * - * @param tool - BlockTool object - * @returns {HTMLElement} - */ - private drawTooltip(tool: BlockTool): HTMLElement { - const toolboxSettings = tool.toolbox || {}; - const name = I18n.t(I18nInternalNS.toolNames, toolboxSettings.title || tool.name); - - let shortcut = tool.shortcut; - - const tooltip = $.make('div', Toolbox.CSS.buttonTooltip); - const hint = document.createTextNode(_.capitalize(name)); - - tooltip.appendChild(hint); - - if (shortcut) { - shortcut = _.beautifyShortcut(shortcut); - - tooltip.appendChild($.make('div', Toolbox.CSS.buttonShortcut, { - textContent: shortcut, - })); - } - - return tooltip; } /** @@ -336,7 +255,7 @@ export default class Toolbox extends EventsDispatcher { * @param {string} toolName - Tool name * @param {string} shortcut - shortcut according to the ShortcutData Module format */ - private enableShortcut(toolName: string, shortcut: string): void { + private enableShortcutForTool(toolName: string, shortcut: string): void { Shortcuts.add({ name: shortcut, on: this.api.ui.nodes.redactor, @@ -352,26 +271,12 @@ export default class Toolbox extends EventsDispatcher { * Fired when the Read-Only mode is activated */ private removeAllShortcuts(): void { - Array - .from(this.tools.values()) - .forEach((tool) => { - const shortcut = tool.shortcut; + this.toolsToBeDisplayed.forEach((tool: BlockTool) => { + const shortcut = tool.shortcut; - if (shortcut) { - Shortcuts.remove(this.api.ui.nodes.redactor, shortcut); - } - }); - } - - /** - * Creates Flipper instance to be able to leaf tools - */ - private enableFlipper(): void { - const tools = Array.from(this.nodes.toolbox.childNodes) as HTMLElement[]; - - this.flipper = new Flipper({ - items: tools, - focusedItemClass: Toolbox.CSS.toolboxButtonActive, + if (shortcut) { + Shortcuts.remove(this.api.ui.nodes.redactor, shortcut); + } }); } diff --git a/src/components/utils/popover.ts b/src/components/utils/popover.ts new file mode 100644 index 00000000..9f6587a7 --- /dev/null +++ b/src/components/utils/popover.ts @@ -0,0 +1,212 @@ +import Dom from '../dom'; +import Listeners from './listeners'; +import Flipper from '../flipper'; + +/** + * Describe parameters for rendering the single item of Popover + */ +export interface PopoverItem { + /** + * Item icon to be appeared near a title + */ + icon: string; + + /** + * Displayed text + */ + label: string; + + /** + * Additional displayed text + */ + secondaryLabel?: string; + + /** + * Itm click handler + * + * @param item - clicked item + */ + onClick: (item: PopoverItem) => void; +} + +/** + * Popover is the UI element for displaying vertical lists + */ +export default class Popover { + /** + * Items list to be displayed + */ + private readonly items: PopoverItem[]; + + /** + * Created nodes + */ + private nodes: { + wrapper: HTMLElement; + } = { + wrapper: null, + } + + /** + * Additional wrapper's class name + */ + private readonly className: string; + + /** + * Listeners util instance + */ + private listeners: Listeners; + + /** + * Flipper - module for keyboard iteration between elements + */ + private flipper: Flipper; + + /** + * Style classes + */ + private static get CSS(): { + popover: string; + popoverOpened: string; + item: string; + itemFocused: string; + itemLabel: string; + itemIcon: string; + itemSecondaryLabel: string; + } { + return { + popover: 'ce-popover', + popoverOpened: 'ce-popover--opened', + item: 'ce-popover__item', + itemFocused: 'ce-popover__item--focused', + itemLabel: 'ce-popover__item-label', + itemIcon: 'ce-popover__item-icon', + itemSecondaryLabel: 'ce-popover__item-secondary-label', + }; + } + + /** + * Creates the Popover + * + * @param options - config + * @param options.items - config for items to be displayed + * @param options.className - additional class name to be added to the popover wrapper + */ + constructor({ items, className }: {items: PopoverItem[]; className?: string}) { + this.items = items; + this.className = className || ''; + this.listeners = new Listeners(); + + this.render(); + this.enableFlipper(); + } + + /** + * Returns rendered wrapper + */ + public getElement(): HTMLElement { + return this.nodes.wrapper; + } + + /** + * Shows the Popover + */ + public show(): void { + this.nodes.wrapper.classList.add(Popover.CSS.popoverOpened); + this.flipper.activate(); + } + + /** + * Hides the Popover + */ + public hide(): void { + this.nodes.wrapper.classList.remove(Popover.CSS.popoverOpened); + this.flipper.deactivate(); + } + + /** + * Clears memory + */ + public destroy(): void { + this.listeners.removeAll(); + } + + /** + * Returns true if some item is focused + */ + public hasFocus(): boolean { + return this.flipper.hasFocus(); + } + + /** + * Makes the UI + */ + private render(): void { + this.nodes.wrapper = Dom.make('div', [Popover.CSS.popover, this.className]); + + this.items.forEach(item => { + this.nodes.wrapper.appendChild(this.createItem(item)); + }); + + this.listeners.on(this.nodes.wrapper, 'click', (event: KeyboardEvent|MouseEvent) => { + const clickedItem = (event.target as HTMLElement).closest(`.${Popover.CSS.item}`) as HTMLElement; + + if (clickedItem) { + this.itemClicked(clickedItem); + } + }); + } + + /** + * Renders the single item + * + * @param item - item data to be rendered + */ + private createItem(item: PopoverItem): HTMLElement { + const el = Dom.make('div', Popover.CSS.item); + const label = Dom.make('div', Popover.CSS.itemLabel, { + innerHTML: item.label, + }); + + if (item.icon) { + el.appendChild(Dom.make('div', Popover.CSS.itemIcon, { + innerHTML: item.icon, + })); + } + + el.appendChild(label); + + if (item.secondaryLabel) { + el.appendChild(Dom.make('div', Popover.CSS.itemSecondaryLabel, { + innerHTML: item.secondaryLabel, + })); + } + + return el; + } + + /** + * Item click handler + * + * @param itemEl - clicked item + */ + private itemClicked(itemEl: HTMLElement): void { + const allItems = this.nodes.wrapper.querySelectorAll(`.${Popover.CSS.item}`); + const itemIndex = Array.from(allItems).indexOf(itemEl); + const clickedItem = this.items[itemIndex]; + + clickedItem.onClick(clickedItem); + } + + /** + * Creates Flipper instance to be able to leaf tools + */ + private enableFlipper(): void { + const tools = Array.from(this.nodes.wrapper.querySelectorAll(`.${Popover.CSS.item}`)) as HTMLElement[]; + + this.flipper = new Flipper({ + items: tools, + focusedItemClass: Popover.CSS.itemFocused, + }); + } +} diff --git a/src/styles/block.css b/src/styles/block.css index 55bbc142..a131abe1 100644 --- a/src/styles/block.css +++ b/src/styles/block.css @@ -1,4 +1,16 @@ +@keyframes fade-in { + from { + opacity: 0; + } + + to { + opacity: 1; + } +} + .ce-block { + animation: fade-in 300ms ease forwards; + &:first-of-type { margin-top: 0; } diff --git a/src/styles/main.css b/src/styles/main.css index 94fa26bd..00f379ec 100644 --- a/src/styles/main.css +++ b/src/styles/main.css @@ -10,3 +10,4 @@ @import './export.css'; @import './stub.css'; @import './rtl.css'; +@import './popover.css'; diff --git a/src/styles/popover.css b/src/styles/popover.css new file mode 100644 index 00000000..50a22ed3 --- /dev/null +++ b/src/styles/popover.css @@ -0,0 +1,74 @@ +.ce-popover { + position: absolute; + visibility: hidden; + transition: opacity 100ms ease; + will-change: opacity; + display: flex; + flex-direction: column; + padding: 4px; + min-width: 180px; + max-height: 284px; + overflow-y: auto; + box-sizing: border-box; + flex-shrink: 0; + overscroll-behavior: contain; + + @apply --overlay-pane; + + flex-wrap: nowrap; + + &--opened { + visibility: visible; + } + + &::-webkit-scrollbar { + width: 7px; + } + + &::-webkit-scrollbar-thumb { + box-sizing: border-box; + box-shadow: inset 0 0 2px 2px var(--bg-light); + border: 3px solid transparent; + border-left-width: 0px; + border-top-width: 4px; + border-bottom-width: 4px; + } + + &__item { + @apply --popover-button; + flex-basis: 100%; + flex-shrink: 0; + + &--focused { + @apply --button-focused; + } + + + &-icon { + @apply --tool-icon; + flex-shrink: 0; + } + + &-label { + flex-shrink: 0; + + &::after { + content: ''; + width: 25px; + display: inline-block; + } + } + + &-secondary-label { + color: var(--grayText); + font-size: 12px; + margin-left: auto; + white-space: nowrap; + letter-spacing: -0.1em; + padding-right: 5px; + margin-bottom: -2px; + flex-shrink: 0; + opacity: 0.6; + } + } +} diff --git a/src/styles/toolbox.css b/src/styles/toolbox.css index c02c5937..b0c8c154 100644 --- a/src/styles/toolbox.css +++ b/src/styles/toolbox.css @@ -1,44 +1,2 @@ .ce-toolbox { - position: absolute; - visibility: hidden; - transition: opacity 100ms ease; - will-change: opacity; - display: flex; - flex-direction: row; - - @media (--mobile){ - position: static; - transform: none !important; - align-items: center; - overflow-x: auto; - } - - &--opened { - opacity: 1; - visibility: visible; - } - - &__button { - @apply --toolbox-button; - flex-shrink: 0; - margin-left: 5px; - } -} - -.ce-toolbox-button-tooltip { - &__shortcut { - opacity: 0.6; - word-spacing: -3px; - margin-top: 3px; - } -} - -/** - * Styles for Narrow mode - */ -.codex-editor--narrow .ce-toolbox { - @media (--not-mobile) { - background: #fff; - z-index: 2; - } } diff --git a/src/styles/variables.css b/src/styles/variables.css index d8528ea6..45d1f94a 100644 --- a/src/styles/variables.css +++ b/src/styles/variables.css @@ -21,7 +21,7 @@ /** * Gray icons hover */ - --color-dark: #1D202B; + --color-dark: #1D202B; /** * Blue icons @@ -95,6 +95,11 @@ } }; + --button-focused: { + box-shadow: inset 0 0 0px 1px rgba(7, 161, 227, 0.08); + background: rgba(34, 186, 255, 0.08) !important; + }; + /** * Styles for Toolbox Buttons and Plus Button */ @@ -103,7 +108,7 @@ cursor: pointer; width: var(--toolbox-buttons-size); height: var(--toolbox-buttons-size); - border-radius: 3px; + border-radius: 7px; display: inline-flex; justify-content: center; align-items: center; @@ -155,8 +160,7 @@ } &--focused { - box-shadow: inset 0 0 0px 1px rgba(7, 161, 227, 0.08); - background: rgba(34, 186, 255, 0.08) !important; + @apply --button-focused; &-animated { animation-name: buttonClicked; @@ -164,5 +168,49 @@ } } }; + + /** + * Element of the Toolbox. Has icon and label + */ + --popover-button: { + display: flex; + padding: 4px; + font-size: 14px; + line-height: 20px; + font-weight: 500; + cursor: pointer; + align-items: center; + border-radius: 7px; + + &:not(:last-of-type){ + margin-bottom: 1px; + } + + &:hover { + background-color: var(--bg-light); + } + }; + + /** + * Tool icon with border + */ + --tool-icon: { + display: inline-flex; + width: 26px; + height: 26px; + border: 1px solid var(--color-gray-border); + border-radius: 5px; + align-items: center; + justify-content: center; + background: #fff; + box-sizing: border-box; + flex-shrink: 0; + margin-right: 10px; + + svg { + width: 12px; + height: 12px; + } + } } diff --git a/src/tools/paragraph b/src/tools/paragraph index 4b193c33..21cbdea6 160000 --- a/src/tools/paragraph +++ b/src/tools/paragraph @@ -1 +1 @@ -Subproject commit 4b193c33c3efe00ffc13b16839cffb5e339df526 +Subproject commit 21cbdea6e5e61094b046f47e8cb423a817cec3ed