@zag-js/popper 1.34.0 → 1.35.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/get-anchor.d.mts +7 -0
- package/dist/get-anchor.d.ts +7 -0
- package/dist/get-anchor.js +66 -0
- package/dist/get-anchor.mjs +40 -0
- package/dist/get-placement.d.mts +8 -0
- package/dist/get-placement.d.ts +8 -0
- package/dist/get-placement.js +237 -0
- package/dist/get-placement.mjs +212 -0
- package/dist/get-styles.d.mts +41 -0
- package/dist/get-styles.d.ts +41 -0
- package/dist/get-styles.js +73 -0
- package/dist/get-styles.mjs +48 -0
- package/dist/index.d.mts +5 -187
- package/dist/index.d.ts +5 -187
- package/dist/index.js +34 -378
- package/dist/index.mjs +9 -376
- package/dist/middleware.d.mts +35 -0
- package/dist/middleware.d.ts +35 -0
- package/dist/middleware.js +108 -0
- package/dist/middleware.mjs +80 -0
- package/dist/placement.d.mts +12 -0
- package/dist/placement.d.ts +12 -0
- package/dist/placement.js +43 -0
- package/dist/placement.mjs +16 -0
- package/dist/types.d.mts +122 -0
- package/dist/types.d.ts +122 -0
- package/dist/types.js +18 -0
- package/dist/types.mjs +0 -0
- package/package.json +3 -3
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { VirtualElement } from '@floating-ui/dom';
|
|
2
|
+
import { MaybeRectElement, AnchorRect } from './types.mjs';
|
|
3
|
+
|
|
4
|
+
declare function createDOMRect(x?: number, y?: number, width?: number, height?: number): DOMRect;
|
|
5
|
+
declare function getAnchorElement(anchorElement: MaybeRectElement, getAnchorRect?: (anchor: MaybeRectElement) => AnchorRect | null): VirtualElement;
|
|
6
|
+
|
|
7
|
+
export { createDOMRect, getAnchorElement };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { VirtualElement } from '@floating-ui/dom';
|
|
2
|
+
import { MaybeRectElement, AnchorRect } from './types.js';
|
|
3
|
+
|
|
4
|
+
declare function createDOMRect(x?: number, y?: number, width?: number, height?: number): DOMRect;
|
|
5
|
+
declare function getAnchorElement(anchorElement: MaybeRectElement, getAnchorRect?: (anchor: MaybeRectElement) => AnchorRect | null): VirtualElement;
|
|
6
|
+
|
|
7
|
+
export { createDOMRect, getAnchorElement };
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/get-anchor.ts
|
|
21
|
+
var get_anchor_exports = {};
|
|
22
|
+
__export(get_anchor_exports, {
|
|
23
|
+
createDOMRect: () => createDOMRect,
|
|
24
|
+
getAnchorElement: () => getAnchorElement
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(get_anchor_exports);
|
|
27
|
+
var import_dom_query = require("@zag-js/dom-query");
|
|
28
|
+
function createDOMRect(x = 0, y = 0, width = 0, height = 0) {
|
|
29
|
+
if (typeof DOMRect === "function") {
|
|
30
|
+
return new DOMRect(x, y, width, height);
|
|
31
|
+
}
|
|
32
|
+
const rect = {
|
|
33
|
+
x,
|
|
34
|
+
y,
|
|
35
|
+
width,
|
|
36
|
+
height,
|
|
37
|
+
top: y,
|
|
38
|
+
right: x + width,
|
|
39
|
+
bottom: y + height,
|
|
40
|
+
left: x
|
|
41
|
+
};
|
|
42
|
+
return { ...rect, toJSON: () => rect };
|
|
43
|
+
}
|
|
44
|
+
function getDOMRect(anchorRect) {
|
|
45
|
+
if (!anchorRect) return createDOMRect();
|
|
46
|
+
const { x, y, width, height } = anchorRect;
|
|
47
|
+
return createDOMRect(x, y, width, height);
|
|
48
|
+
}
|
|
49
|
+
function getAnchorElement(anchorElement, getAnchorRect) {
|
|
50
|
+
return {
|
|
51
|
+
contextElement: (0, import_dom_query.isHTMLElement)(anchorElement) ? anchorElement : anchorElement?.contextElement,
|
|
52
|
+
getBoundingClientRect: () => {
|
|
53
|
+
const anchor = anchorElement;
|
|
54
|
+
const anchorRect = getAnchorRect?.(anchor);
|
|
55
|
+
if (anchorRect || !anchor) {
|
|
56
|
+
return getDOMRect(anchorRect);
|
|
57
|
+
}
|
|
58
|
+
return anchor.getBoundingClientRect();
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
63
|
+
0 && (module.exports = {
|
|
64
|
+
createDOMRect,
|
|
65
|
+
getAnchorElement
|
|
66
|
+
});
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// src/get-anchor.ts
|
|
2
|
+
import { isHTMLElement } from "@zag-js/dom-query";
|
|
3
|
+
function createDOMRect(x = 0, y = 0, width = 0, height = 0) {
|
|
4
|
+
if (typeof DOMRect === "function") {
|
|
5
|
+
return new DOMRect(x, y, width, height);
|
|
6
|
+
}
|
|
7
|
+
const rect = {
|
|
8
|
+
x,
|
|
9
|
+
y,
|
|
10
|
+
width,
|
|
11
|
+
height,
|
|
12
|
+
top: y,
|
|
13
|
+
right: x + width,
|
|
14
|
+
bottom: y + height,
|
|
15
|
+
left: x
|
|
16
|
+
};
|
|
17
|
+
return { ...rect, toJSON: () => rect };
|
|
18
|
+
}
|
|
19
|
+
function getDOMRect(anchorRect) {
|
|
20
|
+
if (!anchorRect) return createDOMRect();
|
|
21
|
+
const { x, y, width, height } = anchorRect;
|
|
22
|
+
return createDOMRect(x, y, width, height);
|
|
23
|
+
}
|
|
24
|
+
function getAnchorElement(anchorElement, getAnchorRect) {
|
|
25
|
+
return {
|
|
26
|
+
contextElement: isHTMLElement(anchorElement) ? anchorElement : anchorElement?.contextElement,
|
|
27
|
+
getBoundingClientRect: () => {
|
|
28
|
+
const anchor = anchorElement;
|
|
29
|
+
const anchorRect = getAnchorRect?.(anchor);
|
|
30
|
+
if (anchorRect || !anchor) {
|
|
31
|
+
return getDOMRect(anchorRect);
|
|
32
|
+
}
|
|
33
|
+
return anchor.getBoundingClientRect();
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
export {
|
|
38
|
+
createDOMRect,
|
|
39
|
+
getAnchorElement
|
|
40
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { MaybeFn, MaybeRectElement, MaybeElement, PositioningOptions } from './types.mjs';
|
|
2
|
+
import '@floating-ui/dom';
|
|
3
|
+
|
|
4
|
+
declare function getPlacement(referenceOrFn: MaybeFn<MaybeRectElement>, floatingOrFn: MaybeFn<MaybeElement>, opts?: PositioningOptions & {
|
|
5
|
+
defer?: boolean | undefined;
|
|
6
|
+
}): () => void;
|
|
7
|
+
|
|
8
|
+
export { getPlacement };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { MaybeFn, MaybeRectElement, MaybeElement, PositioningOptions } from './types.js';
|
|
2
|
+
import '@floating-ui/dom';
|
|
3
|
+
|
|
4
|
+
declare function getPlacement(referenceOrFn: MaybeFn<MaybeRectElement>, floatingOrFn: MaybeFn<MaybeElement>, opts?: PositioningOptions & {
|
|
5
|
+
defer?: boolean | undefined;
|
|
6
|
+
}): () => void;
|
|
7
|
+
|
|
8
|
+
export { getPlacement };
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/get-placement.ts
|
|
21
|
+
var get_placement_exports = {};
|
|
22
|
+
__export(get_placement_exports, {
|
|
23
|
+
getPlacement: () => getPlacement
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(get_placement_exports);
|
|
26
|
+
var import_dom = require("@floating-ui/dom");
|
|
27
|
+
var import_dom_query = require("@zag-js/dom-query");
|
|
28
|
+
var import_utils = require("@zag-js/utils");
|
|
29
|
+
var import_get_anchor = require("./get-anchor.cjs");
|
|
30
|
+
var import_middleware = require("./middleware.cjs");
|
|
31
|
+
var import_placement = require("./placement.cjs");
|
|
32
|
+
var defaultOptions = {
|
|
33
|
+
strategy: "absolute",
|
|
34
|
+
placement: "bottom",
|
|
35
|
+
listeners: true,
|
|
36
|
+
gutter: 8,
|
|
37
|
+
flip: true,
|
|
38
|
+
slide: true,
|
|
39
|
+
overlap: false,
|
|
40
|
+
sameWidth: false,
|
|
41
|
+
fitViewport: false,
|
|
42
|
+
overflowPadding: 8,
|
|
43
|
+
arrowPadding: 4
|
|
44
|
+
};
|
|
45
|
+
function roundByDpr(win, value) {
|
|
46
|
+
const dpr = win.devicePixelRatio || 1;
|
|
47
|
+
return Math.round(value * dpr) / dpr;
|
|
48
|
+
}
|
|
49
|
+
function isApproximatelyEqual(a, b) {
|
|
50
|
+
return a != null && Math.abs(a - b) < 0.5;
|
|
51
|
+
}
|
|
52
|
+
function resolveBoundaryOption(boundary) {
|
|
53
|
+
if (typeof boundary === "function") return boundary();
|
|
54
|
+
if (boundary === "clipping-ancestors") return "clippingAncestors";
|
|
55
|
+
return boundary;
|
|
56
|
+
}
|
|
57
|
+
function getArrowMiddleware(arrowElement, doc, opts) {
|
|
58
|
+
const element = arrowElement || doc.createElement("div");
|
|
59
|
+
return (0, import_dom.arrow)({ element, padding: opts.arrowPadding });
|
|
60
|
+
}
|
|
61
|
+
function getOffsetMiddleware(arrowElement, opts) {
|
|
62
|
+
if ((0, import_utils.isNull)(opts.offset ?? opts.gutter)) return;
|
|
63
|
+
return (0, import_dom.offset)(({ placement }) => {
|
|
64
|
+
const arrowOffset = (arrowElement?.clientHeight || 0) / 2;
|
|
65
|
+
const gutter = opts.offset?.mainAxis ?? opts.gutter;
|
|
66
|
+
const mainAxis = typeof gutter === "number" ? gutter + arrowOffset : gutter ?? arrowOffset;
|
|
67
|
+
const { hasAlign } = (0, import_placement.getPlacementDetails)(placement);
|
|
68
|
+
const shift2 = !hasAlign ? opts.shift : void 0;
|
|
69
|
+
const crossAxis = opts.offset?.crossAxis ?? shift2;
|
|
70
|
+
return (0, import_utils.compact)({
|
|
71
|
+
crossAxis,
|
|
72
|
+
mainAxis,
|
|
73
|
+
alignmentAxis: opts.shift
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
function getFlipMiddleware(opts) {
|
|
78
|
+
if (!opts.flip) return;
|
|
79
|
+
const boundary = resolveBoundaryOption(opts.boundary);
|
|
80
|
+
return (0, import_dom.flip)({
|
|
81
|
+
...boundary ? { boundary } : void 0,
|
|
82
|
+
padding: opts.overflowPadding,
|
|
83
|
+
fallbackPlacements: opts.flip === true ? void 0 : opts.flip
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
function getShiftMiddleware(opts) {
|
|
87
|
+
if (!opts.slide && !opts.overlap) return;
|
|
88
|
+
const boundary = resolveBoundaryOption(opts.boundary);
|
|
89
|
+
return (0, import_dom.shift)({
|
|
90
|
+
...boundary ? { boundary } : void 0,
|
|
91
|
+
mainAxis: opts.slide,
|
|
92
|
+
crossAxis: opts.overlap,
|
|
93
|
+
padding: opts.overflowPadding,
|
|
94
|
+
limiter: (0, import_dom.limitShift)()
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
function getSizeMiddleware(opts) {
|
|
98
|
+
if (opts.sizeMiddleware === false && !opts.sameWidth && !opts.fitViewport) return;
|
|
99
|
+
let lastReferenceWidth;
|
|
100
|
+
let lastReferenceHeight;
|
|
101
|
+
let lastAvailableWidth;
|
|
102
|
+
let lastAvailableHeight;
|
|
103
|
+
return (0, import_dom.size)({
|
|
104
|
+
padding: opts.overflowPadding,
|
|
105
|
+
apply({ elements, rects, availableHeight, availableWidth }) {
|
|
106
|
+
const floating = elements.floating;
|
|
107
|
+
const referenceWidth = Math.round(rects.reference.width);
|
|
108
|
+
const referenceHeight = Math.round(rects.reference.height);
|
|
109
|
+
availableWidth = Math.floor(availableWidth);
|
|
110
|
+
availableHeight = Math.floor(availableHeight);
|
|
111
|
+
if (!isApproximatelyEqual(lastReferenceWidth, referenceWidth)) {
|
|
112
|
+
floating.style.setProperty("--reference-width", `${referenceWidth}px`);
|
|
113
|
+
lastReferenceWidth = referenceWidth;
|
|
114
|
+
}
|
|
115
|
+
if (!isApproximatelyEqual(lastReferenceHeight, referenceHeight)) {
|
|
116
|
+
floating.style.setProperty("--reference-height", `${referenceHeight}px`);
|
|
117
|
+
lastReferenceHeight = referenceHeight;
|
|
118
|
+
}
|
|
119
|
+
if (!isApproximatelyEqual(lastAvailableWidth, availableWidth)) {
|
|
120
|
+
floating.style.setProperty("--available-width", `${availableWidth}px`);
|
|
121
|
+
lastAvailableWidth = availableWidth;
|
|
122
|
+
}
|
|
123
|
+
if (!isApproximatelyEqual(lastAvailableHeight, availableHeight)) {
|
|
124
|
+
floating.style.setProperty("--available-height", `${availableHeight}px`);
|
|
125
|
+
lastAvailableHeight = availableHeight;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
function hideWhenDetachedMiddleware(opts) {
|
|
131
|
+
if (!opts.hideWhenDetached) return;
|
|
132
|
+
return (0, import_dom.hide)({ strategy: "referenceHidden", boundary: resolveBoundaryOption(opts.boundary) ?? "clippingAncestors" });
|
|
133
|
+
}
|
|
134
|
+
function getAutoUpdateOptions(opts) {
|
|
135
|
+
if (!opts) return {};
|
|
136
|
+
if (opts === true) {
|
|
137
|
+
return { ancestorResize: true, ancestorScroll: true, elementResize: true, layoutShift: true };
|
|
138
|
+
}
|
|
139
|
+
return opts;
|
|
140
|
+
}
|
|
141
|
+
function getPlacementImpl(referenceOrVirtual, floating, opts = {}) {
|
|
142
|
+
const anchor = opts.getAnchorElement?.() ?? referenceOrVirtual;
|
|
143
|
+
const reference = (0, import_get_anchor.getAnchorElement)(anchor, opts.getAnchorRect);
|
|
144
|
+
if (!floating || !reference) return;
|
|
145
|
+
const options = Object.assign({}, defaultOptions, opts);
|
|
146
|
+
const arrowEl = floating.querySelector("[data-part=arrow]");
|
|
147
|
+
const middleware = [
|
|
148
|
+
getOffsetMiddleware(arrowEl, options),
|
|
149
|
+
getFlipMiddleware(options),
|
|
150
|
+
getShiftMiddleware(options),
|
|
151
|
+
getArrowMiddleware(arrowEl, floating.ownerDocument, options),
|
|
152
|
+
(0, import_middleware.shiftArrowMiddleware)(arrowEl),
|
|
153
|
+
(0, import_middleware.createTransformOriginMiddleware)(
|
|
154
|
+
{ gutter: options.gutter, offset: options.offset, overlap: options.overlap },
|
|
155
|
+
arrowEl
|
|
156
|
+
),
|
|
157
|
+
getSizeMiddleware(options),
|
|
158
|
+
hideWhenDetachedMiddleware(options),
|
|
159
|
+
import_middleware.rectMiddleware
|
|
160
|
+
];
|
|
161
|
+
const { placement, strategy, onComplete, onPositioned } = options;
|
|
162
|
+
let lastX;
|
|
163
|
+
let lastY;
|
|
164
|
+
let zIndexComputed = false;
|
|
165
|
+
const updatePosition = async () => {
|
|
166
|
+
if (!reference || !floating) return;
|
|
167
|
+
const pos = await (0, import_dom.computePosition)(reference, floating, {
|
|
168
|
+
placement,
|
|
169
|
+
middleware,
|
|
170
|
+
strategy
|
|
171
|
+
});
|
|
172
|
+
onComplete?.(pos);
|
|
173
|
+
const win = (0, import_dom_query.getWindow)(floating);
|
|
174
|
+
const x = roundByDpr(win, pos.x);
|
|
175
|
+
const y = roundByDpr(win, pos.y);
|
|
176
|
+
floating.style.transform = `translate3d(${x}px, ${y}px, 0)`;
|
|
177
|
+
if (!isApproximatelyEqual(lastX, x)) {
|
|
178
|
+
floating.style.setProperty("--x", `${x}px`);
|
|
179
|
+
lastX = x;
|
|
180
|
+
}
|
|
181
|
+
if (!isApproximatelyEqual(lastY, y)) {
|
|
182
|
+
floating.style.setProperty("--y", `${y}px`);
|
|
183
|
+
lastY = y;
|
|
184
|
+
}
|
|
185
|
+
if (options.hideWhenDetached) {
|
|
186
|
+
const isHidden = pos.middlewareData.hide?.referenceHidden;
|
|
187
|
+
if (isHidden) {
|
|
188
|
+
floating.style.setProperty("visibility", "hidden");
|
|
189
|
+
floating.style.setProperty("pointer-events", "none");
|
|
190
|
+
} else {
|
|
191
|
+
floating.style.removeProperty("visibility");
|
|
192
|
+
floating.style.removeProperty("pointer-events");
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
if (!zIndexComputed) {
|
|
196
|
+
const contentEl = floating.firstElementChild;
|
|
197
|
+
if (contentEl) {
|
|
198
|
+
floating.style.setProperty("--z-index", (0, import_dom_query.getComputedStyle)(contentEl).zIndex);
|
|
199
|
+
zIndexComputed = true;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
const update = async () => {
|
|
204
|
+
if (opts.updatePosition) {
|
|
205
|
+
await opts.updatePosition({ updatePosition, floatingElement: floating });
|
|
206
|
+
onPositioned?.({ placed: true });
|
|
207
|
+
} else {
|
|
208
|
+
await updatePosition();
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
const autoUpdateOptions = getAutoUpdateOptions(options.listeners);
|
|
212
|
+
const cancelAutoUpdate = options.listeners ? (0, import_dom.autoUpdate)(reference, floating, update, autoUpdateOptions) : import_utils.noop;
|
|
213
|
+
update();
|
|
214
|
+
return () => {
|
|
215
|
+
cancelAutoUpdate?.();
|
|
216
|
+
onPositioned?.({ placed: false });
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
function getPlacement(referenceOrFn, floatingOrFn, opts = {}) {
|
|
220
|
+
const { defer, ...options } = opts;
|
|
221
|
+
const func = defer ? import_dom_query.raf : (v) => v();
|
|
222
|
+
const cleanups = [];
|
|
223
|
+
cleanups.push(
|
|
224
|
+
func(() => {
|
|
225
|
+
const reference = typeof referenceOrFn === "function" ? referenceOrFn() : referenceOrFn;
|
|
226
|
+
const floating = typeof floatingOrFn === "function" ? floatingOrFn() : floatingOrFn;
|
|
227
|
+
cleanups.push(getPlacementImpl(reference, floating, options));
|
|
228
|
+
})
|
|
229
|
+
);
|
|
230
|
+
return () => {
|
|
231
|
+
cleanups.forEach((fn) => fn?.());
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
235
|
+
0 && (module.exports = {
|
|
236
|
+
getPlacement
|
|
237
|
+
});
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
// src/get-placement.ts
|
|
2
|
+
import { arrow, autoUpdate, computePosition, flip, hide, limitShift, offset, shift, size } from "@floating-ui/dom";
|
|
3
|
+
import { getComputedStyle, getWindow, raf } from "@zag-js/dom-query";
|
|
4
|
+
import { compact, isNull, noop } from "@zag-js/utils";
|
|
5
|
+
import { getAnchorElement } from "./get-anchor.mjs";
|
|
6
|
+
import { createTransformOriginMiddleware, rectMiddleware, shiftArrowMiddleware } from "./middleware.mjs";
|
|
7
|
+
import { getPlacementDetails } from "./placement.mjs";
|
|
8
|
+
var defaultOptions = {
|
|
9
|
+
strategy: "absolute",
|
|
10
|
+
placement: "bottom",
|
|
11
|
+
listeners: true,
|
|
12
|
+
gutter: 8,
|
|
13
|
+
flip: true,
|
|
14
|
+
slide: true,
|
|
15
|
+
overlap: false,
|
|
16
|
+
sameWidth: false,
|
|
17
|
+
fitViewport: false,
|
|
18
|
+
overflowPadding: 8,
|
|
19
|
+
arrowPadding: 4
|
|
20
|
+
};
|
|
21
|
+
function roundByDpr(win, value) {
|
|
22
|
+
const dpr = win.devicePixelRatio || 1;
|
|
23
|
+
return Math.round(value * dpr) / dpr;
|
|
24
|
+
}
|
|
25
|
+
function isApproximatelyEqual(a, b) {
|
|
26
|
+
return a != null && Math.abs(a - b) < 0.5;
|
|
27
|
+
}
|
|
28
|
+
function resolveBoundaryOption(boundary) {
|
|
29
|
+
if (typeof boundary === "function") return boundary();
|
|
30
|
+
if (boundary === "clipping-ancestors") return "clippingAncestors";
|
|
31
|
+
return boundary;
|
|
32
|
+
}
|
|
33
|
+
function getArrowMiddleware(arrowElement, doc, opts) {
|
|
34
|
+
const element = arrowElement || doc.createElement("div");
|
|
35
|
+
return arrow({ element, padding: opts.arrowPadding });
|
|
36
|
+
}
|
|
37
|
+
function getOffsetMiddleware(arrowElement, opts) {
|
|
38
|
+
if (isNull(opts.offset ?? opts.gutter)) return;
|
|
39
|
+
return offset(({ placement }) => {
|
|
40
|
+
const arrowOffset = (arrowElement?.clientHeight || 0) / 2;
|
|
41
|
+
const gutter = opts.offset?.mainAxis ?? opts.gutter;
|
|
42
|
+
const mainAxis = typeof gutter === "number" ? gutter + arrowOffset : gutter ?? arrowOffset;
|
|
43
|
+
const { hasAlign } = getPlacementDetails(placement);
|
|
44
|
+
const shift2 = !hasAlign ? opts.shift : void 0;
|
|
45
|
+
const crossAxis = opts.offset?.crossAxis ?? shift2;
|
|
46
|
+
return compact({
|
|
47
|
+
crossAxis,
|
|
48
|
+
mainAxis,
|
|
49
|
+
alignmentAxis: opts.shift
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
function getFlipMiddleware(opts) {
|
|
54
|
+
if (!opts.flip) return;
|
|
55
|
+
const boundary = resolveBoundaryOption(opts.boundary);
|
|
56
|
+
return flip({
|
|
57
|
+
...boundary ? { boundary } : void 0,
|
|
58
|
+
padding: opts.overflowPadding,
|
|
59
|
+
fallbackPlacements: opts.flip === true ? void 0 : opts.flip
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
function getShiftMiddleware(opts) {
|
|
63
|
+
if (!opts.slide && !opts.overlap) return;
|
|
64
|
+
const boundary = resolveBoundaryOption(opts.boundary);
|
|
65
|
+
return shift({
|
|
66
|
+
...boundary ? { boundary } : void 0,
|
|
67
|
+
mainAxis: opts.slide,
|
|
68
|
+
crossAxis: opts.overlap,
|
|
69
|
+
padding: opts.overflowPadding,
|
|
70
|
+
limiter: limitShift()
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
function getSizeMiddleware(opts) {
|
|
74
|
+
if (opts.sizeMiddleware === false && !opts.sameWidth && !opts.fitViewport) return;
|
|
75
|
+
let lastReferenceWidth;
|
|
76
|
+
let lastReferenceHeight;
|
|
77
|
+
let lastAvailableWidth;
|
|
78
|
+
let lastAvailableHeight;
|
|
79
|
+
return size({
|
|
80
|
+
padding: opts.overflowPadding,
|
|
81
|
+
apply({ elements, rects, availableHeight, availableWidth }) {
|
|
82
|
+
const floating = elements.floating;
|
|
83
|
+
const referenceWidth = Math.round(rects.reference.width);
|
|
84
|
+
const referenceHeight = Math.round(rects.reference.height);
|
|
85
|
+
availableWidth = Math.floor(availableWidth);
|
|
86
|
+
availableHeight = Math.floor(availableHeight);
|
|
87
|
+
if (!isApproximatelyEqual(lastReferenceWidth, referenceWidth)) {
|
|
88
|
+
floating.style.setProperty("--reference-width", `${referenceWidth}px`);
|
|
89
|
+
lastReferenceWidth = referenceWidth;
|
|
90
|
+
}
|
|
91
|
+
if (!isApproximatelyEqual(lastReferenceHeight, referenceHeight)) {
|
|
92
|
+
floating.style.setProperty("--reference-height", `${referenceHeight}px`);
|
|
93
|
+
lastReferenceHeight = referenceHeight;
|
|
94
|
+
}
|
|
95
|
+
if (!isApproximatelyEqual(lastAvailableWidth, availableWidth)) {
|
|
96
|
+
floating.style.setProperty("--available-width", `${availableWidth}px`);
|
|
97
|
+
lastAvailableWidth = availableWidth;
|
|
98
|
+
}
|
|
99
|
+
if (!isApproximatelyEqual(lastAvailableHeight, availableHeight)) {
|
|
100
|
+
floating.style.setProperty("--available-height", `${availableHeight}px`);
|
|
101
|
+
lastAvailableHeight = availableHeight;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
function hideWhenDetachedMiddleware(opts) {
|
|
107
|
+
if (!opts.hideWhenDetached) return;
|
|
108
|
+
return hide({ strategy: "referenceHidden", boundary: resolveBoundaryOption(opts.boundary) ?? "clippingAncestors" });
|
|
109
|
+
}
|
|
110
|
+
function getAutoUpdateOptions(opts) {
|
|
111
|
+
if (!opts) return {};
|
|
112
|
+
if (opts === true) {
|
|
113
|
+
return { ancestorResize: true, ancestorScroll: true, elementResize: true, layoutShift: true };
|
|
114
|
+
}
|
|
115
|
+
return opts;
|
|
116
|
+
}
|
|
117
|
+
function getPlacementImpl(referenceOrVirtual, floating, opts = {}) {
|
|
118
|
+
const anchor = opts.getAnchorElement?.() ?? referenceOrVirtual;
|
|
119
|
+
const reference = getAnchorElement(anchor, opts.getAnchorRect);
|
|
120
|
+
if (!floating || !reference) return;
|
|
121
|
+
const options = Object.assign({}, defaultOptions, opts);
|
|
122
|
+
const arrowEl = floating.querySelector("[data-part=arrow]");
|
|
123
|
+
const middleware = [
|
|
124
|
+
getOffsetMiddleware(arrowEl, options),
|
|
125
|
+
getFlipMiddleware(options),
|
|
126
|
+
getShiftMiddleware(options),
|
|
127
|
+
getArrowMiddleware(arrowEl, floating.ownerDocument, options),
|
|
128
|
+
shiftArrowMiddleware(arrowEl),
|
|
129
|
+
createTransformOriginMiddleware(
|
|
130
|
+
{ gutter: options.gutter, offset: options.offset, overlap: options.overlap },
|
|
131
|
+
arrowEl
|
|
132
|
+
),
|
|
133
|
+
getSizeMiddleware(options),
|
|
134
|
+
hideWhenDetachedMiddleware(options),
|
|
135
|
+
rectMiddleware
|
|
136
|
+
];
|
|
137
|
+
const { placement, strategy, onComplete, onPositioned } = options;
|
|
138
|
+
let lastX;
|
|
139
|
+
let lastY;
|
|
140
|
+
let zIndexComputed = false;
|
|
141
|
+
const updatePosition = async () => {
|
|
142
|
+
if (!reference || !floating) return;
|
|
143
|
+
const pos = await computePosition(reference, floating, {
|
|
144
|
+
placement,
|
|
145
|
+
middleware,
|
|
146
|
+
strategy
|
|
147
|
+
});
|
|
148
|
+
onComplete?.(pos);
|
|
149
|
+
const win = getWindow(floating);
|
|
150
|
+
const x = roundByDpr(win, pos.x);
|
|
151
|
+
const y = roundByDpr(win, pos.y);
|
|
152
|
+
floating.style.transform = `translate3d(${x}px, ${y}px, 0)`;
|
|
153
|
+
if (!isApproximatelyEqual(lastX, x)) {
|
|
154
|
+
floating.style.setProperty("--x", `${x}px`);
|
|
155
|
+
lastX = x;
|
|
156
|
+
}
|
|
157
|
+
if (!isApproximatelyEqual(lastY, y)) {
|
|
158
|
+
floating.style.setProperty("--y", `${y}px`);
|
|
159
|
+
lastY = y;
|
|
160
|
+
}
|
|
161
|
+
if (options.hideWhenDetached) {
|
|
162
|
+
const isHidden = pos.middlewareData.hide?.referenceHidden;
|
|
163
|
+
if (isHidden) {
|
|
164
|
+
floating.style.setProperty("visibility", "hidden");
|
|
165
|
+
floating.style.setProperty("pointer-events", "none");
|
|
166
|
+
} else {
|
|
167
|
+
floating.style.removeProperty("visibility");
|
|
168
|
+
floating.style.removeProperty("pointer-events");
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
if (!zIndexComputed) {
|
|
172
|
+
const contentEl = floating.firstElementChild;
|
|
173
|
+
if (contentEl) {
|
|
174
|
+
floating.style.setProperty("--z-index", getComputedStyle(contentEl).zIndex);
|
|
175
|
+
zIndexComputed = true;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
const update = async () => {
|
|
180
|
+
if (opts.updatePosition) {
|
|
181
|
+
await opts.updatePosition({ updatePosition, floatingElement: floating });
|
|
182
|
+
onPositioned?.({ placed: true });
|
|
183
|
+
} else {
|
|
184
|
+
await updatePosition();
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
const autoUpdateOptions = getAutoUpdateOptions(options.listeners);
|
|
188
|
+
const cancelAutoUpdate = options.listeners ? autoUpdate(reference, floating, update, autoUpdateOptions) : noop;
|
|
189
|
+
update();
|
|
190
|
+
return () => {
|
|
191
|
+
cancelAutoUpdate?.();
|
|
192
|
+
onPositioned?.({ placed: false });
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
function getPlacement(referenceOrFn, floatingOrFn, opts = {}) {
|
|
196
|
+
const { defer, ...options } = opts;
|
|
197
|
+
const func = defer ? raf : (v) => v();
|
|
198
|
+
const cleanups = [];
|
|
199
|
+
cleanups.push(
|
|
200
|
+
func(() => {
|
|
201
|
+
const reference = typeof referenceOrFn === "function" ? referenceOrFn() : referenceOrFn;
|
|
202
|
+
const floating = typeof floatingOrFn === "function" ? floatingOrFn() : floatingOrFn;
|
|
203
|
+
cleanups.push(getPlacementImpl(reference, floating, options));
|
|
204
|
+
})
|
|
205
|
+
);
|
|
206
|
+
return () => {
|
|
207
|
+
cleanups.forEach((fn) => fn?.());
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
export {
|
|
211
|
+
getPlacement
|
|
212
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Placement } from '@floating-ui/dom';
|
|
2
|
+
import { cssVars } from './middleware.mjs';
|
|
3
|
+
import { PositioningOptions } from './types.mjs';
|
|
4
|
+
|
|
5
|
+
interface GetPlacementStylesOptions {
|
|
6
|
+
placement?: Placement | undefined;
|
|
7
|
+
}
|
|
8
|
+
declare function getPlacementStyles(options?: Pick<PositioningOptions, "placement" | "sameWidth" | "fitViewport" | "strategy">): {
|
|
9
|
+
arrow: {
|
|
10
|
+
readonly [cssVars.arrowSizeHalf.variable]: `calc(${string} / 2)`;
|
|
11
|
+
readonly [cssVars.arrowOffset.variable]: `calc(${string} * -1)`;
|
|
12
|
+
readonly position: "absolute";
|
|
13
|
+
readonly width: string;
|
|
14
|
+
readonly height: string;
|
|
15
|
+
};
|
|
16
|
+
arrowTip: {
|
|
17
|
+
readonly transform: any;
|
|
18
|
+
readonly background: string;
|
|
19
|
+
readonly top: "0";
|
|
20
|
+
readonly left: "0";
|
|
21
|
+
readonly width: "100%";
|
|
22
|
+
readonly height: "100%";
|
|
23
|
+
readonly position: "absolute";
|
|
24
|
+
readonly zIndex: "inherit";
|
|
25
|
+
};
|
|
26
|
+
floating: {
|
|
27
|
+
readonly position: "absolute" | "fixed";
|
|
28
|
+
readonly isolation: "isolate";
|
|
29
|
+
readonly minWidth: "max-content" | undefined;
|
|
30
|
+
readonly width: "var(--reference-width)" | undefined;
|
|
31
|
+
readonly maxWidth: "var(--available-width)" | undefined;
|
|
32
|
+
readonly maxHeight: "var(--available-height)" | undefined;
|
|
33
|
+
readonly pointerEvents: "none" | undefined;
|
|
34
|
+
readonly top: "0px";
|
|
35
|
+
readonly left: "0px";
|
|
36
|
+
readonly transform: "translate3d(var(--x), var(--y), 0)" | "translate3d(0, -100vh, 0)";
|
|
37
|
+
readonly zIndex: "var(--z-index)";
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export { type GetPlacementStylesOptions, getPlacementStyles };
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Placement } from '@floating-ui/dom';
|
|
2
|
+
import { cssVars } from './middleware.js';
|
|
3
|
+
import { PositioningOptions } from './types.js';
|
|
4
|
+
|
|
5
|
+
interface GetPlacementStylesOptions {
|
|
6
|
+
placement?: Placement | undefined;
|
|
7
|
+
}
|
|
8
|
+
declare function getPlacementStyles(options?: Pick<PositioningOptions, "placement" | "sameWidth" | "fitViewport" | "strategy">): {
|
|
9
|
+
arrow: {
|
|
10
|
+
readonly [cssVars.arrowSizeHalf.variable]: `calc(${string} / 2)`;
|
|
11
|
+
readonly [cssVars.arrowOffset.variable]: `calc(${string} * -1)`;
|
|
12
|
+
readonly position: "absolute";
|
|
13
|
+
readonly width: string;
|
|
14
|
+
readonly height: string;
|
|
15
|
+
};
|
|
16
|
+
arrowTip: {
|
|
17
|
+
readonly transform: any;
|
|
18
|
+
readonly background: string;
|
|
19
|
+
readonly top: "0";
|
|
20
|
+
readonly left: "0";
|
|
21
|
+
readonly width: "100%";
|
|
22
|
+
readonly height: "100%";
|
|
23
|
+
readonly position: "absolute";
|
|
24
|
+
readonly zIndex: "inherit";
|
|
25
|
+
};
|
|
26
|
+
floating: {
|
|
27
|
+
readonly position: "absolute" | "fixed";
|
|
28
|
+
readonly isolation: "isolate";
|
|
29
|
+
readonly minWidth: "max-content" | undefined;
|
|
30
|
+
readonly width: "var(--reference-width)" | undefined;
|
|
31
|
+
readonly maxWidth: "var(--available-width)" | undefined;
|
|
32
|
+
readonly maxHeight: "var(--available-height)" | undefined;
|
|
33
|
+
readonly pointerEvents: "none" | undefined;
|
|
34
|
+
readonly top: "0px";
|
|
35
|
+
readonly left: "0px";
|
|
36
|
+
readonly transform: "translate3d(var(--x), var(--y), 0)" | "translate3d(0, -100vh, 0)";
|
|
37
|
+
readonly zIndex: "var(--z-index)";
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export { type GetPlacementStylesOptions, getPlacementStyles };
|