diff --git a/app/Resources/js/modules/Dropdown.ts b/app/Resources/js/modules/Dropdown.ts index c896ff14e5153342a1444f65c0429613dcaef98e..06cfb9a531cdfe3e5c4a96de71583258066e0d73 100644 --- a/app/Resources/js/modules/Dropdown.ts +++ b/app/Resources/js/modules/Dropdown.ts @@ -1,4 +1,10 @@ -import { createPopper, Instance, Placement } from "@popperjs/core"; +import { + computePosition, + flip, + offset, + Placement, + shift, +} from "@floating-ui/dom"; const Dropdown = (): void => { const dropdownButtons: NodeListOf<HTMLButtonElement> = @@ -16,46 +22,46 @@ const Dropdown = (): void => { // place the menu at then end of the body to prevent any overflow cuts document.body.appendChild(menu); - let popperInstance: Instance | null = null; - - const create = () => { + const update = () => { const offsetX = menu.dataset.dropdownOffsetX ? parseInt(menu.dataset.dropdownOffsetX) : 0; const offsetY = menu.dataset.dropdownOffsetY ? parseInt(menu.dataset.dropdownOffsetY) : 0; - popperInstance = createPopper(button, menu, { + computePosition(button, menu, { placement: menu.dataset.dropdownPlacement as Placement, - modifiers: [ - { - name: "offset", - options: { - offset: [offsetX, offsetY], - }, - }, + middleware: [ + offset({ mainAxis: offsetY, crossAxis: offsetX }), + flip(), + shift(), ], + }).then(({ x, y }) => { + Object.assign(menu.style, { + left: `${x}px`, + top: `${y}px`, + }); }); }; - const destroy = () => { - if (popperInstance) { - popperInstance.destroy(); - popperInstance = null; - } + const showMenu = () => { + menu.setAttribute("data-show", ""); + button.setAttribute("aria-expanded", "true"); + update(); + }; + + const hideMenu = () => { + menu.removeAttribute("data-show"); + button.setAttribute("aria-expanded", "false"); }; const dropdownToggle = () => { const isExpanded = menu.hasAttribute("data-show"); if (isExpanded) { - menu.removeAttribute("data-show"); - button.setAttribute("aria-expanded", "false"); - destroy(); + hideMenu(); } else { - menu.setAttribute("data-show", ""); - button.setAttribute("aria-expanded", "true"); - create(); + showMenu(); } }; diff --git a/app/Resources/js/modules/Tooltip.ts b/app/Resources/js/modules/Tooltip.ts index 47065dec5324f95139bbc286b80e54e46abfb48a..0d0d2733e7120aa04a5d6acc11e56da0cc7acf3b 100644 --- a/app/Resources/js/modules/Tooltip.ts +++ b/app/Resources/js/modules/Tooltip.ts @@ -1,4 +1,12 @@ -import { createPopper, Placement } from "@popperjs/core"; +import { Coords } from "@floating-ui/core"; +import { + arrow, + computePosition, + flip, + offset, + Placement, + shift, +} from "@floating-ui/dom"; const Tooltip = (): void => { const tooltipContainers: NodeListOf<HTMLElement> = @@ -12,30 +20,60 @@ const Tooltip = (): void => { tooltip.setAttribute("id", "tooltip" + i); tooltip.setAttribute( "class", - "px-2 py-1 text-sm bg-gray-900 text-white rounded max-w-xs z-50" + "absolute px-2 py-1 text-sm bg-gray-900 text-white rounded max-w-xs z-50" ); tooltip.innerHTML = tooltipContent; + const arrowElement = document.createElement("div"); + arrowElement.setAttribute( + "class", + "absolute bg-gray-900 w-2 h-2 rotate-45" + ); + arrowElement.setAttribute("id", "arrow" + i); + tooltip.appendChild(arrowElement); - const popper = createPopper(tooltipReference, tooltip, { - placement: tooltipReference.dataset.tooltip as Placement, - modifiers: [ - { - name: "offset", - options: { - offset: [0, 8], - }, - }, - ], - }); + const update = () => { + computePosition(tooltipReference, tooltip, { + placement: tooltipReference.dataset.tooltip as Placement, + middleware: [ + flip(), + shift(), + offset(8), + arrow({ element: arrowElement }), + ], + }).then(({ x, y, placement, middlewareData }) => { + Object.assign(tooltip.style, { + left: `${x}px`, + top: `${y}px`, + }); + + // Accessing the data + const { x: arrowX, y: arrowY } = middlewareData.arrow as Coords; + + const staticSide = { + top: "bottom", + right: "left", + bottom: "top", + left: "right", + }[placement.split("-")[0]]; + + Object.assign(arrowElement.style, { + left: arrowX != null ? `${arrowX}px` : "", + top: arrowY != null ? `${arrowY}px` : "", + right: "", + bottom: "", + [staticSide as string]: "-4px", + }); + }); + }; - const show = () => { + const showTooltip = () => { tooltipReference.removeAttribute("title"); tooltipReference.setAttribute("aria-describedby", "tooltip" + i); document.body.appendChild(tooltip); - popper.update(); + update(); }; - const hide = () => { + const hideTooltip = () => { const element = document.getElementById("tooltip" + i); tooltipReference.removeAttribute("aria-describedby"); tooltipReference.setAttribute("title", tooltipContent); @@ -48,11 +86,11 @@ const Tooltip = (): void => { const hideEvents = ["mouseleave", "blur"]; showEvents.forEach((event) => { - tooltipReference.addEventListener(event, show); + tooltipReference.addEventListener(event, showTooltip); }); hideEvents.forEach((event) => { - tooltipReference.addEventListener(event, hide); + tooltipReference.addEventListener(event, hideTooltip); }); } }; diff --git a/app/Resources/styles/dropdown.css b/app/Resources/styles/dropdown.css index bf3e2ed00fc9033c6582a57ff342fd2641117626..850f8d35aae5e3121109528c06af14d65639d523 100644 --- a/app/Resources/styles/dropdown.css +++ b/app/Resources/styles/dropdown.css @@ -1,8 +1,8 @@ @layer base { [data-dropdown="menu"] { - @apply z-50; + @apply absolute z-50; } [data-dropdown="menu"]:not([data-show]) { - @apply absolute top-0 left-0 invisible pointer-events-none; + @apply hidden; } } diff --git a/package-lock.json b/package-lock.json index aebd3b99526633b8b04ddc7564684df2bb2b59f7..7fa81b3761c77459f3ce12407921381e838a1b6e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,11 +16,11 @@ "@codemirror/lang-xml": "^0.19.2", "@codemirror/state": "^0.19.6", "@codemirror/view": "^0.19.32", + "@floating-ui/dom": "^0.1.10", "@github/clipboard-copy-element": "^1.1.2", "@github/hotkey": "^1.6.1", "@github/markdown-toolbar-element": "^2.1.0", "@github/time-elements": "^3.1.2", - "@popperjs/core": "^2.11.0", "@tailwindcss/nesting": "^0.0.0-insiders.565cd3e", "@vime/core": "^5.3.0", "choices.js": "^9.0.1", @@ -2355,6 +2355,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@floating-ui/core": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-0.3.1.tgz", + "integrity": "sha512-ensKY7Ub59u16qsVIFEo2hwTCqZ/r9oZZFh51ivcLGHfUwTn8l1Xzng8RJUe91H/UP8PeqeBronAGx0qmzwk2g==" + }, + "node_modules/@floating-ui/dom": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-0.1.10.tgz", + "integrity": "sha512-4kAVoogvQm2N0XE0G6APQJuCNuErjOfPW8Ux7DFxh8+AfugWflwVJ5LDlHOwrwut7z/30NUvdtHzQ3zSip4EzQ==", + "dependencies": { + "@floating-ui/core": "^0.3.0" + } + }, "node_modules/@foliojs-fork/fontkit": { "version": "1.9.1", "license": "MIT", @@ -2606,14 +2619,6 @@ "@octokit/openapi-types": "^11.2.0" } }, - "node_modules/@popperjs/core": { - "version": "2.11.0", - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/popperjs" - } - }, "node_modules/@rollup/plugin-babel": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.0.tgz", @@ -18285,6 +18290,19 @@ } } }, + "@floating-ui/core": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-0.3.1.tgz", + "integrity": "sha512-ensKY7Ub59u16qsVIFEo2hwTCqZ/r9oZZFh51ivcLGHfUwTn8l1Xzng8RJUe91H/UP8PeqeBronAGx0qmzwk2g==" + }, + "@floating-ui/dom": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-0.1.10.tgz", + "integrity": "sha512-4kAVoogvQm2N0XE0G6APQJuCNuErjOfPW8Ux7DFxh8+AfugWflwVJ5LDlHOwrwut7z/30NUvdtHzQ3zSip4EzQ==", + "requires": { + "@floating-ui/core": "^0.3.0" + } + }, "@foliojs-fork/fontkit": { "version": "1.9.1", "requires": { @@ -18491,9 +18509,6 @@ "@octokit/openapi-types": "^11.2.0" } }, - "@popperjs/core": { - "version": "2.11.0" - }, "@rollup/plugin-babel": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.0.tgz", diff --git a/package.json b/package.json index d619d3f90df19f9b1256f83d59cff47d871d350b..18c42eb02c657e1311fa034beebd14af5c177779 100644 --- a/package.json +++ b/package.json @@ -34,11 +34,11 @@ "@codemirror/lang-xml": "^0.19.2", "@codemirror/state": "^0.19.6", "@codemirror/view": "^0.19.32", + "@floating-ui/dom": "^0.1.10", "@github/clipboard-copy-element": "^1.1.2", "@github/hotkey": "^1.6.1", "@github/markdown-toolbar-element": "^2.1.0", "@github/time-elements": "^3.1.2", - "@popperjs/core": "^2.11.0", "@tailwindcss/nesting": "^0.0.0-insiders.565cd3e", "@vime/core": "^5.3.0", "choices.js": "^9.0.1",