wj-elements 0.6.1 → 0.7.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.
Files changed (40) hide show
  1. package/dist/custom-elements.json +24552 -0
  2. package/dist/light.css +1 -0
  3. package/dist/packages/translations/en-gb.d.ts +4 -0
  4. package/dist/packages/translations/sk-sk.d.ts +4 -0
  5. package/dist/packages/wje-breadcrumbs/breadcrumbs.element.d.ts +1 -1
  6. package/dist/packages/wje-chip/chip.element.d.ts +3 -0
  7. package/dist/packages/wje-dropdown/dropdown.element.d.ts +18 -0
  8. package/dist/packages/wje-file-upload/file-upload.element.d.ts +16 -0
  9. package/dist/packages/wje-header/header.element.d.ts +1 -0
  10. package/dist/packages/wje-popup/popup.element.d.ts +41 -1
  11. package/dist/packages/wje-sliding-container/sliding-container.element.d.ts +410 -3
  12. package/dist/packages/wje-toolbar-action/toolbar-action.element.d.ts +11 -0
  13. package/dist/{popup.element-B1HZhDZJ.js → popup.element-CwXvVFK7.js} +251 -43
  14. package/dist/popup.element-CwXvVFK7.js.map +1 -0
  15. package/dist/styles.css +0 -38
  16. package/dist/web-types.json +4176 -0
  17. package/dist/wje-animation.js +1 -1
  18. package/dist/wje-breadcrumbs.js +4 -0
  19. package/dist/wje-breadcrumbs.js.map +1 -1
  20. package/dist/wje-chip.js +11 -2
  21. package/dist/wje-chip.js.map +1 -1
  22. package/dist/wje-dropdown.js +28 -4
  23. package/dist/wje-dropdown.js.map +1 -1
  24. package/dist/wje-file-upload.js +64 -2
  25. package/dist/wje-file-upload.js.map +1 -1
  26. package/dist/wje-header.js +1 -1
  27. package/dist/wje-header.js.map +1 -1
  28. package/dist/wje-master.js +9 -1
  29. package/dist/wje-master.js.map +1 -1
  30. package/dist/wje-popup.js +1 -1
  31. package/dist/wje-select.js +28 -5
  32. package/dist/wje-select.js.map +1 -1
  33. package/dist/wje-sliding-container.js +936 -14
  34. package/dist/wje-sliding-container.js.map +1 -1
  35. package/dist/wje-toolbar-action.js +25 -1
  36. package/dist/wje-toolbar-action.js.map +1 -1
  37. package/dist/wje-toolbar.js +1 -1
  38. package/dist/wje-tooltip.js +1 -1
  39. package/package.json +3 -2
  40. package/dist/popup.element-B1HZhDZJ.js.map +0 -1
