Files

187 lines
6.2 KiB
JavaScript

(function initHelpIconOverlayModule() {
const CLOSE_HANDLERS = {
'.sg-pulldown-demo': (root) => {
root.querySelectorAll('.sg-pulldown-demo').forEach((demo) => {
const trigger = demo.querySelector('.sg-pulldown-demo__trigger');
demo.dataset.open = 'false';
if (trigger) {
trigger.setAttribute('aria-expanded', 'false');
}
});
},
'.sg-sandwich-menu-wrap': (root) => {
root.querySelectorAll('.sg-sandwich-menu-wrap').forEach((wrap) => {
const button = wrap.querySelector('.sg-sandwich-button');
wrap.dataset.open = 'false';
if (button) {
button.setAttribute('aria-expanded', 'false');
}
});
},
};
const getViewportWidth = () => {
if (window.visualViewport && typeof window.visualViewport.width === 'number') {
return window.visualViewport.width;
}
return window.innerWidth;
};
const getViewportHeight = () => {
if (window.visualViewport && typeof window.visualViewport.height === 'number') {
return window.visualViewport.height;
}
return window.innerHeight;
};
const getSafeInsetPx = () => {
const rootStyles = getComputedStyle(document.documentElement);
const spacingSmallRaw = rootStyles.getPropertyValue('--spacing-small').trim();
const rootFontSize = parseFloat(rootStyles.fontSize) || 16;
const spacingSmallValue = parseFloat(spacingSmallRaw);
if (Number.isNaN(spacingSmallValue)) {
return 0;
}
if (spacingSmallRaw.endsWith('rem')) {
return spacingSmallValue * rootFontSize;
}
return spacingSmallValue;
};
const closeAllHelpIcons = (root) => {
root.querySelectorAll('.sg-help-icon-wrap').forEach((wrap) => {
const button = wrap.querySelector('.sg-help-icon');
const panel = wrap.querySelector('.sg-help-icon-panel');
wrap.dataset.open = 'false';
if (panel) {
panel.style.removeProperty('transform');
panel.style.removeProperty('max-height');
panel.style.removeProperty('overflow-y');
}
if (button) {
button.setAttribute('aria-expanded', 'false');
}
});
};
const positionHelpPanel = (wrap, panel) => {
wrap.dataset.align = 'left';
wrap.dataset.vertical = 'bottom';
panel.style.removeProperty('transform');
panel.style.removeProperty('max-height');
panel.style.removeProperty('overflow-y');
const viewportWidth = getViewportWidth();
const panelRect = panel.getBoundingClientRect();
if (panelRect.right > viewportWidth) {
wrap.dataset.align = 'right';
}
const alignedPanelRect = panel.getBoundingClientRect();
if (alignedPanelRect.left < 0) {
wrap.dataset.align = 'left';
}
const clampedRect = panel.getBoundingClientRect();
const safeInset = getSafeInsetPx();
let shiftX = 0;
if (clampedRect.right > (viewportWidth - safeInset)) {
shiftX -= clampedRect.right - (viewportWidth - safeInset);
}
if ((clampedRect.left + shiftX) < safeInset) {
shiftX += safeInset - (clampedRect.left + shiftX);
}
if (shiftX !== 0) {
panel.style.transform = `translateX(${shiftX}px)`;
}
const viewportHeight = getViewportHeight();
const verticalSafeInset = getSafeInsetPx();
const bottomRect = panel.getBoundingClientRect();
if (bottomRect.bottom > (viewportHeight - verticalSafeInset)) {
wrap.dataset.vertical = 'top';
const topRect = panel.getBoundingClientRect();
if (topRect.top < verticalSafeInset) {
const wrapRect = wrap.getBoundingClientRect();
const spaceAbove = Math.max(0, wrapRect.top - verticalSafeInset);
const spaceBelow = Math.max(0, viewportHeight - verticalSafeInset - wrapRect.bottom);
const useTop = spaceAbove >= spaceBelow;
wrap.dataset.vertical = useTop ? 'top' : 'bottom';
const availableHeight = Math.max(96, Math.floor((useTop ? spaceAbove : spaceBelow) - verticalSafeInset));
panel.style.maxHeight = `${availableHeight}px`;
panel.style.overflowY = 'auto';
}
}
};
window.sgInitHelpIconOverlays = (options = {}) => {
const root = options.root || document;
const closeOnOpenSelectors = options.closeOnOpenSelectors || [];
const outsideClickIgnoreSelectors = options.outsideClickIgnoreSelectors || [];
root.querySelectorAll('.sg-help-icon-wrap').forEach((wrap) => {
if (wrap.dataset.helpIconInit === 'true') {
return;
}
wrap.dataset.helpIconInit = 'true';
const button = wrap.querySelector('.sg-help-icon');
const panel = wrap.querySelector('.sg-help-icon-panel');
if (!button || !panel) {
return;
}
button.addEventListener('click', (event) => {
event.stopPropagation();
const nextState = wrap.dataset.open !== 'true';
closeAllHelpIcons(root);
closeOnOpenSelectors.forEach((selector) => {
const handler = CLOSE_HANDLERS[selector];
if (handler) {
handler(root);
}
});
if (!nextState) {
return;
}
wrap.dataset.open = 'true';
button.setAttribute('aria-expanded', 'true');
positionHelpPanel(wrap, panel);
window.requestAnimationFrame(() => {
if (wrap.dataset.open === 'true') {
positionHelpPanel(wrap, panel);
}
});
});
});
const refreshOpenPanels = () => {
root.querySelectorAll('.sg-help-icon-wrap[data-open="true"]').forEach((wrap) => {
const panel = wrap.querySelector('.sg-help-icon-panel');
if (panel) {
positionHelpPanel(wrap, panel);
}
});
};
if (!window.sgHelpIconOverlayResizeBound) {
window.addEventListener('resize', refreshOpenPanels);
if (window.visualViewport && typeof window.visualViewport.addEventListener === 'function') {
window.visualViewport.addEventListener('resize', refreshOpenPanels);
}
window.sgHelpIconOverlayResizeBound = true;
}
document.addEventListener('click', (event) => {
const isInsideIgnoredZone = ['.sg-help-icon-wrap', ...outsideClickIgnoreSelectors]
.some((selector) => event.target.closest(selector));
if (isInsideIgnoredZone) {
return;
}
closeAllHelpIcons(root);
});
};
})();