summaryrefslogtreecommitdiffstatshomepage
path: root/core/modules/navigation/js/tooltip.js
diff options
context:
space:
mode:
Diffstat (limited to 'core/modules/navigation/js/tooltip.js')
-rw-r--r--core/modules/navigation/js/tooltip.js83
1 files changed, 83 insertions, 0 deletions
diff --git a/core/modules/navigation/js/tooltip.js b/core/modules/navigation/js/tooltip.js
new file mode 100644
index 000000000000..a92e045b1f81
--- /dev/null
+++ b/core/modules/navigation/js/tooltip.js
@@ -0,0 +1,83 @@
+/* cspell:ignore uidom */
+/**
+ * @file
+ *
+ * Simple tooltip component.
+ *
+ * To use it just add:
+ *
+ * data-drupal-tooltip="title" - Text displayed in tooltip.
+ *
+ * data-drupal-tooltip-class="extra-class" - Optional class for css.
+ *
+ * data-drupal-tooltip-position="top" - Tooltip position (default right).
+ *
+ * @see https://floating-ui.com/ for available placement options.
+ */
+
+((Drupal, once, { computePosition, offset, shift, flip }) => {
+ /**
+ * Theme function for a tooltip.
+ *
+ * @param {object} dataset
+ * The dataset object.
+ * @param {string} dataset.drupalTooltipClass
+ * Extra class for theming.
+ * @param {string} dataset.drupalTooltip
+ * The text for tooltip.
+ *
+ * @return {HTMLElement}
+ * A DOM Node.
+ */
+ Drupal.theme.tooltipWrapper = (dataset) =>
+ `<div class="toolbar-tooltip ${dataset.drupalTooltipClass || ''}">
+ ${dataset.drupalTooltip}
+ </div>`;
+
+ /**
+ * Attaches the tooltip behavior to all required triggers.
+ *
+ * @type {Drupal~behavior}
+ *
+ * @prop {Drupal~behaviorAttach} attach
+ * Attaches the tooltip behavior.
+ */
+ Drupal.behaviors.tooltipInit = {
+ attach: (context) => {
+ once('tooltip-trigger', '[data-drupal-tooltip]', context).forEach(
+ (trigger) => {
+ trigger.insertAdjacentHTML(
+ 'afterend',
+ Drupal.theme.tooltipWrapper(trigger.dataset),
+ );
+ const tooltip = trigger.nextElementSibling;
+
+ const updatePosition = () => {
+ computePosition(trigger, tooltip, {
+ strategy: 'fixed',
+ placement: trigger.dataset.drupalTooltipPosition || 'right',
+ middleware: [
+ flip({ padding: 16 }),
+ offset(6),
+ shift({ padding: 16 }),
+ ],
+ }).then(({ x, y }) => {
+ Object.assign(tooltip.style, {
+ left: `${x}px`,
+ top: `${y}px`,
+ });
+ });
+ };
+
+ // Small trick to avoid tooltip stays on same place when button size changed.
+ const ro = new ResizeObserver(updatePosition);
+
+ ro.observe(trigger);
+
+ trigger.addEventListener('mouseover', updatePosition);
+ trigger.addEventListener('focus', updatePosition);
+ },
+ );
+ },
+ };
+})(Drupal, once, FloatingUIDOM);