import tippy from "@libs/tippy"; import buildConfig from "../utils/tippy_modifiers"; import { isObject } from "@helpers/lang"; import { isNode } from "@helpers/dom"; import { setData, getData } from "@helpers/alpine"; export default function (Alpine) { Alpine.directive( "dropdown", (el, { value, modifiers, expression }, { evaluate, effect }) => { // Don't run for dropdown sub-elements // like `x-dropdown:trigger` and `x-dropdown:content` if (value) return; const data = getData(el); const settings = buildConfig(modifiers); const result = expression ? evaluate(expression) : {}; const directiveConfig = isObject(result) ? result : {}; let { triggerTarget, contentTarget, ...config } = directiveConfig; contentTarget = contentTarget || el.querySelector("[x-dropdown\\:content]"); content = isNode(contentTarget) ? contentTarget.firstElementChild : contentTarget; triggerTarget = triggerTarget || el.querySelector("[x-dropdown\\:trigger]") || el; // Initialize the dropdown if (!el.__x_dropdown) { // Mix in some helper methods under the `.dropdown` // property for managing the dropdown. const mixin = Alpine.reactive({ dropdown: { open: false, trigger: triggerTarget, content: contentTarget, hide() { el.__x_dropdown.hide(); }, show() { el.__x_dropdown.show(); }, }, }); setData(el, mixin); const dropdown = (el.__x_dropdown = tippy(el, { theme: "coco-app-dropdown", placement: "bottom-start", offset: [0, 0], trigger: "click", interactive: true, animation: false, triggerTarget, content, onShow: (...args) => { mixin.dropdown.open = true; data.$dispatch("dropdown:show", { dropdown: el.__x_dropdown }); }, onHide: (...args) => { mixin.dropdown.open = false; data.$dispatch("dropdown:hide", { dropdown: el.__x_dropdown }); }, onMount() { data.$dispatch("dropdown:mount", { dropdown: el.__x_dropdown }); }, onCreate() { data.$dispatch("dropdown:create", { dropdown: el.__x_dropdown }); }, ...settings, ...config, })); } } ).before("bind"); }