From 94be51b31876e3da45536ae7215dc4c9bbddd948 Mon Sep 17 00:00:00 2001 From: Simon Martens Date: Tue, 3 Jun 2025 22:17:33 +0200 Subject: [PATCH] div-menu --- views/transform/div-menu.js | 278 ++++++++++++++++++++++++++++++++++++ views/transform/form.css | 103 +++++++++++++ views/transform/main.js | 3 + 3 files changed, 384 insertions(+) create mode 100644 views/transform/div-menu.js diff --git a/views/transform/div-menu.js b/views/transform/div-menu.js new file mode 100644 index 0000000..57f341d --- /dev/null +++ b/views/transform/div-menu.js @@ -0,0 +1,278 @@ +const TS_MENU_COMPONENT = "ts-menu"; +const TS_TOGGLE_BUTTON = "ts-menu-toggle-button"; +const TS_POPUP = "ts-menu-popup"; +const TS_LIST = "ts-menu-list"; +const TS_PLACEHOLDER_MESSAGE = "ts-menu-placeholder-message"; +const TS_LIST_ITEM = "ts-menu-list-item"; +const TS_ITEM_ACTION = "ts-menu-item-action"; +const TS_ITEM_IS_SELECTED = "ts-item-is-selected"; +const TS_CONTENT_CLOSE_BUTTON = "ts-content-close-button"; +const TAILWIND_HIDDEN_CLASS = "hidden"; + +export class DivMenu extends HTMLElement { + constructor() { + super(); + this._menuItemsMap = new Map(); + this._targetElement = null; + this._originalChildDivs = []; + this._observer = null; + this._menuPlaceholderMessageElement = null; + + this._toggleMenu = this._toggleMenu.bind(this); + this._handleMenuItemClick = this._handleMenuItemClick.bind(this); + this._handleClickOutside = this._handleClickOutside.bind(this); + this._handleContentClose = this._handleContentClose.bind(this); + this._handleMutations = this._handleMutations.bind(this); + this._checkMenuPlaceholderAndButton = this._checkMenuPlaceholderAndButton.bind(this); + this._clearFormElements = this._clearFormElements.bind(this); + } + + connectedCallback() { + this._originalChildDivs = Array.from(this.children).filter((node) => node.nodeType === Node.ELEMENT_NODE && node.tagName === "DIV"); + this._originalChildDivs.forEach((div) => div.remove()); + + const componentHTML = ` + +
+ +
+ `; + this.innerHTML = componentHTML; + + this._menuButton = this.querySelector(`.${TS_TOGGLE_BUTTON}`); + this._menuPopupElement = this.querySelector(`.${TS_POPUP}`); + this._menuListElement = this.querySelector(`.${TS_LIST}`); + this._menuPlaceholderMessageElement = this.querySelector(`.${TS_PLACEHOLDER_MESSAGE}`); + + if (!this._menuButton || !this._menuPopupElement || !this._menuListElement || !this._menuPlaceholderMessageElement) { + console.error("CRITICAL: Essential parts missing after creating component from string."); + return; + } + + const targetId = this.getAttribute("target-id"); + if (targetId) { + this._targetElement = document.getElementById(targetId); + if (!this._targetElement) console.warn(`TabSelectorMenu: Target ID '${targetId}' not found.`); + } else { + console.warn(`TabSelectorMenu: 'target-id' attribute missing.`); + } + + this._observer = new MutationObserver(this._handleMutations); + + this._originalChildDivs.forEach((sourceDiv) => { + // Use a specific class for the menu label to distinguish from form labels + const menuLabelElement = sourceDiv.querySelector("label.menu-label"); + const itemValue = sourceDiv.dataset.value; + + if (!menuLabelElement || !itemValue) { + console.warn('TabSelectorMenu: Source div missing