UNPKG

@bokeh/bokehjs

Version:

Interactive, novel data visualization

118 lines 3.8 kB
import { AbstractButton, AbstractButtonView } from "./abstract_button"; import { ButtonClick, MenuItemClick } from "../../core/bokeh_events"; import { div } from "../../core/dom"; import { isString } from "../../core/util/types"; import { execute } from "../../core/util/callbacks"; import * as buttons from "../../styles/buttons.css"; import dropdown_css from "../../styles/dropdown.css"; import carets_css, * as carets from "../../styles/caret.css"; import { DividerItem, Menu, MenuItem } from "../ui/menus"; import { build_view } from "../../core/build_views"; export class DropdownView extends AbstractButtonView { static __name__ = "DropdownView"; _open = false; menu; stylesheets() { return [...super.stylesheets(), dropdown_css, carets_css]; } async lazy_initialize() { await super.lazy_initialize(); await this._build_menu(); } connect_signals() { super.connect_signals(); const { menu } = this.model.properties; this.on_change(menu, async () => { const menu_open = this.menu.is_open; await this._build_menu(); this.rerender(); if (menu_open) { this._toggle_menu(); } }); } render() { super.render(); const caret = div({ class: [carets.caret, carets.down] }); if (!this.model.is_split) { this.button_el.append(caret); } else { const toggle = this._render_button(caret); toggle.classList.add(buttons.dropdown_toggle); toggle.addEventListener("click", () => this._toggle_menu()); this.group_el.append(toggle); } } async _build_menu() { const menu_with_items = this.to_menu(); this.menu = await build_view(menu_with_items, { parent: this }); } _toggle_menu() { if (!this.menu.is_open) { this.menu.show({ x: 0, y: this.button_el.offsetHeight }); } else { this.menu.hide(); } } click() { if (!this.model.is_split) { this._toggle_menu(); } else { this.menu.hide(); this.model.trigger_event(new ButtonClick()); super.click(); } } _item_click(i) { this.menu.hide(); const item = this.model.menu[i]; if (item != null) { const value_or_callback = isString(item) ? item : item[1]; if (isString(value_or_callback)) { this.model.trigger_event(new MenuItemClick(value_or_callback)); } else { void execute(value_or_callback, this.model, { index: i }); } } } to_menu() { const items = this.model.menu.map((item, i) => { if (item == null) { return new DividerItem(); } else { const label = isString(item) ? item : item[0]; const menu_item = new MenuItem({ label, action: () => { this._item_click(i); }, }); return menu_item; } }); return new Menu({ items }); } } export class Dropdown extends AbstractButton { static __name__ = "Dropdown"; constructor(attrs) { super(attrs); } static { this.prototype.default_view = DropdownView; this.define(({ Null, Bool, Str, List, Tuple, Or }) => ({ split: [Bool, false], menu: [List(Or(Str, Tuple(Str, Or(Str /*TODO*/)), Null)), []], })); this.override({ label: "Dropdown", }); } get is_split() { return this.split; } } //# sourceMappingURL=dropdown.js.map