UNPKG

bootstrap-vue-next

Version:

Seamless integration of Vue 3, Bootstrap 5, and TypeScript for modern, type-safe UI development

170 lines (169 loc) 6.42 kB
import { l as defaultsKey } from "./keys-CQKrwmvN.mjs"; import { c as unbind, i as resolveActiveStatus, o as resolveContent, s as resolveDirectiveProps, t as bind } from "./floatingUi-BErx3eqf.mjs"; //#region src/directives/utils.ts /** * Gets the component instance UID from a directive binding * @throws Error if binding.instance is not available */ function getDirectiveUid(binding) { if (!binding.instance) throw new Error("[Bootstrap-Vue-Next] Directive binding.instance is not available"); return binding.instance.$.uid; } /** * Initializes UID-namespaced storage on an element for a directive * @param el - The HTML element * @param propertyName - The property name (e.g., '$__tooltip', '$__popover') * @param uid - The component instance UID * @param binding - The directive binding value to cache * @returns The initialized instance state */ function initDirectiveInstance(el, propertyName, uid, binding) { const elWithProps = el; elWithProps[propertyName] = elWithProps[propertyName] ?? Object.create(null); const state = { binding: JSON.stringify([binding.modifiers, binding.value]), destroying: false }; elWithProps[propertyName][uid] = state; return state; } /** * Gets the instance state for a directive, if it exists * @param el - The HTML element * @param propertyName - The property name (e.g., '$__tooltip', '$__popover') * @param uid - The component instance UID * @returns The instance state or undefined if not found */ function getDirectiveInstance(el, propertyName, uid) { return el[propertyName]?.[uid]; } /** * Checks if the directive binding has changed for this instance * @param instance - The directive instance state * @param binding - The current directive binding * @returns true if the binding has changed, false otherwise */ function hasBindingChanged(instance, binding) { const newBinding = JSON.stringify([binding.modifiers, binding.value]); return instance.binding !== newBinding; } /** * Updates the cached binding value for a directive instance * @param instance - The directive instance state * @param binding - The new directive binding */ function updateBindingCache(instance, binding) { instance.binding = JSON.stringify([binding.modifiers, binding.value]); } /** * Cleans up a directive instance * @param el - The HTML element * @param propertyName - The property name (e.g., '$__tooltip', '$__popover') * @param uid - The component instance UID */ function cleanupDirectiveInstance(el, propertyName, uid) { const elWithProps = el; const instance = elWithProps[propertyName]?.[uid]; if (instance) { instance.destroying = true; delete elWithProps[propertyName][uid]; } } function findProvides(binding, vnode) { return (vnode.ctx === binding.instance.$ ? findComponentParent(vnode, binding.instance.$)?.provides : vnode.ctx?.provides) ?? binding.instance.$.provides; } function findComponentParent(vnode, root) { const stack = /* @__PURE__ */ new Set(); const walk = (children) => { for (const child of children) { if (!child) continue; if (child === vnode || child.el && vnode.el && child.el === vnode.el) return true; stack.add(child); let result; if (child.suspense) result = walk([child.ssContent]); else if (Array.isArray(child.children)) result = walk(child.children); else if (child.component?.vnode) result = walk([child.component?.subTree]); if (result) return result; stack.delete(child); } return false; }; if (!walk([root.subTree])) { console.error("Could not find original vnode, will not inherit provides"); return root; } const result = Array.from(stack).reverse(); for (const child of result) if (child.component) return child.component; return root; } /** * Creates a floating UI directive (tooltip or popover) with UID-namespaced state management * @param propertyName - The property name for storing state (e.g., '$__tooltip', '$__popover') * @param componentDefaultsKey - The key for accessing component defaults (e.g., 'BTooltip', 'BPopover') * @param buildProps - Optional function to customize the props passed to bind() * @returns A Vue directive object */ function createFloatingDirective(propertyName, componentDefaultsKey, buildProps) { return { mounted(el, binding, vnode) { const uid = getDirectiveUid(binding); const defaultsMap = findProvides(binding, vnode)[defaultsKey]?.value; if (!resolveActiveStatus(binding.value)) return; const text = resolveContent(binding.value, el); if (!text.body && !text.title) return; initDirectiveInstance(el, propertyName, uid, binding); bind(el, binding, buildProps ? buildProps(text, defaultsMap?.[componentDefaultsKey], binding, el) : { ...defaultsMap?.[componentDefaultsKey] || void 0, ...resolveDirectiveProps(binding, el), ...text }); }, updated(el, binding, vnode) { const uid = getDirectiveUid(binding); let instance = getDirectiveInstance(el, propertyName, uid); const defaultsMap = findProvides(binding, vnode)[defaultsKey]?.value; if (!resolveActiveStatus(binding.value)) { if (instance && el.$__element) { unbind(el); cleanupDirectiveInstance(el, propertyName, uid); } return; } const text = resolveContent(binding.value, el); if (!text.body && !text.title) { if (instance && el.$__element) { unbind(el); cleanupDirectiveInstance(el, propertyName, uid); } return; } if (!instance) { instance = initDirectiveInstance(el, propertyName, uid, binding); bind(el, binding, buildProps ? buildProps(text, defaultsMap?.[componentDefaultsKey], binding, el) : { ...defaultsMap?.[componentDefaultsKey] || void 0, ...resolveDirectiveProps(binding, el), ...text }); return; } if (!hasBindingChanged(instance, binding)) return; if (instance.destroying) return; unbind(el); bind(el, binding, buildProps ? buildProps(text, defaultsMap?.[componentDefaultsKey], binding, el) : { ...defaultsMap?.[componentDefaultsKey] || void 0, ...resolveDirectiveProps(binding, el), ...text }); updateBindingCache(instance, binding); }, beforeUnmount(el, binding) { const uid = getDirectiveUid(binding); if (!getDirectiveInstance(el, propertyName, uid)) return; unbind(el); cleanupDirectiveInstance(el, propertyName, uid); } }; } //#endregion export { findProvides as n, getDirectiveUid as r, createFloatingDirective as t }; //# sourceMappingURL=utils-D_vdhVDP.mjs.map