@destyler/popper 0.0.6 → 0.0.7-beta.9

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/index.d.ts CHANGED
@@ -1,5 +1,173 @@
1
- export { PopperAnchor, PopperAnchorProps, PopperArrow, PopperArrowProps, PopperContent, PopperContentProps, PopperRoot, popperAnchorProps, popperArrowProps, popperContentProps } from './component.js';
2
- import 'vue';
3
- import '@destyler/primitive';
4
- import '@destyler/shared';
5
- import '@floating-ui/vue';
1
+ import { AutoUpdateOptions, Boundary, ComputePositionReturn, Placement, Placement as Placement$1, VirtualElement } from "@floating-ui/dom";
2
+
3
+ //#region src/types.d.ts
4
+ type MaybeRectElement = HTMLElement | VirtualElement | null;
5
+ type MaybeElement = HTMLElement | null;
6
+ type MaybeFn<T> = T | (() => T);
7
+ type PlacementSide = 'top' | 'right' | 'bottom' | 'left';
8
+ type PlacementAlign = 'start' | 'center' | 'end';
9
+ interface AnchorRect {
10
+ x?: number | undefined;
11
+ y?: number | undefined;
12
+ width?: number | undefined;
13
+ height?: number | undefined;
14
+ }
15
+ interface PositioningOptions {
16
+ /**
17
+ * Whether the popover should be hidden when the reference element is detached
18
+ */
19
+ hideWhenDetached?: boolean | undefined;
20
+ /**
21
+ * The strategy to use for positioning
22
+ */
23
+ strategy?: 'absolute' | 'fixed' | undefined;
24
+ /**
25
+ * The initial placement of the floating element
26
+ */
27
+ placement?: Placement | undefined;
28
+ /**
29
+ * The offset of the floating element
30
+ */
31
+ offset?: {
32
+ mainAxis?: number;
33
+ crossAxis?: number;
34
+ } | undefined;
35
+ /**
36
+ * The main axis offset or gap between the reference and floating elements
37
+ */
38
+ gutter?: number | undefined;
39
+ /**
40
+ * The secondary axis offset or gap between the reference and floating elements
41
+ */
42
+ shift?: number | undefined;
43
+ /**
44
+ * The virtual padding around the viewport edges to check for overflow
45
+ */
46
+ overflowPadding?: number | undefined;
47
+ /**
48
+ * The minimum padding between the arrow and the floating element's corner.
49
+ * @default 4
50
+ */
51
+ arrowPadding?: number | undefined;
52
+ /**
53
+ * Whether to flip the placement
54
+ */
55
+ flip?: boolean | Placement[] | undefined;
56
+ /**
57
+ * Whether the popover should slide when it overflows.
58
+ */
59
+ slide?: boolean | undefined;
60
+ /**
61
+ * Whether the floating element can overlap the reference element
62
+ * @default false
63
+ */
64
+ overlap?: boolean | undefined;
65
+ /**
66
+ * Whether to make the floating element same width as the reference element
67
+ */
68
+ sameWidth?: boolean | undefined;
69
+ /**
70
+ * Whether the popover should fit the viewport.
71
+ */
72
+ fitViewport?: boolean | undefined;
73
+ /**
74
+ * The overflow boundary of the reference element
75
+ */
76
+ boundary?: (() => Boundary) | undefined;
77
+ /**
78
+ * Options to activate auto-update listeners
79
+ */
80
+ listeners?: boolean | AutoUpdateOptions | undefined;
81
+ /**
82
+ * Function called when the placement is computed
83
+ */
84
+ onComplete?: ((data: ComputePositionReturn) => void) | undefined;
85
+ /**
86
+ * Function called when the floating element is positioned or not
87
+ */
88
+ onPositioned?: ((data: {
89
+ placed: boolean;
90
+ }) => void) | undefined;
91
+ /**
92
+ * Function that returns the anchor rect
93
+ */
94
+ getAnchorRect?: ((element: HTMLElement | VirtualElement | null) => AnchorRect | null) | undefined;
95
+ /**
96
+ * A callback that will be called when the popover needs to calculate its
97
+ * position.
98
+ */
99
+ updatePosition?: ((data: {
100
+ updatePosition: () => Promise<void>;
101
+ }) => void | Promise<void>) | undefined;
102
+ }
103
+ //#endregion
104
+ //#region src/get-placement.d.ts
105
+ declare function getPlacement(referenceOrFn: MaybeFn<MaybeRectElement>, floatingOrFn: MaybeFn<MaybeElement>, opts?: PositioningOptions & {
106
+ defer?: boolean;
107
+ }): () => void;
108
+ //#endregion
109
+ //#region src/middleware.d.ts
110
+ declare const cssVars: {
111
+ arrowSize: {
112
+ variable: string;
113
+ reference: string;
114
+ };
115
+ arrowSizeHalf: {
116
+ variable: string;
117
+ reference: string;
118
+ };
119
+ arrowBg: {
120
+ variable: string;
121
+ reference: string;
122
+ };
123
+ transformOrigin: {
124
+ variable: string;
125
+ reference: string;
126
+ };
127
+ arrowOffset: {
128
+ variable: string;
129
+ reference: string;
130
+ };
131
+ };
132
+ //#endregion
133
+ //#region src/get-styles.d.ts
134
+ interface GetPlacementStylesOptions {
135
+ placement?: Placement$1 | undefined;
136
+ }
137
+ declare function getPlacementStyles(options?: Pick<PositioningOptions, 'placement' | 'sameWidth' | 'fitViewport' | 'strategy'>): {
138
+ arrow: {
139
+ readonly [cssVars.arrowSizeHalf.variable]: `calc(${string} / 2)`;
140
+ readonly [cssVars.arrowOffset.variable]: `calc(${string} * -1)`;
141
+ readonly position: "absolute";
142
+ readonly width: string;
143
+ readonly height: string;
144
+ };
145
+ arrowTip: {
146
+ readonly transform: any;
147
+ readonly background: string;
148
+ readonly top: "0";
149
+ readonly left: "0";
150
+ readonly width: "100%";
151
+ readonly height: "100%";
152
+ readonly position: "absolute";
153
+ readonly zIndex: "inherit";
154
+ };
155
+ floating: {
156
+ readonly position: "absolute" | "fixed";
157
+ readonly isolation: "isolate";
158
+ readonly minWidth: "max-content" | undefined;
159
+ readonly width: "var(--reference-width)" | undefined;
160
+ readonly maxWidth: "var(--available-width)" | undefined;
161
+ readonly maxHeight: "var(--available-height)" | undefined;
162
+ readonly top: "0px";
163
+ readonly left: "0px";
164
+ readonly transform: "translate3d(var(--x), var(--y), 0)" | "translate3d(0, -100vh, 0)";
165
+ readonly zIndex: "var(--z-index)";
166
+ };
167
+ };
168
+ //#endregion
169
+ //#region src/placement.d.ts
170
+ declare function isValidPlacement(v: string): v is Placement$1;
171
+ declare function getPlacementSide(placement: Placement$1): PlacementSide;
172
+ //#endregion
173
+ export { type AnchorRect, type AutoUpdateOptions, type Boundary, type ComputePositionReturn, type GetPlacementStylesOptions, type Placement, type PlacementAlign, type PlacementSide, type PositioningOptions, getPlacement, getPlacementSide, getPlacementStyles, isValidPlacement };
package/dist/index.js ADDED
@@ -0,0 +1,333 @@
1
+ import { getComputedStyle, getWindow, isHTMLElement, raf } from "@destyler/dom";
2
+ import { compact, isNull, noop, runIfFn } from "@destyler/utils";
3
+ import { arrow, autoUpdate, computePosition, flip, hide, limitShift, offset, shift, size } from "@floating-ui/dom";
4
+
5
+ //#region src/get-anchor.ts
6
+ function createDOMRect(x = 0, y = 0, width = 0, height = 0) {
7
+ if (typeof DOMRect === "function") return new DOMRect(x, y, width, height);
8
+ const rect = {
9
+ x,
10
+ y,
11
+ width,
12
+ height,
13
+ top: y,
14
+ right: x + width,
15
+ bottom: y + height,
16
+ left: x
17
+ };
18
+ return {
19
+ ...rect,
20
+ toJSON: () => rect
21
+ };
22
+ }
23
+ function getDOMRect(anchorRect) {
24
+ if (!anchorRect) return createDOMRect();
25
+ const { x, y, width, height } = anchorRect;
26
+ return createDOMRect(x, y, width, height);
27
+ }
28
+ function getAnchorElement(anchorElement, getAnchorRect) {
29
+ return {
30
+ contextElement: isHTMLElement(anchorElement) ? anchorElement : void 0,
31
+ getBoundingClientRect: () => {
32
+ const anchor = anchorElement;
33
+ const anchorRect = getAnchorRect?.(anchor);
34
+ if (anchorRect || !anchor) return getDOMRect(anchorRect);
35
+ return anchor.getBoundingClientRect();
36
+ }
37
+ };
38
+ }
39
+
40
+ //#endregion
41
+ //#region src/middleware.ts
42
+ const toVar = (value) => ({
43
+ variable: value,
44
+ reference: `var(${value})`
45
+ });
46
+ const cssVars = {
47
+ arrowSize: toVar("--arrow-size"),
48
+ arrowSizeHalf: toVar("--arrow-size-half"),
49
+ arrowBg: toVar("--arrow-background"),
50
+ transformOrigin: toVar("--transform-origin"),
51
+ arrowOffset: toVar("--arrow-offset")
52
+ };
53
+ function getTransformOrigin(arrow$1) {
54
+ return {
55
+ "top": "bottom center",
56
+ "top-start": arrow$1 ? `${arrow$1.x}px bottom` : "left bottom",
57
+ "top-end": arrow$1 ? `${arrow$1.x}px bottom` : "right bottom",
58
+ "bottom": "top center",
59
+ "bottom-start": arrow$1 ? `${arrow$1.x}px top` : "top left",
60
+ "bottom-end": arrow$1 ? `${arrow$1.x}px top` : "top right",
61
+ "left": "right center",
62
+ "left-start": arrow$1 ? `right ${arrow$1.y}px` : "right top",
63
+ "left-end": arrow$1 ? `right ${arrow$1.y}px` : "right bottom",
64
+ "right": "left center",
65
+ "right-start": arrow$1 ? `left ${arrow$1.y}px` : "left top",
66
+ "right-end": arrow$1 ? `left ${arrow$1.y}px` : "left bottom"
67
+ };
68
+ }
69
+ const transformOriginMiddleware = {
70
+ name: "transformOrigin",
71
+ fn({ placement, elements, middlewareData }) {
72
+ const { arrow: arrow$1 } = middlewareData;
73
+ const transformOrigin = getTransformOrigin(arrow$1)[placement];
74
+ const { floating } = elements;
75
+ floating.style.setProperty(cssVars.transformOrigin.variable, transformOrigin);
76
+ return { data: { transformOrigin } };
77
+ }
78
+ };
79
+ const rectMiddleware = {
80
+ name: "rects",
81
+ fn({ rects }) {
82
+ return { data: rects };
83
+ }
84
+ };
85
+ function shiftArrowMiddleware(arrowEl) {
86
+ if (!arrowEl) return;
87
+ return {
88
+ name: "shiftArrow",
89
+ fn({ placement, middlewareData }) {
90
+ if (!middlewareData.arrow) return {};
91
+ const { x, y } = middlewareData.arrow;
92
+ const dir = placement.split("-")[0];
93
+ Object.assign(arrowEl.style, {
94
+ left: x != null ? `${x}px` : "",
95
+ top: y != null ? `${y}px` : "",
96
+ [dir]: `calc(100% + ${cssVars.arrowOffset.reference})`
97
+ });
98
+ return {};
99
+ }
100
+ };
101
+ }
102
+
103
+ //#endregion
104
+ //#region src/placement.ts
105
+ function isValidPlacement(v) {
106
+ return /^(?:top|bottom|left|right)(?:-(?:start|end))?$/.test(v);
107
+ }
108
+ function getPlacementDetails(placement) {
109
+ const [side, align] = placement.split("-");
110
+ return {
111
+ side,
112
+ align,
113
+ hasAlign: align != null
114
+ };
115
+ }
116
+ function getPlacementSide(placement) {
117
+ return placement.split("-")[0];
118
+ }
119
+
120
+ //#endregion
121
+ //#region src/get-placement.ts
122
+ const defaultOptions = {
123
+ strategy: "absolute",
124
+ placement: "bottom",
125
+ listeners: true,
126
+ gutter: 8,
127
+ flip: true,
128
+ slide: true,
129
+ overlap: false,
130
+ sameWidth: false,
131
+ fitViewport: false,
132
+ overflowPadding: 8,
133
+ arrowPadding: 4
134
+ };
135
+ function roundByDpr(win, value) {
136
+ const dpr = win.devicePixelRatio || 1;
137
+ return Math.round(value * dpr) / dpr;
138
+ }
139
+ function getBoundaryMiddleware(opts) {
140
+ return runIfFn(opts.boundary);
141
+ }
142
+ function getArrowMiddleware(arrowElement, opts) {
143
+ if (!arrowElement) return;
144
+ return arrow({
145
+ element: arrowElement,
146
+ padding: opts.arrowPadding
147
+ });
148
+ }
149
+ function getOffsetMiddleware(arrowElement, opts) {
150
+ if (isNull(opts.offset ?? opts.gutter)) return;
151
+ return offset(({ placement }) => {
152
+ const arrowOffset = (arrowElement?.clientHeight || 0) / 2;
153
+ const gutter = opts.offset?.mainAxis ?? opts.gutter;
154
+ const mainAxis = typeof gutter === "number" ? gutter + arrowOffset : gutter ?? arrowOffset;
155
+ const { hasAlign } = getPlacementDetails(placement);
156
+ const shift$1 = !hasAlign ? opts.shift : void 0;
157
+ const crossAxis = opts.offset?.crossAxis ?? shift$1;
158
+ return compact({
159
+ crossAxis,
160
+ mainAxis,
161
+ alignmentAxis: opts.shift
162
+ });
163
+ });
164
+ }
165
+ function getFlipMiddleware(opts) {
166
+ if (!opts.flip) return;
167
+ return flip({
168
+ boundary: getBoundaryMiddleware(opts),
169
+ padding: opts.overflowPadding,
170
+ fallbackPlacements: opts.flip === true ? void 0 : opts.flip
171
+ });
172
+ }
173
+ function getShiftMiddleware(opts) {
174
+ if (!opts.slide && !opts.overlap) return;
175
+ return shift({
176
+ boundary: getBoundaryMiddleware(opts),
177
+ mainAxis: opts.slide,
178
+ crossAxis: opts.overlap,
179
+ padding: opts.overflowPadding,
180
+ limiter: limitShift()
181
+ });
182
+ }
183
+ function getSizeMiddleware(opts) {
184
+ return size({
185
+ padding: opts.overflowPadding,
186
+ apply({ elements, rects, availableHeight, availableWidth }) {
187
+ const floating = elements.floating;
188
+ const referenceWidth = Math.round(rects.reference.width);
189
+ availableWidth = Math.floor(availableWidth);
190
+ availableHeight = Math.floor(availableHeight);
191
+ floating.style.setProperty("--reference-width", `${referenceWidth}px`);
192
+ floating.style.setProperty("--available-width", `${availableWidth}px`);
193
+ floating.style.setProperty("--available-height", `${availableHeight}px`);
194
+ }
195
+ });
196
+ }
197
+ function hideWhenDetachedMiddleware(opts) {
198
+ if (!opts.hideWhenDetached) return;
199
+ return hide({
200
+ strategy: "referenceHidden",
201
+ boundary: opts.boundary?.() ?? "clippingAncestors"
202
+ });
203
+ }
204
+ function getAutoUpdateOptions(opts) {
205
+ if (!opts) return {};
206
+ if (opts === true) return {
207
+ ancestorResize: true,
208
+ ancestorScroll: true,
209
+ elementResize: true,
210
+ layoutShift: true
211
+ };
212
+ return opts;
213
+ }
214
+ function getPlacementImpl(referenceOrVirtual, floating, opts = {}) {
215
+ const reference = getAnchorElement(referenceOrVirtual, opts.getAnchorRect);
216
+ if (!floating || !reference) return;
217
+ const options = Object.assign({}, defaultOptions, opts);
218
+ const arrowEl = floating.querySelector("[data-part=arrow]");
219
+ const middleware = [
220
+ getOffsetMiddleware(arrowEl, options),
221
+ getFlipMiddleware(options),
222
+ getShiftMiddleware(options),
223
+ getArrowMiddleware(arrowEl, options),
224
+ shiftArrowMiddleware(arrowEl),
225
+ transformOriginMiddleware,
226
+ getSizeMiddleware(options),
227
+ hideWhenDetachedMiddleware(options),
228
+ rectMiddleware
229
+ ];
230
+ const { placement, strategy, onComplete, onPositioned } = options;
231
+ const updatePosition = async () => {
232
+ if (!reference || !floating) return;
233
+ const pos = await computePosition(reference, floating, {
234
+ placement,
235
+ middleware,
236
+ strategy
237
+ });
238
+ onComplete?.(pos);
239
+ onPositioned?.({ placed: true });
240
+ const win = getWindow(floating);
241
+ const x = roundByDpr(win, pos.x);
242
+ const y = roundByDpr(win, pos.y);
243
+ floating.style.setProperty("--x", `${x}px`);
244
+ floating.style.setProperty("--y", `${y}px`);
245
+ if (options.hideWhenDetached) {
246
+ const isHidden = pos.middlewareData.hide?.referenceHidden;
247
+ if (isHidden) {
248
+ floating.style.setProperty("visibility", "hidden");
249
+ floating.style.setProperty("pointer-events", "none");
250
+ } else {
251
+ floating.style.removeProperty("visibility");
252
+ floating.style.removeProperty("pointer-events");
253
+ }
254
+ }
255
+ const contentEl = floating.firstElementChild;
256
+ if (contentEl) {
257
+ const styles = getComputedStyle(contentEl);
258
+ floating.style.setProperty("--z-index", styles.zIndex);
259
+ }
260
+ };
261
+ const update = async () => {
262
+ if (opts.updatePosition) {
263
+ await opts.updatePosition({ updatePosition });
264
+ onPositioned?.({ placed: true });
265
+ } else await updatePosition();
266
+ };
267
+ const autoUpdateOptions = getAutoUpdateOptions(options.listeners);
268
+ const cancelAutoUpdate = options.listeners ? autoUpdate(reference, floating, update, autoUpdateOptions) : noop;
269
+ update();
270
+ return () => {
271
+ cancelAutoUpdate?.();
272
+ onPositioned?.({ placed: false });
273
+ };
274
+ }
275
+ function getPlacement(referenceOrFn, floatingOrFn, opts = {}) {
276
+ const { defer,...options } = opts;
277
+ const func = defer ? raf : (v) => v();
278
+ const cleanups = [];
279
+ cleanups.push(func(() => {
280
+ const reference = typeof referenceOrFn === "function" ? referenceOrFn() : referenceOrFn;
281
+ const floating = typeof floatingOrFn === "function" ? floatingOrFn() : floatingOrFn;
282
+ cleanups.push(getPlacementImpl(reference, floating, options));
283
+ }));
284
+ return () => {
285
+ cleanups.forEach((fn) => fn?.());
286
+ };
287
+ }
288
+
289
+ //#endregion
290
+ //#region src/get-styles.ts
291
+ const ARROW_FLOATING_STYLE = {
292
+ bottom: "rotate(45deg)",
293
+ left: "rotate(135deg)",
294
+ top: "rotate(225deg)",
295
+ right: "rotate(315deg)"
296
+ };
297
+ function getPlacementStyles(options = {}) {
298
+ const { placement, sameWidth, fitViewport, strategy = "absolute" } = options;
299
+ return {
300
+ arrow: {
301
+ position: "absolute",
302
+ width: cssVars.arrowSize.reference,
303
+ height: cssVars.arrowSize.reference,
304
+ [cssVars.arrowSizeHalf.variable]: `calc(${cssVars.arrowSize.reference} / 2)`,
305
+ [cssVars.arrowOffset.variable]: `calc(${cssVars.arrowSizeHalf.reference} * -1)`
306
+ },
307
+ arrowTip: {
308
+ transform: placement ? ARROW_FLOATING_STYLE[placement.split("-")[0]] : void 0,
309
+ background: cssVars.arrowBg.reference,
310
+ top: "0",
311
+ left: "0",
312
+ width: "100%",
313
+ height: "100%",
314
+ position: "absolute",
315
+ zIndex: "inherit"
316
+ },
317
+ floating: {
318
+ position: strategy,
319
+ isolation: "isolate",
320
+ minWidth: sameWidth ? void 0 : "max-content",
321
+ width: sameWidth ? "var(--reference-width)" : void 0,
322
+ maxWidth: fitViewport ? "var(--available-width)" : void 0,
323
+ maxHeight: fitViewport ? "var(--available-height)" : void 0,
324
+ top: "0px",
325
+ left: "0px",
326
+ transform: placement ? "translate3d(var(--x), var(--y), 0)" : "translate3d(0, -100vh, 0)",
327
+ zIndex: "var(--z-index)"
328
+ }
329
+ };
330
+ }
331
+
332
+ //#endregion
333
+ export { getPlacement, getPlacementSide, getPlacementStyles, isValidPlacement };
package/package.json CHANGED
@@ -1,45 +1,29 @@
1
1
  {
2
2
  "name": "@destyler/popper",
3
3
  "type": "module",
4
- "version": "0.0.6",
5
- "description": "popper is a component that allows you to create popups, tooltips, and dropdowns.",
4
+ "version": "0.0.7-beta.9",
5
+ "description": "Dynamic positioning logic for UI machines",
6
6
  "author": "Elone Hoo <elonehoo@gmail.com>",
7
7
  "license": "MIT",
8
8
  "exports": {
9
- ".": {
10
- "types": "./dist/index.d.mts",
11
- "default": "./dist/index.mjs"
12
- },
13
- "./resolver": {
14
- "types": "./dist/resolver.d.mts",
15
- "default": "./dist/resolver.mjs"
16
- },
17
- "./component": {
18
- "types": "./dist/component.d.mts",
19
- "default": "./dist/component.mjs"
20
- },
21
- "./*": "./*"
9
+ ".": "./dist/index.js"
22
10
  },
23
- "main": "dist/index.cjs",
24
- "module": "dist/index.mjs",
11
+ "main": "dist/index.js",
12
+ "module": "dist/index.js",
25
13
  "types": "dist/index.d.ts",
26
14
  "files": [
27
15
  "*.d.ts",
28
16
  "dist"
29
17
  ],
30
- "peerDependencies": {
31
- "vue": ">=3.4.21"
32
- },
33
18
  "dependencies": {
34
- "@floating-ui/vue": "^1.0.6",
35
- "@destyler/arrow": "0.0.6",
36
- "@destyler/composition": "0.0.6",
37
- "@destyler/shared": "0.0.6",
38
- "@destyler/primitive": "0.0.6"
19
+ "@floating-ui/dom": "1.7.1",
20
+ "@destyler/dom": "0.0.7-beta.9",
21
+ "@destyler/utils": "0.0.7-beta.9"
39
22
  },
40
23
  "scripts": {
41
24
  "clear": "rimraf ./dist",
42
- "build": "pnpm run clear && unbuild",
43
- "stub": "unbuild --stub"
25
+ "clear:node_modules": "rimraf ./node_modules",
26
+ "build": "pnpm run clear && tsdown",
27
+ "watch": "tsdown --watch"
44
28
  }
45
29
  }
package/README.md DELETED
@@ -1,7 +0,0 @@
1
- # @destyler/popper
2
-
3
- [![NPM version](https://img.shields.io/npm/v/@destyler/popper?color=a1b858&popper=)](https://www.npmjs.com/package/@destyler/popper)
4
-
5
- > popper is a component that allows you to create popups, tooltips, and dropdowns.
6
-
7
- [GitHub](https://github.com/destyler/destyler) | [Documentation](https://destyler-dev.zeabur.app/)