@destyler/popper 0.0.1-beta.7

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.mjs ADDED
@@ -0,0 +1,395 @@
1
+ import { defineComponent, ref, watch, h, computed, watchEffect, mergeProps } from 'vue';
2
+ import { createContext, computedEager } from '@destyler/shared';
3
+ import { destylerPrimitiveProps, DestylerPrimitive, destylerPrimitiveProp } from '@destyler/primitive';
4
+ import { useCustomElement, useForwardRef, useSize } from '@destyler/composition';
5
+ import { offset, shift, limitShift, flip, size, arrow, hide, useFloating, autoUpdate } from '@floating-ui/vue';
6
+ import { destylerArrowProps, DestylerArrow } from '@destyler/arrow';
7
+
8
+ const [injectPopperRootContext, providePopperRootContext] = createContext("DestylerPopperRoot");
9
+ const DestylerPopperRoot = defineComponent({
10
+ name: "DestylerPopperRoot",
11
+ setup() {
12
+ const anchor = ref();
13
+ providePopperRootContext({
14
+ anchor,
15
+ onAnchorChange: (element) => anchor.value = element
16
+ });
17
+ },
18
+ render() {
19
+ return this.$slots.default?.();
20
+ }
21
+ });
22
+
23
+ const destylerPopperAnchorProps = {
24
+ ...destylerPrimitiveProps,
25
+ element: {
26
+ type: Object
27
+ }
28
+ };
29
+ const DestylerPopperAnchor = defineComponent({
30
+ name: "DestylerPopperAnchor",
31
+ props: destylerPopperAnchorProps,
32
+ setup(props) {
33
+ const { customElement, currentElement } = useCustomElement();
34
+ const rootContext = injectPopperRootContext();
35
+ watch(currentElement, () => {
36
+ rootContext.onAnchorChange(props.element ?? currentElement.value);
37
+ });
38
+ return {
39
+ customElement
40
+ };
41
+ },
42
+ render() {
43
+ return h(DestylerPrimitive, {
44
+ as: this.$props.as,
45
+ asChild: this.$props.asChild,
46
+ ref: "customElement"
47
+ }, this.$slots.default?.());
48
+ }
49
+ });
50
+
51
+ function isNotNull(value) {
52
+ return value !== null;
53
+ }
54
+ function transformOrigin(options) {
55
+ return {
56
+ name: "transformOrigin",
57
+ options,
58
+ fn(data) {
59
+ const { placement, rects, middlewareData } = data;
60
+ const cannotCenterArrow = middlewareData.arrow?.centerOffset !== 0;
61
+ const isArrowHidden = cannotCenterArrow;
62
+ const arrowWidth = isArrowHidden ? 0 : options.arrowWidth;
63
+ const arrowHeight = isArrowHidden ? 0 : options.arrowHeight;
64
+ const [placedSide, placedAlign] = getSideAndAlignFromPlacement(placement);
65
+ const noArrowAlign = { start: "0%", center: "50%", end: "100%" }[placedAlign];
66
+ const arrowXCenter = (middlewareData.arrow?.x ?? 0) + arrowWidth / 2;
67
+ const arrowYCenter = (middlewareData.arrow?.y ?? 0) + arrowHeight / 2;
68
+ let x = "";
69
+ let y = "";
70
+ if (placedSide === "bottom") {
71
+ x = isArrowHidden ? noArrowAlign : `${arrowXCenter}px`;
72
+ y = `${-arrowHeight}px`;
73
+ } else if (placedSide === "top") {
74
+ x = isArrowHidden ? noArrowAlign : `${arrowXCenter}px`;
75
+ y = `${rects.floating.height + arrowHeight}px`;
76
+ } else if (placedSide === "right") {
77
+ x = `${-arrowHeight}px`;
78
+ y = isArrowHidden ? noArrowAlign : `${arrowYCenter}px`;
79
+ } else if (placedSide === "left") {
80
+ x = `${rects.floating.width + arrowHeight}px`;
81
+ y = isArrowHidden ? noArrowAlign : `${arrowYCenter}px`;
82
+ }
83
+ return { data: { x, y } };
84
+ }
85
+ };
86
+ }
87
+ function getSideAndAlignFromPlacement(placement) {
88
+ const [side, align = "center"] = placement.split("-");
89
+ return [side, align];
90
+ }
91
+
92
+ const [injectPopperContentContext, providePopperContentContext] = createContext("DestylerPopperContent");
93
+ const destylerPopperContentProps = {
94
+ ...destylerPrimitiveProps,
95
+ side: {
96
+ type: String,
97
+ required: false,
98
+ default: "bottom"
99
+ },
100
+ sideOffset: {
101
+ type: Number,
102
+ required: false,
103
+ default: 0
104
+ },
105
+ align: {
106
+ type: String,
107
+ required: false,
108
+ default: "center"
109
+ },
110
+ alignOffset: {
111
+ type: Number,
112
+ required: false,
113
+ default: 0
114
+ },
115
+ avoidCollisions: {
116
+ type: Boolean,
117
+ required: false,
118
+ default: true
119
+ },
120
+ collisionBoundary: {
121
+ type: [Object, Array, null],
122
+ required: false,
123
+ default: () => []
124
+ },
125
+ collisionPadding: {
126
+ type: [Number, Object],
127
+ required: false,
128
+ default: 0
129
+ },
130
+ arrowPadding: {
131
+ type: Number,
132
+ required: false,
133
+ default: 0
134
+ },
135
+ sticky: {
136
+ type: String,
137
+ required: false,
138
+ default: "partial"
139
+ },
140
+ hideWhenDetached: {
141
+ type: Boolean,
142
+ required: false,
143
+ default: false
144
+ },
145
+ updatePositionStrategy: {
146
+ type: String,
147
+ required: false,
148
+ default: "optimized"
149
+ },
150
+ onPlaced: {
151
+ type: Function,
152
+ required: false
153
+ },
154
+ prioritizePosition: {
155
+ type: Boolean,
156
+ required: false,
157
+ default: false
158
+ }
159
+ };
160
+ const DestylerPopperContent = defineComponent({
161
+ name: "DestylerPopperContent",
162
+ inheritAttrs: false,
163
+ props: destylerPopperContentProps,
164
+ setup(props, { attrs }) {
165
+ const rootContext = injectPopperRootContext();
166
+ const forwardRef = useForwardRef();
167
+ const { customElement, currentElement: contentElement } = useCustomElement();
168
+ const floatingRef = ref();
169
+ const arrow$1 = ref();
170
+ const { width: arrowWidth, height: arrowHeight } = useSize(arrow$1);
171
+ const desiredPlacement = computed(() => props.side + (props.align !== "center" ? `-${props.align}` : ""));
172
+ const collisionPadding = computed(() => {
173
+ return typeof props.collisionPadding === "number" ? props.collisionPadding : { top: 0, right: 0, bottom: 0, left: 0, ...props.collisionPadding };
174
+ });
175
+ const boundary = computed(() => {
176
+ return Array.isArray(props.collisionBoundary) ? props.collisionBoundary : [props.collisionBoundary];
177
+ });
178
+ const detectOverflowOptions = computed(() => {
179
+ return {
180
+ padding: collisionPadding.value,
181
+ boundary: boundary.value.filter(isNotNull),
182
+ // with `strategy: 'fixed'`, this is the only way to get it to respect boundaries
183
+ altBoundary: boundary.value.length > 0
184
+ };
185
+ });
186
+ const computedMiddleware = computedEager(() => {
187
+ return [
188
+ offset({
189
+ mainAxis: props.sideOffset + arrowHeight.value,
190
+ alignmentAxis: props.alignOffset
191
+ }),
192
+ props.avoidCollisions && shift({
193
+ mainAxis: true,
194
+ crossAxis: !!props.prioritizePosition,
195
+ limiter: props.sticky === "partial" ? limitShift() : void 0,
196
+ ...detectOverflowOptions.value
197
+ }),
198
+ !props.prioritizePosition && props.avoidCollisions && flip({
199
+ ...detectOverflowOptions.value
200
+ }),
201
+ size({
202
+ ...detectOverflowOptions.value,
203
+ apply: ({ elements, rects, availableWidth, availableHeight }) => {
204
+ const { width: anchorWidth, height: anchorHeight } = rects.reference;
205
+ const contentStyle = elements.floating.style;
206
+ Object.assign(elements.floating.style, {
207
+ maxWidth: `${availableWidth}px`,
208
+ maxHeight: `${availableHeight}px`
209
+ });
210
+ contentStyle.setProperty(
211
+ "--destyler_popper_available_width",
212
+ `${availableWidth}px`
213
+ );
214
+ contentStyle.setProperty(
215
+ "--destyler_popper_available_height",
216
+ `${availableHeight}px`
217
+ );
218
+ contentStyle.setProperty(
219
+ "--destyler_popper_anchor_width",
220
+ `${anchorWidth}px`
221
+ );
222
+ contentStyle.setProperty(
223
+ "--destyler_popper_anchor_height",
224
+ `${anchorHeight}px`
225
+ );
226
+ }
227
+ }),
228
+ arrow$1.value && arrow({ element: arrow$1.value, padding: props.arrowPadding }),
229
+ transformOrigin({
230
+ arrowWidth: arrowWidth.value,
231
+ arrowHeight: arrowHeight.value
232
+ }),
233
+ props.hideWhenDetached && hide({ strategy: "referenceHidden", ...detectOverflowOptions.value })
234
+ ];
235
+ });
236
+ const { floatingStyles, placement, isPositioned, middlewareData } = useFloating(
237
+ rootContext.anchor,
238
+ floatingRef,
239
+ {
240
+ strategy: "fixed",
241
+ placement: desiredPlacement,
242
+ whileElementsMounted: (...args) => {
243
+ const cleanup = autoUpdate(...args, {
244
+ animationFrame: props.updatePositionStrategy === "always"
245
+ });
246
+ return cleanup;
247
+ },
248
+ middleware: computedMiddleware
249
+ }
250
+ );
251
+ const placedSide = computed(() => getSideAndAlignFromPlacement(placement.value)[0]);
252
+ const placedAlign = computed(() => getSideAndAlignFromPlacement(placement.value)[1]);
253
+ watchEffect(() => {
254
+ if (isPositioned.value)
255
+ props.onPlaced?.();
256
+ });
257
+ const cannotCenterArrow = computed(
258
+ () => middlewareData.value.arrow?.centerOffset !== 0
259
+ );
260
+ const contentZIndex = ref("");
261
+ watchEffect(() => {
262
+ if (contentElement.value)
263
+ contentZIndex.value = window.getComputedStyle(contentElement.value).zIndex;
264
+ });
265
+ const arrowX = computed(() => middlewareData.value.arrow?.x ?? 0);
266
+ const arrowY = computed(() => middlewareData.value.arrow?.y ?? 0);
267
+ providePopperContentContext({
268
+ placedSide,
269
+ onArrowChange: (element) => arrow$1.value = element,
270
+ arrowX,
271
+ arrowY,
272
+ shouldHideArrow: cannotCenterArrow
273
+ });
274
+ return {
275
+ floatingRef,
276
+ floatingStyles,
277
+ isPositioned,
278
+ contentZIndex,
279
+ middlewareData,
280
+ forwardRef,
281
+ customElement,
282
+ placedSide,
283
+ placedAlign,
284
+ attrStyle: attrs.style
285
+ };
286
+ },
287
+ render() {
288
+ return h("div", mergeProps(this.$attrs, {
289
+ "data-destyler-popper-content-wrapper": "",
290
+ "ref": "floatingRef",
291
+ "style": {
292
+ ...this.floatingStyles,
293
+ transform: this.isPositioned ? this.floatingStyles.transform : "translate(0, -200%)",
294
+ minWidth: "max-content",
295
+ zIndex: this.contentZIndex,
296
+ ["--destyler_popper_transform_origin"]: [
297
+ this.middlewareData.transformOrigin?.x,
298
+ this.middlewareData.transformOrigin?.y
299
+ ].join(" ")
300
+ }
301
+ }), h(DestylerPrimitive, mergeProps(this.$attrs, {
302
+ "ref": (vnode) => {
303
+ this.forwardRef(vnode);
304
+ this.customElement = vnode;
305
+ },
306
+ "as": this.$props.as,
307
+ "asChild": this.$props.asChild,
308
+ "data-side": this.placedSide,
309
+ "data-align": this.placedAlign,
310
+ "style": {
311
+ animation: !this.isPositioned ? "none" : void 0,
312
+ opacity: this.middlewareData.hide?.referenceHidden ? 0 : void 0
313
+ }
314
+ }), this.$slots.default?.()));
315
+ }
316
+ });
317
+
318
+ const OPPOSITE_SIDE = {
319
+ top: "bottom",
320
+ right: "left",
321
+ bottom: "top",
322
+ left: "right"
323
+ };
324
+ const destylerPopperArrowProps = {
325
+ ...destylerPrimitiveProp,
326
+ ...destylerArrowProps,
327
+ as: {
328
+ type: [String, Object],
329
+ required: false,
330
+ default: "svg"
331
+ }
332
+ };
333
+ const DestylerPopperArrow = defineComponent({
334
+ name: "DestylerPopperArrow",
335
+ inheritAttrs: false,
336
+ props: destylerPopperArrowProps,
337
+ setup() {
338
+ const contentContext = injectPopperContentContext();
339
+ const baseSide = computed(() => OPPOSITE_SIDE[contentContext.placedSide.value]);
340
+ return {
341
+ contentContext,
342
+ baseSide
343
+ };
344
+ },
345
+ render() {
346
+ return h("span", {
347
+ ref: (el) => {
348
+ this.contentContext.onArrowChange(el);
349
+ return void 0;
350
+ },
351
+ style: {
352
+ position: "absolute",
353
+ left: this.contentContext.arrowX?.value ? `${this.contentContext.arrowX?.value}px` : void 0,
354
+ top: this.contentContext.arrowY?.value ? `${this.contentContext.arrowY?.value}px` : void 0,
355
+ [this.baseSide]: 0,
356
+ transformOrigin: {
357
+ top: "",
358
+ right: "0 0",
359
+ bottom: "center 0",
360
+ left: "100% 0"
361
+ }[this.contentContext.placedSide.value],
362
+ transform: {
363
+ top: "translateY(100%)",
364
+ right: "translateY(50%) rotate(90deg) translateX(-50%)",
365
+ bottom: `rotate(180deg)`,
366
+ left: "translateY(50%) rotate(-90deg) translateX(50%)"
367
+ }[this.contentContext.placedSide.value],
368
+ visibility: this.contentContext.shouldHideArrow.value ? "hidden" : void 0
369
+ }
370
+ }, h(DestylerArrow, mergeProps(this.$attrs, {
371
+ as: this.$props.as,
372
+ asChild: this.$props.asChild,
373
+ width: this.$props.width,
374
+ height: this.$props.height,
375
+ style: {
376
+ display: "block"
377
+ }
378
+ }), this.$slots.default?.()));
379
+ }
380
+ });
381
+
382
+ const name = "@destyler/popper";
383
+
384
+ const packageName = name;
385
+ function DestylerPopperResolver() {
386
+ return {
387
+ type: "component",
388
+ resolve: (name2) => {
389
+ if (name2 === "DestylerTemplate")
390
+ return { name: name2, from: packageName };
391
+ }
392
+ };
393
+ }
394
+
395
+ export { DestylerPopperAnchor, DestylerPopperArrow, DestylerPopperContent, DestylerPopperResolver, DestylerPopperRoot, OPPOSITE_SIDE, destylerPopperAnchorProps, destylerPopperArrowProps, destylerPopperContentProps, getSideAndAlignFromPlacement, injectPopperContentContext, injectPopperRootContext, isNotNull, providePopperContentContext, providePopperRootContext, transformOrigin };
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "@destyler/popper",
3
+ "version": "0.0.1-beta.7",
4
+ "description": "unstyled popper component for vue",
5
+ "author": "Elone Hoo <elonehoo@gmail.com>",
6
+ "license": "MIT",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/index.d.ts",
10
+ "import": "./dist/index.mjs",
11
+ "require": "./dist/index.cjs"
12
+ },
13
+ "./*": "./*"
14
+ },
15
+ "main": "dist/index.cjs",
16
+ "module": "dist/index.mjs",
17
+ "types": "dist/index.d.ts",
18
+ "files": [
19
+ "*.d.ts",
20
+ "dist"
21
+ ],
22
+ "peerDependencies": {
23
+ "vue": ">=3.3.4"
24
+ },
25
+ "dependencies": {
26
+ "@floating-ui/vue": "^1.0.4",
27
+ "@destyler/shared": "0.0.1-beta.7",
28
+ "@destyler/arrow": "0.0.1-beta.7",
29
+ "@destyler/composition": "0.0.1-beta.7",
30
+ "@destyler/primitive": "0.0.1-beta.7"
31
+ },
32
+ "scripts": {
33
+ "clear": "rimraf ./dist",
34
+ "build": "pnpm run clear && unbuild"
35
+ }
36
+ }