@schukai/monster 4.141.3 → 4.142.1

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.
@@ -0,0 +1,228 @@
1
+ /**
2
+ * Copyright © Volker Schukai and all contributing authors, {{copyRightYear}}. All rights reserved.
3
+ * Node module: @schukai/monster
4
+ *
5
+ * SPDX-License-Identifier: AGPL-3.0
6
+ */
7
+
8
+ import { getGlobal } from "../../../types/global.mjs";
9
+
10
+ export {
11
+ FLOATING_LAYOUT_REASON,
12
+ cancelFloatingLayout,
13
+ enqueueFloatingLayout,
14
+ flushFloatingLayoutQueueForTests,
15
+ };
16
+
17
+ const FLOATING_LAYOUT_REASON = Object.freeze({
18
+ OPEN: 1 << 0,
19
+ RESIZE: 1 << 1,
20
+ CONTENT: 1 << 2,
21
+ POSITION: 1 << 3,
22
+ VIEWPORT: 1 << 4,
23
+ SETTLE: 1 << 5,
24
+ });
25
+
26
+ const jobs = new Map();
27
+ let queueFrame = null;
28
+ let queueTimeout = null;
29
+ let flushing = false;
30
+
31
+ function enqueueFloatingLayout({
32
+ popperElement,
33
+ owner = null,
34
+ reason = FLOATING_LAYOUT_REASON.POSITION,
35
+ measure = undefined,
36
+ mutate = undefined,
37
+ position = undefined,
38
+ isActive = undefined,
39
+ onError = undefined,
40
+ } = {}) {
41
+ if (!(popperElement instanceof HTMLElement)) {
42
+ return Promise.resolve();
43
+ }
44
+
45
+ let job = jobs.get(popperElement);
46
+ if (!job) {
47
+ job = createJob(popperElement);
48
+ jobs.set(popperElement, job);
49
+ }
50
+
51
+ job.owner = owner || job.owner;
52
+ job.reasons |= reason;
53
+ if (measure instanceof Function) {
54
+ job.measure = measure;
55
+ }
56
+ if (mutate instanceof Function) {
57
+ job.mutate = mutate;
58
+ }
59
+ if (position instanceof Function) {
60
+ job.position = position;
61
+ }
62
+ job.isActive = isActive instanceof Function ? isActive : job.isActive;
63
+ job.onError = onError instanceof Function ? onError : job.onError;
64
+
65
+ if (job.running) {
66
+ job.pending = true;
67
+ return Promise.resolve();
68
+ }
69
+
70
+ scheduleQueueFlush();
71
+ return job.promise;
72
+ }
73
+
74
+ function cancelFloatingLayout(popperElement) {
75
+ const job = jobs.get(popperElement);
76
+ if (!job) {
77
+ return;
78
+ }
79
+
80
+ job.cancelled = true;
81
+ job.resolve();
82
+ jobs.delete(popperElement);
83
+ }
84
+
85
+ function flushFloatingLayoutQueueForTests() {
86
+ cancelQueueFrame();
87
+ return flushQueue();
88
+ }
89
+
90
+ function createJob(popperElement) {
91
+ let resolve;
92
+ const promise = new Promise((res) => {
93
+ resolve = res;
94
+ });
95
+
96
+ return {
97
+ popperElement,
98
+ owner: null,
99
+ reasons: 0,
100
+ measure: null,
101
+ mutate: null,
102
+ position: null,
103
+ isActive: null,
104
+ onError: null,
105
+ running: false,
106
+ pending: false,
107
+ cancelled: false,
108
+ promise,
109
+ resolve,
110
+ };
111
+ }
112
+
113
+ function scheduleQueueFlush() {
114
+ if (queueFrame !== null) {
115
+ return;
116
+ }
117
+
118
+ const globalObject = getGlobal();
119
+ const schedule =
120
+ globalObject?.requestAnimationFrame instanceof Function
121
+ ? globalObject.requestAnimationFrame.bind(globalObject)
122
+ : (callback) => globalObject.setTimeout(callback, 16);
123
+
124
+ const runScheduledFlush = () => {
125
+ if (queueFrame === null && queueTimeout === null) {
126
+ return;
127
+ }
128
+ queueFrame = null;
129
+ if (queueTimeout !== null) {
130
+ globalObject.clearTimeout(queueTimeout);
131
+ queueTimeout = null;
132
+ }
133
+ flushQueue().catch((error) => {
134
+ setTimeout(() => {
135
+ throw error;
136
+ }, 0);
137
+ });
138
+ };
139
+
140
+ queueFrame = schedule(runScheduledFlush);
141
+ queueTimeout = globalObject.setTimeout(runScheduledFlush, 32);
142
+ }
143
+
144
+ function cancelQueueFrame() {
145
+ if (queueFrame === null && queueTimeout === null) {
146
+ return;
147
+ }
148
+
149
+ const globalObject = getGlobal();
150
+ if (
151
+ queueFrame !== null &&
152
+ globalObject?.cancelAnimationFrame instanceof Function
153
+ ) {
154
+ globalObject.cancelAnimationFrame(queueFrame);
155
+ } else if (queueFrame !== null) {
156
+ globalObject.clearTimeout(queueFrame);
157
+ }
158
+ queueFrame = null;
159
+ if (queueTimeout !== null) {
160
+ globalObject.clearTimeout(queueTimeout);
161
+ queueTimeout = null;
162
+ }
163
+ }
164
+
165
+ async function flushQueue() {
166
+ if (flushing) {
167
+ return;
168
+ }
169
+
170
+ flushing = true;
171
+ const currentJobs = Array.from(jobs.values());
172
+
173
+ for (const job of currentJobs) {
174
+ await flushJob(job);
175
+ }
176
+
177
+ flushing = false;
178
+
179
+ if (Array.from(jobs.values()).some((job) => job.pending && !job.cancelled)) {
180
+ for (const job of jobs.values()) {
181
+ if (job.pending) {
182
+ job.pending = false;
183
+ }
184
+ }
185
+ scheduleQueueFlush();
186
+ }
187
+ }
188
+
189
+ async function flushJob(job) {
190
+ if (job.cancelled || !jobs.has(job.popperElement)) {
191
+ return;
192
+ }
193
+
194
+ const isActive =
195
+ job.isActive instanceof Function ? job.isActive(job.popperElement) : true;
196
+ if (!isActive) {
197
+ job.resolve();
198
+ jobs.delete(job.popperElement);
199
+ return;
200
+ }
201
+
202
+ const reasons = job.reasons;
203
+ job.reasons = 0;
204
+ job.running = true;
205
+
206
+ try {
207
+ const measurement =
208
+ job.measure instanceof Function ? job.measure(reasons) : undefined;
209
+ if (job.mutate instanceof Function) {
210
+ job.mutate(measurement, reasons);
211
+ }
212
+ if (job.position instanceof Function) {
213
+ await job.position(measurement, reasons);
214
+ }
215
+ } catch (error) {
216
+ if (job.onError instanceof Function) {
217
+ job.onError(error);
218
+ } else {
219
+ throw error;
220
+ }
221
+ } finally {
222
+ job.running = false;
223
+ if (!job.pending && job.reasons === 0) {
224
+ job.resolve();
225
+ jobs.delete(job.popperElement);
226
+ }
227
+ }
228
+ }
@@ -25,6 +25,11 @@ import {
25
25
  } from "@floating-ui/dom";
