import App from /**/"./App.js"; import Component from /**/"./Component.js"; import Group from /**/"./Group.js"; import MenuBar from /**/"./MenuBar.js"; import MenuItem from /**/"./MenuItem.js"; // Pseudo environment context let _package = {}; // GUI widget toolkit root class Toolkit { //////////////////////////////// Constants //////////////////////////////// // Event keys static group = Symbol(); // Events emitted by Toolkit.Group static target = Symbol(); // Event target as a Toolkit.Component ///////////////////////// Initialization Methods ////////////////////////// Toolkit() { throw new Error("Cannot be instantiated."); } static { // Environment members Object.assign(_package, { componentKey: Symbol("Toolkit component"), darkQuery : window.matchMedia("(prefers-color-scheme:dark)"), nextId : 0n, override : this.#override, underride : this.#underride }); // Register package classes with the Toolkit namespace _package.register = ()=>{ this.Component = Component(this, _package); this.App = App (this, _package); this.Group = Group (this, _package); this.MenuBar = MenuBar (this, _package); this.MenuItem = MenuItem (this, _package); Object.freeze(this); Object.seal (this); }; } ///////////////////////////// Static Methods ////////////////////////////// // Resolve the Toolkit.Component for an HTML element static component(element) { return element[_package.componentKey] ?? null; } // Terminate an event static consume(event) { event.preventDefault(); event.stopPropagation(); } // Generate a unique element ID static id() { return "tk-" + _package.nextId++; } // Determine whether the user dark mode preference is active static isDark() { return _package.darkQuery.matches; } // Determine whether an element is fully visible static isVisible(element, cache = null) { cache ??= new Map(); for (let e = element; e instanceof Element; e = e.parentNode) { let style; if (!cache.has(e)) cache.set(e, style = getComputedStyle(e)); else style = cache.get(e); if (style.display == "none" || style.visibility == "hidden") return false; } return true; } // Generate a list of focusable descendant elements static listFocusable(element) { let cache = new Map(); return Array.from(element.querySelectorAll( "*:is(a[href],area,button,details,input,textarea,select," + "[tabindex='0']):not([disabled])" )).filter(e=>this.isVisible(e, cache)); } static stylesheet(url) { let style = document.createElement("link"); style.rel = "stylesheet"; style.href = url; return style; } ///////////////////////////// Package Methods ///////////////////////////// // Process overrides for Toolkit.Component initialization static #override(fromCaller, fromSelf) { fromCaller = Object.assign({}, fromCaller ?? {}); fromSelf = Object.assign({}, fromSelf ?? {}); fromSelf.style = Object.assign( fromSelf.style ?? {}, fromCaller.style ?? {}); delete fromCaller.style; Object.assign(fromSelf, fromCaller); return fromSelf; } // Extract override properties for later processing static #underride(overrides, underrides) { let ret = {}; for (let entry of Object.entries(underrides)) { ret[entry[0]] = overrides[entry[0]] ?? underrides[entry[1]]; delete overrides[entry[0]]; } return ret; } } _package.register(); export default Toolkit;