UNPKG

@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

288 lines (284 loc) 12.7 kB
import { p as proxyCustomElement, H, d as createEvent, h, c as Host } from './p-Blhe_h6i.js'; import { h as handleShadowDOMStyles } from './p-tWS3Egrk.js'; import { i as inheritAriaAttributes } from './p-DUWn6PrQ.js'; import { c as createPopper } from './p-BfP9ezJQ.js'; 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 = /*@__PURE__*/ proxyCustomElement(class ModusWcTooltip extends H { constructor() { super(); this.__registerHost(); 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 this; } static get watchers() { return { "position": ["handlePositionChange"], "content": ["handleContentChange"], "contentElement": ["handleContentElementChange"], "forceOpen": ["handleForceOpenChange"] }; } static get style() { return modusWcTooltipCss; } }, [4, "modus-wc-tooltip", { "content": [1], "contentElement": [16, "content-element"], "customClass": [1, "custom-class"], "disabled": [4], "forceOpen": [4, "force-open"], "tooltipId": [1, "tooltip-id"], "position": [1], "escapeDismissed": [32], "isVisible": [32] }, [[4, "keyup", "elementKeyupHandler"], [1, "mouseenter", "handleMouseEnter"], [1, "mouseleave", "handleMouseLeave"]], { "position": ["handlePositionChange"], "content": ["handleContentChange"], "contentElement": ["handleContentElementChange"], "forceOpen": ["handleForceOpenChange"] }]); function defineCustomElement() { if (typeof customElements === "undefined") { return; } const components = ["modus-wc-tooltip"]; components.forEach(tagName => { switch (tagName) { case "modus-wc-tooltip": if (!customElements.get(tagName)) { customElements.define(tagName, ModusWcTooltip); } break; } }); } export { ModusWcTooltip as M, defineCustomElement as d };