26
26
  import { isArray, isFunction, isObject, isString } from "../../../types/is.mjs";
27
27
  import { Processing } from "../../../util/processing.mjs";
28
+ import {
29
+ FLOATING_LAYOUT_REASON,
30
+ cancelFloatingLayout,
31
+ enqueueFloatingLayout,
32
+ } from "./floating-layout-queue.mjs";
28
33
 
29
34
  export {
30
35
  applyAdaptiveFloatingElementSize,
@@ -55,7 +60,14 @@ function positionPopper(controlElement, popperElement, options) {
55
60
  const config = normalizePopperConfig(options, controlElement, popperElement);
56
61
 
57
62
  return new Processing(() => {
58
- enableFloatingPositioning(controlElement, popperElement, config);
63
+ return enqueueFloatingLayout({
64
+ popperElement,
65
+ reason: FLOATING_LAYOUT_REASON.POSITION,
66
+ isActive: () => isPositionedPopperOpen(popperElement),
67
+ position: () => {
68
+ enableFloatingPositioning(controlElement, popperElement, config);
69
+ },
70
+ });
59
71
  }).run();
60
72
  }
61
73
 
@@ -87,8 +99,16 @@ function enableFloatingPositioning(controlElement, popperElement, config) {
87
99
  return;
88
100
  }
89
101
 
90
- runFloatingUpdateHook(popperElement);
91
- syncFloatingPopover(controlElement, popperElement, config);
102
+ enqueueFloatingLayout({
103
+ popperElement,
104
+ reason:
105
+ FLOATING_LAYOUT_REASON.POSITION | FLOATING_LAYOUT_REASON.RESIZE,
106
+ isActive: () => isPositionedPopperOpen(popperElement),
107
+ position: () => {
108
+ runFloatingUpdateHook(popperElement);
109
+ syncFloatingPopover(controlElement, popperElement, config);
110
+ },
111
+ });
92
112
  });
