mirror of
https://github.com/LukeHagar/arbiter.git
synced 2025-12-10 12:27:49 +00:00
247 lines
8.3 KiB
JavaScript
247 lines
8.3 KiB
JavaScript
(function (global, factory) {
|
|
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@floating-ui/dom'), require('@floating-ui/utils/dom'), require('vue-demi')) :
|
|
typeof define === 'function' && define.amd ? define(['exports', '@floating-ui/dom', '@floating-ui/utils/dom', 'vue-demi'], factory) :
|
|
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.FloatingUIVue = {}, global.FloatingUIDOM, global.FloatingUIUtilsDOM, global.VueDemi));
|
|
})(this, (function (exports, dom, dom$1, vueDemi) { 'use strict';
|
|
|
|
function isComponentPublicInstance(target) {
|
|
return target != null && typeof target === 'object' && '$el' in target;
|
|
}
|
|
function unwrapElement(target) {
|
|
if (isComponentPublicInstance(target)) {
|
|
const element = target.$el;
|
|
return dom$1.isNode(element) && dom$1.getNodeName(element) === '#comment' ? null : element;
|
|
}
|
|
return target;
|
|
}
|
|
|
|
function toValue(source) {
|
|
return typeof source === 'function' ? source() : vueDemi.unref(source);
|
|
}
|
|
|
|
/**
|
|
* Positions an inner element of the floating element such that it is centered to the reference element.
|
|
* @param options The arrow options.
|
|
* @see https://floating-ui.com/docs/arrow
|
|
*/
|
|
function arrow(options) {
|
|
return {
|
|
name: 'arrow',
|
|
options,
|
|
fn(args) {
|
|
const element = unwrapElement(toValue(options.element));
|
|
if (element == null) {
|
|
return {};
|
|
}
|
|
return dom.arrow({
|
|
element,
|
|
padding: options.padding
|
|
}).fn(args);
|
|
}
|
|
};
|
|
}
|
|
|
|
function getDPR(element) {
|
|
if (typeof window === 'undefined') {
|
|
return 1;
|
|
}
|
|
const win = element.ownerDocument.defaultView || window;
|
|
return win.devicePixelRatio || 1;
|
|
}
|
|
|
|
function roundByDPR(element, value) {
|
|
const dpr = getDPR(element);
|
|
return Math.round(value * dpr) / dpr;
|
|
}
|
|
|
|
/**
|
|
* Computes the `x` and `y` coordinates that will place the floating element next to a reference element when it is given a certain CSS positioning strategy.
|
|
* @param reference The reference template ref.
|
|
* @param floating The floating template ref.
|
|
* @param options The floating options.
|
|
* @see https://floating-ui.com/docs/vue
|
|
*/
|
|
function useFloating(reference, floating, options) {
|
|
if (options === void 0) {
|
|
options = {};
|
|
}
|
|
const whileElementsMountedOption = options.whileElementsMounted;
|
|
const openOption = vueDemi.computed(() => {
|
|
var _toValue;
|
|
return (_toValue = toValue(options.open)) != null ? _toValue : true;
|
|
});
|
|
const middlewareOption = vueDemi.computed(() => toValue(options.middleware));
|
|
const placementOption = vueDemi.computed(() => {
|
|
var _toValue2;
|
|
return (_toValue2 = toValue(options.placement)) != null ? _toValue2 : 'bottom';
|
|
});
|
|
const strategyOption = vueDemi.computed(() => {
|
|
var _toValue3;
|
|
return (_toValue3 = toValue(options.strategy)) != null ? _toValue3 : 'absolute';
|
|
});
|
|
const transformOption = vueDemi.computed(() => {
|
|
var _toValue4;
|
|
return (_toValue4 = toValue(options.transform)) != null ? _toValue4 : true;
|
|
});
|
|
const referenceElement = vueDemi.computed(() => unwrapElement(reference.value));
|
|
const floatingElement = vueDemi.computed(() => unwrapElement(floating.value));
|
|
const x = vueDemi.ref(0);
|
|
const y = vueDemi.ref(0);
|
|
const strategy = vueDemi.ref(strategyOption.value);
|
|
const placement = vueDemi.ref(placementOption.value);
|
|
const middlewareData = vueDemi.shallowRef({});
|
|
const isPositioned = vueDemi.ref(false);
|
|
const floatingStyles = vueDemi.computed(() => {
|
|
const initialStyles = {
|
|
position: strategy.value,
|
|
left: '0',
|
|
top: '0'
|
|
};
|
|
if (!floatingElement.value) {
|
|
return initialStyles;
|
|
}
|
|
const xVal = roundByDPR(floatingElement.value, x.value);
|
|
const yVal = roundByDPR(floatingElement.value, y.value);
|
|
if (transformOption.value) {
|
|
return {
|
|
...initialStyles,
|
|
transform: "translate(" + xVal + "px, " + yVal + "px)",
|
|
...(getDPR(floatingElement.value) >= 1.5 && {
|
|
willChange: 'transform'
|
|
})
|
|
};
|
|
}
|
|
return {
|
|
position: strategy.value,
|
|
left: xVal + "px",
|
|
top: yVal + "px"
|
|
};
|
|
});
|
|
let whileElementsMountedCleanup;
|
|
function update() {
|
|
if (referenceElement.value == null || floatingElement.value == null) {
|
|
return;
|
|
}
|
|
const open = openOption.value;
|
|
dom.computePosition(referenceElement.value, floatingElement.value, {
|
|
middleware: middlewareOption.value,
|
|
placement: placementOption.value,
|
|
strategy: strategyOption.value
|
|
}).then(position => {
|
|
x.value = position.x;
|
|
y.value = position.y;
|
|
strategy.value = position.strategy;
|
|
placement.value = position.placement;
|
|
middlewareData.value = position.middlewareData;
|
|
/**
|
|
* The floating element's position may be recomputed while it's closed
|
|
* but still mounted (such as when transitioning out). To ensure
|
|
* `isPositioned` will be `false` initially on the next open, avoid
|
|
* setting it to `true` when `open === false` (must be specified).
|
|
*/
|
|
isPositioned.value = open !== false;
|
|
});
|
|
}
|
|
function cleanup() {
|
|
if (typeof whileElementsMountedCleanup === 'function') {
|
|
whileElementsMountedCleanup();
|
|
whileElementsMountedCleanup = undefined;
|
|
}
|
|
}
|
|
function attach() {
|
|
cleanup();
|
|
if (whileElementsMountedOption === undefined) {
|
|
update();
|
|
return;
|
|
}
|
|
if (referenceElement.value != null && floatingElement.value != null) {
|
|
whileElementsMountedCleanup = whileElementsMountedOption(referenceElement.value, floatingElement.value, update);
|
|
return;
|
|
}
|
|
}
|
|
function reset() {
|
|
if (!openOption.value) {
|
|
isPositioned.value = false;
|
|
}
|
|
}
|
|
vueDemi.watch([middlewareOption, placementOption, strategyOption, openOption], update, {
|
|
flush: 'sync'
|
|
});
|
|
vueDemi.watch([referenceElement, floatingElement], attach, {
|
|
flush: 'sync'
|
|
});
|
|
vueDemi.watch(openOption, reset, {
|
|
flush: 'sync'
|
|
});
|
|
if (vueDemi.getCurrentScope()) {
|
|
vueDemi.onScopeDispose(cleanup);
|
|
}
|
|
return {
|
|
x: vueDemi.shallowReadonly(x),
|
|
y: vueDemi.shallowReadonly(y),
|
|
strategy: vueDemi.shallowReadonly(strategy),
|
|
placement: vueDemi.shallowReadonly(placement),
|
|
middlewareData: vueDemi.shallowReadonly(middlewareData),
|
|
isPositioned: vueDemi.shallowReadonly(isPositioned),
|
|
floatingStyles,
|
|
update
|
|
};
|
|
}
|
|
|
|
Object.defineProperty(exports, "autoPlacement", {
|
|
enumerable: true,
|
|
get: function () { return dom.autoPlacement; }
|
|
});
|
|
Object.defineProperty(exports, "autoUpdate", {
|
|
enumerable: true,
|
|
get: function () { return dom.autoUpdate; }
|
|
});
|
|
Object.defineProperty(exports, "computePosition", {
|
|
enumerable: true,
|
|
get: function () { return dom.computePosition; }
|
|
});
|
|
Object.defineProperty(exports, "detectOverflow", {
|
|
enumerable: true,
|
|
get: function () { return dom.detectOverflow; }
|
|
});
|
|
Object.defineProperty(exports, "flip", {
|
|
enumerable: true,
|
|
get: function () { return dom.flip; }
|
|
});
|
|
Object.defineProperty(exports, "getOverflowAncestors", {
|
|
enumerable: true,
|
|
get: function () { return dom.getOverflowAncestors; }
|
|
});
|
|
Object.defineProperty(exports, "hide", {
|
|
enumerable: true,
|
|
get: function () { return dom.hide; }
|
|
});
|
|
Object.defineProperty(exports, "inline", {
|
|
enumerable: true,
|
|
get: function () { return dom.inline; }
|
|
});
|
|
Object.defineProperty(exports, "limitShift", {
|
|
enumerable: true,
|
|
get: function () { return dom.limitShift; }
|
|
});
|
|
Object.defineProperty(exports, "offset", {
|
|
enumerable: true,
|
|
get: function () { return dom.offset; }
|
|
});
|
|
Object.defineProperty(exports, "platform", {
|
|
enumerable: true,
|
|
get: function () { return dom.platform; }
|
|
});
|
|
Object.defineProperty(exports, "shift", {
|
|
enumerable: true,
|
|
get: function () { return dom.shift; }
|
|
});
|
|
Object.defineProperty(exports, "size", {
|
|
enumerable: true,
|
|
get: function () { return dom.size; }
|
|
});
|
|
exports.arrow = arrow;
|
|
exports.useFloating = useFloating;
|
|
|
|
}));
|