+ Overlays
+ Managed by VMKUIKit.Overlays using data-toggle attributes.
+
+ Dropdown toggle
+
+
+
+
+
+ Tooltip toggle
+
+
+ Overlay-managed tooltip
+
+
diff --git a/src/js/components/overlays.js b/src/js/components/overlays.js
new file mode 100644
index 0000000..d46a20f
--- /dev/null
+++ b/src/js/components/overlays.js
@@ -0,0 +1,107 @@
+/**
+ * Overlays browser helper.
+ *
+ * Mirrors gnexus-ui-kit Overlays public surface:
+ * init(root), closeAll()
+ *
+ * Centralizes management of dropdown, popover and tooltip toggle state
+ * using data-* trigger attributes. Complements the dedicated dropdowns.js,
+ * popover.js and tooltips.js helpers.
+ */
+
+const initializedRoots = new WeakSet();
+let keyboardDismissInitialized = false;
+
+function closeNode(node) {
+ node.classList.remove("is-open");
+ node.querySelectorAll("[aria-expanded='true']").forEach(trigger => {
+ trigger.setAttribute("aria-expanded", "false");
+ });
+}
+
+function closeAll(except = null) {
+ document.querySelectorAll(".dropdown.is-open, .popover.is-open, .tooltip.is-open").forEach(node => {
+ if(node !== except) {
+ closeNode(node);
+ }
+ });
+}
+
+function initDropdowns(root = document) {
+ root.addEventListener("click", event => {
+ const trigger = event.target.closest("[data-dropdown-toggle]");
+
+ if(!trigger) {
+ return;
+ }
+
+ const dropdown = trigger.closest(".dropdown");
+
+ if(!dropdown) {
+ return;
+ }
+
+ event.preventDefault();
+ const isOpen = dropdown.classList.contains("is-open");
+ closeAll(dropdown);
+ dropdown.classList.toggle("is-open", !isOpen);
+ trigger.setAttribute("aria-expanded", String(!isOpen));
+ });
+}
+
+function initTooltips(root = document) {
+ root.addEventListener("click", event => {
+ const trigger = event.target.closest("[data-tooltip-toggle]");
+
+ if(!trigger) {
+ return;
+ }
+
+ const tooltip = trigger.closest(".tooltip");
+
+ if(!tooltip) {
+ return;
+ }
+
+ event.preventDefault();
+ const isOpen = tooltip.classList.contains("is-open");
+ closeAll(tooltip);
+ tooltip.classList.toggle("is-open", !isOpen);
+ });
+}
+
+function initDismiss(root = document) {
+ root.addEventListener("click", event => {
+ if(event.target.closest(".dropdown, .popover, .tooltip")) {
+ return;
+ }
+
+ closeAll();
+ });
+
+ if(!keyboardDismissInitialized) {
+ document.addEventListener("keydown", event => {
+ if(event.key === "Escape") {
+ closeAll();
+ }
+ });
+
+ keyboardDismissInitialized = true;
+ }
+}
+
+function init(root = document) {
+ if(initializedRoots.has(root)) {
+ return;
+ }
+
+ initDropdowns(root);
+ initTooltips(root);
+ initDismiss(root);
+ initializedRoots.add(root);
+}
+
+export default {
+ init,
+ closeAll
+};
diff --git a/src/js/index.js b/src/js/index.js
index d7b0558..d50c279 100644
--- a/src/js/index.js
+++ b/src/js/index.js
@@ -9,6 +9,7 @@
import confirmPopup from "./components/confirm-popup.js";
import InputPatterns from "./components/input-patterns.js";
import editableString from "./components/editable-string.js";
+import Overlays from "./components/overlays.js";
import Tabs from "./components/tabs.js";
import Progress from "./components/progress.js";
import Tables from "./components/tables.js";
@@ -30,6 +31,7 @@
confirmPopup,
InputPatterns,
editableString,
+ Overlays,
Tabs,
Progress,
Tables,
@@ -60,8 +62,9 @@
Loader.init?.();
NavigationShell.init?.();
InputPatterns.init?.();
+ Overlays.init?.();
});
}
-export { Icons as Helper, Toasts, Modals, confirmPopup, InputPatterns, editableString, Tabs, Progress, Tables, Lists, Skeleton, Tooltips, Dropdowns, NavigationShell, Background, Breadcrumbs, Accordion, Popover, Loader };
+export { Icons as Helper, Toasts, Modals, confirmPopup, InputPatterns, editableString, Overlays, Tabs, Progress, Tables, Lists, Skeleton, Tooltips, Dropdowns, NavigationShell, Background, Breadcrumbs, Accordion, Popover, Loader };
export default api;
diff --git a/src/scss/components/_dropdown.scss b/src/scss/components/_dropdown.scss
index 97be422..bea83e5 100644
--- a/src/scss/components/_dropdown.scss
+++ b/src/scss/components/_dropdown.scss
@@ -31,7 +31,8 @@
visibility $motion-fast $motion-ease,
transform $motion-fast $motion-ease;
- &.is-open {
+ &.is-open,
+ .dropdown.is-open & {
opacity: 1;
visibility: visible;
transform: translateY(0);
diff --git a/src/scss/components/_tooltip.scss b/src/scss/components/_tooltip.scss
index 3b300d6..81acf54 100644
--- a/src/scss/components/_tooltip.scss
+++ b/src/scss/components/_tooltip.scss
@@ -105,6 +105,7 @@
}
&.is-visible .tooltip-content,
+ &.is-open .tooltip-content,
&:hover .tooltip-content,
.tooltip-trigger:focus + .tooltip-content,
.tooltip-trigger:focus-within + .tooltip-content {
@@ -114,6 +115,7 @@
}
&[data-placement="left"].is-visible .tooltip-content,
+ &[data-placement="left"].is-open .tooltip-content,
&[data-placement="left"]:hover .tooltip-content {
transform: translateY(-50%) translateX(0);
}