93
113
  runFloatingUpdateHook(popperElement);
94
114
  syncFloatingPopover(controlElement, popperElement, config);
@@ -165,6 +185,7 @@ function syncFloatingPopover(
165
185
  }
166
186
 
167
187
  function closePositionedPopper(popperElement) {
188
+ cancelFloatingLayout(popperElement);
168
189
  stopAutoUpdate(popperElement);
169
190
  cancelFloatingAppearanceFrame(popperElement);
170
191
  delete popperElement.dataset.monsterAppearance;
@@ -189,7 +210,10 @@ function normalizePopperConfig(options, controlElement, popperElement) {
189
210
  options,
190
211
  );
191
212
 
192
- if (!(config.boundaryElement instanceof HTMLElement)) {
213
+ if (
214
+ config.boundaryElement !== null &&
215
+ !(config.boundaryElement instanceof HTMLElement)
216
+ ) {
193
217
  config.boundaryElement = resolveClippingBoundaryElement(
194
218
  controlElement,
195
219
  popperElement,
@@ -981,7 +1005,7 @@ function startAutoUpdate(controlElement, popperElement, callback) {
981
1005
  autoUpdateCleanupMap.set(
982
1006
  popperElement,
983
1007
  autoUpdate(controlElement, popperElement, callback, {
984
- elementResize: typeof ResizeObserver === "function",
1008
+ elementResize: false,
985
1009
  layoutShift: false,
986
1010
  }),
987
1011
  );
@@ -1009,7 +1033,15 @@ function startFloatingResizeObserver(controlElement, popperElement, config) {
1009
1033
  return;
1010
1034
  }
1011
1035
 
1012
- scheduleSettlingPass(controlElement, popperElement, config);
1036
+ enqueueFloatingLayout({
1037
+ popperElement,
1038
+ reason: FLOATING_LAYOUT_REASON.SETTLE,
1039
+ isActive: () => isPositionedPopperOpen(popperElement),
1040
+ position: () => {
1041
+ runFloatingUpdateHook(popperElement);
1042
+ syncFloatingPopover(controlElement, popperElement, config, false);
1043
+ },
1044
+ });
1013
1045
  });
1014
1046
 
1015
1047
  observer.observe(popperElement);
@@ -1038,8 +1070,15 @@ function scheduleSettlingPass(controlElement, popperElement, config) {
1038
1070
  return;
1039
1071
  }
1040
1072
 
1041
- runFloatingUpdateHook(popperElement);
1042
- syncFloatingPopover(controlElement, popperElement, config, false);
1073
+ enqueueFloatingLayout({
1074
+ popperElement,
1075
+ reason: FLOATING_LAYOUT_REASON.SETTLE,
1076
+ isActive: () => isPositionedPopperOpen(popperElement),
1077
+ position: () => {
1078
+ runFloatingUpdateHook(popperElement);
1079
+ syncFloatingPopover(controlElement, popperElement, config, false);
1080
+ },
1081
+ });
1043
1082
  });
1044
1083
 
1045
1084
  settlingFrameMap.set(popperElement, frameId);
@@ -99,6 +99,25 @@ class Panel extends CustomElement {
99
99
  calcHeight.call(this);
100
100
  }
101
101
 
102
+ /**
103
+ * Get the height that fits this panel into the currently available viewport.
104
+ *
105
+ * @return {number}
106
+ */
107
+ getMaximumHeight() {
108
+ return getMaximumPanelHeight.call(this);
109
+ }
110
+
111
+ /**
112
+ * Recalculate and apply the current maximum panel height.
113
+ *
114
+ * @return {Panel}
115
+ */
116
+ recalculateHeight() {
117
+ calcHeight.call(this);
118
+ return this;
119
+ }
120
+
102
121
  /**
103
122
  * This method is called by the dom and should not be called directly.
104
123
  *
@@ -145,11 +164,24 @@ class Panel extends CustomElement {
145
164
  function calcHeight() {
146
165
  this.style.boxSizing = "border-box";
147
166
 
148
- let height = calculateMaximumHeight.call(this, this);
149
- if (height < 0) {
167
+ const height = getMaximumPanelHeight.call(this);
168
+ if (height < 0 || Number.isNaN(height)) {
150
169
  return;
151
170
  }
152
171
 
172
+ this.style.height = `${height}px`;
173
+ }
174
+
175
+ /**
176
+ * @private
177
+ * @return {number}
178
+ */
179
+ function getMaximumPanelHeight() {
180
+ let height = calculateMaximumHeight.call(this, this);
181
+ if (height < 0 || Number.isNaN(height)) {
182
+ return -1;
183
+ }
184
+
153
185
  const parent =
154
186
  this.parentNode instanceof HTMLElement ? this.parentNode : null;
155
187
  const parentHeight = parent?.clientHeight || 0;
@@ -157,7 +189,7 @@ function calcHeight() {
157
189
  height = Math.min(height, parentHeight);
158
190
  }
159
191
 
160
- this.style.height = `${height}px`;
192
+ return height;
161
193
  }
162
194
 
163
195
  /**
@@ -202,12 +234,18 @@ function calculateMaximumHeight(element) {
202
234
  const boxShadowVertical = parseFloat(style.boxShadow.split(" ")[3] || 0);
203
235
 
204
236
  // Accumulate values
205
- totalBottomBorder += isNaN(borderBottomWidth) ? 0 : borderBottomWidth;
237
+ totalBottomBorder += Number.isNaN(borderBottomWidth)
238
+ ? 0
239
+ : borderBottomWidth;
206
240
  totalBottomPadding +=
207
- isNaN(paddingBottom) || boxSizing === "border-box" ? 0 : paddingBottom;
208
- totalBottomMargin += isNaN(marginBottom) ? 0 : marginBottom;
209
- totalOutlineHeight += isNaN(outlineHeight) ? 0 : outlineHeight;
210
- totalBoxShadowHeight += isNaN(boxShadowVertical) ? 0 : boxShadowVertical;
241
+ Number.isNaN(paddingBottom) || boxSizing === "border-box"
242
+ ? 0
243
+ : paddingBottom;
244
+ totalBottomMargin += Number.isNaN(marginBottom) ? 0 : marginBottom;
245
+ totalOutlineHeight += Number.isNaN(outlineHeight) ? 0 : outlineHeight;
246
+ totalBoxShadowHeight += Number.isNaN(boxShadowVertical)
247
+ ? 0
248
+ : boxShadowVertical;
211
249
 
212
250
  currentElement = currentElement.parentNode || currentElement.host;
213
251
  }
@@ -221,7 +259,7 @@ function calculateMaximumHeight(element) {
221
259
  totalBottomMargin -
222
260
  totalOutlineHeight -
223
261
  totalBoxShadowHeight;
224
- return maximumHeight + this.getOption("heightAdjustment");
262
+ return maximumHeight + getNumericOption.call(this, "heightAdjustment");
225
263
  }
226
264
 
227
265
  /**
@@ -234,7 +272,7 @@ function attachResizeObserver() {
234
272
  try {
235
273
  this[timerCallbackSymbol].touch();
236
274
  return;
237
- } catch (e) {
275
+ } catch {
238
276
  delete this[timerCallbackSymbol];
239
277
  }
240
278
  }
@@ -244,8 +282,13 @@ function attachResizeObserver() {
244
282
  });
245
283
  });
246
284
 
247
- this[resizeObserverSymbol].observe(this.ownerDocument.body);
248
- this[resizeObserverSymbol].observe(document.scrollingElement);
285
+ if (this.ownerDocument.body instanceof Element) {
286
+ this[resizeObserverSymbol].observe(this.ownerDocument.body);
287
+ }
288
+
289
+ if (this.ownerDocument.scrollingElement instanceof Element) {
290
+ this[resizeObserverSymbol].observe(this.ownerDocument.scrollingElement);
291
+ }
249
292
  }
250
293
 
251
294
  function disconnectResizeObserver() {
@@ -254,6 +297,16 @@ function disconnectResizeObserver() {
254
297
  }
255
298
  }
256
299
 
300
+ /**
301
+ * @private
302
+ * @param {string} name
303
+ * @return {number}
304
+ */
305
+ function getNumericOption(name) {
306
+ const value = Number.parseFloat(this.getOption(name));
307
+ return Number.isNaN(value) ? 0 : value;
308
+ }
309
+
257
310
  /**
258
311
  * @private
259
312
  * @return {Panel}
@@ -175,9 +175,9 @@ class SplitPanel extends CustomElement {
175
175
  setDimension(dimension) {
176
176
  // check if percent and greater than100
177
177
  if (dimension.includes("%")) {
178
- if (parseInt(dimension) > 100) {
178
+ if (parseFloat(dimension) > 100) {
179
179
  throw new Error("dimension must be less than 100%");
180
- } else if (parseInt(dimension) < 0) {
180
+ } else if (parseFloat(dimension) < 0) {
181
181
  throw new Error("dimension must be greater than 0%");
182
182
  }
183
183
  }
@@ -217,17 +217,19 @@ class SplitPanel extends CustomElement {
217
217
  function applyPanelDimensions() {
218
218
  const splitType = this.getOption("splitType");
219
219
  const dimension = this[internalSymbol].getSubject().currentDimension;
220
+ const draggerSize = getDraggerSize.call(this);
220
221
 
221
222
  if (splitType === TYPE_VERTICAL) {
222
223
  this[startPanelElementSymbol].style.width = dimension;
223
- this[endPanelElementSymbol].style.width = `calc(100% - ${dimension} - 5px)`;
224
+ this[endPanelElementSymbol].style.width =
225
+ `calc(100% - ${dimension} - ${draggerSize})`;
224
226
  this[draggerElementSymbol].style.cursor = "ew-resize";
225
227
  this[splitScreenElementSymbol].classList.add("vertical");
226
228
  this[splitScreenElementSymbol].classList.remove("horizontal");
227
229
  } else {
228
230
  this[startPanelElementSymbol].style.height = dimension;
229
231
  this[endPanelElementSymbol].style.height =
230
- `calc(100% - ${dimension} - 5px)`;
232
+ `calc(100% - ${dimension} - ${draggerSize})`;
231
233
  this[draggerElementSymbol].style.cursor = "ns-resize";
232
234
  this[splitScreenElementSymbol].classList.add("horizontal");
233
235
  this[splitScreenElementSymbol].classList.remove("vertical");
@@ -267,6 +269,29 @@ function initControlReferences() {
267
269
  );
268
270
  }
269
271
 
272
+ /**
273
+ * @private
274
+ * @return {string}
275
+ */
276
+ function getDraggerSize() {
277
+ if (!(this[draggerElementSymbol] instanceof Element)) {
278
+ return "0px";
279
+ }
280
+
281
+ const inlineProperty =
282
+ this[draggerElementSymbol] instanceof HTMLElement
283
+ ? this[draggerElementSymbol].style
284
+ .getPropertyValue("--monster-dragger-width")
285
+ .trim()
286
+ : "";
287
+ const computedProperty = window
288
+ .getComputedStyle(this[draggerElementSymbol])
289
+ .getPropertyValue("--monster-dragger-width")
290
+ .trim();
291
+
292
+ return inlineProperty || computedProperty || "0px";
293
+ }
294
+
270
295
  /**
271
296
  * @private
272
297
  */
@@ -316,43 +341,42 @@ function initEventHandler() {
316
341
  if (!touch) return;
317
342
 
318
343
  // identical logic as in mousemove - but with touch.clientX/clientY
319
- let draggerWidth =
320
- getComputedStyle(self[draggerElementSymbol]).getPropertyValue(
321
- "--monster-dragger-width",
322
- ) || "0";
344
+ const draggerWidth = getDraggerSize.call(self);
323
345
 
324
346
  if (self.getOption("splitType") === TYPE_HORIZONTAL) {
325
- const containerOffsetTop = self[splitScreenElementSymbol].offsetTop;
326
- let newTopHeight = touch.clientY - containerOffsetTop;
347
+ const containerRect =
348
+ self[splitScreenElementSymbol].getBoundingClientRect();
349
+ let newTopHeight = touch.clientY - containerRect.top;
327
350
 
328
351
  const min = this.getOption("dimension").min;
329
352
  const max = this.getOption("dimension").max;
330
353
  const topAsPercent =
331
354
  (newTopHeight / this[splitScreenElementSymbol].offsetHeight) * 100;
332
355
 
333
- if (parseInt(min) > topAsPercent) newTopHeight = min;
334
- else if (parseInt(max) < topAsPercent) newTopHeight = max;
335
- else newTopHeight = topAsPercent + "%";
356
+ if (parseFloat(min) > topAsPercent) newTopHeight = min;
357
+ else if (parseFloat(max) < topAsPercent) newTopHeight = max;
358
+ else newTopHeight = `${topAsPercent}%`;
336
359
 
337
360
  const newTopHeightPx =
338
- (parseInt(newTopHeight) / 100) *
361
+ (parseFloat(newTopHeight) / 100) *
339
362
  this[splitScreenElementSymbol].offsetHeight;
340
363
 
341
364
  self[startPanelElementSymbol].style.height = `${newTopHeightPx}px`;
342
365
  self[endPanelElementSymbol].style.height =
343
366
  `calc(100% - ${newTopHeightPx}px - ${draggerWidth})`;
344
367
  } else {
345
- const containerOffsetLeft = self[splitScreenElementSymbol].offsetLeft;
346
- let newLeftWidth = touch.clientX - containerOffsetLeft;
368
+ const containerRect =
369
+ self[splitScreenElementSymbol].getBoundingClientRect();
370
+ let newLeftWidth = touch.clientX - containerRect.left;
347
371
 
348
372
  const min = this.getOption("dimension").min;
349
373
  const max = this.getOption("dimension").max;
350
374
  const leftAsPercent =
351
375
  (newLeftWidth / this[splitScreenElementSymbol].offsetWidth) * 100;
352
376
 
353
- if (parseInt(min) > leftAsPercent) newLeftWidth = min;
354
- else if (parseInt(max) < leftAsPercent) newLeftWidth = max;
355
- else newLeftWidth = leftAsPercent + "%";
377
+ if (parseFloat(min) > leftAsPercent) newLeftWidth = min;
378
+ else if (parseFloat(max) < leftAsPercent) newLeftWidth = max;
379
+ else newLeftWidth = `${leftAsPercent}%`;
356
380
 
357
381
  self[startPanelElementSymbol].style.width = `${newLeftWidth}`;
358
382
  self[endPanelElementSymbol].style.width =
@@ -370,7 +394,7 @@ function initEventHandler() {
370
394
  document.addEventListener("touchend", dragTouchEnd);
371
395
  });
372
396
 
373
- let userSelectDefault = getDocument().body.style.userSelect;
397
+ const userSelectDefault = getDocument().body.style.userSelect;
374
398
 
375
399
  this[draggerElementSymbol].addEventListener("mousedown", () => {
376
400
  self[internalSymbol].getSubject().isDragging = true;
@@ -378,18 +402,7 @@ function initEventHandler() {
378
402
  const eventListener = (e) => {
379
403
  e.preventDefault();
380
404
 
381
- // the 5px are wrong and must be calc from css property --monster-dragger-width
382
-
383
- let draggerWidth = getComputedStyle(
384
- self[draggerElementSymbol],
385
- ).getPropertyValue("--monster-dragger-width");
386
- if (
387
- draggerWidth === "" ||
388
- draggerWidth === undefined ||
389
- draggerWidth === null
390
- ) {
391
- draggerWidth = "0";
392
- }
405
+ const draggerWidth = getDraggerSize.call(self);
393
406
 
394
407
  if (!self[internalSymbol].getSubject().isDragging) {
395
408
  return;
@@ -398,36 +411,38 @@ function initEventHandler() {
398
411
  getDocument().body.style.userSelect = "none";
399
412
 
400
413
  if (self.getOption("splitType") === TYPE_HORIZONTAL) {
401
- const containerOffsetTop = self[splitScreenElementSymbol].offsetTop;
414
+ const containerRect =
415
+ self[splitScreenElementSymbol].getBoundingClientRect();
402
416
  const topPanel = self[startPanelElementSymbol];
403
417
  const bottomPanel = self[endPanelElementSymbol];
404
- let newTopHeight = e.clientY - containerOffsetTop;
418
+ let newTopHeight = e.clientY - containerRect.top;
405
419
 
406
420
  const min = this.getOption("dimension").min;
407
421
  const max = this.getOption("dimension").max;
408
422
 
409
423
  const topAsPercent =
410
424
  (newTopHeight / this[splitScreenElementSymbol].offsetHeight) * 100;
411
- if (parseInt(min) > topAsPercent) {
425
+ if (parseFloat(min) > topAsPercent) {
412
426
  newTopHeight = min;
413
- } else if (parseInt(max) < topAsPercent) {
427
+ } else if (parseFloat(max) < topAsPercent) {
414
428
  newTopHeight = max;
415
429
  } else {
416
- newTopHeight = topAsPercent + "%";
430
+ newTopHeight = `${topAsPercent}%`;
417
431
  }
418
432
 
419
433
  // calc new top height to pixel
420
434
  const newTopHeightPx =
421
- (parseInt(newTopHeight) / 100) *
435
+ (parseFloat(newTopHeight) / 100) *
422
436
  this[splitScreenElementSymbol].offsetHeight;
423
437
 
424
438
  topPanel.style.height = `${newTopHeightPx}px`;
425
- bottomPanel.style.height = `calc(100% - ${newTopHeightPx}px - ${draggerWidth})`; // 5px is dragger height
439
+ bottomPanel.style.height = `calc(100% - ${newTopHeightPx}px - ${draggerWidth})`;
426
440
  } else {
427
- const containerOffsetLeft = self[splitScreenElementSymbol].offsetLeft;
441
+ const containerRect =
442
+ self[splitScreenElementSymbol].getBoundingClientRect();
428
443
  const leftPanel = self[startPanelElementSymbol];
429
444
  const rightPanel = self[endPanelElementSymbol];
430
- let newLeftWidth = e.clientX - containerOffsetLeft;
445
+ let newLeftWidth = e.clientX - containerRect.left;
431
446
 
432
447
  const min = this.getOption("dimension").min;
433
448
  const max = this.getOption("dimension").max;
@@ -435,26 +450,26 @@ function initEventHandler() {
435
450
  const leftAsPercent =
436
451
  (newLeftWidth / this[splitScreenElementSymbol].offsetWidth) * 100;
437
452
 
438
- if (parseInt(min) > leftAsPercent) {
453
+ if (parseFloat(min) > leftAsPercent) {
439
454
  newLeftWidth = min;
440
- } else if (parseInt(max) < leftAsPercent) {
455
+ } else if (parseFloat(max) < leftAsPercent) {
441
456
  newLeftWidth = max;
442
457
  } else {
443
- newLeftWidth = leftAsPercent + "%";
458
+ newLeftWidth = `${leftAsPercent}%`;
444
459
  }
445
460
 
446
461
  leftPanel.style.width = `${newLeftWidth}`;
447
- rightPanel.style.width = `calc(100% - ${newLeftWidth} - ${draggerWidth})`; // 5px is dragger width
462
+ rightPanel.style.width = `calc(100% - ${newLeftWidth} - ${draggerWidth})`;
448
463
  }
449
464
  };
450
465
 
451
- const dragEventHandler = (e) => {
466
+ const dragEventHandler = () => {
452
467
  self[internalSymbol].getSubject().isDragging = false;
453
468
 
454
469
  document.body.style.userSelect = userSelectDefault;
455
470
 
456
471
  document.removeEventListener("mousemove", eventListener);
457
- document.removeEventListener("mouseup", eventListener);
472
+ document.removeEventListener("mouseup", dragEventHandler);
458
473
  };
459
474
 
460
475
  document.addEventListener("mousemove", eventListener);