15 | Click on the Vite and React logos to learn more
16 |
17 | Click on the Vite and React logos to learn more
18 |
19 | Click on the Vite and React logos to learn more
20 |
21 | Click on the Vite and React logos to learn more
22 |
23 | Click on the Vite and React logos to learn more
24 |
25 | Click on the Vite and React logos to learn more
26 |
27 | Click on the Vite and React logos to learn more
28 |
29 | Click on the Vite and React logos to learn more
30 |
31 | Click on the Vite and React logos to learn more
32 |
33 | Click on the Vite and React logos to learn more
34 |
35 | Click on the Vite and React logos to learn more
36 |
37 | Click on the Vite and React logos to learn more
38 |
39 | Click on the Vite and React logos to learn more
40 |
41 | Click on the Vite and React logos to learn more
42 |
43 | Click on the Vite and React logos to learn more
44 |
45 | Click on the Vite and React logos to learn more
46 |
47 | Click on the Vite and React logos to learn more
48 |
49 | Click on the Vite and React logos to learn more
50 |
51 | Click on the Vite and React logos to learn more
52 |
53 | Click on the Vite and React logos to learn more
54 |
55 | Click on the Vite and React logos to learn more
56 |
57 | Click on the Vite and React logos to learn more
58 |
59 | Click on the Vite and React logos to learn more
60 |
61 | Click on the Vite and React logos to learn more
62 |
63 | Click on the Vite and React logos to learn more
64 |
65 | Click on the Vite and React logos to learn more
66 |
67 | Click on the Vite and React logos to learn more
68 |
69 | Click on the Vite and React logos to learn more
70 |
71 | Click on the Vite and React logos to learn more
72 |
73 | Click on the Vite and React logos to learn more
74 |
75 | Click on the Vite and React logos to learn more
76 |
77 | Click on the Vite and React logos to learn more
78 |
79 | Click on the Vite and React logos to learn more
80 |
81 | Click on the Vite and React logos to learn more
82 |
83 | Click on the Vite and React logos to learn more
84 |
85 | Click on the Vite and React logos to learn more
86 |
87 | Click on the Vite and React logos to learn more
88 |
89 | Click on the Vite and React logos to learn more
90 |
91 | Click on the Vite and React logos to learn more
92 |
93 | Click on the Vite and React logos to learn more
94 |
95 | Click on the Vite and React logos to learn more
96 |
97 | Click on the Vite and React logos to learn more
98 |
99 | Click on the Vite and React logos to learn more
100 |
101 | Click on the Vite and React logos to learn more
102 |
103 | Click on the Vite and React logos to learn more
104 |
105 | Click on the Vite and React logos to learn more
106 |
107 | Click on the Vite and React logos to learn more
108 |
109 | Click on the Vite and React logos to learn more
110 |
111 | Click on the Vite and React logos to learn more
112 |
113 | Click on the Vite and React logos to learn more
114 |
115 | Click on the Vite and React logos to learn more
116 |
117 | Click on the Vite and React logos to learn more
118 |
119 | Click on the Vite and React logos to learn more
120 |
121 | Click on the Vite and React logos to learn more
122 |
123 | Click on the Vite and React logos to learn more
124 |
125 | Click on the Vite and React logos to learn more
126 |
127 | Click on the Vite and React logos to learn more
128 |
129 | Click on the Vite and React logos to learn more
130 |
131 | Click on the Vite and React logos to learn more
132 |
133 | Click on the Vite and React logos to learn more
134 |
135 | Click on the Vite and React logos to learn more
136 |
137 | Click on the Vite and React logos to learn more
138 |
139 | Click on the Vite and React logos to learn more
140 |
141 | Click on the Vite and React logos to learn more
142 |
143 | Click on the Vite and React logos to learn more
144 |
145 | Click on the Vite and React logos to learn more
146 |
147 |
31 | Click on the Vite and React logos to learn more
32 |
33 | Click on the Vite and React logos to learn more
34 |
35 | Click on the Vite and React logos to learn more
36 |
37 | Click on the Vite and React logos to learn more
38 |
39 | Click on the Vite and React logos to learn more
40 |
41 | Click on the Vite and React logos to learn more
42 |
43 | Click on the Vite and React logos to learn more
44 |
45 | Click on the Vite and React logos to learn more
46 |
47 | Click on the Vite and React logos to learn more
48 |
49 | Click on the Vite and React logos to learn more
50 |
51 | Click on the Vite and React logos to learn more
52 |
53 | Click on the Vite and React logos to learn more
54 |
55 | Click on the Vite and React logos to learn more
56 |
57 | Click on the Vite and React logos to learn more
58 |
59 | Click on the Vite and React logos to learn more
60 |
61 | Click on the Vite and React logos to learn more
62 |
63 | Click on the Vite and React logos to learn more
64 |
65 | Click on the Vite and React logos to learn more
66 |
67 | Click on the Vite and React logos to learn more
68 |
69 | Click on the Vite and React logos to learn more
70 |
71 | Click on the Vite and React logos to learn more
72 |
73 | Click on the Vite and React logos to learn more
74 |
75 | Click on the Vite and React logos to learn more
76 |
77 | Click on the Vite and React logos to learn more
78 |
79 | Click on the Vite and React logos to learn more
80 |
81 | Click on the Vite and React logos to learn more
82 |
83 | Click on the Vite and React logos to learn more
84 |
85 | Click on the Vite and React logos to learn more
86 |
87 | Click on the Vite and React logos to learn more
88 |
89 | Click on the Vite and React logos to learn more
90 |
91 | Click on the Vite and React logos to learn more
92 |
93 | Click on the Vite and React logos to learn more
94 |
95 | Click on the Vite and React logos to learn more
96 |
97 | Click on the Vite and React logos to learn more
98 |
99 | Click on the Vite and React logos to learn more
100 |
101 | Click on the Vite and React logos to learn more
102 |
103 | Click on the Vite and React logos to learn more
104 |
105 | Click on the Vite and React logos to learn more
106 |
107 | Click on the Vite and React logos to learn more
108 |
109 | Click on the Vite and React logos to learn more
110 |
111 | Click on the Vite and React logos to learn more
112 |
113 | Click on the Vite and React logos to learn more
114 |
115 | Click on the Vite and React logos to learn more
116 |
117 | Click on the Vite and React logos to learn more
118 |
119 | Click on the Vite and React logos to learn more
120 |
121 | Click on the Vite and React logos to learn more
122 |
123 | Click on the Vite and React logos to learn more
124 |
125 | Click on the Vite and React logos to learn more
126 |
127 | Click on the Vite and React logos to learn more
128 |
129 | Click on the Vite and React logos to learn more
130 |
131 | Click on the Vite and React logos to learn more
132 |
133 | Click on the Vite and React logos to learn more
134 |
135 | Click on the Vite and React logos to learn more
136 |
137 | Click on the Vite and React logos to learn more
138 |
139 | Click on the Vite and React logos to learn more
140 |
141 | Click on the Vite and React logos to learn more
142 |
143 | Click on the Vite and React logos to learn more
144 |
145 | Click on the Vite and React logos to learn more
146 |
147 | Click on the Vite and React logos to learn more
148 |
149 | Click on the Vite and React logos to learn more
150 |
151 | Click on the Vite and React logos to learn more
152 |
153 | Click on the Vite and React logos to learn more
154 |
155 | Click on the Vite and React logos to learn more
156 |
157 | Click on the Vite and React logos to learn more
158 |
159 | Click on the Vite and React logos to learn more
160 |
161 | Click on the Vite and React logos to learn more
162 |
163 |
42 | Edit
43 | components/HelloWorld.vue to test HMR
44 |
45 |
46 |
47 |
48 | Check out
49 | create-vue, the official Vue + Vite starter
52 |
53 |
54 | Install
55 | Volar
58 | in your IDE for a better DX
59 |
60 |
Click on the Vite and Vue logos to learn more
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 | Click on the Vite and React logos to learn more
69 |
70 | Click on the Vite and React logos to learn more
71 |
72 | Click on the Vite and React logos to learn more
73 |
74 | Click on the Vite and React logos to learn more
75 |
76 | Click on the Vite and React logos to learn more
77 |
78 | Click on the Vite and React logos to learn more
79 |
80 | Click on the Vite and React logos to learn more
81 |
82 | Click on the Vite and React logos to learn more
83 |
84 | Click on the Vite and React logos to learn more
85 |
86 | Click on the Vite and React logos to learn more
87 |
88 | Click on the Vite and React logos to learn more
89 |
90 | Click on the Vite and React logos to learn more
91 |
92 | Click on the Vite and React logos to learn more
93 |
94 | Click on the Vite and React logos to learn more
95 |
96 | Click on the Vite and React logos to learn more
97 |
98 | Click on the Vite and React logos to learn more
99 |
100 | Click on the Vite and React logos to learn more
101 |
102 | Click on the Vite and React logos to learn more
103 |
104 | Click on the Vite and React logos to learn more
105 |
106 | Click on the Vite and React logos to learn more
107 |
108 | Click on the Vite and React logos to learn more
109 |
110 | Click on the Vite and React logos to learn more
111 |
112 | Click on the Vite and React logos to learn more
113 |
114 | Click on the Vite and React logos to learn more
115 |
116 | Click on the Vite and React logos to learn more
117 |
118 | Click on the Vite and React logos to learn more
119 |
120 | Click on the Vite and React logos to learn more
121 |
122 | Click on the Vite and React logos to learn more
123 |
124 | Click on the Vite and React logos to learn more
125 |
126 | Click on the Vite and React logos to learn more
127 |
128 | Click on the Vite and React logos to learn more
129 |
130 | Click on the Vite and React logos to learn more
131 |
132 | Click on the Vite and React logos to learn more
133 |
134 | Click on the Vite and React logos to learn more
135 |
136 | Click on the Vite and React logos to learn more
137 |
138 | Click on the Vite and React logos to learn more
139 |
140 | Click on the Vite and React logos to learn more
141 |
142 | Click on the Vite and React logos to learn more
143 |
144 | Click on the Vite and React logos to learn more
145 |
146 | Click on the Vite and React logos to learn more
147 |
148 | Click on the Vite and React logos to learn more
149 |
150 | Click on the Vite and React logos to learn more
151 |
152 | Click on the Vite and React logos to learn more
153 |
154 | Click on the Vite and React logos to learn more
155 |
156 | Click on the Vite and React logos to learn more
157 |
158 | Click on the Vite and React logos to learn more
159 |
160 | Click on the Vite and React logos to learn more
161 |
162 | Click on the Vite and React logos to learn more
163 |
164 | Click on the Vite and React logos to learn more
165 |
166 | Click on the Vite and React logos to learn more
167 |
168 | Click on the Vite and React logos to learn more
169 |
170 | Click on the Vite and React logos to learn more
171 |
172 | Click on the Vite and React logos to learn more
173 |
174 | Click on the Vite and React logos to learn more
175 |
176 | Click on the Vite and React logos to learn more
177 |
178 | Click on the Vite and React logos to learn more
179 |
180 | Click on the Vite and React logos to learn more
181 |
182 | Click on the Vite and React logos to learn more
183 |
184 | Click on the Vite and React logos to learn more
185 |
186 | Click on the Vite and React logos to learn more
187 |
188 | Click on the Vite and React logos to learn more
189 |
190 | Click on the Vite and React logos to learn more
191 |
192 | Click on the Vite and React logos to learn more
193 |
194 | Click on the Vite and React logos to learn more
195 |
196 | Click on the Vite and React logos to learn more
197 |
198 | Click on the Vite and React logos to learn more
199 |
200 |
40 | Click on the Vite and React logos to learn more
41 |
42 | Click on the Vite and React logos to learn more
43 |
44 | Click on the Vite and React logos to learn more
45 |
46 | Click on the Vite and React logos to learn more
47 |
48 | Click on the Vite and React logos to learn more
49 |
50 | Click on the Vite and React logos to learn more
51 |
52 | Click on the Vite and React logos to learn more
53 |
54 | Click on the Vite and React logos to learn more
55 |
56 | Click on the Vite and React logos to learn more
57 |
58 | Click on the Vite and React logos to learn more
59 |
60 | Click on the Vite and React logos to learn more
61 |
62 | Click on the Vite and React logos to learn more
63 |
64 | Click on the Vite and React logos to learn more
65 |
66 | Click on the Vite and React logos to learn more
67 |
68 | Click on the Vite and React logos to learn more
69 |
70 | Click on the Vite and React logos to learn more
71 |
72 | Click on the Vite and React logos to learn more
73 |
74 | Click on the Vite and React logos to learn more
75 |
76 | Click on the Vite and React logos to learn more
77 |
78 | Click on the Vite and React logos to learn more
79 |
80 | Click on the Vite and React logos to learn more
81 |
82 | Click on the Vite and React logos to learn more
83 |
84 | Click on the Vite and React logos to learn more
85 |
86 | Click on the Vite and React logos to learn more
87 |
88 | Click on the Vite and React logos to learn more
89 |
90 | Click on the Vite and React logos to learn more
91 |
92 | Click on the Vite and React logos to learn more
93 |
94 | Click on the Vite and React logos to learn more
95 |
96 | Click on the Vite and React logos to learn more
97 |
98 | Click on the Vite and React logos to learn more
99 |
100 | Click on the Vite and React logos to learn more
101 |
102 | Click on the Vite and React logos to learn more
103 |
104 | Click on the Vite and React logos to learn more
105 |
106 | Click on the Vite and React logos to learn more
107 |
108 | Click on the Vite and React logos to learn more
109 |
110 | Click on the Vite and React logos to learn more
111 |
112 | Click on the Vite and React logos to learn more
113 |
114 | Click on the Vite and React logos to learn more
115 |
116 | Click on the Vite and React logos to learn more
117 |
118 | Click on the Vite and React logos to learn more
119 |
120 | Click on the Vite and React logos to learn more
121 |
122 | Click on the Vite and React logos to learn more
123 |
124 | Click on the Vite and React logos to learn more
125 |
126 | Click on the Vite and React logos to learn more
127 |
128 | Click on the Vite and React logos to learn more
129 |
130 | Click on the Vite and React logos to learn more
131 |
132 | Click on the Vite and React logos to learn more
133 |
134 | Click on the Vite and React logos to learn more
135 |
136 | Click on the Vite and React logos to learn more
137 |
138 | Click on the Vite and React logos to learn more
139 |
140 | Click on the Vite and React logos to learn more
141 |
142 | Click on the Vite and React logos to learn more
143 |
144 | Click on the Vite and React logos to learn more
145 |
146 | Click on the Vite and React logos to learn more
147 |
148 | Click on the Vite and React logos to learn more
149 |
150 | Click on the Vite and React logos to learn more
151 |
152 | Click on the Vite and React logos to learn more
153 |
154 | Click on the Vite and React logos to learn more
155 |
156 | Click on the Vite and React logos to learn more
157 |
158 | Click on the Vite and React logos to learn more
159 |
160 | Click on the Vite and React logos to learn more
161 |
162 | Click on the Vite and React logos to learn more
163 |
164 | Click on the Vite and React logos to learn more
165 |
166 | Click on the Vite and React logos to learn more
167 |
168 | Click on the Vite and React logos to learn more
169 |
170 | Click on the Vite and React logos to learn more
171 |
172 |
173 |
174 |
175 |
176 |
177 | Click on the Vite and React logos to learn more
178 |
179 | Click on the Vite and React logos to learn more
180 |
181 | Click on the Vite and React logos to learn more
182 |
183 | Click on the Vite and React logos to learn more
184 |
185 | Click on the Vite and React logos to learn more
186 |
187 | Click on the Vite and React logos to learn more
188 |
189 | Click on the Vite and React logos to learn more
190 |
191 | Click on the Vite and React logos to learn more
192 |
193 | Click on the Vite and React logos to learn more
194 |
195 | Click on the Vite and React logos to learn more
196 |
197 | Click on the Vite and React logos to learn more
198 |
199 | Click on the Vite and React logos to learn more
200 |
201 | Click on the Vite and React logos to learn more
202 |
203 | Click on the Vite and React logos to learn more
204 |
205 | Click on the Vite and React logos to learn more
206 |
207 | Click on the Vite and React logos to learn more
208 |
209 | Click on the Vite and React logos to learn more
210 |
211 | Click on the Vite and React logos to learn more
212 |
213 | Click on the Vite and React logos to learn more
214 |
215 | Click on the Vite and React logos to learn more
216 |
217 | Click on the Vite and React logos to learn more
218 |
219 | Click on the Vite and React logos to learn more
220 |
221 | Click on the Vite and React logos to learn more
222 |
223 | Click on the Vite and React logos to learn more
224 |
225 | Click on the Vite and React logos to learn more
226 |
227 | Click on the Vite and React logos to learn more
228 |
229 | Click on the Vite and React logos to learn more
230 |
231 | Click on the Vite and React logos to learn more
232 |
233 | Click on the Vite and React logos to learn more
234 |
235 | Click on the Vite and React logos to learn more
236 |
237 | Click on the Vite and React logos to learn more
238 |
239 | Click on the Vite and React logos to learn more
240 |
241 | Click on the Vite and React logos to learn more
242 |
243 | Click on the Vite and React logos to learn more
244 |
245 | Click on the Vite and React logos to learn more
246 |
247 | Click on the Vite and React logos to learn more
248 |
249 | Click on the Vite and React logos to learn more
250 |
251 | Click on the Vite and React logos to learn more
252 |
253 | Click on the Vite and React logos to learn more
254 |
255 | Click on the Vite and React logos to learn more
256 |
257 | Click on the Vite and React logos to learn more
258 |
259 | Click on the Vite and React logos to learn more
260 |
261 | Click on the Vite and React logos to learn more
262 |
263 | Click on the Vite and React logos to learn more
264 |
265 | Click on the Vite and React logos to learn more
266 |
267 | Click on the Vite and React logos to learn more
268 |
269 | Click on the Vite and React logos to learn more
270 |
271 | Click on the Vite and React logos to learn more
272 |
273 | Click on the Vite and React logos to learn more
274 |
275 | Click on the Vite and React logos to learn more
276 |
277 | Click on the Vite and React logos to learn more
278 |
279 | Click on the Vite and React logos to learn more
280 |
281 | Click on the Vite and React logos to learn more
282 |
283 | Click on the Vite and React logos to learn more
284 |
285 | Click on the Vite and React logos to learn more
286 |
287 | Click on the Vite and React logos to learn more
288 |
289 | Click on the Vite and React logos to learn more
290 |
291 | Click on the Vite and React logos to learn more
292 |
293 | Click on the Vite and React logos to learn more
294 |
295 | Click on the Vite and React logos to learn more
296 |
297 | Click on the Vite and React logos to learn more
298 |
299 | Click on the Vite and React logos to learn more
300 |
301 | Click on the Vite and React logos to learn more
302 |
303 | Click on the Vite and React logos to learn more
304 |
305 | Click on the Vite and React logos to learn more
306 |
307 | Click on the Vite and React logos to learn more
308 |
309 |
40 | Click on the Vite and React logos to learn more
41 |
42 | Click on the Vite and React logos to learn more
43 |
44 | Click on the Vite and React logos to learn more
45 |
46 | Click on the Vite and React logos to learn more
47 |
48 | Click on the Vite and React logos to learn more
49 |
50 | Click on the Vite and React logos to learn more
51 |
52 | Click on the Vite and React logos to learn more
53 |
54 | Click on the Vite and React logos to learn more
55 |
56 | Click on the Vite and React logos to learn more
57 |
58 | Click on the Vite and React logos to learn more
59 |
60 | Click on the Vite and React logos to learn more
61 |
62 | Click on the Vite and React logos to learn more
63 |
64 | Click on the Vite and React logos to learn more
65 |
66 | Click on the Vite and React logos to learn more
67 |
68 | Click on the Vite and React logos to learn more
69 |
70 | Click on the Vite and React logos to learn more
71 |
72 | Click on the Vite and React logos to learn more
73 |
74 | Click on the Vite and React logos to learn more
75 |
76 | Click on the Vite and React logos to learn more
77 |
78 | Click on the Vite and React logos to learn more
79 |
80 | Click on the Vite and React logos to learn more
81 |
82 | Click on the Vite and React logos to learn more
83 |
84 | Click on the Vite and React logos to learn more
85 |
86 | Click on the Vite and React logos to learn more
87 |
88 | Click on the Vite and React logos to learn more
89 |
90 | Click on the Vite and React logos to learn more
91 |
92 | Click on the Vite and React logos to learn more
93 |
94 | Click on the Vite and React logos to learn more
95 |
96 | Click on the Vite and React logos to learn more
97 |
98 | Click on the Vite and React logos to learn more
99 |
100 | Click on the Vite and React logos to learn more
101 |
102 | Click on the Vite and React logos to learn more
103 |
104 | Click on the Vite and React logos to learn more
105 |
106 | Click on the Vite and React logos to learn more
107 |
108 | Click on the Vite and React logos to learn more
109 |
110 | Click on the Vite and React logos to learn more
111 |
112 | Click on the Vite and React logos to learn more
113 |
114 | Click on the Vite and React logos to learn more
115 |
116 | Click on the Vite and React logos to learn more
117 |
118 | Click on the Vite and React logos to learn more
119 |
120 | Click on the Vite and React logos to learn more
121 |
122 | Click on the Vite and React logos to learn more
123 |
124 | Click on the Vite and React logos to learn more
125 |
126 | Click on the Vite and React logos to learn more
127 |
128 | Click on the Vite and React logos to learn more
129 |
130 | Click on the Vite and React logos to learn more
131 |
132 | Click on the Vite and React logos to learn more
133 |
134 | Click on the Vite and React logos to learn more
135 |
136 | Click on the Vite and React logos to learn more
137 |
138 | Click on the Vite and React logos to learn more
139 |
140 | Click on the Vite and React logos to learn more
141 |
142 | Click on the Vite and React logos to learn more
143 |
144 | Click on the Vite and React logos to learn more
145 |
146 | Click on the Vite and React logos to learn more
147 |
148 | Click on the Vite and React logos to learn more
149 |
150 | Click on the Vite and React logos to learn more
151 |
152 | Click on the Vite and React logos to learn more
153 |
154 | Click on the Vite and React logos to learn more
155 |
156 | Click on the Vite and React logos to learn more
157 |
158 | Click on the Vite and React logos to learn more
159 |
160 | Click on the Vite and React logos to learn more
161 |
162 | Click on the Vite and React logos to learn more
163 |
164 | Click on the Vite and React logos to learn more
165 |
166 | Click on the Vite and React logos to learn more
167 |
168 | Click on the Vite and React logos to learn more
169 |
170 | Click on the Vite and React logos to learn more
171 |
172 |
173 |
174 |
175 |
176 |
177 | Click on the Vite and React logos to learn more
178 |
179 | Click on the Vite and React logos to learn more
180 |
181 | Click on the Vite and React logos to learn more
182 |
183 | Click on the Vite and React logos to learn more
184 |
185 | Click on the Vite and React logos to learn more
186 |
187 | Click on the Vite and React logos to learn more
188 |
189 | Click on the Vite and React logos to learn more
190 |
191 | Click on the Vite and React logos to learn more
192 |
193 | Click on the Vite and React logos to learn more
194 |
195 | Click on the Vite and React logos to learn more
196 |
197 | Click on the Vite and React logos to learn more
198 |
199 | Click on the Vite and React logos to learn more
200 |
201 | Click on the Vite and React logos to learn more
202 |
203 | Click on the Vite and React logos to learn more
204 |
205 | Click on the Vite and React logos to learn more
206 |
207 | Click on the Vite and React logos to learn more
208 |
209 | Click on the Vite and React logos to learn more
210 |
211 | Click on the Vite and React logos to learn more
212 |
213 | Click on the Vite and React logos to learn more
214 |
215 | Click on the Vite and React logos to learn more
216 |
217 | Click on the Vite and React logos to learn more
218 |
219 | Click on the Vite and React logos to learn more
220 |
221 | Click on the Vite and React logos to learn more
222 |
223 | Click on the Vite and React logos to learn more
224 |
225 | Click on the Vite and React logos to learn more
226 |
227 | Click on the Vite and React logos to learn more
228 |
229 | Click on the Vite and React logos to learn more
230 |
231 | Click on the Vite and React logos to learn more
232 |
233 | Click on the Vite and React logos to learn more
234 |
235 | Click on the Vite and React logos to learn more
236 |
237 | Click on the Vite and React logos to learn more
238 |
239 | Click on the Vite and React logos to learn more
240 |
241 | Click on the Vite and React logos to learn more
242 |
243 | Click on the Vite and React logos to learn more
244 |
245 | Click on the Vite and React logos to learn more
246 |
247 | Click on the Vite and React logos to learn more
248 |
249 | Click on the Vite and React logos to learn more
250 |
251 | Click on the Vite and React logos to learn more
252 |
253 | Click on the Vite and React logos to learn more
254 |
255 | Click on the Vite and React logos to learn more
256 |
257 | Click on the Vite and React logos to learn more
258 |
259 | Click on the Vite and React logos to learn more
260 |
261 | Click on the Vite and React logos to learn more
262 |
263 | Click on the Vite and React logos to learn more
264 |
265 | Click on the Vite and React logos to learn more
266 |
267 | Click on the Vite and React logos to learn more
268 |
269 | Click on the Vite and React logos to learn more
270 |
271 | Click on the Vite and React logos to learn more
272 |
273 | Click on the Vite and React logos to learn more
274 |
275 | Click on the Vite and React logos to learn more
276 |
277 | Click on the Vite and React logos to learn more
278 |
279 | Click on the Vite and React logos to learn more
280 |
281 | Click on the Vite and React logos to learn more
282 |
283 | Click on the Vite and React logos to learn more
284 |
285 | Click on the Vite and React logos to learn more
286 |
287 | Click on the Vite and React logos to learn more
288 |
289 | Click on the Vite and React logos to learn more
290 |
291 | Click on the Vite and React logos to learn more
292 |
293 | Click on the Vite and React logos to learn more
294 |
295 | Click on the Vite and React logos to learn more
296 |
297 | Click on the Vite and React logos to learn more
298 |
299 | Click on the Vite and React logos to learn more
300 |
301 | Click on the Vite and React logos to learn more
302 |
303 | Click on the Vite and React logos to learn more
304 |
305 | Click on the Vite and React logos to learn more
306 |
307 | Click on the Vite and React logos to learn more
308 |
309 |
310 |
311 |
337 |
338 |
339 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # body-scroll-lock-upgrade
2 |
3 | body-scroll-lock upgrade version, repair body-scroll-lock v4.0.0-beta.0 bug。
4 |
5 | They stopped maintenance. I had to work it out myself, using the same approach, with a new version of typeScript. And fix the original problem, available for everyone to use.
6 |
7 | # Changelog
8 |
9 | Refer to the [releases](https://github.com/rick-liruixin/body-scroll-lock-upgrade/releases) page.
10 |
11 | `If you think it works for you, please give me a star ⭐️ to encourage me`
12 |
13 | go to [github](https://github.com/rick-liruixin/body-scroll-lock-upgrade) ⭐️⭐️⭐️⭐️⭐️
14 |
15 | # source document
16 |
17 |
18 |
19 | ## Why BSL?
20 |
21 | Enables body scroll locking (for iOS Mobile and Tablet, Android, desktop Safari/Chrome/Firefox) without breaking scrolling of a target element (eg. modal/lightbox/flyouts/nav-menus).
22 |
23 | _Features:_
24 |
25 | - disables body scroll WITHOUT disabling scroll of a target element
26 | - works on iOS mobile/tablet (!!)
27 | - works on Android
28 | - works on Safari desktop
29 | - works on Chrome/Firefox
30 | - works with vanilla JS and frameworks such as React / Angular / VueJS
31 | - supports nested target elements (eg. a modal that appears on top of a flyout)
32 | - can reserve scrollbar width
33 | - `-webkit-overflow-scrolling: touch` still works
34 |
35 | _Aren't the alternative approaches sufficient?_
36 |
37 | - the approach `document.body.ontouchmove = (e) => { e.preventDefault(); return false; };` locks the
38 | body scroll, but ALSO locks the scroll of a target element (eg. modal).
39 | - the approach `overflow: hidden` on the body or html elements doesn't work for all browsers
40 | - the `position: fixed` approach causes the body scroll to reset
41 | - some approaches break inertia/momentum/rubber-band scrolling on iOS
42 |
43 | ## Install
44 |
45 | $ yarn add body-scroll-lock-upgrade
46 |
47 | or
48 |
49 | $ npm install body-scroll-lock-upgrade
50 |
51 | You can also load via a `` tag (refer to the lib folder).
52 |
53 | ## Usage examples
54 |
55 | ##### Common JS
56 |
57 | ```javascript
58 | // 1. Import the functions
59 | const bodyScrollLock = require('body-scroll-lock-upgrade');
60 | const disableBodyScroll = bodyScrollLock.disableBodyScroll;
61 | const enableBodyScroll = bodyScrollLock.enableBodyScroll;
62 |
63 | // 2. Get a target element that you want to persist scrolling for (such as a modal/lightbox/flyout/nav).
64 | // Specifically, the target element is the one we would like to allow scroll on (NOT a parent of that element).
65 | // This is also the element to apply the CSS '-webkit-overflow-scrolling: touch;' if desired.
66 | const targetElement = document.querySelector('#someElementId');
67 |
68 | // 3. ...in some event handler after showing the target element...disable body scroll
69 | disableBodyScroll(targetElement);
70 |
71 | // 4. ...in some event handler after hiding the target element...
72 | enableBodyScroll(targetElement);
73 | ```
74 |
75 | ##### React/ES6
76 |
77 | ```javascript
78 | // 1. Import the functions
79 | import {
80 | disableBodyScroll,
81 | enableBodyScroll,
82 | clearAllBodyScrollLocks,
83 | } from 'body-scroll-lock-upgrade';
84 |
85 | class SomeComponent extends React.Component {
86 | targetElement = null;
87 |
88 | componentDidMount() {
89 | // 2. Get a target element that you want to persist scrolling for (such as a modal/lightbox/flyout/nav).
90 | // Specifically, the target element is the one we would like to allow scroll on (NOT a parent of that element).
91 | // This is also the element to apply the CSS '-webkit-overflow-scrolling: touch;' if desired.
92 | this.targetElement = document.querySelector('#targetElementId');
93 | }
94 |
95 | showTargetElement = () => {
96 | // ... some logic to show target element
97 |
98 | // 3. Disable body scroll
99 | disableBodyScroll(this.targetElement);
100 | };
101 |
102 | hideTargetElement = () => {
103 | // ... some logic to hide target element
104 |
105 | // 4. Re-enable body scroll
106 | enableBodyScroll(this.targetElement);
107 | };
108 |
109 | componentWillUnmount() {
110 | // 5. Useful if we have called disableBodyScroll for multiple target elements,
111 | // and we just want a kill-switch to undo all that.
112 | // OR useful for if the `hideTargetElement()` function got circumvented eg. visitor
113 | // clicks a link which takes him/her to a different page within the app.
114 | clearAllBodyScrollLocks();
115 | }
116 |
117 | render() {
118 | return
some JSX to go here
;
119 | }
120 | }
121 | ```
122 |
123 | ##### React/ES6 with Refs
124 |
125 | ```javascript
126 | // 1. Import the functions
127 | import {
128 | disableBodyScroll,
129 | enableBodyScroll,
130 | clearAllBodyScrollLocks,
131 | } from 'body-scroll-lock-upgrade';
132 |
133 | class SomeComponent extends React.Component {
134 | // 2. Initialise your ref and targetElement here
135 | targetRef = React.createRef();
136 | targetElement = null;
137 |
138 | componentDidMount() {
139 | // 3. Get a target element that you want to persist scrolling for (such as a modal/lightbox/flyout/nav).
140 | // Specifically, the target element is the one we would like to allow scroll on (NOT a parent of that element).
141 | // This is also the element to apply the CSS '-webkit-overflow-scrolling: touch;' if desired.
142 | this.targetElement = this.targetRef.current;
143 | }
144 |
145 | showTargetElement = () => {
146 | // ... some logic to show target element
147 |
148 | // 4. Disable body scroll
149 | disableBodyScroll(this.targetElement);
150 | };
151 |
152 | hideTargetElement = () => {
153 | // ... some logic to hide target element
154 |
155 | // 5. Re-enable body scroll
156 | enableBodyScroll(this.targetElement);
157 | };
158 |
159 | componentWillUnmount() {
160 | // 5. Useful if we have called disableBodyScroll for multiple target elements,
161 | // and we just want a kill-switch to undo all that.
162 | // OR useful for if the `hideTargetElement()` function got circumvented eg. visitor
163 | // clicks a link which takes him/her to a different page within the app.
164 | clearAllBodyScrollLocks();
165 | }
166 |
167 | render() {
168 | return (
169 | // 6. Pass your ref with the reference to the targetElement to SomeOtherComponent
170 |
171 | some JSX to go here
172 |
173 | );
174 | }
175 | }
176 |
177 | // 7. SomeOtherComponent needs to be a Class component to receive the ref (unless Hooks - https://reactjs.org/docs/hooks-faq.html#can-i-make-a-ref-to-a-function-component - are used).
178 | class SomeOtherComponent extends React.Component {
179 | componentDidMount() {
180 | // Your logic on mount goes here
181 | }
182 |
183 | // 8. BSL will be applied to div below in SomeOtherComponent and persist scrolling for the container
184 | render() {
185 | return
some JSX to go here
;
186 | }
187 | }
188 | ```
189 |
190 | ##### Angular
191 |
192 | ```javascript
193 | import { Component, ElementRef, OnDestroy, ViewChild } from '@angular/core';
194 |
195 | // 1. Import the functions
196 | import {
197 | disableBodyScroll,
198 | enableBodyScroll,
199 | clearAllBodyScrollLocks,
200 | } from 'body-scroll-lock-upgrade';
201 |
202 | @Component({
203 | selector: 'app-scroll-block',
204 | templateUrl: './scroll-block.component.html',
205 | styleUrls: ['./scroll-block.component.css'],
206 | })
207 | export class SomeComponent implements OnDestroy {
208 | // 2. Get a target element that you want to persist scrolling for (such as a modal/lightbox/flyout/nav).
209 | // Specifically, the target element is the one we would like to allow scroll on (NOT a parent of that element).
210 | // This is also the element to apply the CSS '-webkit-overflow-scrolling: touch;' if desired.
211 | @ViewChild('scrollTarget') scrollTarget: ElementRef;
212 |
213 | showTargetElement() {
214 | // ... some logic to show target element
215 |
216 | // 3. Disable body scroll
217 | disableBodyScroll(this.scrollTarget.nativeElement);
218 | }
219 |
220 | hideTargetElement() {
221 | // ... some logic to hide target element
222 |
223 | // 4. Re-enable body scroll
224 | enableBodyScroll(this.scrollTarget.nativeElement);
225 | }
226 |
227 | ngOnDestroy() {
228 | // 5. Useful if we have called disableBodyScroll for multiple target elements,
229 | // and we just want a kill-switch to undo all that.
230 | // OR useful for if the `hideTargetElement()` function got circumvented eg. visitor
231 | // clicks a link which takes him/her to a different page within the app.
232 | clearAllBodyScrollLocks();
233 | }
234 | }
235 | ```
236 |
237 | ##### Vanilla JS
238 |
239 | Then in the javascript:
240 |
241 | ```javascript
242 |
243 |
267 |
268 | // UMD
269 |
270 |
286 | ```
287 |
288 | ## Demo
289 |
290 | Check out the demo, powered by Vercel.
291 |
292 | - https://bodyscrolllock.vercel.app for a basic example
293 | - https://bodyscrolllock-modal.vercel.app for an example with a modal.
294 |
295 | ## Functions
296 |
297 | | Function | Arguments | Return | Description |
298 | | :------------------------ | :------------------------------------------------------------- | :----: | :----------------------------------------------------------- |
299 | | `disableBodyScroll` | `targetElement: HTMLElement` `options: BodyScrollOptions` | `void` | Disables body scroll while enabling scroll on target element |
300 | | `enableBodyScroll` | `targetElement: HTMLElement` | `void` | Enables body scroll and removing listeners on target element |
301 | | `clearAllBodyScrollLocks` | `null` | `void` | Clears all scroll locks |
302 |
303 | ## Options
304 |
305 | ### reserveScrollBarGap
306 |
307 | **optional, default:** false
308 |
309 | If the overflow property of the body is set to hidden, the body widens by the width of the scrollbar. This produces an
310 | unpleasant flickering effect, especially on websites with centered content. If the `reserveScrollBarGap` option is set,
311 | this gap is filled by a `padding-right` on the body element. If `disableBodyScroll` is called for the last target element,
312 | or `clearAllBodyScrollLocks` is called, the `padding-right` is automatically reset to the previous value.
313 |
314 | ```js
315 | import { disableBodyScroll } from 'body-scroll-lock-upgrade';
316 | import type { BodyScrollOptions } from 'body-scroll-lock-upgrade';
317 |
318 | const options: BodyScrollOptions = {
319 | reserveScrollBarGap: true,
320 | };
321 |
322 | disableBodyScroll(targetElement, options);
323 | ```
324 |
325 | ### allowTouchMove
326 |
327 | **optional, default:** undefined
328 |
329 | To disable scrolling on iOS, `disableBodyScroll` prevents `touchmove` events.
330 | However, there are cases where you have called `disableBodyScroll` on an
331 | element, but its children still require `touchmove` events to function.
332 |
333 | See below for 2 use cases:
334 |
335 | ##### Simple
336 |
337 | ```javascript
338 | disableBodyScroll(container, {
339 | allowTouchMove: (el) => el.tagName === 'TEXTAREA',
340 | });
341 | ```
342 |
343 | ##### More Complex
344 |
345 | Javascript:
346 |
347 | ```javascript
348 | disableBodyScroll(container, {
349 | allowTouchMove: (el) => {
350 | while (el && el !== document.body) {
351 | if (el.getAttribute('body-scroll-lock-ignore') !== null) {
352 | return true;
353 | }
354 |
355 | el = el.parentElement;
356 | }
357 | },
358 | });
359 | ```
360 |
361 | Html:
362 |
363 | ```html
364 |
365 |
...
366 |
367 | ```
368 |
369 | ## References
370 |
371 | https://medium.com/jsdownunder/locking-body-scroll-for-all-devices-22def9615177
372 | https://stackoverflow.com/questions/41594997/ios-10-safari-prevent-scrolling-behind-a-fixed-overlay-and-maintain-scroll-posi
373 |
--------------------------------------------------------------------------------
/lib/index.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"index.js","sources":["../src/body-scroll-lock.ts"],"sourcesContent":["export type BodyScrollOptions = {\n reserveScrollBarGap?: boolean | undefined;\n allowTouchMove?: ((el: EventTarget) => boolean) | undefined;\n};\n\ntype BodyStyleType = {\n position: string;\n top: string;\n left: string;\n width: string;\n height: string;\n overflow: string;\n};\n\ninterface Lock {\n targetElement: HTMLElement;\n options: BodyScrollOptions;\n}\n\n// Older browsers don't support event options, feature detect it.\nlet hasPassiveEvents = false;\nif (typeof window !== 'undefined') {\n const passiveTestOptions: any = {\n get passive() {\n hasPassiveEvents = true;\n return undefined;\n },\n };\n (window as any).addEventListener('testPassive', null, passiveTestOptions);\n (window as any).removeEventListener('testPassive', null, passiveTestOptions);\n}\n\nconst isIosDevice =\n typeof window !== 'undefined' &&\n window.navigator &&\n window.navigator.platform &&\n (/iP(ad|hone|od)/.test(window.navigator.platform) ||\n (window.navigator.platform === 'MacIntel' &&\n window.navigator.maxTouchPoints > 1));\ntype HandleScrollEvent = TouchEvent;\n\nlet locks: Array = [];\nlet locksIndex: Map = new Map();\nlet documentListenerAdded: boolean = false;\nlet initialClientY: number = -1;\nlet previousBodyOverflowSetting: string | undefined;\nlet htmlStyle:\n | {\n height: string;\n overflow: string;\n }\n | undefined;\nlet bodyStyle: BodyStyleType | undefined;\n\nlet previousBodyPaddingRight: string | undefined;\n\n// returns true if `el` should be allowed to receive touchmove events.\nconst allowTouchMove = (el: EventTarget): boolean =>\n locks.some((lock) => {\n if (lock.options.allowTouchMove && lock.options.allowTouchMove(el)) {\n return true;\n }\n\n return false;\n });\n\nconst preventDefault = (rawEvent: HandleScrollEvent): boolean => {\n const e: any = rawEvent || window.event;\n\n // For the case whereby consumers adds a touchmove event listener to document.\n // Recall that we do document.addEventListener('touchmove', preventDefault, { passive: false })\n // in disableBodyScroll - so if we provide this opportunity to allowTouchMove, then\n // the touchmove event on document will break.\n if (allowTouchMove(e.target)) {\n return true;\n }\n\n // Do not prevent if the event has more than one touch (usually meaning this is a multi touch gesture like pinch to zoom).\n if (e.touches.length > 1) return true;\n\n if (e.preventDefault) e.preventDefault();\n\n return false;\n};\n\nconst setOverflowHidden = (options?: BodyScrollOptions) => {\n // If previousBodyPaddingRight is already set, don't set it again.\n if (previousBodyPaddingRight === undefined) {\n const reserveScrollBarGap =\n !!options && options.reserveScrollBarGap === true;\n const scrollBarGap =\n window.innerWidth -\n document.documentElement.getBoundingClientRect().width;\n\n if (reserveScrollBarGap && scrollBarGap > 0) {\n const computedBodyPaddingRight = parseInt(\n window\n .getComputedStyle(document.body)\n .getPropertyValue('padding-right'),\n 10\n );\n previousBodyPaddingRight = document.body.style.paddingRight;\n document.body.style.paddingRight = `${\n computedBodyPaddingRight + scrollBarGap\n }px`;\n }\n }\n\n // If previousBodyOverflowSetting is already set, don't set it again.\n if (previousBodyOverflowSetting === undefined) {\n previousBodyOverflowSetting = document.body.style.overflow;\n document.body.style.overflow = 'hidden';\n }\n};\n\nconst restoreOverflowSetting = () => {\n if (previousBodyPaddingRight !== undefined) {\n document.body.style.paddingRight = previousBodyPaddingRight;\n\n // Restore previousBodyPaddingRight to undefined so setOverflowHidden knows it\n // can be set again.\n previousBodyPaddingRight = undefined;\n }\n\n if (previousBodyOverflowSetting !== undefined) {\n document.body.style.overflow = previousBodyOverflowSetting;\n\n // Restore previousBodyOverflowSetting to undefined\n // so setOverflowHidden knows it can be set again.\n previousBodyOverflowSetting = undefined;\n }\n};\n\nconst setPositionFixed = () =>\n window.requestAnimationFrame(() => {\n const $html = document.documentElement;\n const $body = document.body;\n // If bodyStyle is already set, don't set it again.\n if (bodyStyle === undefined) {\n htmlStyle = { ...$html.style };\n bodyStyle = { ...$body.style };\n\n // Update the dom inside an animation frame\n const { scrollY, scrollX, innerHeight } = window;\n\n $html.style.height = '100%';\n $html.style.overflow = 'hidden';\n\n $body.style.position = 'fixed';\n $body.style.top = `${-scrollY}px`;\n $body.style.left = `${-scrollX}px`;\n $body.style.width = '100%';\n $body.style.height = 'auto';\n $body.style.overflow = 'hidden';\n\n setTimeout(\n () =>\n window.requestAnimationFrame(() => {\n // Attempt to check if the bottom bar appeared due to the position change\n const bottomBarHeight = innerHeight - window.innerHeight;\n if (bottomBarHeight && scrollY >= innerHeight) {\n // Move the content further up so that the bottom bar doesn't hide it\n $body.style.top = -(scrollY + bottomBarHeight) + 'px';\n }\n }),\n 300\n );\n }\n });\n\nconst restorePositionSetting = () => {\n if (bodyStyle !== undefined) {\n // Convert the position from \"px\" to Int\n const y = -parseInt(document.body.style.top, 10);\n const x = -parseInt(document.body.style.left, 10);\n\n // Restore styles\n const $html = document.documentElement;\n const $body = document.body;\n\n $html.style.height = htmlStyle?.height || '';\n $html.style.overflow = htmlStyle?.overflow || '';\n\n $body.style.position = bodyStyle.position || '';\n $body.style.top = bodyStyle.top || '';\n $body.style.left = bodyStyle.left || '';\n $body.style.width = bodyStyle.width || '';\n $body.style.height = bodyStyle.height || '';\n $body.style.overflow = bodyStyle.overflow || '';\n\n // Restore scroll\n window.scrollTo(x, y);\n\n bodyStyle = undefined;\n }\n};\n\n// https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollHeight#Problems_and_solutions\nconst isTargetElementTotallyScrolled = (targetElement: HTMLElement): boolean =>\n targetElement\n ? targetElement.scrollHeight - targetElement.scrollTop <=\n targetElement.clientHeight\n : false;\n\nconst handleScroll = (\n event: HandleScrollEvent,\n targetElement: HTMLElement\n): boolean => {\n const clientY = event.targetTouches[0].clientY - initialClientY;\n\n if (allowTouchMove(event.target as EventTarget)) {\n return false;\n }\n\n if (targetElement && targetElement.scrollTop === 0 && clientY > 0) {\n // element is at the top of its scroll.\n return preventDefault(event);\n }\n\n if (isTargetElementTotallyScrolled(targetElement) && clientY < 0) {\n // element is at the bottom of its scroll.\n return preventDefault(event);\n }\n\n event.stopPropagation();\n return true;\n};\n\n/**\n *\n * @param targetElement HTMLElement\n * @param options BodyScrollOptions\n * @returns void\n */\nexport const disableBodyScroll = (\n targetElement: HTMLElement,\n options?: BodyScrollOptions\n): void => {\n // targetElement must be provided\n if (!targetElement) {\n // eslint-disable-next-line no-console\n console.error(\n 'disableBodyScroll unsuccessful - targetElement must be provided when calling disableBodyScroll on IOS devices.'\n );\n return;\n }\n\n locksIndex.set(\n targetElement,\n locksIndex?.get(targetElement)\n ? (locksIndex?.get(targetElement) as number) + 1\n : 1\n );\n // disableBodyScroll must not have been called on this targetElement before\n if (locks.some((lock) => lock.targetElement === targetElement)) {\n return;\n }\n\n const lock = {\n targetElement,\n options: options || {},\n };\n locks = [...locks, lock];\n\n if (isIosDevice) {\n setPositionFixed();\n } else {\n setOverflowHidden(options);\n }\n\n if (isIosDevice) {\n targetElement.ontouchstart = (event: HandleScrollEvent) => {\n if (event.targetTouches.length === 1) {\n // detect single touch.\n initialClientY = event.targetTouches[0].clientY;\n }\n };\n targetElement.ontouchmove = (event: HandleScrollEvent) => {\n if (event.targetTouches.length === 1) {\n // detect single touch.\n handleScroll(event, targetElement);\n }\n };\n\n if (!documentListenerAdded) {\n document.addEventListener(\n 'touchmove',\n preventDefault,\n hasPassiveEvents ? { passive: false } : undefined\n );\n documentListenerAdded = true;\n }\n }\n};\n\nexport const clearAllBodyScrollLocks = (): void => {\n if (isIosDevice) {\n // Clear all locks ontouchstart/ontouchmove handlers, and the references.\n locks.forEach((lock: Lock) => {\n lock.targetElement.ontouchstart = null;\n lock.targetElement.ontouchmove = null;\n });\n\n if (documentListenerAdded) {\n (document as any).removeEventListener(\n 'touchmove',\n preventDefault,\n hasPassiveEvents ? { passive: false } : undefined\n );\n documentListenerAdded = false;\n }\n\n // Reset initial clientY.\n initialClientY = -1;\n }\n\n if (isIosDevice) {\n restorePositionSetting();\n } else {\n restoreOverflowSetting();\n }\n\n locks = [];\n locksIndex.clear();\n};\n\n/**\n * @param targetElement\n * @returns void\n */\nexport const enableBodyScroll = (targetElement: HTMLElement): void => {\n if (!targetElement) {\n // eslint-disable-next-line no-console\n console.error(\n 'enableBodyScroll unsuccessful - targetElement must be provided when calling enableBodyScroll on IOS devices.'\n );\n return;\n }\n\n locksIndex.set(\n targetElement,\n locksIndex?.get(targetElement)\n ? (locksIndex?.get(targetElement) as number) - 1\n : 0\n );\n if (locksIndex?.get(targetElement) === 0) {\n locks = locks.filter((lock) => lock.targetElement !== targetElement);\n locksIndex?.delete(targetElement);\n }\n\n if (isIosDevice) {\n targetElement.ontouchstart = null;\n targetElement.ontouchmove = null;\n\n if (documentListenerAdded && locks.length === 0) {\n (document as any).removeEventListener(\n 'touchmove',\n preventDefault,\n hasPassiveEvents ? { passive: false } : undefined\n );\n documentListenerAdded = false;\n }\n }\n\n if (locks.length === 0) {\n if (isIosDevice) {\n restorePositionSetting();\n } else {\n restoreOverflowSetting();\n }\n }\n};\n"],"names":["lock"],"mappings":";;AAoBA,IAAI,mBAAmB;AACvB,IAAI,OAAO,WAAW,aAAa;AACjC,QAAM,qBAA0B;AAAA,IAC9B,IAAI,UAAU;AACO,yBAAA;AACZ,aAAA;AAAA,IACT;AAAA,EAAA;AAED,SAAe,iBAAiB,eAAe,MAAM,kBAAkB;AACvE,SAAe,oBAAoB,eAAe,MAAM,kBAAkB;AAC7E;AAEA,MAAM,cACJ,OAAO,WAAW,eAClB,OAAO,aACP,OAAO,UAAU,aAChB,iBAAiB,KAAK,OAAO,UAAU,QAAQ,KAC7C,OAAO,UAAU,aAAa,cAC7B,OAAO,UAAU,iBAAiB;AAGxC,IAAI,QAAqB,CAAA;AACzB,IAAI,iCAAmC;AACvC,IAAI,wBAAiC;AACrC,IAAI,iBAAyB;AAC7B,IAAI;AACJ,IAAI;AAMJ,IAAI;AAEJ,IAAI;AAGJ,MAAM,iBAAiB,CAAC,OACtB,MAAM,KAAK,CAAC,SAAS;AACnB,MAAI,KAAK,QAAQ,kBAAkB,KAAK,QAAQ,eAAe,EAAE,GAAG;AAC3D,WAAA;AAAA,EACT;AAEO,SAAA;AACT,CAAC;AAEH,MAAM,iBAAiB,CAAC,aAAyC;AACzD,QAAA,IAAS,YAAY,OAAO;AAM9B,MAAA,eAAe,EAAE,MAAM,GAAG;AACrB,WAAA;AAAA,EACT;AAGI,MAAA,EAAE,QAAQ,SAAS;AAAU,WAAA;AAEjC,MAAI,EAAE;AAAgB,MAAE,eAAe;AAEhC,SAAA;AACT;AAEA,MAAM,oBAAoB,CAAC,YAAgC;AAEzD,MAAI,6BAA6B,QAAW;AAC1C,UAAM,sBACJ,CAAC,CAAC,WAAW,QAAQ,wBAAwB;AAC/C,UAAM,eACJ,OAAO,aACP,SAAS,gBAAgB,sBAAwB,EAAA;AAE/C,QAAA,uBAAuB,eAAe,GAAG;AAC3C,YAAM,2BAA2B;AAAA,QAC/B,OACG,iBAAiB,SAAS,IAAI,EAC9B,iBAAiB,eAAe;AAAA,QACnC;AAAA,MAAA;AAEyB,iCAAA,SAAS,KAAK,MAAM;AAC/C,eAAS,KAAK,MAAM,eAAe,GACjC,2BAA2B;AAAA,IAE/B;AAAA,EACF;AAGA,MAAI,gCAAgC,QAAW;AACf,kCAAA,SAAS,KAAK,MAAM;AACzC,aAAA,KAAK,MAAM,WAAW;AAAA,EACjC;AACF;AAEA,MAAM,yBAAyB,MAAM;AACnC,MAAI,6BAA6B,QAAW;AACjC,aAAA,KAAK,MAAM,eAAe;AAIR,+BAAA;AAAA,EAC7B;AAEA,MAAI,gCAAgC,QAAW;AACpC,aAAA,KAAK,MAAM,WAAW;AAID,kCAAA;AAAA,EAChC;AACF;AAEA,MAAM,mBAAmB,MACvB,OAAO,sBAAsB,MAAM;AACjC,QAAM,QAAQ,SAAS;AACvB,QAAM,QAAQ,SAAS;AAEvB,MAAI,cAAc,QAAW;AACf,gBAAA,EAAE,GAAG,MAAM;AACX,gBAAA,EAAE,GAAG,MAAM;AAGvB,UAAM,EAAE,SAAS,SAAS,YAAA,IAAgB;AAE1C,UAAM,MAAM,SAAS;AACrB,UAAM,MAAM,WAAW;AAEvB,UAAM,MAAM,WAAW;AACjB,UAAA,MAAM,MAAM,GAAG,CAAC;AAChB,UAAA,MAAM,OAAO,GAAG,CAAC;AACvB,UAAM,MAAM,QAAQ;AACpB,UAAM,MAAM,SAAS;AACrB,UAAM,MAAM,WAAW;AAEvB;AAAA,MACE,MACE,OAAO,sBAAsB,MAAM;AAE3B,cAAA,kBAAkB,cAAc,OAAO;AACzC,YAAA,mBAAmB,WAAW,aAAa;AAE7C,gBAAM,MAAM,MAAM,EAAE,UAAU,mBAAmB;AAAA,QACnD;AAAA,MAAA,CACD;AAAA,MACH;AAAA,IAAA;AAAA,EAEJ;AACF,CAAC;AAEH,MAAM,yBAAyB,MAAM;AACnC,MAAI,cAAc,QAAW;AAE3B,UAAM,IAAI,CAAC,SAAS,SAAS,KAAK,MAAM,KAAK,EAAE;AAC/C,UAAM,IAAI,CAAC,SAAS,SAAS,KAAK,MAAM,MAAM,EAAE;AAGhD,UAAM,QAAQ,SAAS;AACvB,UAAM,QAAQ,SAAS;AAEjB,UAAA,MAAM,UAAS,uCAAW,WAAU;AACpC,UAAA,MAAM,YAAW,uCAAW,aAAY;AAExC,UAAA,MAAM,WAAW,UAAU,YAAY;AACvC,UAAA,MAAM,MAAM,UAAU,OAAO;AAC7B,UAAA,MAAM,OAAO,UAAU,QAAQ;AAC/B,UAAA,MAAM,QAAQ,UAAU,SAAS;AACjC,UAAA,MAAM,SAAS,UAAU,UAAU;AACnC,UAAA,MAAM,WAAW,UAAU,YAAY;AAGtC,WAAA,SAAS,GAAG,CAAC;AAER,gBAAA;AAAA,EACd;AACF;AAGA,MAAM,iCAAiC,CAAC,kBACtC,gBACI,cAAc,eAAe,cAAc,aAC3C,cAAc,eACd;AAEN,MAAM,eAAe,CACnB,OACA,kBACY;AACZ,QAAM,UAAU,MAAM,cAAc,CAAC,EAAE,UAAU;AAE7C,MAAA,eAAe,MAAM,MAAqB,GAAG;AACxC,WAAA;AAAA,EACT;AAEA,MAAI,iBAAiB,cAAc,cAAc,KAAK,UAAU,GAAG;AAEjE,WAAO,eAAe,KAAK;AAAA,EAC7B;AAEA,MAAI,+BAA+B,aAAa,KAAK,UAAU,GAAG;AAEhE,WAAO,eAAe,KAAK;AAAA,EAC7B;AAEA,QAAM,gBAAgB;AACf,SAAA;AACT;AAQa,MAAA,oBAAoB,CAC/B,eACA,YACS;AAET,MAAI,CAAC,eAAe;AAEV,YAAA;AAAA,MACN;AAAA,IAAA;AAEF;AAAA,EACF;AAEW,aAAA;AAAA,IACT;AAAA,KACA,yCAAY,IAAI,mBACX,yCAAY,IAAI,kBAA4B,IAC7C;AAAA,EAAA;AAGN,MAAI,MAAM,KAAK,CAACA,UAASA,MAAK,kBAAkB,aAAa,GAAG;AAC9D;AAAA,EACF;AAEA,QAAM,OAAO;AAAA,IACX;AAAA,IACA,SAAS,WAAW,CAAC;AAAA,EAAA;AAEf,UAAA,CAAC,GAAG,OAAO,IAAI;AAEvB,MAAI,aAAa;AACE;EAAA,OACZ;AACL,sBAAkB,OAAO;AAAA,EAC3B;AAEA,MAAI,aAAa;AACD,kBAAA,eAAe,CAAC,UAA6B;AACrD,UAAA,MAAM,cAAc,WAAW,GAAG;AAEnB,yBAAA,MAAM,cAAc,CAAC,EAAE;AAAA,MAC1C;AAAA,IAAA;AAEY,kBAAA,cAAc,CAAC,UAA6B;AACpD,UAAA,MAAM,cAAc,WAAW,GAAG;AAEpC,qBAAa,OAAO,aAAa;AAAA,MACnC;AAAA,IAAA;AAGF,QAAI,CAAC,uBAAuB;AACjB,eAAA;AAAA,QACP;AAAA,QACA;AAAA,QACA,mBAAmB,EAAE,SAAS,MAAA,IAAU;AAAA,MAAA;AAElB,8BAAA;AAAA,IAC1B;AAAA,EACF;AACF;AAEO,MAAM,0BAA0B,MAAY;AACjD,MAAI,aAAa;AAET,UAAA,QAAQ,CAAC,SAAe;AAC5B,WAAK,cAAc,eAAe;AAClC,WAAK,cAAc,cAAc;AAAA,IAAA,CAClC;AAED,QAAI,uBAAuB;AACxB,eAAiB;AAAA,QAChB;AAAA,QACA;AAAA,QACA,mBAAmB,EAAE,SAAS,MAAA,IAAU;AAAA,MAAA;AAElB,8BAAA;AAAA,IAC1B;AAGiB,qBAAA;AAAA,EACnB;AAEA,MAAI,aAAa;AACQ;EAAA,OAClB;AACkB;EACzB;AAEA,UAAQ,CAAA;AACR,aAAW,MAAM;AACnB;AAMa,MAAA,mBAAmB,CAAC,kBAAqC;AACpE,MAAI,CAAC,eAAe;AAEV,YAAA;AAAA,MACN;AAAA,IAAA;AAEF;AAAA,EACF;AAEW,aAAA;AAAA,IACT;AAAA,KACA,yCAAY,IAAI,mBACX,yCAAY,IAAI,kBAA4B,IAC7C;AAAA,EAAA;AAEN,OAAI,yCAAY,IAAI,oBAAmB,GAAG;AACxC,YAAQ,MAAM,OAAO,CAAC,SAAS,KAAK,kBAAkB,aAAa;AACnE,6CAAY,OAAO;AAAA,EACrB;AAEA,MAAI,aAAa;AACf,kBAAc,eAAe;AAC7B,kBAAc,cAAc;AAExB,QAAA,yBAAyB,MAAM,WAAW,GAAG;AAC9C,eAAiB;AAAA,QAChB;AAAA,QACA;AAAA,QACA,mBAAmB,EAAE,SAAS,MAAA,IAAU;AAAA,MAAA;AAElB,8BAAA;AAAA,IAC1B;AAAA,EACF;AAEI,MAAA,MAAM,WAAW,GAAG;AACtB,QAAI,aAAa;AACQ;IAAA,OAClB;AACkB;IACzB;AAAA,EACF;AACF;;;;"}
--------------------------------------------------------------------------------
/lib/index.esm.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"index.esm.js","sources":["../src/body-scroll-lock.ts"],"sourcesContent":["export type BodyScrollOptions = {\n reserveScrollBarGap?: boolean | undefined;\n allowTouchMove?: ((el: EventTarget) => boolean) | undefined;\n};\n\ntype BodyStyleType = {\n position: string;\n top: string;\n left: string;\n width: string;\n height: string;\n overflow: string;\n};\n\ninterface Lock {\n targetElement: HTMLElement;\n options: BodyScrollOptions;\n}\n\n// Older browsers don't support event options, feature detect it.\nlet hasPassiveEvents = false;\nif (typeof window !== 'undefined') {\n const passiveTestOptions: any = {\n get passive() {\n hasPassiveEvents = true;\n return undefined;\n },\n };\n (window as any).addEventListener('testPassive', null, passiveTestOptions);\n (window as any).removeEventListener('testPassive', null, passiveTestOptions);\n}\n\nconst isIosDevice =\n typeof window !== 'undefined' &&\n window.navigator &&\n window.navigator.platform &&\n (/iP(ad|hone|od)/.test(window.navigator.platform) ||\n (window.navigator.platform === 'MacIntel' &&\n window.navigator.maxTouchPoints > 1));\ntype HandleScrollEvent = TouchEvent;\n\nlet locks: Array = [];\nlet locksIndex: Map = new Map();\nlet documentListenerAdded: boolean = false;\nlet initialClientY: number = -1;\nlet previousBodyOverflowSetting: string | undefined;\nlet htmlStyle:\n | {\n height: string;\n overflow: string;\n }\n | undefined;\nlet bodyStyle: BodyStyleType | undefined;\n\nlet previousBodyPaddingRight: string | undefined;\n\n// returns true if `el` should be allowed to receive touchmove events.\nconst allowTouchMove = (el: EventTarget): boolean =>\n locks.some((lock) => {\n if (lock.options.allowTouchMove && lock.options.allowTouchMove(el)) {\n return true;\n }\n\n return false;\n });\n\nconst preventDefault = (rawEvent: HandleScrollEvent): boolean => {\n const e: any = rawEvent || window.event;\n\n // For the case whereby consumers adds a touchmove event listener to document.\n // Recall that we do document.addEventListener('touchmove', preventDefault, { passive: false })\n // in disableBodyScroll - so if we provide this opportunity to allowTouchMove, then\n // the touchmove event on document will break.\n if (allowTouchMove(e.target)) {\n return true;\n }\n\n // Do not prevent if the event has more than one touch (usually meaning this is a multi touch gesture like pinch to zoom).\n if (e.touches.length > 1) return true;\n\n if (e.preventDefault) e.preventDefault();\n\n return false;\n};\n\nconst setOverflowHidden = (options?: BodyScrollOptions) => {\n // If previousBodyPaddingRight is already set, don't set it again.\n if (previousBodyPaddingRight === undefined) {\n const reserveScrollBarGap =\n !!options && options.reserveScrollBarGap === true;\n const scrollBarGap =\n window.innerWidth -\n document.documentElement.getBoundingClientRect().width;\n\n if (reserveScrollBarGap && scrollBarGap > 0) {\n const computedBodyPaddingRight = parseInt(\n window\n .getComputedStyle(document.body)\n .getPropertyValue('padding-right'),\n 10\n );\n previousBodyPaddingRight = document.body.style.paddingRight;\n document.body.style.paddingRight = `${\n computedBodyPaddingRight + scrollBarGap\n }px`;\n }\n }\n\n // If previousBodyOverflowSetting is already set, don't set it again.\n if (previousBodyOverflowSetting === undefined) {\n previousBodyOverflowSetting = document.body.style.overflow;\n document.body.style.overflow = 'hidden';\n }\n};\n\nconst restoreOverflowSetting = () => {\n if (previousBodyPaddingRight !== undefined) {\n document.body.style.paddingRight = previousBodyPaddingRight;\n\n // Restore previousBodyPaddingRight to undefined so setOverflowHidden knows it\n // can be set again.\n previousBodyPaddingRight = undefined;\n }\n\n if (previousBodyOverflowSetting !== undefined) {\n document.body.style.overflow = previousBodyOverflowSetting;\n\n // Restore previousBodyOverflowSetting to undefined\n // so setOverflowHidden knows it can be set again.\n previousBodyOverflowSetting = undefined;\n }\n};\n\nconst setPositionFixed = () =>\n window.requestAnimationFrame(() => {\n const $html = document.documentElement;\n const $body = document.body;\n // If bodyStyle is already set, don't set it again.\n if (bodyStyle === undefined) {\n htmlStyle = { ...$html.style };\n bodyStyle = { ...$body.style };\n\n // Update the dom inside an animation frame\n const { scrollY, scrollX, innerHeight } = window;\n\n $html.style.height = '100%';\n $html.style.overflow = 'hidden';\n\n $body.style.position = 'fixed';\n $body.style.top = `${-scrollY}px`;\n $body.style.left = `${-scrollX}px`;\n $body.style.width = '100%';\n $body.style.height = 'auto';\n $body.style.overflow = 'hidden';\n\n setTimeout(\n () =>\n window.requestAnimationFrame(() => {\n // Attempt to check if the bottom bar appeared due to the position change\n const bottomBarHeight = innerHeight - window.innerHeight;\n if (bottomBarHeight && scrollY >= innerHeight) {\n // Move the content further up so that the bottom bar doesn't hide it\n $body.style.top = -(scrollY + bottomBarHeight) + 'px';\n }\n }),\n 300\n );\n }\n });\n\nconst restorePositionSetting = () => {\n if (bodyStyle !== undefined) {\n // Convert the position from \"px\" to Int\n const y = -parseInt(document.body.style.top, 10);\n const x = -parseInt(document.body.style.left, 10);\n\n // Restore styles\n const $html = document.documentElement;\n const $body = document.body;\n\n $html.style.height = htmlStyle?.height || '';\n $html.style.overflow = htmlStyle?.overflow || '';\n\n $body.style.position = bodyStyle.position || '';\n $body.style.top = bodyStyle.top || '';\n $body.style.left = bodyStyle.left || '';\n $body.style.width = bodyStyle.width || '';\n $body.style.height = bodyStyle.height || '';\n $body.style.overflow = bodyStyle.overflow || '';\n\n // Restore scroll\n window.scrollTo(x, y);\n\n bodyStyle = undefined;\n }\n};\n\n// https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollHeight#Problems_and_solutions\nconst isTargetElementTotallyScrolled = (targetElement: HTMLElement): boolean =>\n targetElement\n ? targetElement.scrollHeight - targetElement.scrollTop <=\n targetElement.clientHeight\n : false;\n\nconst handleScroll = (\n event: HandleScrollEvent,\n targetElement: HTMLElement\n): boolean => {\n const clientY = event.targetTouches[0].clientY - initialClientY;\n\n if (allowTouchMove(event.target as EventTarget)) {\n return false;\n }\n\n if (targetElement && targetElement.scrollTop === 0 && clientY > 0) {\n // element is at the top of its scroll.\n return preventDefault(event);\n }\n\n if (isTargetElementTotallyScrolled(targetElement) && clientY < 0) {\n // element is at the bottom of its scroll.\n return preventDefault(event);\n }\n\n event.stopPropagation();\n return true;\n};\n\n/**\n *\n * @param targetElement HTMLElement\n * @param options BodyScrollOptions\n * @returns void\n */\nexport const disableBodyScroll = (\n targetElement: HTMLElement,\n options?: BodyScrollOptions\n): void => {\n // targetElement must be provided\n if (!targetElement) {\n // eslint-disable-next-line no-console\n console.error(\n 'disableBodyScroll unsuccessful - targetElement must be provided when calling disableBodyScroll on IOS devices.'\n );\n return;\n }\n\n locksIndex.set(\n targetElement,\n locksIndex?.get(targetElement)\n ? (locksIndex?.get(targetElement) as number) + 1\n : 1\n );\n // disableBodyScroll must not have been called on this targetElement before\n if (locks.some((lock) => lock.targetElement === targetElement)) {\n return;\n }\n\n const lock = {\n targetElement,\n options: options || {},\n };\n locks = [...locks, lock];\n\n if (isIosDevice) {\n setPositionFixed();\n } else {\n setOverflowHidden(options);\n }\n\n if (isIosDevice) {\n targetElement.ontouchstart = (event: HandleScrollEvent) => {\n if (event.targetTouches.length === 1) {\n // detect single touch.\n initialClientY = event.targetTouches[0].clientY;\n }\n };\n targetElement.ontouchmove = (event: HandleScrollEvent) => {\n if (event.targetTouches.length === 1) {\n // detect single touch.\n handleScroll(event, targetElement);\n }\n };\n\n if (!documentListenerAdded) {\n document.addEventListener(\n 'touchmove',\n preventDefault,\n hasPassiveEvents ? { passive: false } : undefined\n );\n documentListenerAdded = true;\n }\n }\n};\n\nexport const clearAllBodyScrollLocks = (): void => {\n if (isIosDevice) {\n // Clear all locks ontouchstart/ontouchmove handlers, and the references.\n locks.forEach((lock: Lock) => {\n lock.targetElement.ontouchstart = null;\n lock.targetElement.ontouchmove = null;\n });\n\n if (documentListenerAdded) {\n (document as any).removeEventListener(\n 'touchmove',\n preventDefault,\n hasPassiveEvents ? { passive: false } : undefined\n );\n documentListenerAdded = false;\n }\n\n // Reset initial clientY.\n initialClientY = -1;\n }\n\n if (isIosDevice) {\n restorePositionSetting();\n } else {\n restoreOverflowSetting();\n }\n\n locks = [];\n locksIndex.clear();\n};\n\n/**\n * @param targetElement\n * @returns void\n */\nexport const enableBodyScroll = (targetElement: HTMLElement): void => {\n if (!targetElement) {\n // eslint-disable-next-line no-console\n console.error(\n 'enableBodyScroll unsuccessful - targetElement must be provided when calling enableBodyScroll on IOS devices.'\n );\n return;\n }\n\n locksIndex.set(\n targetElement,\n locksIndex?.get(targetElement)\n ? (locksIndex?.get(targetElement) as number) - 1\n : 0\n );\n if (locksIndex?.get(targetElement) === 0) {\n locks = locks.filter((lock) => lock.targetElement !== targetElement);\n locksIndex?.delete(targetElement);\n }\n\n if (isIosDevice) {\n targetElement.ontouchstart = null;\n targetElement.ontouchmove = null;\n\n if (documentListenerAdded && locks.length === 0) {\n (document as any).removeEventListener(\n 'touchmove',\n preventDefault,\n hasPassiveEvents ? { passive: false } : undefined\n );\n documentListenerAdded = false;\n }\n }\n\n if (locks.length === 0) {\n if (isIosDevice) {\n restorePositionSetting();\n } else {\n restoreOverflowSetting();\n }\n }\n};\n"],"names":["lock"],"mappings":"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"}
--------------------------------------------------------------------------------
/lib/index.umd.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"index.umd.js","sources":["../src/body-scroll-lock.ts"],"sourcesContent":["export type BodyScrollOptions = {\n reserveScrollBarGap?: boolean | undefined;\n allowTouchMove?: ((el: EventTarget) => boolean) | undefined;\n};\n\ntype BodyStyleType = {\n position: string;\n top: string;\n left: string;\n width: string;\n height: string;\n overflow: string;\n};\n\ninterface Lock {\n targetElement: HTMLElement;\n options: BodyScrollOptions;\n}\n\n// Older browsers don't support event options, feature detect it.\nlet hasPassiveEvents = false;\nif (typeof window !== 'undefined') {\n const passiveTestOptions: any = {\n get passive() {\n hasPassiveEvents = true;\n return undefined;\n },\n };\n (window as any).addEventListener('testPassive', null, passiveTestOptions);\n (window as any).removeEventListener('testPassive', null, passiveTestOptions);\n}\n\nconst isIosDevice =\n typeof window !== 'undefined' &&\n window.navigator &&\n window.navigator.platform &&\n (/iP(ad|hone|od)/.test(window.navigator.platform) ||\n (window.navigator.platform === 'MacIntel' &&\n window.navigator.maxTouchPoints > 1));\ntype HandleScrollEvent = TouchEvent;\n\nlet locks: Array = [];\nlet locksIndex: Map = new Map();\nlet documentListenerAdded: boolean = false;\nlet initialClientY: number = -1;\nlet previousBodyOverflowSetting: string | undefined;\nlet htmlStyle:\n | {\n height: string;\n overflow: string;\n }\n | undefined;\nlet bodyStyle: BodyStyleType | undefined;\n\nlet previousBodyPaddingRight: string | undefined;\n\n// returns true if `el` should be allowed to receive touchmove events.\nconst allowTouchMove = (el: EventTarget): boolean =>\n locks.some((lock) => {\n if (lock.options.allowTouchMove && lock.options.allowTouchMove(el)) {\n return true;\n }\n\n return false;\n });\n\nconst preventDefault = (rawEvent: HandleScrollEvent): boolean => {\n const e: any = rawEvent || window.event;\n\n // For the case whereby consumers adds a touchmove event listener to document.\n // Recall that we do document.addEventListener('touchmove', preventDefault, { passive: false })\n // in disableBodyScroll - so if we provide this opportunity to allowTouchMove, then\n // the touchmove event on document will break.\n if (allowTouchMove(e.target)) {\n return true;\n }\n\n // Do not prevent if the event has more than one touch (usually meaning this is a multi touch gesture like pinch to zoom).\n if (e.touches.length > 1) return true;\n\n if (e.preventDefault) e.preventDefault();\n\n return false;\n};\n\nconst setOverflowHidden = (options?: BodyScrollOptions) => {\n // If previousBodyPaddingRight is already set, don't set it again.\n if (previousBodyPaddingRight === undefined) {\n const reserveScrollBarGap =\n !!options && options.reserveScrollBarGap === true;\n const scrollBarGap =\n window.innerWidth -\n document.documentElement.getBoundingClientRect().width;\n\n if (reserveScrollBarGap && scrollBarGap > 0) {\n const computedBodyPaddingRight = parseInt(\n window\n .getComputedStyle(document.body)\n .getPropertyValue('padding-right'),\n 10\n );\n previousBodyPaddingRight = document.body.style.paddingRight;\n document.body.style.paddingRight = `${\n computedBodyPaddingRight + scrollBarGap\n }px`;\n }\n }\n\n // If previousBodyOverflowSetting is already set, don't set it again.\n if (previousBodyOverflowSetting === undefined) {\n previousBodyOverflowSetting = document.body.style.overflow;\n document.body.style.overflow = 'hidden';\n }\n};\n\nconst restoreOverflowSetting = () => {\n if (previousBodyPaddingRight !== undefined) {\n document.body.style.paddingRight = previousBodyPaddingRight;\n\n // Restore previousBodyPaddingRight to undefined so setOverflowHidden knows it\n // can be set again.\n previousBodyPaddingRight = undefined;\n }\n\n if (previousBodyOverflowSetting !== undefined) {\n document.body.style.overflow = previousBodyOverflowSetting;\n\n // Restore previousBodyOverflowSetting to undefined\n // so setOverflowHidden knows it can be set again.\n previousBodyOverflowSetting = undefined;\n }\n};\n\nconst setPositionFixed = () =>\n window.requestAnimationFrame(() => {\n const $html = document.documentElement;\n const $body = document.body;\n // If bodyStyle is already set, don't set it again.\n if (bodyStyle === undefined) {\n htmlStyle = { ...$html.style };\n bodyStyle = { ...$body.style };\n\n // Update the dom inside an animation frame\n const { scrollY, scrollX, innerHeight } = window;\n\n $html.style.height = '100%';\n $html.style.overflow = 'hidden';\n\n $body.style.position = 'fixed';\n $body.style.top = `${-scrollY}px`;\n $body.style.left = `${-scrollX}px`;\n $body.style.width = '100%';\n $body.style.height = 'auto';\n $body.style.overflow = 'hidden';\n\n setTimeout(\n () =>\n window.requestAnimationFrame(() => {\n // Attempt to check if the bottom bar appeared due to the position change\n const bottomBarHeight = innerHeight - window.innerHeight;\n if (bottomBarHeight && scrollY >= innerHeight) {\n // Move the content further up so that the bottom bar doesn't hide it\n $body.style.top = -(scrollY + bottomBarHeight) + 'px';\n }\n }),\n 300\n );\n }\n });\n\nconst restorePositionSetting = () => {\n if (bodyStyle !== undefined) {\n // Convert the position from \"px\" to Int\n const y = -parseInt(document.body.style.top, 10);\n const x = -parseInt(document.body.style.left, 10);\n\n // Restore styles\n const $html = document.documentElement;\n const $body = document.body;\n\n $html.style.height = htmlStyle?.height || '';\n $html.style.overflow = htmlStyle?.overflow || '';\n\n $body.style.position = bodyStyle.position || '';\n $body.style.top = bodyStyle.top || '';\n $body.style.left = bodyStyle.left || '';\n $body.style.width = bodyStyle.width || '';\n $body.style.height = bodyStyle.height || '';\n $body.style.overflow = bodyStyle.overflow || '';\n\n // Restore scroll\n window.scrollTo(x, y);\n\n bodyStyle = undefined;\n }\n};\n\n// https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollHeight#Problems_and_solutions\nconst isTargetElementTotallyScrolled = (targetElement: HTMLElement): boolean =>\n targetElement\n ? targetElement.scrollHeight - targetElement.scrollTop <=\n targetElement.clientHeight\n : false;\n\nconst handleScroll = (\n event: HandleScrollEvent,\n targetElement: HTMLElement\n): boolean => {\n const clientY = event.targetTouches[0].clientY - initialClientY;\n\n if (allowTouchMove(event.target as EventTarget)) {\n return false;\n }\n\n if (targetElement && targetElement.scrollTop === 0 && clientY > 0) {\n // element is at the top of its scroll.\n return preventDefault(event);\n }\n\n if (isTargetElementTotallyScrolled(targetElement) && clientY < 0) {\n // element is at the bottom of its scroll.\n return preventDefault(event);\n }\n\n event.stopPropagation();\n return true;\n};\n\n/**\n *\n * @param targetElement HTMLElement\n * @param options BodyScrollOptions\n * @returns void\n */\nexport const disableBodyScroll = (\n targetElement: HTMLElement,\n options?: BodyScrollOptions\n): void => {\n // targetElement must be provided\n if (!targetElement) {\n // eslint-disable-next-line no-console\n console.error(\n 'disableBodyScroll unsuccessful - targetElement must be provided when calling disableBodyScroll on IOS devices.'\n );\n return;\n }\n\n locksIndex.set(\n targetElement,\n locksIndex?.get(targetElement)\n ? (locksIndex?.get(targetElement) as number) + 1\n : 1\n );\n // disableBodyScroll must not have been called on this targetElement before\n if (locks.some((lock) => lock.targetElement === targetElement)) {\n return;\n }\n\n const lock = {\n targetElement,\n options: options || {},\n };\n locks = [...locks, lock];\n\n if (isIosDevice) {\n setPositionFixed();\n } else {\n setOverflowHidden(options);\n }\n\n if (isIosDevice) {\n targetElement.ontouchstart = (event: HandleScrollEvent) => {\n if (event.targetTouches.length === 1) {\n // detect single touch.\n initialClientY = event.targetTouches[0].clientY;\n }\n };\n targetElement.ontouchmove = (event: HandleScrollEvent) => {\n if (event.targetTouches.length === 1) {\n // detect single touch.\n handleScroll(event, targetElement);\n }\n };\n\n if (!documentListenerAdded) {\n document.addEventListener(\n 'touchmove',\n preventDefault,\n hasPassiveEvents ? { passive: false } : undefined\n );\n documentListenerAdded = true;\n }\n }\n};\n\nexport const clearAllBodyScrollLocks = (): void => {\n if (isIosDevice) {\n // Clear all locks ontouchstart/ontouchmove handlers, and the references.\n locks.forEach((lock: Lock) => {\n lock.targetElement.ontouchstart = null;\n lock.targetElement.ontouchmove = null;\n });\n\n if (documentListenerAdded) {\n (document as any).removeEventListener(\n 'touchmove',\n preventDefault,\n hasPassiveEvents ? { passive: false } : undefined\n );\n documentListenerAdded = false;\n }\n\n // Reset initial clientY.\n initialClientY = -1;\n }\n\n if (isIosDevice) {\n restorePositionSetting();\n } else {\n restoreOverflowSetting();\n }\n\n locks = [];\n locksIndex.clear();\n};\n\n/**\n * @param targetElement\n * @returns void\n */\nexport const enableBodyScroll = (targetElement: HTMLElement): void => {\n if (!targetElement) {\n // eslint-disable-next-line no-console\n console.error(\n 'enableBodyScroll unsuccessful - targetElement must be provided when calling enableBodyScroll on IOS devices.'\n );\n return;\n }\n\n locksIndex.set(\n targetElement,\n locksIndex?.get(targetElement)\n ? (locksIndex?.get(targetElement) as number) - 1\n : 0\n );\n if (locksIndex?.get(targetElement) === 0) {\n locks = locks.filter((lock) => lock.targetElement !== targetElement);\n locksIndex?.delete(targetElement);\n }\n\n if (isIosDevice) {\n targetElement.ontouchstart = null;\n targetElement.ontouchmove = null;\n\n if (documentListenerAdded && locks.length === 0) {\n (document as any).removeEventListener(\n 'touchmove',\n preventDefault,\n hasPassiveEvents ? { passive: false } : undefined\n );\n documentListenerAdded = false;\n }\n }\n\n if (locks.length === 0) {\n if (isIosDevice) {\n restorePositionSetting();\n } else {\n restoreOverflowSetting();\n }\n }\n};\n"],"names":["lock"],"mappings":"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"}
--------------------------------------------------------------------------------