-
Notifications
You must be signed in to change notification settings - Fork 34
Expand file tree
/
Copy pathindex.ts
More file actions
105 lines (96 loc) · 2.84 KB
/
index.ts
File metadata and controls
105 lines (96 loc) · 2.84 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
import type {
autoUpdate,
computePosition,
shift,
flip,
offset,
ReferenceElement,
Middleware,
} from "@floating-ui/dom";
import { load as floatinguiLoad } from "@internal/floating-ui";
interface DropdownUtilOptions {
reverse?: boolean;
flip?: boolean;
strategy?: "absolute" | "fixed";
offset?: number;
}
export class DropdownUtil {
declare host: ReferenceElement;
declare overlay: HTMLElement;
declare cleanupFn: any;
declare options: DropdownUtilOptions;
declare loaded: boolean;
declare triggerShow: boolean;
declare computePosition: typeof computePosition;
declare autoUpdate: typeof autoUpdate;
declare offset: typeof offset;
declare flip: typeof flip;
declare shift: typeof shift;
constructor(
host: HTMLElement,
overlay: HTMLElement,
options?: DropdownUtilOptions,
) {
this.host = host as ReferenceElement;
this.overlay = overlay as HTMLElement;
this.options = options ?? {};
floatinguiLoad()
.then((floatingUI) => {
this.computePosition =
floatingUI.computePosition as typeof computePosition;
this.autoUpdate = floatingUI.autoUpdate as typeof autoUpdate;
this.offset = floatingUI.offset;
this.flip = floatingUI.flip;
this.shift = floatingUI.shift;
this.loaded = true;
if (this.triggerShow) {
this.triggerShow = false;
this.show();
}
})
.catch(() => {
// This is the case where it's loaded on the server.
// Should be no-op
});
}
show() {
if (this.loaded) {
this.cleanupFn = this.autoUpdate(
this.host,
this.overlay,
this.update.bind(this),
);
} else {
this.triggerShow = true;
}
}
update() {
if (!this.loaded) return;
const middleware = [] as Middleware[];
middleware.push(this.offset(this.options.offset ?? 4));
if (this.options.flip) {
middleware.push(
this.flip({
crossAxis: true,
}),
);
}
middleware.push(this.shift());
this.computePosition(this.host, this.overlay, {
placement: this.options.reverse ? "bottom-end" : "bottom-start",
strategy: this.options.strategy ?? "fixed",
middleware,
}).then(({ x, y }) => {
Object.assign(this.overlay.style, {
left: `${x}px`,
top: `${y}px`,
});
});
}
cleanup() {
this.cleanupFn?.();
}
hide() {
if (this.cleanup) this.cleanup();
}
}