mirror of
https://github.com/DaanVandenBosch/phantasmal-world.git
synced 2025-04-04 22:58:29 +08:00
Improved dropdown button and select widget behavior.
This commit is contained in:
parent
24f0cdb461
commit
4dde973951
@ -10,6 +10,7 @@
|
||||
color: var(--control-text-color);
|
||||
outline: none;
|
||||
font-size: 13px;
|
||||
font-family: var(--font-family);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
|
@ -24,16 +24,18 @@ export class DropDownButton<T> 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<T>(items, to_label);
|
||||
const menu = new Menu<T>(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<T> 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<T> 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;
|
||||
}
|
||||
|
@ -11,12 +11,18 @@ export class Menu<T> extends Widget {
|
||||
|
||||
private readonly to_label: (element: T) => string;
|
||||
private readonly items: Property<T[]>;
|
||||
private readonly related_element: HTMLElement;
|
||||
private readonly _selected: WidgetProperty<T | undefined>;
|
||||
|
||||
constructor(items: T[] | Property<T[]>, to_label: (element: T) => string) {
|
||||
constructor(
|
||||
items: T[] | Property<T[]>,
|
||||
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<T> extends Widget {
|
||||
|
||||
this.to_label = to_label;
|
||||
this.items = Array.isArray(items) ? property(items) : items;
|
||||
this.related_element = related_element;
|
||||
|
||||
this._selected = new WidgetProperty<T | undefined>(this, undefined, this.set_selected);
|
||||
this.selected = this._selected;
|
||||
@ -41,7 +48,9 @@ export class Menu<T> 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<T> 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;
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
.core_Select {
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
width: 150px;
|
||||
width: 160px;
|
||||
}
|
||||
|
||||
.core_Select .core_Button {
|
||||
|
@ -27,18 +27,20 @@ export class Select<T> extends LabelledControl {
|
||||
to_label: (element: T) => string,
|
||||
options?: SelectOptions<T>,
|
||||
) {
|
||||
const element = el.div({ class: "core_Select" });
|
||||
const button = new Button("", {
|
||||
icon_right: Icon.TriangleDown,
|
||||
});
|
||||
const menu = new Menu<T>(items, to_label);
|
||||
const menu = new Menu<T>(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<T | undefined>(this, undefined, this.set_selected);
|
||||
this.selected = this._selected;
|
||||
|
@ -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);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
@ -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] {
|
||||
|
Loading…
Reference in New Issue
Block a user