UNPKG

js-draw

Version:

Draw pictures using a pen, touchscreen, or mouse! JS-draw is a drawing library for JavaScript and TypeScript.

202 lines (201 loc) 7.53 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.makeDropdownToolbar = void 0; const OverflowWidget_1 = __importDefault(require("./widgets/OverflowWidget")); const AbstractToolbar_1 = __importDefault(require("./AbstractToolbar")); const constants_1 = require("./constants"); /** * @example * * ```ts,runnable * import { makeDropdownToolbar, Editor } from 'js-draw'; * * const editor = new Editor(document.body); * const toolbar = makeDropdownToolbar(editor); * toolbar.addDefaults(); * * toolbar.addExitButton(editor => { * // TODO * }); * * toolbar.addSaveButton(editor => { * // TODO * }); * ``` * * Returns a subclass of {@link AbstractToolbar}. * * @see * - {@link makeEdgeToolbar} * - {@link AbstractToolbar.addSaveButton} * - {@link AbstractToolbar.addExitButton} */ const makeDropdownToolbar = (editor) => { return new DropdownToolbar(editor, editor.getRootElement(), editor.localization); }; exports.makeDropdownToolbar = makeDropdownToolbar; class DropdownToolbar extends AbstractToolbar_1.default { /** @internal */ constructor(editor, parent, localizationTable) { super(editor, localizationTable); // Flex-order of the next widget to be added. this.widgetOrderCounter = 0; // Widget to toggle overflow menu. this.overflowWidget = null; this.reLayoutQueued = false; this.container = document.createElement('div'); this.container.classList.add(`${constants_1.toolbarCSSPrefix}root`); this.container.classList.add(`${constants_1.toolbarCSSPrefix}element`); this.container.classList.add(`${constants_1.toolbarCSSPrefix}dropdown-toolbar`); this.container.setAttribute('role', 'toolbar'); parent.appendChild(this.container); if ('ResizeObserver' in window) { this.resizeObserver = new ResizeObserver((_entries) => { this.reLayout(); }); this.resizeObserver.observe(this.container); } else { console.warn('ResizeObserver not supported. Toolbar will not resize.'); } } queueReLayout() { if (!this.reLayoutQueued) { this.reLayoutQueued = true; requestAnimationFrame(() => this.reLayout()); } } reLayout() { this.reLayoutQueued = false; if (!this.overflowWidget) { return; } const getTotalWidth = (widgetList) => { let totalWidth = 0; for (const widget of widgetList) { if (!widget.isHidden()) { totalWidth += widget.getButtonWidth(); } } return totalWidth; }; // Returns true if there is enough empty space to move the first child // from the overflow menu to the main menu. const canRemoveFirstChildFromOverflow = (freeSpaceInMainMenu) => { const overflowChildren = this.overflowWidget?.getChildWidgets() ?? []; if (overflowChildren.length === 0) { return false; } return overflowChildren[0].getButtonWidth() <= freeSpaceInMainMenu; }; const allWidgets = this.getAllWidgets(); let overflowWidgetsWidth = getTotalWidth(this.overflowWidget.getChildWidgets()); let shownWidgetWidth = getTotalWidth(allWidgets) - overflowWidgetsWidth; let availableWidth = this.container.clientWidth * 0.87; // If on a device that has enough vertical space, allow // showing two rows of buttons. // TODO: Fix magic numbers if (window.innerHeight > availableWidth * 1.75) { availableWidth *= 1.75; } let updatedChildren = false; // If we can remove at least one child from the overflow menu, if (canRemoveFirstChildFromOverflow(availableWidth - shownWidgetWidth)) { // Move widgets to the main menu. const overflowChildren = this.overflowWidget.clearChildren(); for (const child of overflowChildren) { child.addTo(this.container); child.setIsToplevel(true); if (!child.isHidden()) { shownWidgetWidth += child.getButtonWidth(); } } overflowWidgetsWidth = 0; updatedChildren = true; } if (shownWidgetWidth >= availableWidth) { // Move widgets to the overflow menu. // Start with the rightmost widget, move to the leftmost for (let i = allWidgets.length - 1; i >= 0 && shownWidgetWidth >= availableWidth; i--) { const child = allWidgets[i]; if (this.overflowWidget.hasAsChild(child)) { continue; } if (child.canBeInOverflowMenu()) { shownWidgetWidth -= child.getButtonWidth(); this.overflowWidget.addToOverflow(child); } } updatedChildren = true; } // Hide/show the overflow widget. this.overflowWidget.setHidden(this.overflowWidget.getChildWidgets().length === 0); if (updatedChildren) { this.setupColorPickers(); } } addWidgetInternal(widget) { const container = widget.addTo(this.container); // Ensure that the widget gets displayed in the correct // place in the toolbar, even if it's removed and re-added. container.style.order = `${this.widgetOrderCounter++}`; this.queueReLayout(); } removeWidgetInternal(widget) { widget.remove(); this.queueReLayout(); } addSpacer(options = {}) { const spacer = document.createElement('div'); spacer.classList.add(`${constants_1.toolbarCSSPrefix}spacer`); if (options.grow) { spacer.style.flexGrow = `${options.grow}`; } if (options.minSize) { spacer.style.minWidth = options.minSize; } if (options.maxSize) { spacer.style.maxWidth = options.maxSize; } spacer.style.order = `${this.widgetOrderCounter++}`; this.container.appendChild(spacer); } /** * Adds a widget that toggles the overflow menu. Call `addOverflowWidget` to ensure * that this widget is in the correct space (if shown). * * @example * ```ts * toolbar.addDefaultToolWidgets(); * toolbar.addOverflowWidget(); * toolbar.addDefaultActionButtons(); * ``` * shows the overflow widget between the default tool widgets and the default action buttons, * if shown. */ addOverflowWidget() { this.overflowWidget = new OverflowWidget_1.default(this.editor, this.localizationTable); this.addWidget(this.overflowWidget); } /** * Adds both the default tool widgets and action buttons. Equivalent to * ```ts * toolbar.addDefaultToolWidgets(); * toolbar.addOverflowWidget(); * toolbar.addDefaultActionButtons(); * ``` */ addDefaults() { this.addDefaultToolWidgets(); this.addOverflowWidget(); this.addDefaultActionButtons(); } onRemove() { this.container.remove(); this.resizeObserver.disconnect(); } } exports.default = DropdownToolbar;