@@ -3,7 +3,7 @@ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { en
3
3
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
4
  import WJElement from "./wje-element.js";
5
5
  import { event } from "./event.js";
6
- const styles = ":host {\n display: block;\n z-index: 9999;\n position: relative;\n height: 100%;\n right: unset;\n left: unset;\n .close-button {\n position: absolute;\n top: 0;\n right: 0;\n z-index: 1000;\n }\n}\n\n:host([hide-button]) {\n .close-button {\n display: none;\n }\n}\n\n.sliding-container-wrapper {\n height: 100%;\n position: relative;\n overflow: hidden;\n}\n\n.native-sliding-container {\n\n position: absolute;\n width: 0;\n height: 100%;\n}\n\n.native-sliding-container-inner {\n height: 100%;\n position: absolute;\n}\n";
6
+ const styles = ":host {\n display: block;\n z-index: var(--wje-sliding-container-z-index, 1000);\n position: relative;\n height: 100%;\n right: unset;\n left: unset;\n .close-button {\n position: absolute;\n top: 0;\n right: 0;\n z-index: 2;\n }\n}\n\n:host([hide-button]) {\n .close-button {\n display: none;\n }\n}\n\n.sliding-container-backdrop {\n display: none;\n}\n\n.sliding-container-wrapper {\n height: 100%;\n position: relative;\n overflow: hidden;\n}\n\n.native-sliding-container {\n\n position: absolute;\n width: 0;\n height: 100%;\n}\n\n.native-sliding-container-inner {\n height: 100%;\n position: absolute;\n}\n\n.sliding-container-sheet-handle-area {\n display: none;\n}\n\n:host(.bottom-sheet) {\n inset: 0;\n pointer-events: none;\n z-index: var(--wje-sliding-container-bottom-sheet-z-index, var(--wje-sliding-container-z-index, 1000));\n}\n\n:host(.bottom-sheet.open) {\n overscroll-behavior: contain;\n}\n\n:host(.bottom-sheet) .sliding-container-backdrop {\n display: none;\n position: fixed;\n inset: 0;\n z-index: var(--wje-sliding-container-bottom-sheet-backdrop-z-index, 0);\n opacity: 0;\n pointer-events: none;\n touch-action: none;\n overscroll-behavior: none;\n background: var(--wje-sliding-container-backdrop-background, var(--wje-backdrop, rgba(0, 0, 0, .35)));\n}\n\n:host(.bottom-sheet.open) .sliding-container-backdrop {\n pointer-events: auto;\n}\n\n:host(.bottom-sheet) .sliding-container-wrapper {\n position: fixed;\n inset: 0;\n overflow: visible;\n pointer-events: none;\n z-index: var(--wje-sliding-container-bottom-sheet-panel-z-index, 1);\n}\n\n:host(.bottom-sheet) .sliding-container-transparent {\n display: none;\n}\n\n:host(.bottom-sheet) .native-sliding-container {\n position: fixed;\n top: auto;\n height: fit-content;\n overflow: hidden;\n pointer-events: auto;\n display: flex;\n flex-direction: column;\n overscroll-behavior: contain;\n background: var(--wje-sliding-container-background);\n box-shadow: var(--wje-sliding-container-box-shadow, var(--wje-sliding-container-shadow));\n border-radius: var(--wje-sliding-container-sheet-border-radius, var(--wje-sliding-container-border-radius) var(--wje-sliding-container-border-radius) 0 0);\n}\n\n:host(.bottom-sheet) .native-sliding-container-inner {\n position: relative;\n flex: 1 1 auto;\n min-height: 0;\n height: auto;\n max-height: inherit;\n overflow: auto;\n overscroll-behavior: contain;\n}\n\n:host(.bottom-sheet) .sliding-container-sheet-handle-area {\n display: flex;\n align-items: center;\n justify-content: center;\n flex: 0 0 var(--wje-sliding-container-sheet-handle-area-height, 24px);\n height: var(--wje-sliding-container-sheet-handle-area-height, 24px);\n cursor: grab;\n pointer-events: auto;\n touch-action: none;\n user-select: none;\n -webkit-user-select: none;\n}\n\n:host(.bottom-sheet) .sliding-container-sheet-handle-area:active {\n cursor: grabbing;\n}\n\n:host(.bottom-sheet) .sliding-container-sheet-handle {\n width: var(--wje-sliding-container-sheet-handle-width, 36px);\n height: var(--wje-sliding-container-sheet-handle-height, 2px);\n background: var(--wje-sliding-container-sheet-handle-background, var(--wje-border-color));\n border-radius: var(--wje-sliding-container-sheet-handle-radius, 999px);\n}\n";
7
7
  class SlidingContainer extends WJElement {
8
8
  /**
9
9
  * Creates an instance of SlidingContainer.
@@ -12,6 +12,197 @@ class SlidingContainer extends WJElement {
12
12
  constructor() {
13
13
  super();
14
14
  __publicField(this, "className", "SlidingContainer");
15
+ /**
16
+ * Handles backdrop click dismissal.
17
+ * @param {MouseEvent} e The click event.
18
+ */
19
+ __publicField(this, "handleBackdropClick", (e) => {
20
+ if (this.isEventInsideSheet(e) || Date.now() < this._sheetIgnoreDismissUntil || Date.now() < this._sheetBackdropHandledUntil) {
21
+ e.preventDefault();
22
+ e.stopPropagation();
23
+ return;
24
+ }
25
+ if (this.isBackdropElement(e.target)) {
26
+ this.close(e);
27
+ }
28
+ });
29
+ /**
30
+ * Stops a handle interaction from dismissing the bottom sheet.
31
+ * @param {Event} e The interaction emitted by the resize handle.
32
+ */
33
+ __publicField(this, "stopSheetHandleEvent", (e) => {
34
+ var _a;
35
+ if (!this.isBottomSheet()) return;
36
+ this._sheetIgnoreDismissUntil = Date.now() + 500;
37
+ e.preventDefault();
38
+ e.stopPropagation();
39
+ (_a = e.stopImmediatePropagation) == null ? void 0 : _a.call(e);
40
+ });
41
+ /**
42
+ * Prevents scroll events from reaching the page behind the bottom sheet.
43
+ * @param {Event} e The scroll event.
44
+ */
45
+ __publicField(this, "preventBottomSheetScroll", (e) => {
46
+ if (!this.isBottomSheet() || !this.classList.contains("open")) return;
47
+ e.preventDefault();
48
+ e.stopPropagation();
49
+ });
50
+ /**
51
+ * Starts mobile bottom sheet resizing.
52
+ * @param {PointerEvent} e The pointer event.
53
+ */
54
+ __publicField(this, "handleSheetDragStart", (e) => {
55
+ var _a, _b;
56
+ if (!this.sheetResizable || !this.isBottomSheet()) return;
57
+ e.preventDefault();
58
+ e.stopPropagation();
59
+ (_a = e.stopImmediatePropagation) == null ? void 0 : _a.call(e);
60
+ this._sheetIgnoreDismissUntil = Date.now() + 500;
61
+ if (this._sheetDrag) return;
62
+ this.startSheetDrag(e.pointerId, e.clientY);
63
+ try {
64
+ (_b = this.sheetHandleArea) == null ? void 0 : _b.setPointerCapture(e.pointerId);
65
+ } catch {
66
+ }
67
+ window.addEventListener("pointermove", this.handleSheetDragMove);
68
+ window.addEventListener("pointerup", this.handleSheetDragEnd);
69
+ window.addEventListener("pointercancel", this.handleSheetDragEnd);
70
+ });
71
+ /**
72
+ * Starts mobile bottom sheet resizing from a touch event.
73
+ * @param {TouchEvent} e The touch event.
74
+ */
75
+ __publicField(this, "handleSheetTouchStart", (e) => {
76
+ var _a, _b;
77
+ if (!this.sheetResizable || !this.isBottomSheet() || this._sheetDrag) return;
78
+ const touch = (_a = e.touches) == null ? void 0 : _a[0];
79
+ if (!touch) return;
80
+ e.preventDefault();
81
+ e.stopPropagation();
82
+ (_b = e.stopImmediatePropagation) == null ? void 0 : _b.call(e);
83
+ this._sheetIgnoreDismissUntil = Date.now() + 500;
84
+ this.startSheetDrag("touch", touch.clientY);
85
+ window.addEventListener("touchmove", this.handleSheetTouchMove, { passive: false });
86
+ window.addEventListener("touchend", this.handleSheetTouchEnd, { passive: false });
87
+ window.addEventListener("touchcancel", this.handleSheetTouchEnd, { passive: false });
88
+ });
89
+ /**
90
+ * Starts tracking a possible backdrop dismiss tap.
91
+ * @param {PointerEvent} e The pointer event.
92
+ */
93
+ __publicField(this, "handleBackdropPointerStart", (e) => {
94
+ if (!this.isBottomSheet() || !this.isBackdropElement(e.target) || this.isEventInsideSheet(e) || Date.now() < this._sheetIgnoreDismissUntil) {
95
+ this._sheetBackdropGesture = null;
96
+ return;
97
+ }
98
+ this._sheetBackdropGesture = {
99
+ pointerId: e.pointerId,
100
+ startX: e.clientX,
101
+ startY: e.clientY,
102
+ hasMoved: false
103
+ };
104
+ });
105
+ /**
106
+ * Tracks movement during a possible backdrop dismiss tap.
107
+ * @param {PointerEvent} e The pointer event.
108
+ */
109
+ __publicField(this, "handleBackdropPointerMove", (e) => {
110
+ if (!this._sheetBackdropGesture || e.pointerId !== this._sheetBackdropGesture.pointerId) return;
111
+ const distanceX = Math.abs(e.clientX - this._sheetBackdropGesture.startX);
112
+ const distanceY = Math.abs(e.clientY - this._sheetBackdropGesture.startY);
113
+ if (distanceX > 8 || distanceY > 8) {
114
+ this._sheetBackdropGesture.hasMoved = true;
115
+ }
116
+ });
117
+ /**
118
+ * Finishes a possible backdrop dismiss tap.
119
+ * @param {PointerEvent} e The pointer event.
120
+ */
121
+ __publicField(this, "handleBackdropPointerEnd", (e) => {
122
+ if (!this._sheetBackdropGesture || e.pointerId !== this._sheetBackdropGesture.pointerId) return;
123
+ const shouldClose = !this._sheetBackdropGesture.hasMoved && this.isBackdropElement(e.target) && !this.isEventInsideSheet(e) && Date.now() >= this._sheetIgnoreDismissUntil;
124
+ this._sheetBackdropGesture = null;
125
+ this._sheetBackdropHandledUntil = Date.now() + 350;
126
+ if (shouldClose) {
127
+ e.preventDefault();
128
+ e.stopPropagation();
129
+ this.close(e);
130
+ }
131
+ });
132
+ /**
133
+ * Cancels a possible backdrop dismiss tap.
134
+ */
135
+ __publicField(this, "handleBackdropPointerCancel", () => {
136
+ this._sheetBackdropGesture = null;
137
+ this._sheetBackdropHandledUntil = Date.now() + 350;
138
+ });
139
+ /**
140
+ * Resizes the mobile bottom sheet during dragging.
141
+ * @param {PointerEvent} e The pointer event.
142
+ */
143
+ __publicField(this, "handleSheetDragMove", (e) => {
144
+ var _a;
145
+ if (!this._sheetDrag || e.pointerId !== this._sheetDrag.pointerId) return;
146
+ e.preventDefault();
147
+ e.stopPropagation();
148
+ (_a = e.stopImmediatePropagation) == null ? void 0 : _a.call(e);
149
+ this.updateSheetDrag(e.clientY);
150
+ });
151
+ /**
152
+ * Resizes the mobile bottom sheet during touch dragging.
153
+ * @param {TouchEvent} e The touch event.
154
+ */
155
+ __publicField(this, "handleSheetTouchMove", (e) => {
156
+ var _a, _b;
157
+ if (!this._sheetDrag || this._sheetDrag.pointerId !== "touch") return;
158
+ const touch = (_a = e.touches) == null ? void 0 : _a[0];
159
+ if (!touch) return;
160
+ e.preventDefault();
161
+ e.stopPropagation();
162
+ (_b = e.stopImmediatePropagation) == null ? void 0 : _b.call(e);
163
+ this.updateSheetDrag(touch.clientY);
164
+ });
165
+ /**
166
+ * Ends mobile bottom sheet resizing.
167
+ * @param {PointerEvent} e The pointer event.
168
+ */
169
+ __publicField(this, "handleSheetDragEnd", (e) => {
170
+ var _a, _b, _c;
171
+ const hasMoved = (_a = this._sheetDrag) == null ? void 0 : _a.hasMoved;
172
+ if (this._sheetDrag && (e == null ? void 0 : e.pointerId) === this._sheetDrag.pointerId) {
173
+ e.preventDefault();
174
+ e.stopPropagation();
175
+ (_b = e.stopImmediatePropagation) == null ? void 0 : _b.call(e);
176
+ try {
177
+ (_c = this.sheetHandleArea) == null ? void 0 : _c.releasePointerCapture(e.pointerId);
178
+ } catch {
179
+ }
180
+ }
181
+ if (hasMoved) {
182
+ this._sheetIgnoreDismissUntil = Date.now() + 350;
183
+ } else {
184
+ this._sheetIgnoreDismissUntil = Date.now() + 500;
185
+ }
186
+ this.endSheetDrag();
187
+ });
188
+ /**
189
+ * Ends mobile bottom sheet resizing from a touch event.
190
+ * @param {TouchEvent} e The touch event.
191
+ */
192
+ __publicField(this, "handleSheetTouchEnd", (e) => {
193
+ var _a;
194
+ if (!this._sheetDrag || this._sheetDrag.pointerId !== "touch") return;
195
+ const hasMoved = this._sheetDrag.hasMoved;
196
+ if (e.type !== "touchcancel") {
197
+ e.preventDefault();
198
+ }
199
+ e.stopPropagation();
200
+ if (e.type !== "touchcancel") {
201
+ (_a = e.stopImmediatePropagation) == null ? void 0 : _a.call(e);
202
+ }
203
+ this._sheetIgnoreDismissUntil = Date.now() + (hasMoved ? 350 : 700);
204
+ this.endSheetDrag();
205
+ });
15
206
  /**
16
207
  * Triggers the event based on the target element.
17
208
  * If the target element is different from the last caller, it refreshes the children by calling the `open` method.
@@ -28,11 +219,18 @@ class SlidingContainer extends WJElement {
28
219
  });
29
220
  this._isOpen = false;
30
221
  this._lastCaller = null;
222
+ this._sheetDrag = null;
223
+ this._sheetIgnoreDismissUntil = 0;
224
+ this._sheetBackdropGesture = null;
225
+ this._sheetBackdropHandledUntil = 0;
226
+ this._bottomSheetScopeFrame = null;
31
227
  this._resizeObserver = new ResizeObserver((entries) => {
32
228
  for (let entry of entries) {
33
229
  if (entry.contentBoxSize) {
34
230
  if (this.drawingStatus < 3) return;
35
- if (this.screenBreakPoint && window.innerWidth <= this.screenBreakPoint) {
231
+ if (this.isBottomSheet()) {
232
+ this.checkForVariant(this.variant);
233
+ } else if (this.screenBreakPoint && window.innerWidth <= this.screenBreakPoint) {
36
234
  if (this.variant !== "over") {
37
235
  this.variant = "over";
38
236
  } else {
@@ -155,6 +353,34 @@ class SlidingContainer extends WJElement {
155
353
  set screenBreakPoint(value) {
156
354
  this.setAttribute("screen-break-point", value);
157
355
  }
356
+ /**
357
+ * Sets mobile presentation mode.
358
+ * @param {string} value The mobile presentation mode.
359
+ */
360
+ set mobilePresentation(value) {
361
+ this.setAttribute("mobile-presentation", value);
362
+ }
363
+ /**
364
+ * Gets mobile presentation mode.
365
+ * @returns {string|null} The mobile presentation mode.
366
+ */
367
+ get mobilePresentation() {
368
+ return this.getAttribute("mobile-presentation");
369
+ }
370
+ /**
371
+ * Sets the breakpoint for mobile presentation.
372
+ * @param {string} value The mobile breakpoint.
373
+ */
374
+ set mobileBreakPoint(value) {
375
+ this.setAttribute("mobile-break-point", value);
376
+ }
377
+ /**
378
+ * Gets the breakpoint for mobile presentation.
379
+ * @returns {string} The mobile breakpoint.
380
+ */
381
+ get mobileBreakPoint() {
382
+ return this.getAttribute("mobile-break-point") || "768";
383
+ }
158
384
  /**
159
385
  * Sets the duration of the animation by updating the `animation-duration` attribute.
160
386
  * @param {string} value The duration value for the animation, specified in a format
@@ -192,6 +418,97 @@ class SlidingContainer extends WJElement {
192
418
  get hasOpacity() {
193
419
  return this.hasAttribute("has-opacity") ?? false;
194
420
  }
421
+ /**
422
+ * Determines if the bottom sheet should close when the backdrop is clicked.
423
+ * @returns {boolean} True if backdrop dismiss is enabled.
424
+ */
425
+ get backdropDismiss() {
426
+ return this.hasAttribute("backdrop-dismiss") ?? false;
427
+ }
428
+ /**
429
+ * Enables resizing for the mobile bottom sheet.
430
+ * @returns {boolean} True if the sheet can be resized.
431
+ */
432
+ get sheetResizable() {
433
+ return this.hasAttribute("sheet-resizable") ?? false;
434
+ }
435
+ /**
436
+ * Sets resizing for the mobile bottom sheet.
437
+ * @param {boolean|string} value The value to set.
438
+ */
439
+ set sheetResizable(value) {
440
+ this.setAttribute("sheet-resizable", value);
441
+ }
442
+ /**
443
+ * Gets the mobile bottom sheet panel scope. The backdrop always covers the viewport.
444
+ * @returns {string} Either 'viewport', 'container', or 'parent'.
445
+ */
446
+ get sheetScope() {
447
+ return this.getAttribute("sheet-scope") || "viewport";
448
+ }
449
+ /**
450
+ * Sets the mobile bottom sheet panel scope.
451
+ * @param {string} value The new boundary mode for the mobile sheet.
452
+ */
453
+ set sheetScope(value) {
454
+ this.setAttribute("sheet-scope", value);
455
+ }
456
+ /**
457
+ * Gets the selector used for container-scoped mobile bottom sheet panels.
458
+ * @returns {string|null} A CSS selector used to find the composed boundary ancestor.
459
+ */
460
+ get sheetBoundary() {
461
+ return this.getAttribute("sheet-boundary");
462
+ }
463
+ /**
464
+ * Sets the selector used for container-scoped mobile bottom sheet panels.
465
+ * @param {string} value Selector for the boundary element.
466
+ */
467
+ set sheetBoundary(value) {
468
+ this.setAttribute("sheet-boundary", value);
469
+ }
470
+ /**
471
+ * Gets the mobile bottom sheet opening height.
472
+ * @returns {string|null} The opening height.
473
+ */
474
+ get sheetHeight() {
475
+ return this.getAttribute("sheet-height");
476
+ }
477
+ /**
478
+ * Sets the mobile bottom sheet opening height.
479
+ * @param {string} value The opening height.
480
+ */
481
+ set sheetHeight(value) {
482
+ this.setAttribute("sheet-height", value);
483
+ }
484
+ /**
485
+ * Gets the minimum mobile bottom sheet height while resizing.
486
+ * @returns {string|null} The minimum height.
487
+ */
488
+ get sheetMinHeight() {
489
+ return this.getAttribute("sheet-min-height");
490
+ }
491
+ /**
492
+ * Sets the minimum mobile bottom sheet height while resizing.
493
+ * @param {string} value The minimum height.
494
+ */
495
+ set sheetMinHeight(value) {
496
+ this.setAttribute("sheet-min-height", value);
497
+ }
498
+ /**
499
+ * Gets the maximum mobile bottom sheet height while resizing.
500
+ * @returns {string|null} The maximum height.
501
+ */
502
+ get sheetMaxHeight() {
503
+ return this.getAttribute("sheet-max-height");
504
+ }
505
+ /**
506
+ * Sets the maximum mobile bottom sheet height while resizing.
507
+ * @param {string} value The maximum height.
508
+ */
509
+ set sheetMaxHeight(value) {
510
+ this.setAttribute("sheet-max-height", value);
511
+ }
195
512
  /**
196
513
  * Sets the value of the 'add-to-height' attribute.
197
514
  * This attribute is used to modify or adjust the height dynamically.
@@ -220,7 +537,7 @@ class SlidingContainer extends WJElement {
220
537
  * @returns {string[]}
221
538
  */
222
539
  static get observedAttributes() {
223
- return ["max-width", "max-height", "trigger", "direction", "variant", "screen-break-point", "remove-child-after-close", "animation-duration", "animation-easing", "has-opacity"];
540
+ return ["max-width", "max-height", "trigger", "direction", "variant", "screen-break-point", "remove-child-after-close", "animation-duration", "animation-easing", "has-opacity", "mobile-presentation", "mobile-break-point", "backdrop-dismiss", "sheet-resizable", "sheet-scope", "sheet-boundary", "sheet-height", "sheet-min-height", "sheet-max-height"];
224
541
  }
225
542
  /**
226
543
  * Returns the CSS styles for the component.
@@ -244,6 +561,20 @@ class SlidingContainer extends WJElement {
244
561
  var _a, _b;
245
562
  (_a = this.animation) == null ? void 0 : _a.cancel();
246
563
  (_b = this.nativeAnimation) == null ? void 0 : _b.cancel();
564
+ this.endSheetDrag();
565
+ this.removePortalBackdrop();
566
+ document.removeEventListener(this.trigger, this.triggerEvent);
567
+ }
568
+ /**
569
+ * Cleans up global listeners and portaled layers.
570
+ */
571
+ afterDisconnect() {
572
+ var _a, _b, _c;
573
+ (_a = this.animation) == null ? void 0 : _a.cancel();
574
+ (_b = this.nativeAnimation) == null ? void 0 : _b.cancel();
575
+ this.endSheetDrag();
576
+ this.removePortalBackdrop();
577
+ (_c = this._resizeObserver) == null ? void 0 : _c.disconnect();
247
578
  document.removeEventListener(this.trigger, this.triggerEvent);
248
579
  }
249
580
  /**
@@ -255,44 +586,72 @@ class SlidingContainer extends WJElement {
255
586
  */
256
587
  draw(context, store, params) {
257
588
  let fragment = document.createDocumentFragment();
589
+ const isBottomSheet = this.isBottomSheet();
590
+ let backdrop = document.createElement("div");
591
+ backdrop.setAttribute("part", "backdrop");
592
+ backdrop.classList.add("sliding-container-backdrop");
593
+ if (this._isOpen && isBottomSheet) {
594
+ backdrop.style.opacity = "var(--wje-sliding-container-backdrop-opacity, 1)";
595
+ }
596
+ this.addBackdropListeners(backdrop);
258
597
  let wrapperDiv = document.createElement("div");
259
598
  wrapperDiv.classList.add("sliding-container-wrapper");
260
599
  let transparentDiv = document.createElement("div");
261
600
  transparentDiv.classList.add("sliding-container-transparent");
262
- if (this._isOpen) {
601
+ if (this._isOpen && !isBottomSheet) {
263
602
  transparentDiv.style.width = this.maxWidth;
264
603
  }
265
604
  let native = document.createElement("div");
266
605
  native.setAttribute("part", "sliding-container");
267
606
  native.classList.add("native-sliding-container");
268
- native.style.width = 0;
607
+ native.style.width = isBottomSheet ? "100%" : 0;
269
608
  if (this.hasOpacity) {
270
609
  native.style.opacity = 0;
271
610
  }
272
611
  if (this._isOpen) {
273
- native.style.width = this.maxWidth;
612
+ native.style.width = isBottomSheet ? "100%" : this.maxWidth;
613
+ if (isBottomSheet) {
614
+ native.style.transform = "translateY(0)";
615
+ }
274
616
  if (this.hasOpacity) {
275
617
  native.style.opacity = 1;
276
618
  }
619
+ } else if (isBottomSheet) {
620
+ native.style.transform = "translateY(100%)";
277
621
  }
278
- if (this.direction === "right") {
622
+ if (isBottomSheet) {
623
+ native.style.left = 0;
624
+ native.style.right = 0;
625
+ native.style.bottom = 0;
626
+ native.style.maxHeight = this.maxHeight;
627
+ } else if (this.direction === "right") {
279
628
  native.style.right = 0;
280
629
  } else {
281
630
  native.style.left = 0;
282
631
  }
283
- let slot = document.createElement("slot");
284
632
  const nativeInner = document.createElement("div");
285
633
  nativeInner.classList.add("native-sliding-container-inner");
286
- nativeInner.style.width = this.maxWidth;
634
+ nativeInner.style.width = isBottomSheet ? "100%" : this.maxWidth;
635
+ if (isBottomSheet) {
636
+ nativeInner.style.maxHeight = this.maxHeight;
637
+ }
638
+ let slot = document.createElement("slot");
639
+ this.sheetHandleArea = null;
287
640
  nativeInner.append(slot);
288
641
  nativeInner.append(this.htmlCloseButton());
642
+ if (this.sheetResizable) {
643
+ native.append(this.htmlSheetHandle());
644
+ }
289
645
  native.append(nativeInner);
290
646
  wrapperDiv.append(transparentDiv);
291
647
  wrapperDiv.append(native);
648
+ fragment.append(backdrop);
292
649
  fragment.append(wrapperDiv);
650
+ this.backdropElement = backdrop;
293
651
  this.transparentDiv = transparentDiv;
294
652
  this.wrapperDiv = wrapperDiv;
295
653
  this.nativeElement = native;
654
+ this.nativeInner = nativeInner;
296
655
  return fragment;
297
656
  }
298
657
  /**
@@ -304,11 +663,123 @@ class SlidingContainer extends WJElement {
304
663
  afterDraw() {
305
664
  this.syncAria();
306
665
  document.addEventListener(this.trigger, this.triggerEvent);
307
- if (this.screenBreakPoint && window.innerWidth <= this.screenBreakPoint) {
666
+ if (!this.isBottomSheet() && this.screenBreakPoint && window.innerWidth <= this.screenBreakPoint) {
308
667
  this.variant = "over";
309
668
  }
310
669
  this.checkForVariant(this.variant);
311
670
  }
671
+ /**
672
+ * Returns whether the mobile bottom sheet presentation is active.
673
+ * @returns {boolean}
674
+ */
675
+ isBottomSheet() {
676
+ return this.mobilePresentation === "bottom-sheet" && window.innerWidth <= +this.mobileBreakPoint;
677
+ }
678
+ /**
679
+ * Adds interaction listeners to a backdrop element.
680
+ * @param {HTMLElement} backdrop The backdrop element.
681
+ */
682
+ addBackdropListeners(backdrop) {
683
+ backdrop.addEventListener("wheel", this.preventBottomSheetScroll, { passive: false });
684
+ backdrop.addEventListener("touchmove", this.preventBottomSheetScroll, { passive: false });
685
+ if (!this.backdropDismiss) return;
686
+ backdrop.addEventListener("pointerdown", this.handleBackdropPointerStart);
687
+ backdrop.addEventListener("pointermove", this.handleBackdropPointerMove);
688
+ backdrop.addEventListener("pointerup", this.handleBackdropPointerEnd);
689
+ backdrop.addEventListener("pointercancel", this.handleBackdropPointerCancel);
690
+ backdrop.addEventListener("click", this.handleBackdropClick);
691
+ }
692
+ /**
693
+ * Removes interaction listeners from a backdrop element.
694
+ * @param {HTMLElement} backdrop The backdrop element.
695
+ */
696
+ removeBackdropListeners(backdrop) {
697
+ backdrop.removeEventListener("wheel", this.preventBottomSheetScroll);
698
+ backdrop.removeEventListener("touchmove", this.preventBottomSheetScroll);
699
+ backdrop.removeEventListener("pointerdown", this.handleBackdropPointerStart);
700
+ backdrop.removeEventListener("pointermove", this.handleBackdropPointerMove);
701
+ backdrop.removeEventListener("pointerup", this.handleBackdropPointerEnd);
702
+ backdrop.removeEventListener("pointercancel", this.handleBackdropPointerCancel);
703
+ backdrop.removeEventListener("click", this.handleBackdropClick);
704
+ }
705
+ /**
706
+ * Checks whether an element is one of this component's backdrop layers.
707
+ * @param {EventTarget|null} element The event target.
708
+ * @returns {boolean}
709
+ */
710
+ isBackdropElement(element) {
711
+ return element === this.backdropElement || element === this._portalBackdropElement;
712
+ }
713
+ /**
714
+ * Gets the backdrop element that is active for the current presentation.
715
+ * @param {object} options Options for resolving the backdrop.
716
+ * @param {boolean} options.createPortal Creates the body-level mobile backdrop when needed.
717
+ * @returns {HTMLElement|null}
718
+ */
719
+ getBackdropElement({ createPortal = false } = {}) {
720
+ if (!this.isBottomSheet()) return this.backdropElement;
721
+ if (createPortal) return this.ensurePortalBackdrop();
722
+ return this._portalBackdropElement || this.backdropElement;
723
+ }
724
+ /**
725
+ * Creates the body-level backdrop used by mobile bottom sheets.
726
+ * @returns {HTMLElement} Element appended to document.body for page-level dimming.
727
+ */
728
+ ensurePortalBackdrop() {
729
+ if (!this._portalBackdropElement) {
730
+ this._portalBackdropElement = document.createElement("div");
731
+ this._portalBackdropElement.setAttribute("data-wje-sliding-container-backdrop", "");
732
+ this._portalBackdropElement.classList.add("sliding-container-backdrop", "sliding-container-backdrop-portal");
733
+ this.addBackdropListeners(this._portalBackdropElement);
734
+ document.body.append(this._portalBackdropElement);
735
+ }
736
+ this.syncPortalBackdropStyles();
737
+ return this._portalBackdropElement;
738
+ }
739
+ /**
740
+ * Removes the body-level mobile backdrop.
741
+ */
742
+ removePortalBackdrop() {
743
+ if (!this._portalBackdropElement) return;
744
+ this.removeBackdropListeners(this._portalBackdropElement);
745
+ this._portalBackdropElement.remove();
746
+ this._portalBackdropElement = null;
747
+ }
748
+ /**
749
+ * Gets the full-page z-index for the body-level mobile backdrop.
750
+ * @returns {string}
751
+ */
752
+ getPortalBackdropZIndex() {
753
+ const hostStyle = getComputedStyle(this);
754
+ const configuredZIndex = hostStyle.getPropertyValue("--wje-sliding-container-portal-backdrop-z-index").trim();
755
+ if (configuredZIndex) return configuredZIndex;
756
+ const hostZIndex = Number.parseInt(hostStyle.zIndex, 10);
757
+ if (Number.isFinite(hostZIndex)) return String(hostZIndex - 1);
758
+ return "999";
759
+ }
760
+ /**
761
+ * Gets the target opacity for the active mobile backdrop.
762
+ * @returns {string}
763
+ */
764
+ getBackdropOpenOpacity() {
765
+ return getComputedStyle(this).getPropertyValue("--wje-sliding-container-backdrop-opacity").trim() || "1";
766
+ }
767
+ /**
768
+ * Syncs visual styles from the component to the body-level backdrop.
769
+ */
770
+ syncPortalBackdropStyles() {
771
+ if (!this._portalBackdropElement) return;
772
+ const backdropStyle = this.backdropElement ? getComputedStyle(this.backdropElement) : null;
773
+ this._portalBackdropElement.style.position = "fixed";
774
+ this._portalBackdropElement.style.inset = "0";
775
+ this._portalBackdropElement.style.display = "block";
776
+ this._portalBackdropElement.style.opacity = this.classList.contains("open") ? this.getBackdropOpenOpacity() : "0";
777
+ this._portalBackdropElement.style.pointerEvents = this.classList.contains("open") ? "auto" : "none";
778
+ this._portalBackdropElement.style.touchAction = "none";
779
+ this._portalBackdropElement.style.overscrollBehavior = "none";
780
+ this._portalBackdropElement.style.background = (backdropStyle == null ? void 0 : backdropStyle.background) || "rgba(0, 0, 0, .35)";
781
+ this._portalBackdropElement.style.zIndex = this.getPortalBackdropZIndex();
782
+ }
312
783
  /**
313
784
  * Sync ARIA attributes on host.
314
785
  */
@@ -341,6 +812,28 @@ class SlidingContainer extends WJElement {
341
812
  });
342
813
  return closeButton;
343
814
  }
815
+ /**
816
+ * Creates the mobile bottom sheet resize handle.
817
+ * @returns {HTMLElement} The resize handle element.
818
+ */
819
+ htmlSheetHandle() {
820
+ const handleArea = document.createElement("div");
821
+ handleArea.setAttribute("part", "sheet-handle-area");
822
+ handleArea.setAttribute("role", "separator");
823
+ handleArea.setAttribute("aria-orientation", "horizontal");
824
+ handleArea.classList.add("sliding-container-sheet-handle-area");
825
+ const handle = document.createElement("div");
826
+ handle.setAttribute("part", "sheet-handle");
827
+ handle.classList.add("sliding-container-sheet-handle");
828
+ handleArea.append(handle);
829
+ handleArea.addEventListener("pointerdown", this.handleSheetDragStart, { capture: true });
830
+ handleArea.addEventListener("touchstart", this.handleSheetTouchStart, { capture: true, passive: false });
831
+ handleArea.addEventListener("click", this.stopSheetHandleEvent, { capture: true });
832
+ handleArea.addEventListener("mousedown", this.stopSheetHandleEvent, { capture: true });
833
+ handleArea.addEventListener("mouseup", this.stopSheetHandleEvent, { capture: true });
834
+ this.sheetHandleArea = handleArea;
835
+ return handleArea;
836
+ }
344
837
  /**
345
838
  * Retrieves the parent element of the current element.
346
839
  * If the parent element is not found, it attempts to find the root host element.
@@ -353,6 +846,108 @@ class SlidingContainer extends WJElement {
353
846
  }
354
847
  return parentElement;
355
848
  }
849
+ /**
850
+ * Finds the closest element across shadow DOM boundaries.
851
+ * @param {string} selector The selector to match.
852
+ * @returns {Element|null} The matched composed ancestor.
853
+ */
854
+ getClosestComposedElement(selector) {
855
+ var _a;
856
+ let currentElement = this;
857
+ while (currentElement) {
858
+ let matches = false;
859
+ try {
860
+ matches = currentElement instanceof Element && currentElement.matches(selector);
861
+ } catch {
862
+ return null;
863
+ }
864
+ if (matches) {
865
+ return currentElement;
866
+ }
867
+ if (currentElement.parentElement) {
868
+ currentElement = currentElement.parentElement;
869
+ continue;
870
+ }
871
+ const root = (_a = currentElement.getRootNode) == null ? void 0 : _a.call(currentElement);
872
+ currentElement = root instanceof ShadowRoot ? root.host : null;
873
+ }
874
+ return null;
875
+ }
876
+ /**
877
+ * Returns the viewport frame.
878
+ * @returns {{top: number, left: number, right: number, bottom: number, width: number, height: number}}
879
+ */
880
+ getViewportFrame() {
881
+ return {
882
+ top: 0,
883
+ left: 0,
884
+ right: window.innerWidth,
885
+ bottom: window.innerHeight,
886
+ width: window.innerWidth,
887
+ height: window.innerHeight
888
+ };
889
+ }
890
+ /**
891
+ * Returns the element that bounds the mobile bottom sheet panel.
892
+ * @returns {Element|null} The scope element, or null for viewport scope.
893
+ */
894
+ getBottomSheetScopeElement() {
895
+ if (this.sheetScope === "viewport") return null;
896
+ if (this.sheetScope === "parent") return this.getParentElement();
897
+ if (this.sheetBoundary) return this.getClosestComposedElement(this.sheetBoundary);
898
+ return this.getParentElement();
899
+ }
900
+ /**
901
+ * Returns the frame used by the mobile bottom sheet panel.
902
+ * @returns {{top: number, left: number, right: number, bottom: number, width: number, height: number}}
903
+ */
904
+ getBottomSheetScopeFrame() {
905
+ const scopeElement = this.getBottomSheetScopeElement();
906
+ if (!scopeElement) return this.getViewportFrame();
907
+ const rect = scopeElement.getBoundingClientRect();
908
+ const top = Math.max(rect.top, 0);
909
+ const left = Math.max(rect.left, 0);
910
+ const right = Math.min(rect.right, window.innerWidth);
911
+ const bottom = Math.min(rect.bottom, window.innerHeight);
912
+ const width = right - left;
913
+ const height = bottom - top;
914
+ if (width <= 0 || height <= 0) {
915
+ return this.getViewportFrame();
916
+ }
917
+ return {
918
+ top,
919
+ left,
920
+ right,
921
+ bottom,
922
+ width,
923
+ height
924
+ };
925
+ }
926
+ /**
927
+ * Applies a fixed frame to a bottom sheet layer.
928
+ * @param {HTMLElement|SlidingContainer} element The element to update.
929
+ * @param {object} frame The frame to apply.
930
+ */
931
+ setBottomSheetLayerFrame(element, frame) {
932
+ element.style.top = frame.top + "px";
933
+ element.style.left = frame.left + "px";
934
+ element.style.right = "auto";
935
+ element.style.bottom = "auto";
936
+ element.style.width = frame.width + "px";
937
+ element.style.height = frame.height + "px";
938
+ }
939
+ /**
940
+ * Removes fixed frame styles from a bottom sheet layer.
941
+ * @param {HTMLElement|SlidingContainer} element The element to reset.
942
+ */
943
+ resetBottomSheetLayerFrame(element) {
944
+ element == null ? void 0 : element.style.removeProperty("top");
945
+ element == null ? void 0 : element.style.removeProperty("left");
946
+ element == null ? void 0 : element.style.removeProperty("right");
947
+ element == null ? void 0 : element.style.removeProperty("bottom");
948
+ element == null ? void 0 : element.style.removeProperty("width");
949
+ element == null ? void 0 : element.style.removeProperty("height");
950
+ }
356
951
  /**
357
952
  * Adjusts the position and dimensions of the current element based on the specified variant.
358
953
  *
@@ -362,6 +957,11 @@ class SlidingContainer extends WJElement {
362
957
  * @returns {void} No value is returned, the method modifies the element's style properties directly.
363
958
  */
364
959
  checkForVariant(variant) {
960
+ if (this.isBottomSheet()) {
961
+ this.setBottomSheetVariant();
962
+ return;
963
+ }
964
+ this.resetBottomSheetVariant();
365
965
  if (variant === "over") {
366
966
  this.style.position = "fixed";
367
967
  let computentStyleOfParent = window.getComputedStyle(this.getParentElement());
@@ -390,6 +990,246 @@ class SlidingContainer extends WJElement {
390
990
  }
391
991
  }
392
992
  }
993
+ /**
994
+ * Applies the mobile bottom sheet layout.
995
+ */
996
+ setBottomSheetVariant() {
997
+ const scopeFrame = this.getBottomSheetScopeFrame();
998
+ const backdropFrame = this.getViewportFrame();
999
+ const backdrop = this.getBackdropElement({
1000
+ createPortal: this.classList.contains("open") || this._isOpen
1001
+ });
1002
+ this._bottomSheetScopeFrame = scopeFrame;
1003
+ this.classList.add("bottom-sheet");
1004
+ this.style.position = "fixed";
1005
+ this.setBottomSheetLayerFrame(this, scopeFrame);
1006
+ this.setBottomSheetLayerFrame(backdrop, backdropFrame);
1007
+ this.setBottomSheetLayerFrame(this.wrapperDiv, scopeFrame);
1008
+ this.syncPortalBackdropStyles();
1009
+ this.wrapperDiv.style.height = "100%";
1010
+ this.transparentDiv.style.width = 0;
1011
+ this.nativeElement.style.left = scopeFrame.left + "px";
1012
+ this.nativeElement.style.right = "auto";
1013
+ this.nativeElement.style.bottom = window.innerHeight - scopeFrame.bottom + "px";
1014
+ this.nativeElement.style.top = "auto";
1015
+ this.nativeElement.style.width = scopeFrame.width + "px";
1016
+ if (this._sheetDrag) {
1017
+ this.nativeElement.style.maxHeight = this.getSheetMaxHeightInPixels() + "px";
1018
+ } else {
1019
+ this.setSheetHeight();
1020
+ }
1021
+ this.setBottomSheetVisualState(this.classList.contains("open"));
1022
+ this.nativeInner.style.width = "100%";
1023
+ this.nativeInner.style.maxHeight = this.nativeElement.style.maxHeight;
1024
+ }
1025
+ /**
1026
+ * Removes layout styles managed by the mobile bottom sheet mode.
1027
+ */
1028
+ resetBottomSheetVariant() {
1029
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
1030
+ if (!this.classList.contains("bottom-sheet")) return;
1031
+ this.classList.remove("bottom-sheet");
1032
+ this.style.removeProperty("position");
1033
+ this.resetBottomSheetLayerFrame(this);
1034
+ this.resetBottomSheetLayerFrame(this.backdropElement);
1035
+ this.removePortalBackdrop();
1036
+ this.resetBottomSheetLayerFrame(this.wrapperDiv);
1037
+ if (this.transparentDiv) {
1038
+ this.transparentDiv.style.width = this._isOpen ? this.maxWidth : 0;
1039
+ }
1040
+ (_a = this.nativeElement) == null ? void 0 : _a.style.removeProperty("left");
1041
+ (_b = this.nativeElement) == null ? void 0 : _b.style.removeProperty("right");
1042
+ (_c = this.nativeElement) == null ? void 0 : _c.style.removeProperty("bottom");
1043
+ (_d = this.nativeElement) == null ? void 0 : _d.style.removeProperty("top");
1044
+ (_e = this.nativeElement) == null ? void 0 : _e.style.removeProperty("height");
1045
+ (_f = this.nativeElement) == null ? void 0 : _f.style.removeProperty("max-height");
1046
+ (_g = this.nativeElement) == null ? void 0 : _g.style.removeProperty("transform");
1047
+ if (this.nativeElement) {
1048
+ if (this.direction === "right") {
1049
+ this.nativeElement.style.right = 0;
1050
+ } else {
1051
+ this.nativeElement.style.left = 0;
1052
+ }
1053
+ this.nativeElement.style.width = this._isOpen ? this.maxWidth : 0;
1054
+ }
1055
+ (_h = this.nativeInner) == null ? void 0 : _h.style.removeProperty("max-height");
1056
+ if (this.nativeInner) {
1057
+ this.nativeInner.style.width = this.maxWidth;
1058
+ }
1059
+ (_i = this.backdropElement) == null ? void 0 : _i.style.removeProperty("opacity");
1060
+ this._bottomSheetScopeFrame = null;
1061
+ this.endSheetDrag();
1062
+ }
1063
+ /**
1064
+ * Applies the current visual open or closed state to the mobile bottom sheet.
1065
+ * @param {boolean} isOpen True when the sheet should be visible.
1066
+ */
1067
+ setBottomSheetVisualState(isOpen) {
1068
+ this.nativeElement.style.transform = isOpen ? "translateY(0)" : "translateY(100%)";
1069
+ const backdrop = this.getBackdropElement({ createPortal: isOpen || Boolean(this._portalBackdropElement) });
1070
+ if (this.hasOpacity) {
1071
+ this.nativeElement.style.opacity = isOpen ? 1 : 0;
1072
+ }
1073
+ if (backdrop) {
1074
+ backdrop.style.opacity = isOpen ? this.getBackdropOpenOpacity() : "0";
1075
+ backdrop.style.pointerEvents = isOpen ? "auto" : "none";
1076
+ }
1077
+ if (!isOpen) {
1078
+ this.removePortalBackdrop();
1079
+ }
1080
+ }
1081
+ /**
1082
+ * Gets the CSS height limit used for the mobile bottom sheet.
1083
+ * @returns {string} The CSS max height.
1084
+ */
1085
+ getSheetMaxHeight() {
1086
+ return this.sheetMaxHeight || this.maxHeight;
1087
+ }
1088
+ /**
1089
+ * Applies the configured bottom sheet opening height.
1090
+ */
1091
+ setSheetHeight() {
1092
+ const maxHeightInPixels = this.getSheetMaxHeightInPixels();
1093
+ this.nativeElement.style.maxHeight = maxHeightInPixels + "px";
1094
+ if (!this.sheetHeight) {
1095
+ this.nativeElement.style.removeProperty("height");
1096
+ return;
1097
+ }
1098
+ const minHeight = Math.min(this.getSheetMinHeightInPixels(), maxHeightInPixels);
1099
+ const height = this.resolveCssHeight(this.sheetHeight, maxHeightInPixels);
1100
+ const clampedHeight = this.clamp(height, minHeight, maxHeightInPixels);
1101
+ this.nativeElement.style.height = clampedHeight + "px";
1102
+ }
1103
+ /**
1104
+ * Resolves the sheet minimum height in pixels.
1105
+ * @returns {number} The minimum height.
1106
+ */
1107
+ getSheetMinHeightInPixels() {
1108
+ const availableHeight = this.getBottomSheetAvailableHeight();
1109
+ return Math.min(
1110
+ this.resolveCssHeight(this.sheetMinHeight || "30vh", availableHeight * 0.3),
1111
+ availableHeight
1112
+ );
1113
+ }
1114
+ /**
1115
+ * Resolves the sheet maximum height in pixels.
1116
+ * @returns {number} The maximum height.
1117
+ */
1118
+ getSheetMaxHeightInPixels() {
1119
+ const availableHeight = this.getBottomSheetAvailableHeight();
1120
+ return Math.min(
1121
+ this.resolveCssHeight(this.getSheetMaxHeight(), availableHeight * 0.9),
1122
+ availableHeight
1123
+ );
1124
+ }
1125
+ /**
1126
+ * Returns available height for the bottom sheet scope.
1127
+ * @returns {number} Pixel height that can be used inside the current sheet frame.
1128
+ */
1129
+ getBottomSheetAvailableHeight() {
1130
+ var _a;
1131
+ return ((_a = this._bottomSheetScopeFrame) == null ? void 0 : _a.height) || this.getBottomSheetScopeFrame().height || window.innerHeight;
1132
+ }
1133
+ /**
1134
+ * Resolves a CSS height value against the viewport.
1135
+ * @param {string} value The configured sheet height.
1136
+ * @param {number} fallback The fallback height in pixels.
1137
+ * @returns {number} The resolved height.
1138
+ */
1139
+ resolveCssHeight(value, fallback) {
1140
+ if (!value || value === "auto") return fallback;
1141
+ const normalizedValue = `${value}`.trim();
1142
+ const parsedValue = Number.parseFloat(normalizedValue);
1143
+ if (Number.isNaN(parsedValue)) return fallback;
1144
+ if (normalizedValue.endsWith("px")) return parsedValue;
1145
+ if (normalizedValue.endsWith("vh")) return window.innerHeight * parsedValue / 100;
1146
+ if (normalizedValue.endsWith("vw")) return window.innerWidth * parsedValue / 100;
1147
+ if (normalizedValue.endsWith("%")) return window.innerHeight * parsedValue / 100;
1148
+ if (/^-?\d+(\.\d+)?$/.test(normalizedValue)) return parsedValue;
1149
+ return fallback;
1150
+ }
1151
+ /**
1152
+ * Clamps a number between min and max.
1153
+ * @param {number} value The measured height.
1154
+ * @param {number} min The minimum.
1155
+ * @param {number} max The maximum.
1156
+ * @returns {number} The clamped value.
1157
+ */
1158
+ clamp(value, min, max) {
1159
+ return Math.min(Math.max(value, min), max);
1160
+ }
1161
+ /**
1162
+ * Checks whether an event came from the resize handle.
1163
+ * @param {Event} e The event to check.
1164
+ * @returns {boolean} True when the event belongs to the resize handle.
1165
+ */
1166
+ isSheetHandleEvent(e) {
1167
+ if (!(e == null ? void 0 : e.composedPath)) return false;
1168
+ return e.composedPath().includes(this.sheetHandleArea);
1169
+ }
1170
+ /**
1171
+ * Checks whether an event happened inside the visible bottom sheet.
1172
+ * @param {Event} e The event to check.
1173
+ * @returns {boolean} True when the event coordinates are inside the sheet.
1174
+ */
1175
+ isEventInsideSheet(e) {
1176
+ if (!this.nativeElement || typeof (e == null ? void 0 : e.clientX) !== "number" || typeof (e == null ? void 0 : e.clientY) !== "number") return false;
1177
+ const rect = this.nativeElement.getBoundingClientRect();
1178
+ return e.clientX >= rect.left && e.clientX <= rect.right && e.clientY >= rect.top && e.clientY <= rect.bottom;
1179
+ }
1180
+ /**
1181
+ * Stores the initial drag state for the mobile bottom sheet.
1182
+ * @param {number|string} pointerId The pointer identifier.
1183
+ * @param {number} startY The starting Y coordinate.
1184
+ */
1185
+ startSheetDrag(pointerId, startY) {
1186
+ var _a, _b;
1187
+ if (this.classList.contains("open")) {
1188
+ this.setBottomSheetVisualState(true);
1189
+ }
1190
+ (_a = this.animation) == null ? void 0 : _a.cancel();
1191
+ (_b = this.nativeAnimation) == null ? void 0 : _b.cancel();
1192
+ this.animation = null;
1193
+ this.nativeAnimation = null;
1194
+ const fallbackHeight = this.resolveCssHeight(this.sheetHeight, window.innerHeight * 0.5);
1195
+ const currentHeight = this.nativeElement.getBoundingClientRect().height || fallbackHeight;
1196
+ this._sheetDrag = {
1197
+ pointerId,
1198
+ startY,
1199
+ startHeight: currentHeight,
1200
+ minHeight: this.getSheetMinHeightInPixels(),
1201
+ maxHeight: this.getSheetMaxHeightInPixels(),
1202
+ hasMoved: false
1203
+ };
1204
+ }
1205
+ /**
1206
+ * Applies a new height while the bottom sheet is being dragged.
1207
+ * @param {number} clientY The current Y coordinate.
1208
+ */
1209
+ updateSheetDrag(clientY) {
1210
+ const distance = this._sheetDrag.startY - clientY;
1211
+ if (Math.abs(distance) > 3) {
1212
+ this._sheetDrag.hasMoved = true;
1213
+ }
1214
+ const height = this.clamp(
1215
+ this._sheetDrag.startHeight + distance,
1216
+ this._sheetDrag.minHeight,
1217
+ this._sheetDrag.maxHeight
1218
+ );
1219
+ this.nativeElement.style.height = height + "px";
1220
+ }
1221
+ /**
1222
+ * Cleans up mobile bottom sheet resizing listeners.
1223
+ */
1224
+ endSheetDrag() {
1225
+ window.removeEventListener("pointermove", this.handleSheetDragMove);
1226
+ window.removeEventListener("pointerup", this.handleSheetDragEnd);
1227
+ window.removeEventListener("pointercancel", this.handleSheetDragEnd);
1228
+ window.removeEventListener("touchmove", this.handleSheetTouchMove);
1229
+ window.removeEventListener("touchend", this.handleSheetTouchEnd);
1230
+ window.removeEventListener("touchcancel", this.handleSheetTouchEnd);
1231
+ this._sheetDrag = null;
1232
+ }
393
1233
  /**
394
1234
  * Executes before the element is opened.
395
1235
  */
@@ -431,6 +1271,9 @@ class SlidingContainer extends WJElement {
431
1271
  direction: "normal",
432
1272
  easing: this.animationEasing
433
1273
  };
1274
+ if (this.isBottomSheet()) {
1275
+ return this.doAnimateBottomSheetTransition(options);
1276
+ }
434
1277
  if (this.animation && ((_b = (_a = this.animation) == null ? void 0 : _a.effect) == null ? void 0 : _b.target) !== this.transparentDiv) {
435
1278
  this.animation.cancel();
436
1279
  this.animation = null;
@@ -500,13 +1343,75 @@ class SlidingContainer extends WJElement {
500
1343
  );
501
1344
  }
502
1345
  }
503
- return new Promise((resolve, reject) => {
1346
+ return new Promise((resolve) => {
504
1347
  this.animation.onfinish = () => {
505
1348
  this._isOpen = !this._isOpen;
506
1349
  resolve();
507
1350
  };
508
1351
  });
509
1352
  }
1353
+ /**
1354
+ * Animates the mobile bottom sheet and its backdrop.
1355
+ * @param {object} options Web Animation options.
1356
+ * @returns {Promise<void>}
1357
+ */
1358
+ doAnimateBottomSheetTransition(options) {
1359
+ var _a, _b, _c, _d;
1360
+ const shouldOpen = !this._isOpen;
1361
+ const backdropElement = this.getBackdropElement({ createPortal: true });
1362
+ const closedBackdrop = {
1363
+ opacity: 0
1364
+ };
1365
+ const openBackdrop = {
1366
+ opacity: this.getBackdropOpenOpacity()
1367
+ };
1368
+ const closedSheet = {
1369
+ ...this.hasOpacity ? { opacity: 0 } : {},
1370
+ transform: "translateY(100%)"
1371
+ };
1372
+ const openSheet = {
1373
+ ...this.hasOpacity ? { opacity: 1 } : {},
1374
+ transform: "translateY(0)"
1375
+ };
1376
+ if (this.animation && ((_b = (_a = this.animation) == null ? void 0 : _a.effect) == null ? void 0 : _b.target) !== backdropElement) {
1377
+ this.animation.cancel();
1378
+ this.animation = null;
1379
+ }
1380
+ if (this.nativeAnimation && ((_d = (_c = this.nativeAnimation) == null ? void 0 : _c.effect) == null ? void 0 : _d.target) !== this.nativeElement) {
1381
+ this.nativeAnimation.cancel();
1382
+ this.nativeAnimation = null;
1383
+ }
1384
+ if (shouldOpen) {
1385
+ if (this.animation && this.nativeAnimation) {
1386
+ this.animation.reverse();
1387
+ this.nativeAnimation.reverse();
1388
+ } else {
1389
+ this.animation = backdropElement.animate([closedBackdrop, openBackdrop], options);
1390
+ this.nativeAnimation = this.nativeElement.animate([closedSheet, openSheet], options);
1391
+ }
1392
+ } else {
1393
+ if (this.animation && this.nativeAnimation) {
1394
+ this.animation.reverse();
1395
+ this.nativeAnimation.reverse();
1396
+ } else {
1397
+ this.animation = backdropElement.animate([openBackdrop, closedBackdrop], options);
1398
+ this.nativeAnimation = this.nativeElement.animate([openSheet, closedSheet], options);
1399
+ }
1400
+ }
1401
+ return new Promise((resolve) => {
1402
+ let isFinished = false;
1403
+ const finish = () => {
1404
+ if (isFinished) return;
1405
+ isFinished = true;
1406
+ this._isOpen = shouldOpen;
1407
+ this.classList.toggle("open", shouldOpen);
1408
+ this.setBottomSheetVisualState(shouldOpen);
1409
+ resolve();
1410
+ };
1411
+ this.nativeAnimation.onfinish = finish;
1412
+ this.nativeAnimation.oncancel = finish;
1413
+ });
1414
+ }
510
1415
  /**
511
1416
  * Opens the sliding container by performing necessary preparatory and transitional operations.
512
1417
  * @param {Event} e The event that triggered the open operation.
@@ -532,11 +1437,18 @@ class SlidingContainer extends WJElement {
532
1437
  * @returns {Promise<void>} A promise that resolves when the closing operation, including animations and child element removal, is completed.
533
1438
  */
534
1439
  async close(e) {
1440
+ if (this.isBottomSheet() && e instanceof Event && (this.isSheetHandleEvent(e) || this.isBackdropElement(e.target) && Date.now() < this._sheetIgnoreDismissUntil)) {
1441
+ return;
1442
+ }
535
1443
  await Promise.resolve(this.beforeClose(e)).then(async () => {
536
1444
  if (this._isOpen) {
537
1445
  this.classList.remove("open");
538
1446
  event.dispatchCustomEvent(this, "wje-sliding-container:beforeClose");
539
- await this.doAnimateTransition();
1447
+ await this.doAnimateTransition().catch(() => {
1448
+ if (this.isBottomSheet()) {
1449
+ this.setBottomSheetClosedState();
1450
+ }
1451
+ });
540
1452
  this.syncAria();
541
1453
  await Promise.resolve(this.afterClose(e)).then(() => {
542
1454
  if (this.removeChildAfterClose) {
@@ -549,6 +1461,14 @@ class SlidingContainer extends WJElement {
549
1461
  }
550
1462
  });
551
1463
  }
1464
+ /**
1465
+ * Forces the closed visual state for the mobile bottom sheet.
1466
+ */
1467
+ setBottomSheetClosedState() {
1468
+ this._isOpen = false;
1469
+ this.classList.remove("open");
1470
+ this.setBottomSheetVisualState(false);
1471
+ }
552
1472
  /**
553
1473
  * Toggles the state between open and closed.
554
1474
  * @param {Event} e The event object triggering the toggle.
@@ -556,9 +1476,9 @@ class SlidingContainer extends WJElement {
556
1476
  */
557
1477
  async toggle(e) {
558
1478
  if (this._isOpen) {
559
- await this.close(event);
1479
+ await this.close(e);
560
1480
  } else {
561
- await this.open(event);
1481
+ await this.open(e);
562
1482
  }
563
1483
  }
564
1484
  /**
@@ -568,6 +1488,8 @@ class SlidingContainer extends WJElement {
568
1488
  */
569
1489
  componentCleanup() {
570
1490
  var _a;
1491
+ this.endSheetDrag();
1492
+ this.removePortalBackdrop();
571
1493
  (_a = this._resizeObserver) == null ? void 0 : _a.disconnect();
572
1494
  this._resizeObserver = null;
573
1495
  }