@trimble-oss/moduswebcomponents
Version:
Modus Web Components is a modern, accessible UI library built with Stencil JS that provides reusable web components following Trimble's Modus design system. This updated version focuses on improved flexibility, enhanced theming options, comprehensive cust
594 lines (584 loc) • 37.6 kB
JavaScript
import { r as registerInstance, d as createEvent, h, e as Host, g as getElement } from './index-C1-Dpkp7.js';
import { h as handleShadowDOMStyles } from './base-component-tWS3Egrk.js';
import { i as inheritAriaAttributes } from './utils-DN2BGzSQ.js';
import { c as createPopper } from './popper-BfP9ezJQ.js';
const convertPropsToClasses$1 = ({ bordered, orientation, size, }) => {
let classes = '';
if (bordered) {
classes = `${classes} modus-wc-menu--bordered`;
}
if (orientation === 'horizontal') {
classes = `${classes} modus-wc-menu-horizontal`;
}
if (size) {
classes = `${classes} modus-wc-menu-${size}`;
}
return classes.trim();
};
const modusWcMenuCss = "modus-wc-menu.modus-wc-menu-submenu{display:contents}modus-wc-menu .modus-wc-menu{background-color:var(--modus-wc-color-base-page);border-radius:var(--modus-wc-border-radius-md);list-style:none;margin:0;overflow:hidden;padding:0;padding-inline-start:0}modus-wc-menu .modus-wc-menu.modus-wc-menu--bordered{border:var(--modus-wc-border-width-xs) solid var(--modus-wc-color-base-200)}modus-wc-menu .modus-wc-menu-dropdown{display:none;list-style:none}modus-wc-menu .modus-wc-menu-dropdown-show{display:block}[data-theme=modus-classic-light] modus-wc-menu .modus-wc-menu{background-color:var(--modus-wc-color-white);border-color:var(--modus-wc-color-gray-0)}[data-theme=modus-classic-dark] modus-wc-menu .modus-wc-menu{background-color:var(--modus-wc-color-black);border-color:var(--modus-wc-color-gray-8)}";
const ModusWcMenu = class {
constructor(hostRef) {
registerInstance(this, hostRef);
this.menuFocusout = createEvent(this, "menuFocusout", 7);
this.menuSelectionChange = createEvent(this, "menuSelectionChange", 7);
this.inheritedAttributes = {};
this.selectedItems = [];
/** Custom CSS class to apply to the ul element. */
this.customClass = '';
/** The orientation of the menu. */
this.orientation = 'vertical';
/** The selection mode of the menu. */
this.selectionMode = 'single';
/** The size of the menu. */
this.size = 'md';
this.getMenuRole = () => this.orientation === 'horizontal' ? 'menubar' : 'menu';
}
onSelectionModeChange() {
this.selectedItems = [];
}
componentWillLoad() {
handleShadowDOMStyles(this.el);
if (!this.el.ariaLabel) {
this.el.ariaLabel = 'Menu';
}
this.inheritedAttributes = inheritAriaAttributes(this.el);
}
getClasses() {
// For submenus, only add the dropdown class
if (this.isSubMenu) {
const classList = ['modus-wc-menu-dropdown'];
if (this.customClass)
classList.push(this.customClass);
return classList.join(' ');
}
// For regular menus, add all the standard classes
const classList = ['modus-wc-menu modus-wc-w-full'];
const propClasses = convertPropsToClasses$1({
bordered: this.bordered,
orientation: this.orientation,
size: this.size,
});
// The order CSS classes are added matters to CSS specificity
if (propClasses)
classList.push(propClasses);
if (this.customClass)
classList.push(this.customClass);
return classList.join(' ');
}
getMenuItems() {
return Array.from(this.el.querySelectorAll('modus-wc-menu-item')).filter((item) => item.closest('modus-wc-menu') === this.el);
}
handleItemSelect(e) {
if (this.selectionMode !== 'multiple')
return;
const item = e.target;
const isCurrentlySelected = this.selectedItems.includes(item);
if (e.detail.selected && !isCurrentlySelected) {
this.selectedItems = [...this.selectedItems, item];
}
else if (!e.detail.selected && isCurrentlySelected) {
this.selectedItems = this.selectedItems.filter((i) => i !== item);
}
this.menuSelectionChange.emit({ selectedItems: this.selectedItems });
}
handleKeyDown(e) {
if (e.key !== 'ArrowDown' && e.key !== 'ArrowUp')
return;
e.preventDefault();
const items = this.getMenuItems();
const focusableItems = items.filter((item) => !item.disabled);
if (focusableItems.length === 0)
return;
const activeEl = document.activeElement;
const currentMenuItem = activeEl === null || activeEl === void 0 ? void 0 : activeEl.closest('modus-wc-menu-item');
const currentIndex = focusableItems.indexOf(currentMenuItem);
let nextIndex;
if (e.key === 'ArrowDown') {
nextIndex =
currentIndex < focusableItems.length - 1 ? currentIndex + 1 : 0;
}
else {
nextIndex =
currentIndex > 0 ? currentIndex - 1 : focusableItems.length - 1;
}
const nextLi = focusableItems[nextIndex].querySelector('li');
if (nextLi) {
nextLi.focus();
}
}
handleFocusout(e) {
if (!this.el.contains(e.relatedTarget)) {
this.menuFocusout.emit(e);
if (this.isSubMenu) {
e.stopPropagation();
}
}
}
render() {
return (h(Host, { key: '19854fb1e7960407db704bb954ff66bb355ab042', class: this.isSubMenu ? 'modus-wc-menu-submenu' : undefined }, h("ul", Object.assign({ key: '0752b609c2ed4a897c8a6e8ecc73718cff4c8d09', "aria-orientation": this.orientation, class: this.getClasses(), role: this.getMenuRole() }, this.inheritedAttributes), h("slot", { key: '4957e81fa8566c990a5f06464d2d26dee3af5ba7' }))));
}
get el() { return getElement(this); }
static get watchers() { return {
"selectionMode": ["onSelectionModeChange"]
}; }
};
ModusWcMenu.style = modusWcMenuCss;
const convertPropsToClasses = ({ active, bordered, disabled, focused, size, }) => {
let classes = '';
if (bordered) {
classes = `${classes} modus-wc-menu-item-bordered`;
}
if (disabled) {
classes = `${classes} modus-wc-menu-item-disabled`;
}
if (active) {
classes = `${classes} modus-wc-menu-item-active`;
}
if (focused) {
classes = `${classes} modus-wc-menu-item-focused`;
}
if (size) {
classes = `${classes} modus-wc-menu-item-${size}`;
}
return classes.trim();
};
const modusWcMenuItemCss = "modus-wc-menu-item .modus-wc-menu-item button{align-items:center;border-radius:inherit;display:flex;width:100%}modus-wc-menu-item .modus-wc-menu-item button:hover{background-color:transparent}modus-wc-menu-item .modus-wc-menu-item button:focus{background-color:transparent}modus-wc-menu-item .modus-wc-menu-item button.modus-wc-menu-dropdown-toggle::after{color:var(--modus-wc-color-base-content)}modus-wc-menu-item .modus-wc-menu-item button .modus-wc-menu-item-content{align-items:center;display:flex;width:100%}modus-wc-menu-item .modus-wc-menu-item button .modus-wc-menu-item-content [slot=start-icon]{padding-inline-end:var(--modus-wc-spacing-sm)}modus-wc-menu-item .modus-wc-menu-item button .modus-wc-menu-item-content modus-wc-checkbox{padding-inline-end:var(--modus-wc-spacing-sm)}modus-wc-menu-item .modus-wc-menu-item button .modus-wc-menu-item-content .modus-wc-menu-item-labels{padding-inline-end:var(--modus-wc-spacing-xs);padding-inline-start:var(--modus-wc-spacing-md);white-space:nowrap}modus-wc-menu-item .modus-wc-menu-item button .modus-wc-menu-item-content .modus-wc-menu-item-sublabel{font-size:var(--modus-wc-font-size-sm);white-space:nowrap}modus-wc-menu-item .modus-wc-menu-item button .modus-wc-menu-item-content .modus-wc-menu-item-selected-icon{margin-left:auto}modus-wc-menu-item .modus-wc-menu-item.modus-wc-menu-item-sm button{font-size:var(--modus-wc-font-size-sm)}modus-wc-menu-item .modus-wc-menu-item.modus-wc-menu-item-sm button .modus-wc-menu-item-sublabel{font-size:var(--modus-wc-font-size-xs)}modus-wc-menu-item .modus-wc-menu-item.modus-wc-menu-item-md button{font-size:var(--modus-wc-font-size-md)}modus-wc-menu-item .modus-wc-menu-item.modus-wc-menu-item-md button .modus-wc-menu-item-sublabel{font-size:var(--modus-wc-font-size-sm)}modus-wc-menu-item .modus-wc-menu-item.modus-wc-menu-item-lg button{font-size:var(--modus-wc-font-size-lg)}modus-wc-menu-item .modus-wc-menu-item.modus-wc-menu-item-lg button .modus-wc-menu-item-sublabel{font-size:var(--modus-wc-font-size-md)}modus-wc-menu-item .modus-wc-menu-item.modus-wc-menu-item-bordered{border-bottom:var(--modus-wc-border-width-xs) solid var(--modus-wc-color-base-200);border-radius:0;border-top:var(--modus-wc-border-width-xs) solid var(--modus-wc-color-base-200)}modus-wc-menu-item .modus-wc-menu-item:not(.modus-wc-menu-item-selected){color:var(--modus-wc-color-base-content)}modus-wc-menu-item .modus-wc-menu-item.modus-wc-menu-item-selected{background-color:color-mix(in sRGB, var(--modus-wc-color-primary-pale) 50%, transparent);border-radius:inherit;color:var(--modus-wc-base-content)}modus-wc-menu-item .modus-wc-menu-item.modus-wc-menu-item-selected:focus{background-color:color-mix(in sRGB, var(--modus-wc-color-primary-pale) 50%, transparent)}modus-wc-menu-item .modus-wc-menu-item.modus-wc-menu-item-selected button{background-color:transparent}modus-wc-menu-item .modus-wc-menu-item.modus-wc-menu-item-selected button:hover,modus-wc-menu-item .modus-wc-menu-item.modus-wc-menu-item-selected button:focus{background-color:transparent;border-radius:inherit;box-shadow:none;color:inherit}modus-wc-menu-item .modus-wc-menu-item.modus-wc-menu-item-active{background-color:color-mix(in sRGB, var(--modus-wc-color-primary-pale) 50%, transparent);border-radius:inherit;color:var(--modus-wc-color-base-content)}modus-wc-menu-item .modus-wc-menu-item.modus-wc-menu-item-active:focus{background-color:color-mix(in sRGB, var(--modus-wc-color-primary-pale) 50%, transparent)}modus-wc-menu-item .modus-wc-menu-item.modus-wc-menu-item-active button{background-color:transparent}modus-wc-menu-item .modus-wc-menu-item.modus-wc-menu-item-active button:hover,modus-wc-menu-item .modus-wc-menu-item.modus-wc-menu-item-active button:focus{background-color:transparent;border-radius:inherit;box-shadow:none;color:inherit}modus-wc-menu-item .modus-wc-menu-item.modus-wc-menu-item-disabled{opacity:0.4}modus-wc-menu-item .modus-wc-menu-item.modus-wc-menu-item-disabled button{pointer-events:none}modus-wc-menu-item .modus-wc-menu-item:not(.modus-wc-menu-item-disabled):not(.modus-wc-menu-item-focused):not(:has(.modus-wc-menu-dropdown)):hover{background-color:var(--modus-wc-color-base-100);outline:none}modus-wc-menu-item .modus-wc-menu-item.modus-wc-menu-item-focused:not(.modus-wc-menu-item-disabled):not(:has(.modus-wc-menu-dropdown)):hover{background-color:var(--modus-wc-color-base-100)}modus-wc-menu-item .modus-wc-menu-item:not(.modus-wc-menu-item-active):not(.modus-wc-menu-item-disabled):not(:has(.modus-wc-menu-dropdown)):focus:not(:focus-visible),modus-wc-menu-item .modus-wc-menu-item:not(.modus-wc-menu-item-active):not(.modus-wc-menu-item-disabled):not(:has(.modus-wc-menu-dropdown)).modus-wc-arrow-focused{background-color:var(--modus-wc-color-base-100);color:var(--modus-wc-color-primary);outline:none}modus-wc-menu-item .modus-wc-menu-item:focus-visible{background-color:transparent;outline:2px solid var(--modus-wc-color-primary);outline-offset:-2px}modus-wc-menu-item .modus-wc-menu-item.modus-wc-menu-item-focused{border-radius:inherit;outline:2px solid var(--modus-wc-color-primary);outline-offset:-2px}[data-theme=modus-classic-dark] modus-wc-menu-item .modus-wc-menu-item:not(.modus-wc-menu-item-active),[data-theme=connect-dark] modus-wc-menu-item .modus-wc-menu-item:not(.modus-wc-menu-item-active){color:var(--modus-wc-color-gray-light)}[data-theme=modus-classic-dark] modus-wc-menu-item .modus-wc-menu-item button.modus-wc-menu-dropdown-toggle::after,[data-theme=connect-dark] modus-wc-menu-item .modus-wc-menu-item button.modus-wc-menu-dropdown-toggle::after{color:var(--modus-wc-color-gray-3)}[data-theme=modus-classic-dark] modus-wc-menu-item .modus-wc-menu-item:not(.modus-wc-menu-item-disabled):not(.modus-wc-menu-item-focused):not(:has(.modus-wc-menu-dropdown)):hover,[data-theme=connect-dark] modus-wc-menu-item .modus-wc-menu-item:not(.modus-wc-menu-item-disabled):not(.modus-wc-menu-item-focused):not(:has(.modus-wc-menu-dropdown)):hover{background-color:var(--modus-wc-color-gray-9);color:inherit;outline:none}[data-theme=modus-classic-dark] modus-wc-menu-item .modus-wc-menu-item.modus-wc-menu-item-focused:not(.modus-wc-menu-item-disabled):not(:has(.modus-wc-menu-dropdown)):hover,[data-theme=connect-dark] modus-wc-menu-item .modus-wc-menu-item.modus-wc-menu-item-focused:not(.modus-wc-menu-item-disabled):not(:has(.modus-wc-menu-dropdown)):hover{background-color:var(--modus-wc-color-gray-9);color:inherit}[data-theme=modus-classic-dark] modus-wc-menu-item .modus-wc-menu-item.modus-wc-menu-item-active,[data-theme=modus-classic-dark] modus-wc-menu-item .modus-wc-menu-item:active:not(.modus-wc-menu-item-disabled):not(:has(.modus-wc-menu-dropdown)),[data-theme=connect-dark] modus-wc-menu-item .modus-wc-menu-item.modus-wc-menu-item-active,[data-theme=connect-dark] modus-wc-menu-item .modus-wc-menu-item:active:not(.modus-wc-menu-item-disabled):not(:has(.modus-wc-menu-dropdown)){background-color:color-mix(in sRGB, var(--modus-wc-color-primary) 30%, transparent)}[data-theme=modus-classic-dark] modus-wc-menu-item .modus-wc-menu-item.modus-wc-menu-item-active button,[data-theme=modus-classic-dark] modus-wc-menu-item .modus-wc-menu-item:active:not(.modus-wc-menu-item-disabled):not(:has(.modus-wc-menu-dropdown)) button,[data-theme=connect-dark] modus-wc-menu-item .modus-wc-menu-item.modus-wc-menu-item-active button,[data-theme=connect-dark] modus-wc-menu-item .modus-wc-menu-item:active:not(.modus-wc-menu-item-disabled):not(:has(.modus-wc-menu-dropdown)) button{background-color:transparent}[data-theme=modus-classic-dark] modus-wc-menu-item .modus-wc-menu-item.modus-wc-menu-item-active button:hover,[data-theme=modus-classic-dark] modus-wc-menu-item .modus-wc-menu-item.modus-wc-menu-item-active button:focus,[data-theme=modus-classic-dark] modus-wc-menu-item .modus-wc-menu-item:active:not(.modus-wc-menu-item-disabled):not(:has(.modus-wc-menu-dropdown)) button:hover,[data-theme=modus-classic-dark] modus-wc-menu-item .modus-wc-menu-item:active:not(.modus-wc-menu-item-disabled):not(:has(.modus-wc-menu-dropdown)) button:focus,[data-theme=connect-dark] modus-wc-menu-item .modus-wc-menu-item.modus-wc-menu-item-active button:hover,[data-theme=connect-dark] modus-wc-menu-item .modus-wc-menu-item.modus-wc-menu-item-active button:focus,[data-theme=connect-dark] modus-wc-menu-item .modus-wc-menu-item:active:not(.modus-wc-menu-item-disabled):not(:has(.modus-wc-menu-dropdown)) button:hover,[data-theme=connect-dark] modus-wc-menu-item .modus-wc-menu-item:active:not(.modus-wc-menu-item-disabled):not(:has(.modus-wc-menu-dropdown)) button:focus{background-color:transparent;box-shadow:none;color:inherit}[data-theme=modus-classic-dark] modus-wc-menu-item .modus-wc-menu-item:not(.modus-wc-menu-item-active):not(.modus-wc-menu-item-disabled):not(:has(.modus-wc-menu-dropdown)):focus:not(:focus-visible),[data-theme=modus-classic-dark] modus-wc-menu-item .modus-wc-menu-item:not(.modus-wc-menu-item-active):not(.modus-wc-menu-item-disabled):not(:has(.modus-wc-menu-dropdown)).modus-wc-arrow-focused,[data-theme=connect-dark] modus-wc-menu-item .modus-wc-menu-item:not(.modus-wc-menu-item-active):not(.modus-wc-menu-item-disabled):not(:has(.modus-wc-menu-dropdown)):focus:not(:focus-visible),[data-theme=connect-dark] modus-wc-menu-item .modus-wc-menu-item:not(.modus-wc-menu-item-active):not(.modus-wc-menu-item-disabled):not(:has(.modus-wc-menu-dropdown)).modus-wc-arrow-focused{background-color:var(--modus-wc-color-gray-9)}[data-theme=connect-light] modus-wc-menu-item .modus-wc-menu-item>button.modus-wc-menu-dropdown-toggle::after,[data-theme=connect-dark] modus-wc-menu-item .modus-wc-menu-item>button.modus-wc-menu-dropdown-toggle::after{color:var(--modus-wc-color-white)}[data-theme=connect-light] modus-wc-side-navigation modus-wc-menu .modus-wc-menu li.modus-wc-menu-item:not(.modus-wc-menu-item-active):hover{background-color:transparent}[data-theme=connect-light] modus-wc-side-navigation modus-wc-menu-item .modus-wc-menu-item:not(.modus-wc-menu-item-disabled):not(.modus-wc-menu-item-focused):not(:has(.modus-wc-menu-dropdown)):hover{background-color:transparent;outline:none}[data-theme=connect-light] modus-wc-side-navigation modus-wc-menu-item .modus-wc-menu-item.modus-wc-menu-item-focused:not(.modus-wc-menu-item-disabled):not(:has(.modus-wc-menu-dropdown)):hover{background-color:transparent}[data-theme=connect-light] modus-wc-side-navigation modus-wc-menu-item .modus-wc-menu-item:not(.modus-wc-menu-item-active):not(.modus-wc-menu-item-disabled):not(:has(.modus-wc-menu-dropdown)):focus:not(:focus-visible),[data-theme=connect-light] modus-wc-side-navigation modus-wc-menu-item .modus-wc-menu-item:not(.modus-wc-menu-item-active):not(.modus-wc-menu-item-disabled):not(:has(.modus-wc-menu-dropdown)).modus-wc-arrow-focused{background-color:transparent}[data-theme=connect-light] modus-wc-side-navigation modus-wc-menu-item .modus-wc-menu-item:not(.modus-wc-menu-item-active)>button:hover{background-color:var(--modus-wc-color-trimble-blue);color:var(--modus-wc-color-white)}";
const ModusWcMenuItem = class {
constructor(hostRef) {
registerInstance(this, hostRef);
this.itemSelect = createEvent(this, "itemSelect", 7);
this.inheritedAttributes = {};
/** Custom CSS class to apply to the li element. */
this.customClass = '';
/** The text rendered in the menu item. */
this.label = '';
/** The size of the menu item. */
this.size = 'md';
/** The position of the tooltip relative to the menu item. */
this.tooltipPosition = 'auto';
/** The unique identifying value of the menu item. */
this.value = '';
/** Internal state to track if submenu is expanded */
this.isExpanded = false;
this.handleItemSelect = () => {
if (this.hasSubmenu) {
// Check if side nav is expanded (if this menu is inside a side nav)
const sideNav = this.el.closest('modus-wc-side-navigation');
if (sideNav &&
!sideNav.expanded) {
// Don't allow submenu expansion when side nav is collapsed
// Still emit the event for consistency
this.itemSelect.emit({ value: this.value });
return;
}
// The submenu should be inside this menu-item element (slotted content)
const submenu = this.el.querySelector('.modus-wc-menu-dropdown');
const liElement = this.el.querySelector('li');
if (submenu && liElement) {
submenu.classList.toggle('modus-wc-menu-dropdown-show');
const buttonElement = liElement.querySelector('button');
// Update internal expanded state and add/remove class
this.isExpanded = submenu.classList.contains('modus-wc-menu-dropdown-show');
if (this.isExpanded) {
liElement.classList.add('modus-wc-menu-item-expanded');
if (buttonElement) {
buttonElement.classList.add('modus-wc-menu-dropdown-show');
}
}
else {
liElement.classList.remove('modus-wc-menu-item-expanded');
if (buttonElement) {
buttonElement.classList.remove('modus-wc-menu-dropdown-show');
}
}
}
}
else if (this.resolveSelectionMode() === 'multiple' || this.checkbox) {
this.selected = !this.selected;
}
else {
if (this.resolveSelectionMode() === 'single') {
this.deselectSiblings();
}
this.selected = true;
}
this.itemSelect.emit({ value: this.value, selected: this.selected });
};
}
componentWillLoad() {
handleShadowDOMStyles(this.el);
this.inheritedAttributes = inheritAriaAttributes(this.el);
this._selectionMode = this.resolveSelectionMode();
}
componentDidLoad() {
if (typeof MutationObserver === 'undefined')
return;
const parentMenu = this.el.closest('modus-wc-menu');
if (parentMenu) {
this.parentMenuObserver = new MutationObserver((mutations) => {
for (const mutation of mutations) {
if (mutation.attributeName === 'selection-mode') {
this.handleSelectionModeChange();
break;
}
}
});
this.parentMenuObserver.observe(parentMenu, { attributes: true });
}
}
disconnectedCallback() {
var _a;
(_a = this.parentMenuObserver) === null || _a === void 0 ? void 0 : _a.disconnect();
}
handleSelectionModeChange() {
this._selectionMode = this.resolveSelectionMode();
this.selected = false;
}
handleKeyDown(e) {
if (this.disabled)
return;
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
this.handleItemSelect();
}
}
/**
* Public method to collapse the submenu if it's expanded
*/
async collapseSubmenu() {
if (this.hasSubmenu && this.isExpanded) {
const submenu = this.el.querySelector('.modus-wc-menu-dropdown');
const liElement = this.el.querySelector('li');
if (submenu && liElement) {
submenu.classList.remove('modus-wc-menu-dropdown-show');
liElement.classList.remove('modus-wc-menu-item-expanded');
this.isExpanded = false;
}
}
return Promise.resolve();
}
getRootMenu() {
var _a, _b;
let menu = this.el.closest('modus-wc-menu');
while (menu) {
const parent = (_b = (_a = menu.parentElement) === null || _a === void 0 ? void 0 : _a.closest('modus-wc-menu')) !== null && _b !== void 0 ? _b : null;
if (!parent)
break;
menu = parent;
}
return menu;
}
deselectSiblings() {
const rootMenu = this.getRootMenu();
if (!rootMenu)
return;
const allItems = rootMenu.querySelectorAll('modus-wc-menu-item');
allItems.forEach((item) => {
if (item !== this.el) {
item.selected = false;
}
});
}
resolveSelectionMode() {
var _a;
return (_a = this.el.closest('modus-wc-menu')) === null || _a === void 0 ? void 0 : _a.selectionMode;
}
getClasses() {
const classList = ['modus-wc-menu-item'];
const isActive = !this.hasSubmenu && !!this.selected;
const propClasses = convertPropsToClasses({
active: isActive,
bordered: this.bordered,
disabled: this.disabled,
focused: this.focused,
size: this.size,
});
if (propClasses)
classList.push(propClasses);
if (this.customClass)
classList.push(this.customClass);
return classList.join(' ');
}
getButtonClasses() {
return this.hasSubmenu ? 'modus-wc-menu-dropdown-toggle' : '';
}
getRole(mode) {
if (mode === 'multiple')
return 'menuitemcheckbox';
if (mode === 'single')
return 'menuitemradio';
return 'menuitem';
}
hasCheckbox(mode) {
return this.checkbox || mode === 'multiple';
}
getAriaChecked(mode) {
if (!this.hasCheckbox(mode))
return undefined;
return this.selected ? 'true' : 'false';
}
getAriaSelected(mode) {
if (this.hasCheckbox(mode))
return undefined;
if (mode === 'single')
return this.selected ? 'true' : 'false';
return undefined;
}
render() {
const mode = this._selectionMode;
return (h(Host, { key: '08962b2c66e30cdc6222a2e4f02966c085be3f97' }, h("li", Object.assign({ key: 'be6621a5e9a1a6c0a8a68c09d9df355bbfb5e491', "aria-checked": this.getAriaChecked(mode), "aria-selected": this.getAriaSelected(mode), "aria-disabled": this.disabled, class: this.getClasses(), role: this.getRole(mode), tabIndex: this.disabled ? -1 : 0 }, this.inheritedAttributes), h("button", { key: '16730f36cf2c30cc8edd9b294ebf2fbf780c8f52', class: this.getButtonClasses(), disabled: this.disabled, onClick: this.handleItemSelect, tabIndex: -1, type: "button" }, h("div", { key: '1a85d975363a5831584b2cf09aff08ec862580fb', class: "modus-wc-menu-item-content" }, (this.checkbox || mode === 'multiple') && (h("modus-wc-checkbox", { key: '45b72935af96ab83d638a96bda0ff5eb3667f0fe', "aria-label": "Checkbox", disabled: this.disabled, size: this.size, value: !!this.selected })), h("slot", { key: '3d6a429564ed102acf8eaa068d42aecee654ddf1', name: "start-icon" }), h("div", { key: 'e824b9bc909b8289d5c80a0d530e1c8aa423b228', class: "modus-wc-menu-item-labels" }, this.tooltipContent ? (h("modus-wc-tooltip", { content: this.tooltipContent, position: this.tooltipPosition, customClass: "modus-wc-menu-item-tooltip" }, h("div", null, this.label))) : (h("div", null, this.label)), this.subLabel && (h("div", { key: 'ae2b477265c3acc4e2d34cd0157110b47eadfc80', class: "modus-wc-menu-item-sublabel" }, this.subLabel))))), h("slot", { key: 'cfd85f94459545f39ac4b14844ee3f8aa50d93bf' }))));
}
get el() { return getElement(this); }
};
ModusWcMenuItem.style = modusWcMenuItemCss;
const modusWcTooltipCss = ".modus-wc-tooltip-content[popover]{overflow:visible}.modus-wc-tooltip-content{background-color:var(--modus-wc-color-neutral-content);border-radius:0.25rem;color:var(--modus-wc-color-neutral);font-size:0.875rem;font-weight:var(--modus-wc-font-weight-regular);max-width:20rem;overflow-wrap:break-word;padding:0.25rem 0.5rem;pointer-events:none;position:relative;text-align:center;white-space:normal;width:max-content;z-index:1000}.modus-wc-tooltip-arrow,.modus-wc-tooltip-arrow::before{background:inherit;height:8px;position:absolute;width:8px}.modus-wc-tooltip-arrow{text-align:initial;visibility:hidden}.modus-wc-tooltip-arrow::before{background-color:var(--modus-wc-color-neutral-content);content:\"\";transform:rotate(45deg);visibility:visible}.modus-wc-tooltip-content[data-popper-placement^=top] .modus-wc-tooltip-arrow{bottom:-4px}.modus-wc-tooltip-content[data-popper-placement^=bottom] .modus-wc-tooltip-arrow{top:-4px}.modus-wc-tooltip-content[data-popper-placement^=left] .modus-wc-tooltip-arrow{right:-4px}.modus-wc-tooltip-content[data-popper-placement^=right] .modus-wc-tooltip-arrow{left:-4px}[data-theme=modus-classic-light] .modus-wc-tooltip-content{background-color:var(--modus-wc-color-gray-7);color:var(--modus-wc-color-white)}[data-theme=modus-classic-light] .modus-wc-tooltip-arrow::before{background-color:var(--modus-wc-color-gray-7)}[data-theme=modus-classic-dark] .modus-wc-tooltip-content{background-color:var(--modus-wc-color-gray-0);color:var(--modus-wc-color-trimble-gray)}[data-theme=modus-classic-dark] .modus-wc-tooltip-arrow::before{background-color:var(--modus-wc-color-gray-0)}[data-theme=connect-light] .modus-wc-tooltip-content,[data-theme=connect-dark] .modus-wc-tooltip-content{background-color:var(--modus-wc-color-base-content);color:var(--modus-wc-color-base-page)}[data-theme=connect-light] .modus-wc-tooltip-arrow::before,[data-theme=connect-dark] .modus-wc-tooltip-arrow::before{background-color:var(--modus-wc-color-base-content)}";
const ModusWcTooltip = class {
constructor(hostRef) {
registerInstance(this, hostRef);
this.dismissEscape = createEvent(this, "dismissEscape", 7);
this.inheritedAttributes = {};
this.popperInstance = null;
this.tooltipElement = null;
this.triggerElement = null;
/** The text content of the tooltip. When contentElement is also set, contentElement takes precedence. */
this.content = '';
/** Custom CSS class to apply to the inner div. */
this.customClass = '';
/** Disables displaying the tooltip on hover */
this.disabled = false;
/** The position that the tooltip will render in relation to the element. */
this.position = 'auto';
/** Track if tooltip was dismissed with Escape key */
this.escapeDismissed = false;
/** Track if tooltip is currently visible */
this.isVisible = false;
this.handleWindowResize = () => {
if (this.popperInstance && this.isVisible) {
void this.popperInstance.update();
}
};
this.handleWindowScroll = () => {
if (this.popperInstance && this.isVisible) {
void this.popperInstance.update();
}
};
}
handlePositionChange() {
if (this.popperInstance) {
void this.popperInstance.setOptions({
placement: this.position === 'auto' ? 'top' : this.position,
});
void this.popperInstance.update();
}
}
handleContentChange() {
if (this.contentElement)
return;
this.applyContentToTooltip();
}
handleContentElementChange() {
this.applyContentToTooltip();
}
handleForceOpenChange(forceOpen) {
if (forceOpen && !this.disabled) {
this.showTooltip();
}
else {
this.hideTooltip();
}
}
componentWillLoad() {
handleShadowDOMStyles(this.el);
this.inheritedAttributes = inheritAriaAttributes(this.el);
}
elementKeyupHandler(event) {
switch (event.code) {
case 'Escape': {
// Allow Escape to dismiss tooltip when it's visible
// When forceOpen is true, Escape should NOT dismiss it
if (this.isVisible && !this.forceOpen) {
this.escapeDismissed = true;
this.dismissEscape.emit();
this.hideTooltip();
}
break;
}
}
}
componentDidLoad() {
this.triggerElement = this.el.querySelector('div > :first-child');
this.tooltipElement = document.createElement('div');
this.tooltipElement.className = `modus-wc-tooltip-content ${this.customClass || ''}`;
this.tooltipElement.setAttribute('role', 'tooltip');
if (this.tooltipId) {
this.tooltipElement.id = this.tooltipId;
}
const arrow = document.createElement('div');
arrow.className = 'modus-wc-tooltip-arrow';
this.tooltipElement.appendChild(arrow);
this.tooltipElement.setAttribute('popover', 'manual');
this.applyContentToTooltip();
document.body.appendChild(this.tooltipElement);
this.tooltipElement.style.display = 'none';
if (this.triggerElement && this.tooltipElement) {
this.initializePopper();
}
if (this.forceOpen && !this.disabled && !this.escapeDismissed) {
this.showTooltip();
}
}
disconnectedCallback() {
if (this.popperInstance) {
this.popperInstance.destroy();
this.popperInstance = null;
}
if (this.tooltipElement) {
if (typeof this.tooltipElement.hidePopover === 'function') {
try {
this.tooltipElement.hidePopover();
}
catch (_a) {
// Already hidden or element not connected
}
}
if (this.tooltipElement.parentElement) {
this.tooltipElement.parentElement.removeChild(this.tooltipElement);
}
}
window.removeEventListener('resize', this.handleWindowResize);
window.removeEventListener('scroll', this.handleWindowScroll, true);
}
/** Precedence: contentElement (rich HTML) → content (plain string). Arrow is always kept last. */
applyContentToTooltip() {
if (!this.tooltipElement)
return;
const arrow = this.tooltipElement.querySelector('.modus-wc-tooltip-arrow');
Array.from(this.tooltipElement.childNodes).forEach((node) => {
if (node !== arrow) {
this.tooltipElement.removeChild(node);
}
});
if (this.contentElement && 'nodeType' in this.contentElement) {
this.tooltipElement.insertBefore(this.contentElement.cloneNode(true), arrow);
}
else {
this.tooltipElement.insertBefore(document.createTextNode(this.content), arrow);
}
}
initializePopper() {
if (!this.triggerElement || !this.tooltipElement)
return;
const placement = this.position === 'auto' ? 'top' : this.position;
const arrowElement = this.tooltipElement.querySelector('.modus-wc-tooltip-arrow');
this.popperInstance = createPopper(this.triggerElement, this.tooltipElement, {
placement,
strategy: 'fixed',
modifiers: [
{
name: 'offset',
options: {
offset: [0, 8],
},
},
{
name: 'preventOverflow',
options: {
padding: 8,
boundary: 'viewport',
},
},
{
name: 'flip',
options: {
fallbackPlacements: ['top', 'right', 'bottom', 'left'],
padding: 8,
boundary: 'viewport',
},
},
{
name: 'arrow',
options: {
element: arrowElement,
padding: 5,
},
},
{
name: 'computeStyles',
options: {
adaptive: true,
gpuAcceleration: true,
},
},
{
name: 'eventListeners',
options: {
scroll: true,
resize: true,
},
},
],
});
window.addEventListener('resize', this.handleWindowResize);
window.addEventListener('scroll', this.handleWindowScroll, true);
}
showTooltip() {
if (this.disabled || this.escapeDismissed || !this.tooltipElement)
return;
this.tooltipElement.style.display = 'block';
if (typeof this.tooltipElement.showPopover === 'function') {
try {
this.tooltipElement.showPopover();
}
catch (_a) {
// Already showing or element not connected
}
}
this.isVisible = true;
if (this.popperInstance) {
void this.popperInstance.update();
// Force a second update after a short delay to ensure arrow positioning
setTimeout(() => {
if (this.popperInstance) {
void this.popperInstance.update();
}
}, 10);
}
}
hideTooltip() {
if (!this.tooltipElement)
return;
if (!this.forceOpen || this.escapeDismissed) {
if (typeof this.tooltipElement.hidePopover === 'function') {
try {
this.tooltipElement.hidePopover();
}
catch (_a) {
// Already hidden or element not connected
}
}
this.tooltipElement.style.display = 'none';
this.isVisible = false;
}
}
handleMouseEnter() {
this.escapeDismissed = false;
this.showTooltip();
}
handleMouseLeave() {
if (!this.forceOpen) {
this.hideTooltip();
}
}
render() {
return (h(Host, { key: 'cce7d08b0e748ee680f15744b442655d7a32c13e' }, h("div", Object.assign({ key: '7a384a1329786729aeee04a689f88b16b2951808', "aria-describedby": this.tooltipId, id: this.tooltipId }, this.inheritedAttributes), h("slot", { key: '13ef7dbaae4806f15d8dcb21ee5590b7e838504c' }))));
}
get el() { return getElement(this); }
static get watchers() { return {
"position": ["handlePositionChange"],
"content": ["handleContentChange"],
"contentElement": ["handleContentElementChange"],
"forceOpen": ["handleForceOpenChange"]
}; }
};
ModusWcTooltip.style = modusWcTooltipCss;
export { ModusWcMenu as modus_wc_menu, ModusWcMenuItem as modus_wc_menu_item, ModusWcTooltip as modus_wc_tooltip };