diff --git a/src/core/gui/Button.css b/src/core/gui/Button.css index d00ec431..7061b9f5 100644 --- a/src/core/gui/Button.css +++ b/src/core/gui/Button.css @@ -10,6 +10,7 @@ color: var(--control-text-color); outline: none; font-size: 13px; + font-family: var(--font-family); overflow: hidden; } diff --git a/src/core/gui/DropDownButton.ts b/src/core/gui/DropDownButton.ts index 3897b480..16edccca 100644 --- a/src/core/gui/DropDownButton.ts +++ b/src/core/gui/DropDownButton.ts @@ -24,16 +24,18 @@ export class DropDownButton extends Control { to_label: (element: T) => string, options?: DropDownButtonOptions, ) { + const element = el.div({ class: "core_DropDownButton" }); const button = new Button(text, { icon_left: options && options.icon_left, icon_right: Icon.TriangleDown, }); - const menu = new Menu(items, to_label); + const menu = new Menu(items, to_label, element); - super(el.div({ class: "core_DropDownButton" }, button.element, menu.element), options); + super(element, options); this.button = this.disposable(button); this.menu = this.disposable(menu); + this.element.append(this.button.element, this.menu.element); this._chosen = emitter(); this.chosen = this._chosen; @@ -41,7 +43,9 @@ export class DropDownButton extends Control { this.just_opened = false; this.disposables( - disposable_listener(button.element, "mousedown", e => this.button_mousedown(e)), + disposable_listener(button.element, "mousedown", () => this.button_mousedown(), { + capture: true, + }), button.mouseup.observe(() => this.button_mouseup()), @@ -59,8 +63,7 @@ export class DropDownButton extends Control { this.button.enabled.val = enabled; } - private button_mousedown(e: Event): void { - e.stopPropagation(); + private button_mousedown(): void { this.just_opened = !this.menu.visible.val; this.menu.visible.val = true; } diff --git a/src/core/gui/Menu.ts b/src/core/gui/Menu.ts index fbb71a06..2d78ced5 100644 --- a/src/core/gui/Menu.ts +++ b/src/core/gui/Menu.ts @@ -11,12 +11,18 @@ export class Menu extends Widget { private readonly to_label: (element: T) => string; private readonly items: Property; + private readonly related_element: HTMLElement; private readonly _selected: WidgetProperty; - constructor(items: T[] | Property, to_label: (element: T) => string) { + constructor( + items: T[] | Property, + to_label: (element: T) => string, + related_element: HTMLElement, + ) { super(el.div({ class: "core_Menu" })); - this.element.hidden = true; + this.visible.val = false; + this.element.onmouseup = (e: Event) => this.mouseup(e); const inner_element = el.div({ class: "core_Menu_inner" }); @@ -24,6 +30,7 @@ export class Menu extends Widget { this.to_label = to_label; this.items = Array.isArray(items) ? property(items) : items; + this.related_element = related_element; this._selected = new WidgetProperty(this, undefined, this.set_selected); this.selected = this._selected; @@ -41,7 +48,9 @@ export class Menu extends Widget { { call_now: true }, ), - disposable_listener(document, "mousedown", (e: Event) => this.document_mousedown(e)), + disposable_listener(document, "mousedown", (e: Event) => this.document_mousedown(e), { + capture: true, + }), ); } @@ -63,7 +72,11 @@ export class Menu extends Widget { } private document_mousedown(e: Event): void { - if (this.visible.val && !this.element.contains(e.target as Node)) { + if ( + this.visible.val && + !this.element.contains(e.target as Node) && + !this.related_element.contains(e.target as Node) + ) { this.visible.val = false; } } diff --git a/src/core/gui/Select.css b/src/core/gui/Select.css index d2ff6d8b..225f8d5a 100644 --- a/src/core/gui/Select.css +++ b/src/core/gui/Select.css @@ -1,7 +1,7 @@ .core_Select { position: relative; display: inline-flex; - width: 150px; + width: 160px; } .core_Select .core_Button { diff --git a/src/core/gui/Select.ts b/src/core/gui/Select.ts index b45f491b..e7ed9109 100644 --- a/src/core/gui/Select.ts +++ b/src/core/gui/Select.ts @@ -27,18 +27,20 @@ export class Select extends LabelledControl { to_label: (element: T) => string, options?: SelectOptions, ) { + const element = el.div({ class: "core_Select" }); const button = new Button("", { icon_right: Icon.TriangleDown, }); - const menu = new Menu(items, to_label); + const menu = new Menu(items, to_label, element); - super(el.div({ class: "core_Select" }, button.element, menu.element), options); + super(element, options); this.preferred_label_position = "left"; this.to_label = to_label; this.button = this.disposable(button); this.menu = this.disposable(menu); + this.element.append(this.button.element, this.menu.element); this._selected = new WidgetProperty(this, undefined, this.set_selected); this.selected = this._selected; diff --git a/src/core/gui/dom.ts b/src/core/gui/dom.ts index 30486161..40e0bcda 100644 --- a/src/core/gui/dom.ts +++ b/src/core/gui/dom.ts @@ -129,11 +129,11 @@ export function disposable_listener( listener: EventListenerOrEventListenerObject, options?: AddEventListenerOptions, ): Disposable { - element.addEventListener(event, listener); + element.addEventListener(event, listener, options); return { dispose(): void { - element.removeEventListener(event, listener, options); + element.removeEventListener(event, listener); }, }; } diff --git a/src/core/gui/index.css b/src/core/gui/index.css index d72fb8cf..37e07ead 100644 --- a/src/core/gui/index.css +++ b/src/core/gui/index.css @@ -4,6 +4,7 @@ --bg-color: hsl(0, 0%, 15%); --text-color: hsl(0, 0%, 80%); --text-color-disabled: hsl(0, 0%, 55%); + --font-family: Verdana, Geneva, sans-serif; --border-color: hsl(0, 0%, 25%); /* Scrollbars */ @@ -63,7 +64,7 @@ body { font-size: 13px; background-color: var(--bg-color); color: var(--text-color); - font-family: Verdana, Geneva, sans-serif; + font-family: var(--font-family); } #root *[hidden] {