+import WoltlabCoreMenuItemElement from "./woltlab-core-menu-item";
+
export class WoltlabCoreMenuGroupElement extends HTMLElement {
+ readonly #items = new Set<WoltlabCoreMenuItemElement>();
+ #value = "";
+
connectedCallback() {
+ const shadow = this.attachShadow({ mode: "open" });
+ const slot = document.createElement("slot");
+ slot.addEventListener("slotchange", () => {
+ this.#items.clear();
+
+ for (const element of slot.assignedElements()) {
+ if (!(element instanceof WoltlabCoreMenuItemElement)) {
+ element.remove();
+ continue;
+ }
+
+ this.#items.add(element);
+
+ element.setRole("menuitemcheckbox");
+
+ element.addEventListener("change", () => {
+ this.#updateValue();
+ });
+ }
+ });
+
+ shadow.append(slot);
+
this.setAttribute("role", "group");
this.label = this.getAttribute("label")!;
this.setAttribute("label", label);
this.setAttribute("aria-label", label);
}
+
+ get value(): string {
+ return this.#value;
+ }
+
+ set value(value: string) {
+ const values = value.split(",");
+
+ this.#items.forEach((item) => {
+ item.selected = values.includes(item.value);
+ });
+
+ this.#updateValue();
+ }
+
+ #updateValue(): void {
+ this.#value = Array.from(this.#items)
+ .filter((item) => item.selected)
+ .map((item) => item.value)
+ .join(",");
+
+ this.setAttribute("value", this.#value);
+ }
}
export default WoltlabCoreMenuGroupElement;
-import WoltlabCoreMenuGroupElement from "./woltlab-core-menu-group";
+type Role = "menuitem" | "menuitemcheckbox";
-const enum MenuItemType {
- Checkbox,
- Item,
+interface WoltlabCoreMenuItemEventMap {
+ beforeSelect: CustomEvent;
+ change: CustomEvent;
}
+// eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging
export class WoltlabCoreMenuItemElement extends HTMLElement {
- #type: MenuItemType = MenuItemType.Item;
#checkmark?: FaIcon;
+ constructor() {
+ super();
+
+ this.addEventListener("click", () => {
+ if (this.disabled) {
+ return;
+ }
+
+ const evt = new CustomEvent("beforeSelect", {
+ cancelable: true,
+ });
+ this.dispatchEvent(evt);
+
+ if (!evt.defaultPrevented) {
+ this.selected = !this.selected;
+
+ const evt = new CustomEvent("change");
+ this.dispatchEvent(evt);
+ }
+ });
+ }
+
connectedCallback() {
const shadow = this.attachShadow({ mode: "open" });
shadow.append(defaultSlot);
this.tabIndex = -1;
- this.disabled = this.hasAttribute("disabled");
-
- if (this.parentElement! instanceof WoltlabCoreMenuGroupElement) {
- this.#type = MenuItemType.Checkbox;
- this.setAttribute("role", "menuitemcheckbox");
-
- this.selected = this.hasAttribute("selected");
-
- if (this.#checkmark === undefined) {
- this.#checkmark = document.createElement("fa-icon");
- this.#checkmark.setIcon("check");
- this.#checkmark.slot = "checkmark";
- }
-
- this.append(this.#checkmark);
- } else {
- this.#type = MenuItemType.Item;
- this.setAttribute("role", "menuitem");
-
- this.removeAttribute("aria-checked");
-
- this.#checkmark?.remove();
- }
+ this.setAttribute("role", "menuitem");
}
get selected(): boolean {
- if (this.#type !== MenuItemType.Item) {
- return false;
- }
-
return this.hasAttribute("selected");
}
set selected(checked: boolean) {
- if (this.#type !== MenuItemType.Checkbox) {
- return;
- }
-
if (checked) {
this.setAttribute("selected", "");
} else {
set value(value: string) {
this.setAttribute("value", value);
}
+
+ setRole(role: Role): void {
+ this.setAttribute("role", role);
+ this.#updateAriaSelected();
+
+ if (role === "menuitem") {
+ this.#checkmark?.remove();
+ } else if (role === "menuitemcheckbox") {
+ if (this.#checkmark === undefined) {
+ this.#checkmark = document.createElement("fa-icon");
+ this.#checkmark.setIcon("check");
+ this.#checkmark.slot = "checkmark";
+ }
+
+ this.append(this.#checkmark);
+ }
+ }
+
+ #updateAriaSelected(): void {
+ const role = this.getAttribute("role") as Role;
+ if (role === "menuitemcheckbox") {
+ this.setAttribute("aria-checked", String(this.selected === true));
+ }
+ }
}
-export default WoltlabCoreMenuItemElement;
+// eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging
+export interface WoltlabCoreMenuItemElement extends HTMLElement {
+ addEventListener: {
+ <T extends keyof WoltlabCoreMenuItemEventMap>(
+ type: T,
+ listener: (this: WoltlabCoreMenuItemElement, ev: WoltlabCoreMenuItemEventMap[T]) => any,
+ options?: boolean | AddEventListenerOptions,
+ ): void;
+ } & HTMLElement["addEventListener"];
+}
window.customElements.define("woltlab-core-menu-item", WoltlabCoreMenuItemElement);
+
+export default WoltlabCoreMenuItemElement;
-define(["require", "exports"], function (require, exports) {
+define(["require", "exports", "tslib", "./woltlab-core-menu-item"], function (require, exports, tslib_1, woltlab_core_menu_item_1) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.WoltlabCoreMenuGroupElement = void 0;
+ woltlab_core_menu_item_1 = tslib_1.__importDefault(woltlab_core_menu_item_1);
class WoltlabCoreMenuGroupElement extends HTMLElement {
+ #items = new Set();
+ #value = "";
connectedCallback() {
+ const shadow = this.attachShadow({ mode: "open" });
+ const slot = document.createElement("slot");
+ slot.addEventListener("slotchange", () => {
+ this.#items.clear();
+ for (const element of slot.assignedElements()) {
+ if (!(element instanceof woltlab_core_menu_item_1.default)) {
+ element.remove();
+ continue;
+ }
+ this.#items.add(element);
+ element.setRole("menuitemcheckbox");
+ element.addEventListener("change", () => {
+ this.#updateValue();
+ });
+ }
+ });
+ shadow.append(slot);
this.setAttribute("role", "group");
this.label = this.getAttribute("label");
}
this.setAttribute("label", label);
this.setAttribute("aria-label", label);
}
+ get value() {
+ return this.#value;
+ }
+ set value(value) {
+ const values = value.split(",");
+ this.#items.forEach((item) => {
+ item.selected = values.includes(item.value);
+ });
+ this.#updateValue();
+ }
+ #updateValue() {
+ this.#value = Array.from(this.#items)
+ .filter((item) => item.selected)
+ .map((item) => item.value)
+ .join(",");
+ this.setAttribute("value", this.#value);
+ }
}
exports.WoltlabCoreMenuGroupElement = WoltlabCoreMenuGroupElement;
exports.default = WoltlabCoreMenuGroupElement;
-define(["require", "exports", "tslib", "./woltlab-core-menu-group"], function (require, exports, tslib_1, woltlab_core_menu_group_1) {
+define(["require", "exports"], function (require, exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.WoltlabCoreMenuItemElement = void 0;
- woltlab_core_menu_group_1 = tslib_1.__importDefault(woltlab_core_menu_group_1);
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging
class WoltlabCoreMenuItemElement extends HTMLElement {
- #type = 1 /* MenuItemType.Item */;
#checkmark;
+ constructor() {
+ super();
+ this.addEventListener("click", () => {
+ if (this.disabled) {
+ return;
+ }
+ const evt = new CustomEvent("beforeSelect", {
+ cancelable: true,
+ });
+ this.dispatchEvent(evt);
+ if (!evt.defaultPrevented) {
+ this.selected = !this.selected;
+ const evt = new CustomEvent("change");
+ this.dispatchEvent(evt);
+ }
+ });
+ }
connectedCallback() {
const shadow = this.attachShadow({ mode: "open" });
const checkmarkSlot = document.createElement("slot");
defaultSlot.id = "slot";
shadow.append(defaultSlot);
this.tabIndex = -1;
- this.disabled = this.hasAttribute("disabled");
- if (this.parentElement instanceof woltlab_core_menu_group_1.default) {
- this.#type = 0 /* MenuItemType.Checkbox */;
- this.setAttribute("role", "menuitemcheckbox");
- this.selected = this.hasAttribute("selected");
- if (this.#checkmark === undefined) {
- this.#checkmark = document.createElement("fa-icon");
- this.#checkmark.setIcon("check");
- this.#checkmark.slot = "checkmark";
- }
- this.append(this.#checkmark);
- }
- else {
- this.#type = 1 /* MenuItemType.Item */;
- this.setAttribute("role", "menuitem");
- this.removeAttribute("aria-checked");
- this.#checkmark?.remove();
- }
+ this.setAttribute("role", "menuitem");
}
get selected() {
- if (this.#type !== 1 /* MenuItemType.Item */) {
- return false;
- }
return this.hasAttribute("selected");
}
set selected(checked) {
- if (this.#type !== 0 /* MenuItemType.Checkbox */) {
- return;
- }
if (checked) {
this.setAttribute("selected", "");
}
set value(value) {
this.setAttribute("value", value);
}
+ setRole(role) {
+ this.setAttribute("role", role);
+ this.#updateAriaSelected();
+ if (role === "menuitem") {
+ this.#checkmark?.remove();
+ }
+ else if (role === "menuitemcheckbox") {
+ if (this.#checkmark === undefined) {
+ this.#checkmark = document.createElement("fa-icon");
+ this.#checkmark.setIcon("check");
+ this.#checkmark.slot = "checkmark";
+ }
+ this.append(this.#checkmark);
+ }
+ }
+ #updateAriaSelected() {
+ const role = this.getAttribute("role");
+ if (role === "menuitemcheckbox") {
+ this.setAttribute("aria-checked", String(this.selected === true));
+ }
+ }
}
exports.WoltlabCoreMenuItemElement = WoltlabCoreMenuItemElement;
- exports.default = WoltlabCoreMenuItemElement;
window.customElements.define("woltlab-core-menu-item", WoltlabCoreMenuItemElement);
+ exports.default = WoltlabCoreMenuItemElement;
});