@surdeddd/bottom-sheet 0.23.4 → 0.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +513 -527
- package/README.ru.md +533 -545
- package/dist/{BottomSheetCore-C5tJYVMY.d.cts → BottomSheetCore-B_r4KCQL.d.cts} +48 -13
- package/dist/{BottomSheetCore-DxSrC4QC.d.ts → BottomSheetCore-B_r4KCQL.d.ts} +48 -13
- package/dist/{BottomSheetEngine-B3F9qukX.d.cts → BottomSheetEngine-0F7mjyvF.d.cts} +1 -1
- package/dist/{BottomSheetEngine-BchzgqGG.d.ts → BottomSheetEngine-CJV_DDrM.d.ts} +1 -1
- package/dist/core.cjs +810 -436
- package/dist/core.d.cts +2 -3
- package/dist/core.d.ts +2 -3
- package/dist/core.js +810 -436
- package/dist/debug.d.cts +0 -1
- package/dist/debug.d.ts +0 -1
- package/dist/{default-features-DwVTzDwP.d.ts → default-features-4Xwv6aVt.d.ts} +4 -2
- package/dist/{default-features-BGiCSmV1.d.cts → default-features-DX2NOxP6.d.cts} +4 -2
- package/dist/element.cjs +1421 -697
- package/dist/element.d.cts +11 -3
- package/dist/element.d.ts +11 -3
- package/dist/element.iife.global.js +2 -2
- package/dist/element.js +1421 -697
- package/dist/features.cjs +334 -190
- package/dist/features.d.cts +3 -4
- package/dist/features.d.ts +3 -4
- package/dist/features.js +334 -191
- package/dist/{index-C7TSQkVK.d.cts → index-2shlxhcG.d.cts} +1 -1
- package/dist/{index-CdM1tke5.d.ts → index-CNCRQnpc.d.ts} +1 -1
- package/dist/index.cjs +1129 -631
- package/dist/index.d.cts +11 -6
- package/dist/index.d.ts +11 -6
- package/dist/index.js +1129 -632
- package/dist/integrations/formik.cjs +21 -10
- package/dist/integrations/formik.d.cts +0 -1
- package/dist/integrations/formik.d.ts +0 -1
- package/dist/integrations/formik.js +22 -11
- package/dist/integrations/react-hook-form.cjs +21 -12
- package/dist/integrations/react-hook-form.d.cts +0 -1
- package/dist/integrations/react-hook-form.d.ts +0 -1
- package/dist/integrations/react-hook-form.js +21 -12
- package/dist/option-keys-DItuAjUw.d.cts +6 -0
- package/dist/option-keys-a5DYNwwO.d.ts +6 -0
- package/dist/overlay.cjs +386 -189
- package/dist/overlay.d.cts +1 -3
- package/dist/overlay.d.ts +1 -3
- package/dist/overlay.js +386 -189
- package/dist/preact.d.cts +3 -4
- package/dist/preact.d.ts +3 -4
- package/dist/qwik-lib/index.qwik.cjs +1306 -671
- package/dist/qwik-lib/index.qwik.mjs +1306 -671
- package/dist/qwik.cjs +1326 -701
- package/dist/qwik.d.cts +12 -30
- package/dist/qwik.d.ts +12 -30
- package/dist/qwik.js +1326 -701
- package/dist/react.cjs +1373 -750
- package/dist/react.d.cts +26 -12
- package/dist/react.d.ts +26 -12
- package/dist/react.js +1375 -752
- package/dist/solid.cjs +1332 -727
- package/dist/solid.d.cts +13 -438
- package/dist/solid.d.ts +13 -438
- package/dist/solid.js +1334 -729
- package/dist/solid.source.jsx +1374 -751
- package/dist/styles.css +20 -6
- package/dist/svelte-core.cjs +1209 -676
- package/dist/svelte-core.js +1207 -677
- package/dist/svelte-src/BottomSheet.svelte +101 -58
- package/dist/svelte.cjs +1323 -705
- package/dist/svelte.d.cts +45 -25
- package/dist/svelte.d.ts +45 -25
- package/dist/svelte.js +1323 -705
- package/dist/vue.cjs +1354 -773
- package/dist/vue.d.cts +20 -3
- package/dist/vue.d.ts +20 -3
- package/dist/vue.js +1354 -773
- package/dist/webgl.cjs +38 -7
- package/dist/webgl.d.cts +0 -1
- package/dist/webgl.d.ts +0 -1
- package/dist/webgl.js +38 -7
- package/llms.txt +330 -0
- package/package.json +41 -19
- package/dist/transform-jVfAikE9.d.cts +0 -3
- package/dist/transform-jVfAikE9.d.ts +0 -3
|
@@ -5,6 +5,13 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
5
5
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
6
6
|
const jsxRuntime = require("@builder.io/qwik/jsx-runtime");
|
|
7
7
|
const qwik = require("@builder.io/qwik");
|
|
8
|
+
const STORE_KEY = /* @__PURE__ */ Symbol.for("@surdeddd/bottom-sheet/shared/1");
|
|
9
|
+
function shared(name, init) {
|
|
10
|
+
const host = globalThis;
|
|
11
|
+
const store = host[STORE_KEY] ?? (host[STORE_KEY] = {});
|
|
12
|
+
if (!(name in store)) store[name] = init();
|
|
13
|
+
return store[name];
|
|
14
|
+
}
|
|
8
15
|
const BASE_Z = 100;
|
|
9
16
|
const STEP = 10;
|
|
10
17
|
class SheetStack {
|
|
@@ -71,7 +78,7 @@ class SheetStack {
|
|
|
71
78
|
});
|
|
72
79
|
}
|
|
73
80
|
}
|
|
74
|
-
const sheetStack = new SheetStack();
|
|
81
|
+
const sheetStack = shared("stack", () => new SheetStack());
|
|
75
82
|
function buildTransformTemplate(axis) {
|
|
76
83
|
switch (axis) {
|
|
77
84
|
case "bottom":
|
|
@@ -86,7 +93,7 @@ function buildTransformTemplate(axis) {
|
|
|
86
93
|
}
|
|
87
94
|
const offsetFromMatrix = (axis, m) => axis === "bottom" ? m.m42 : axis === "top" ? -m.m42 : axis === "left" ? -m.m41 : m.m41;
|
|
88
95
|
const layoutAxis = (axis) => axis === "left" || axis === "right" ? "width" : "height";
|
|
89
|
-
const counters = {};
|
|
96
|
+
const counters = shared("instanceIds", () => ({}));
|
|
90
97
|
function nextInstanceId(prefix) {
|
|
91
98
|
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
|
92
99
|
return `${prefix}-${crypto.randomUUID()}`;
|
|
@@ -114,7 +121,13 @@ function createEventBus() {
|
|
|
114
121
|
for (const fn of [
|
|
115
122
|
...set
|
|
116
123
|
]) {
|
|
117
|
-
|
|
124
|
+
try {
|
|
125
|
+
fn(payload);
|
|
126
|
+
} catch (err) {
|
|
127
|
+
queueMicrotask(() => {
|
|
128
|
+
throw err;
|
|
129
|
+
});
|
|
130
|
+
}
|
|
118
131
|
}
|
|
119
132
|
},
|
|
120
133
|
listenerCount(event) {
|
|
@@ -125,7 +138,18 @@ function createEventBus() {
|
|
|
125
138
|
}
|
|
126
139
|
};
|
|
127
140
|
}
|
|
141
|
+
function devWarn(...args) {
|
|
142
|
+
if (typeof process !== "undefined" && process.env && process.env.NODE_ENV !== "production" && typeof console !== "undefined") {
|
|
143
|
+
console.warn(...args);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
128
146
|
let probe = null;
|
|
147
|
+
const rejected = /* @__PURE__ */ new Set();
|
|
148
|
+
const warnRejected = (value) => {
|
|
149
|
+
if (rejected.has(value)) return;
|
|
150
|
+
rejected.add(value);
|
|
151
|
+
devWarn(`[BottomSheet] snap size "${value}" is not a CSS length the browser accepts — it resolves to 0.`);
|
|
152
|
+
};
|
|
129
153
|
const PROBE_ATTR = "data-bs-probe";
|
|
130
154
|
const ensureProbe = (axis) => {
|
|
131
155
|
if (typeof document === "undefined") return null;
|
|
@@ -172,16 +196,13 @@ const resolveSnap = (point, mode, measureFit) => {
|
|
|
172
196
|
if (!el) return 0;
|
|
173
197
|
if (axis === "vertical") {
|
|
174
198
|
el.style.height = point;
|
|
199
|
+
if (el.style.height === "") warnRejected(point);
|
|
175
200
|
return Math.max(0, el.getBoundingClientRect().height);
|
|
176
201
|
}
|
|
177
202
|
el.style.width = point;
|
|
203
|
+
if (el.style.width === "") warnRejected(point);
|
|
178
204
|
return Math.max(0, el.getBoundingClientRect().width);
|
|
179
205
|
};
|
|
180
|
-
function devWarn(...args) {
|
|
181
|
-
if (typeof process !== "undefined" && process.env && process.env.NODE_ENV !== "production" && typeof console !== "undefined") {
|
|
182
|
-
console.warn(...args);
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
206
|
const resolveSnapList = (points, mode, measureFit) => points.map((p) => {
|
|
186
207
|
const raw = resolveSnap(p.size, mode, measureFit);
|
|
187
208
|
if (!Number.isFinite(raw) || raw < 0) {
|
|
@@ -196,6 +217,10 @@ const resolveSnapList = (points, mode, measureFit) => points.map((p) => {
|
|
|
196
217
|
size: raw
|
|
197
218
|
};
|
|
198
219
|
}).sort((a, b) => a.size - b.size);
|
|
220
|
+
const startsClosed = (points, initial, allowed) => {
|
|
221
|
+
const id = initial ?? allowed?.[0] ?? points[0]?.id;
|
|
222
|
+
return points.find((p) => p.id === id)?.size === 0;
|
|
223
|
+
};
|
|
199
224
|
const VH_NOT_DVH = /(^|[^a-z])vh\b/i;
|
|
200
225
|
const auditVhUsage = (points) => {
|
|
201
226
|
for (const p of points) {
|
|
@@ -306,6 +331,7 @@ class SnapResolver {
|
|
|
306
331
|
setMode(mode) {
|
|
307
332
|
if (mode === this.mode) return;
|
|
308
333
|
this.mode = mode;
|
|
334
|
+
this.notified = false;
|
|
309
335
|
this.recompute();
|
|
310
336
|
}
|
|
311
337
|
setAllowedIds(ids) {
|
|
@@ -315,14 +341,20 @@ class SnapResolver {
|
|
|
315
341
|
findById(id) {
|
|
316
342
|
return findById(id, this.resolved);
|
|
317
343
|
}
|
|
318
|
-
findDragSettleTarget(args) {
|
|
344
|
+
findDragSettleTarget(args, openOnly = false) {
|
|
319
345
|
return findDragSettleTarget({
|
|
320
346
|
...args,
|
|
321
347
|
resolved: this.resolved,
|
|
322
|
-
allowed: this.
|
|
348
|
+
allowed: this.pool(openOnly),
|
|
323
349
|
maxAxisSize: this.maxAxisSize
|
|
324
350
|
});
|
|
325
351
|
}
|
|
352
|
+
nearest(size, openOnly) {
|
|
353
|
+
return findNearest(size, this.resolved, this.pool(openOnly));
|
|
354
|
+
}
|
|
355
|
+
pool(openOnly) {
|
|
356
|
+
return openOnly ? this.allowedIds.filter((id) => (this.findById(id)?.size ?? 0) > 0) : this.allowedIds;
|
|
357
|
+
}
|
|
326
358
|
getAllowedRange() {
|
|
327
359
|
return this.rangeCache ?? (this.rangeCache = allowedRange(this.resolved, this.allowedIds));
|
|
328
360
|
}
|
|
@@ -364,22 +396,23 @@ const SIZE_WRITE_EPSILON = 0.5;
|
|
|
364
396
|
const OPACITY_WRITE_EPSILON = 5e-3;
|
|
365
397
|
const POINTER_EVENTS_OPACITY_THRESHOLD = 0.05;
|
|
366
398
|
const RANGE_DIVISION_EPSILON = 1e-4;
|
|
399
|
+
const seatOf = (deps) => {
|
|
400
|
+
const snap = deps.resolveActiveSnap();
|
|
401
|
+
const max = deps.getMaxAxisSize();
|
|
402
|
+
return {
|
|
403
|
+
target: snap ? Math.min(snap.size, max) : null,
|
|
404
|
+
max
|
|
405
|
+
};
|
|
406
|
+
};
|
|
407
|
+
const sameSeat = (before, after) => before.target !== null && after.target !== null && Math.abs(after.target - before.target) < SIZE_WRITE_EPSILON && Math.abs(after.max - before.max) < SIZE_WRITE_EPSILON;
|
|
367
408
|
function installResizeObserver(deps) {
|
|
368
409
|
if (typeof window === "undefined") {
|
|
369
410
|
return () => {
|
|
370
411
|
};
|
|
371
412
|
}
|
|
372
|
-
const seatFor = () => {
|
|
373
|
-
const snap = deps.resolveActiveSnap();
|
|
374
|
-
const max = deps.getMaxAxisSize();
|
|
375
|
-
return {
|
|
376
|
-
target: snap ? Math.min(snap.size, max) : null,
|
|
377
|
-
max
|
|
378
|
-
};
|
|
379
|
-
};
|
|
380
413
|
const onResize = () => {
|
|
381
414
|
if (deps.isDestroyed()) return;
|
|
382
|
-
const before =
|
|
415
|
+
const before = seatOf(deps);
|
|
383
416
|
deps.recomputeSnaps();
|
|
384
417
|
const mode = deps.getMode();
|
|
385
418
|
const isVerticalAxis = mode === "bottom" || mode === "top";
|
|
@@ -388,21 +421,8 @@ function installResizeObserver(deps) {
|
|
|
388
421
|
if (viewportSize2 > 0 && viewportSize2 < max) {
|
|
389
422
|
deps.setMaxAxisSize(viewportSize2);
|
|
390
423
|
}
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
return;
|
|
394
|
-
}
|
|
395
|
-
const wasAnimating = deps.isAnimating?.() ?? false;
|
|
396
|
-
deps.cancelInFlight();
|
|
397
|
-
deps.newCycle();
|
|
398
|
-
const current = deps.resolveActiveSnap();
|
|
399
|
-
const newMax = deps.getMaxAxisSize();
|
|
400
|
-
const targetSize = current ? Math.min(current.size, newMax) : Math.min(deps.getSize(), newMax);
|
|
401
|
-
deps.setSize(targetSize);
|
|
402
|
-
if (current && !deps.isDragging()) {
|
|
403
|
-
deps.applySize(targetSize);
|
|
404
|
-
if (wasAnimating) deps.resyncAfterCancel?.();
|
|
405
|
-
}
|
|
424
|
+
if (sameSeat(before, seatOf(deps))) return;
|
|
425
|
+
deps.reseat();
|
|
406
426
|
};
|
|
407
427
|
let resizeObserver = null;
|
|
408
428
|
if (typeof ResizeObserver !== "undefined") {
|
|
@@ -414,7 +434,7 @@ function installResizeObserver(deps) {
|
|
|
414
434
|
window.addEventListener("orientationchange", onResize);
|
|
415
435
|
const onVisibility = () => {
|
|
416
436
|
if (deps.isDestroyed()) return;
|
|
417
|
-
if (document.hidden) deps.
|
|
437
|
+
if (document.hidden) deps.landNow();
|
|
418
438
|
};
|
|
419
439
|
document.addEventListener("visibilitychange", onVisibility);
|
|
420
440
|
return () => {
|
|
@@ -437,6 +457,16 @@ const contentTargets = (scroller) => {
|
|
|
437
457
|
}
|
|
438
458
|
return out;
|
|
439
459
|
};
|
|
460
|
+
const chromeTargets = (deps) => {
|
|
461
|
+
const out = [];
|
|
462
|
+
for (const child of Array.from(deps.element.children)) {
|
|
463
|
+
if (child !== deps.scrollContainer) out.push(child);
|
|
464
|
+
}
|
|
465
|
+
if (deps.handle !== deps.element && !out.includes(deps.handle)) {
|
|
466
|
+
out.push(deps.handle);
|
|
467
|
+
}
|
|
468
|
+
return out;
|
|
469
|
+
};
|
|
440
470
|
function installFitObserver(deps) {
|
|
441
471
|
if (typeof ResizeObserver === "undefined") return () => {
|
|
442
472
|
};
|
|
@@ -452,7 +482,6 @@ function installFitObserver(deps) {
|
|
|
452
482
|
});
|
|
453
483
|
};
|
|
454
484
|
const ro = new ResizeObserver(schedule);
|
|
455
|
-
ro.observe(deps.handle);
|
|
456
485
|
const scroller = deps.scrollContainer;
|
|
457
486
|
const observed = /* @__PURE__ */ new Set();
|
|
458
487
|
const slots = /* @__PURE__ */ new Set();
|
|
@@ -469,7 +498,10 @@ function installFitObserver(deps) {
|
|
|
469
498
|
};
|
|
470
499
|
const resync = () => {
|
|
471
500
|
trackSlots();
|
|
472
|
-
const targets =
|
|
501
|
+
const targets = [
|
|
502
|
+
...chromeTargets(deps),
|
|
503
|
+
...contentTargets(scroller)
|
|
504
|
+
];
|
|
473
505
|
for (const el of observed) {
|
|
474
506
|
if (!targets.includes(el)) {
|
|
475
507
|
ro.unobserve(el);
|
|
@@ -484,15 +516,16 @@ function installFitObserver(deps) {
|
|
|
484
516
|
}
|
|
485
517
|
schedule();
|
|
486
518
|
};
|
|
519
|
+
resync();
|
|
487
520
|
let mo;
|
|
488
|
-
if (
|
|
489
|
-
resync
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
}
|
|
521
|
+
if (typeof MutationObserver !== "undefined") {
|
|
522
|
+
mo = new MutationObserver(resync);
|
|
523
|
+
mo.observe(deps.element, {
|
|
524
|
+
childList: true
|
|
525
|
+
});
|
|
526
|
+
if (scroller) mo.observe(scroller, {
|
|
527
|
+
childList: true
|
|
528
|
+
});
|
|
496
529
|
}
|
|
497
530
|
return () => {
|
|
498
531
|
ro.disconnect();
|
|
@@ -503,6 +536,77 @@ function installFitObserver(deps) {
|
|
|
503
536
|
if (raf) cancelAnimationFrame(raf);
|
|
504
537
|
};
|
|
505
538
|
}
|
|
539
|
+
const resolveTeleportTarget = (target) => {
|
|
540
|
+
if (!target) return null;
|
|
541
|
+
if (typeof target !== "string") return target;
|
|
542
|
+
if (typeof document === "undefined") return null;
|
|
543
|
+
if (target === "body") return document.body;
|
|
544
|
+
return document.querySelector(target);
|
|
545
|
+
};
|
|
546
|
+
const ROOT_CLASS = "bs-root";
|
|
547
|
+
const homes = /* @__PURE__ */ new WeakMap();
|
|
548
|
+
const homeRootOf = (root) => (root && homes.get(root)) ?? null;
|
|
549
|
+
const mirrorClasses = (home, wrapper) => {
|
|
550
|
+
wrapper.className = home?.className ?? "";
|
|
551
|
+
wrapper.classList.add(ROOT_CLASS);
|
|
552
|
+
};
|
|
553
|
+
const teleportElements = (els, target) => {
|
|
554
|
+
const nodes = els.filter((el) => !!el && el.parentNode !== target);
|
|
555
|
+
if (nodes.length === 0) return () => {
|
|
556
|
+
};
|
|
557
|
+
const home = nodes[0].closest(`.${ROOT_CLASS}`);
|
|
558
|
+
if (home && home.parentNode === target) return () => {
|
|
559
|
+
};
|
|
560
|
+
const wrapper = target.ownerDocument.createElement("div");
|
|
561
|
+
wrapper.setAttribute("data-bs-teleported", "");
|
|
562
|
+
mirrorClasses(home, wrapper);
|
|
563
|
+
let watcher = null;
|
|
564
|
+
if (home) {
|
|
565
|
+
for (const name of Array.from(home.style)) {
|
|
566
|
+
if (name.startsWith("--")) {
|
|
567
|
+
wrapper.style.setProperty(name, home.style.getPropertyValue(name));
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
homes.set(wrapper, home);
|
|
571
|
+
if (typeof MutationObserver !== "undefined") {
|
|
572
|
+
watcher = new MutationObserver(() => mirrorClasses(home, wrapper));
|
|
573
|
+
watcher.observe(home, {
|
|
574
|
+
attributes: true,
|
|
575
|
+
attributeFilter: [
|
|
576
|
+
"class"
|
|
577
|
+
]
|
|
578
|
+
});
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
target.appendChild(wrapper);
|
|
582
|
+
const records = [];
|
|
583
|
+
for (const el of nodes) {
|
|
584
|
+
records.push({
|
|
585
|
+
el,
|
|
586
|
+
parent: el.parentNode,
|
|
587
|
+
next: el.nextSibling
|
|
588
|
+
});
|
|
589
|
+
wrapper.appendChild(el);
|
|
590
|
+
}
|
|
591
|
+
return () => {
|
|
592
|
+
watcher?.disconnect();
|
|
593
|
+
for (let i = records.length - 1; i >= 0; i--) {
|
|
594
|
+
const { el, parent, next } = records[i];
|
|
595
|
+
if (parent && parent.isConnected) {
|
|
596
|
+
const before = next && next.parentNode === parent ? next : null;
|
|
597
|
+
try {
|
|
598
|
+
parent.insertBefore(el, before);
|
|
599
|
+
} catch {
|
|
600
|
+
el.parentNode?.removeChild(el);
|
|
601
|
+
}
|
|
602
|
+
} else {
|
|
603
|
+
el.parentNode?.removeChild(el);
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
homes.delete(wrapper);
|
|
607
|
+
wrapper.parentNode?.removeChild(wrapper);
|
|
608
|
+
};
|
|
609
|
+
};
|
|
506
610
|
function createMaxHeightController(deps) {
|
|
507
611
|
let maxHeightCap;
|
|
508
612
|
let maxHeightRaw;
|
|
@@ -591,8 +695,9 @@ function installSliderKeyboard(deps) {
|
|
|
591
695
|
const isVerticalAxis = deps.mode === "bottom" || deps.mode === "top";
|
|
592
696
|
const stepUp = isVerticalAxis ? "ArrowUp" : "ArrowRight";
|
|
593
697
|
const stepDown = isVerticalAxis ? "ArrowDown" : "ArrowLeft";
|
|
594
|
-
const
|
|
595
|
-
const
|
|
698
|
+
const flipped = deps.mode === "top" || deps.mode === "right";
|
|
699
|
+
const sheetExpandsKey = flipped ? stepDown : stepUp;
|
|
700
|
+
const sheetCollapsesKey = flipped ? stepUp : stepDown;
|
|
596
701
|
const onHandleKey = (e) => {
|
|
597
702
|
if (deps.isDestroyed()) return;
|
|
598
703
|
const allowed = deps.getAllowedIds();
|
|
@@ -674,18 +779,19 @@ class WriteSentinel {
|
|
|
674
779
|
}
|
|
675
780
|
function resolveSheetAnchoredStyle(mode, position, inset) {
|
|
676
781
|
const sizeOffset = `calc(var(--bs-size, 0px) + ${inset})`;
|
|
782
|
+
const lifted = `calc(var(--bs-size, 0px) + var(--bs-keyboard-inset, 0px) + ${inset})`;
|
|
677
783
|
switch (mode) {
|
|
678
784
|
case "bottom":
|
|
679
785
|
if (position === "sheet-top-left") return {
|
|
680
|
-
bottom:
|
|
786
|
+
bottom: lifted,
|
|
681
787
|
left: inset
|
|
682
788
|
};
|
|
683
789
|
if (position === "sheet-top-right") return {
|
|
684
|
-
bottom:
|
|
790
|
+
bottom: lifted,
|
|
685
791
|
right: inset
|
|
686
792
|
};
|
|
687
793
|
return {
|
|
688
|
-
bottom:
|
|
794
|
+
bottom: lifted,
|
|
689
795
|
left: "50%",
|
|
690
796
|
transform: "translateX(-50%)"
|
|
691
797
|
};
|
|
@@ -733,6 +839,13 @@ function resolveSheetAnchoredStyle(mode, position, inset) {
|
|
|
733
839
|
};
|
|
734
840
|
}
|
|
735
841
|
}
|
|
842
|
+
function resetOverlayPosition(ws) {
|
|
843
|
+
ws.top = "";
|
|
844
|
+
ws.bottom = "";
|
|
845
|
+
ws.left = "";
|
|
846
|
+
ws.right = "";
|
|
847
|
+
ws.transform = "";
|
|
848
|
+
}
|
|
736
849
|
function applyOverlayPosition(ws, mode, position, inset) {
|
|
737
850
|
switch (position) {
|
|
738
851
|
case "top-left":
|
|
@@ -791,6 +904,8 @@ function applyOverlayPosition(ws, mode, position, inset) {
|
|
|
791
904
|
}
|
|
792
905
|
const VALID_CSS_LENGTH = /^-?\d+(?:\.\d+)?(?:px|em|rem|%)$/;
|
|
793
906
|
const DEFAULT_SCRIM_DIM = "rgba(0, 0, 0, 0.4)";
|
|
907
|
+
const BACKDROP_COLOR_VAR = "--bs-backdrop-color";
|
|
908
|
+
const unit = (value) => Number.isFinite(value) ? Math.min(Math.max(value, 0), 1) : 1;
|
|
794
909
|
class ScrimController {
|
|
795
910
|
constructor(deps, opts) {
|
|
796
911
|
__publicField(this, "screenComponent");
|
|
@@ -805,11 +920,13 @@ class ScrimController {
|
|
|
805
920
|
__publicField(this, "scrimMode");
|
|
806
921
|
__publicField(this, "backdropRange");
|
|
807
922
|
__publicField(this, "screenRange");
|
|
923
|
+
__publicField(this, "backdropPeak");
|
|
808
924
|
__publicField(this, "scrimEnabled", true);
|
|
809
925
|
__publicField(this, "savedScrimRanges", null);
|
|
810
926
|
__publicField(this, "scrimTapToCloseEnabled", false);
|
|
811
927
|
__publicField(this, "detachScrimTap", null);
|
|
812
928
|
__publicField(this, "scrimOverlayTeardown", null);
|
|
929
|
+
__publicField(this, "placeOverlay", null);
|
|
813
930
|
__publicField(this, "backdropOpacitySentinel", new WriteSentinel());
|
|
814
931
|
__publicField(this, "screenOpacitySentinel", new WriteSentinel());
|
|
815
932
|
__publicField(this, "lastBackdropPointer", "");
|
|
@@ -832,6 +949,8 @@ class ScrimController {
|
|
|
832
949
|
0,
|
|
833
950
|
1
|
|
834
951
|
];
|
|
952
|
+
this.backdropPeak = unit(opts.backdropOpacity ?? 1);
|
|
953
|
+
this.setBackdropColor(opts.backdropColor);
|
|
835
954
|
this.scrimTapToCloseEnabled = opts.scrimTapToClose ?? false;
|
|
836
955
|
const explicitColor = opts.scrimColor ?? preset?.color;
|
|
837
956
|
const effectiveColor = explicitColor ?? (this.scrimMode !== "off" && !this.backdrop ? DEFAULT_SCRIM_DIM : void 0);
|
|
@@ -861,18 +980,19 @@ class ScrimController {
|
|
|
861
980
|
this.setScrimTapToClose(true);
|
|
862
981
|
}
|
|
863
982
|
}
|
|
864
|
-
applyOpacity(progress, progressChanged) {
|
|
865
|
-
if (!progressChanged && this.backdropOpacitySentinel.value !== -1 && this.screenOpacitySentinel.value !== -1) {
|
|
983
|
+
applyOpacity(progress, progressChanged, epsilon = OPACITY_WRITE_EPSILON) {
|
|
984
|
+
if (epsilon > 0 && !progressChanged && this.backdropOpacitySentinel.value !== -1 && this.screenOpacitySentinel.value !== -1) {
|
|
866
985
|
return;
|
|
867
986
|
}
|
|
868
987
|
if (this.backdrop) {
|
|
869
988
|
const [s, e] = this.backdropRange;
|
|
870
989
|
const range = Math.max(e - s, RANGE_DIVISION_EPSILON);
|
|
871
|
-
const
|
|
872
|
-
|
|
990
|
+
const along = Math.min(Math.max((progress - s) / range, 0), 1);
|
|
991
|
+
const backdropOpacity = along * this.backdropPeak;
|
|
992
|
+
if (this.backdropOpacitySentinel.shouldWrite(backdropOpacity, epsilon)) {
|
|
873
993
|
this.backdrop.style.opacity = String(backdropOpacity);
|
|
874
994
|
}
|
|
875
|
-
const nextPointer =
|
|
995
|
+
const nextPointer = along > POINTER_EVENTS_OPACITY_THRESHOLD ? "auto" : "none";
|
|
876
996
|
if (nextPointer !== this.lastBackdropPointer) {
|
|
877
997
|
this.backdrop.style.pointerEvents = nextPointer;
|
|
878
998
|
this.lastBackdropPointer = nextPointer;
|
|
@@ -881,7 +1001,7 @@ class ScrimController {
|
|
|
881
1001
|
if (this.screenComponent && this.scrimMode !== "off") {
|
|
882
1002
|
const [ss, se] = this.screenRange;
|
|
883
1003
|
const screenOpacity = Math.min(1, Math.max(0, (progress - ss) / Math.max(RANGE_DIVISION_EPSILON, se - ss)));
|
|
884
|
-
if (this.screenOpacitySentinel.shouldWrite(screenOpacity,
|
|
1004
|
+
if (this.screenOpacitySentinel.shouldWrite(screenOpacity, epsilon)) {
|
|
885
1005
|
this.screenComponent.style.opacity = String(screenOpacity);
|
|
886
1006
|
}
|
|
887
1007
|
const nextDisplay = screenOpacity > 0 ? "" : "none";
|
|
@@ -897,6 +1017,17 @@ class ScrimController {
|
|
|
897
1017
|
this.invalidateOpacityCache();
|
|
898
1018
|
applySize();
|
|
899
1019
|
}
|
|
1020
|
+
setBackdropColor(color) {
|
|
1021
|
+
if (this.isDestroyed() || !this.backdrop) return;
|
|
1022
|
+
if (color) this.backdrop.style.setProperty(BACKDROP_COLOR_VAR, color);
|
|
1023
|
+
else this.backdrop.style.removeProperty(BACKDROP_COLOR_VAR);
|
|
1024
|
+
}
|
|
1025
|
+
setBackdropOpacity(value, applySize) {
|
|
1026
|
+
if (this.isDestroyed()) return;
|
|
1027
|
+
this.backdropPeak = unit(value);
|
|
1028
|
+
this.invalidateOpacityCache();
|
|
1029
|
+
applySize();
|
|
1030
|
+
}
|
|
900
1031
|
setScreenRange(range, applySize) {
|
|
901
1032
|
if (this.isDestroyed()) return;
|
|
902
1033
|
this.screenRange = range;
|
|
@@ -925,6 +1056,8 @@ class ScrimController {
|
|
|
925
1056
|
if (this.isDestroyed() || mode === this.mode) return;
|
|
926
1057
|
this.mode = mode;
|
|
927
1058
|
this.invalidateOpacityCache();
|
|
1059
|
+
if (this.scrimMode === "above-sheet") this.applyAboveSheetInset();
|
|
1060
|
+
this.placeOverlay?.();
|
|
928
1061
|
}
|
|
929
1062
|
setScrimMode(mode, applySize) {
|
|
930
1063
|
if (this.isDestroyed()) return;
|
|
@@ -937,7 +1070,7 @@ class ScrimController {
|
|
|
937
1070
|
if (previous === "above-sheet" && mode !== "above-sheet") {
|
|
938
1071
|
s.position = "";
|
|
939
1072
|
s.inset = "";
|
|
940
|
-
|
|
1073
|
+
this.syncPointer();
|
|
941
1074
|
}
|
|
942
1075
|
if (mode === "above-sheet") {
|
|
943
1076
|
this.applyAboveSheetInset();
|
|
@@ -962,9 +1095,6 @@ class ScrimController {
|
|
|
962
1095
|
if (enabled === installed) return;
|
|
963
1096
|
if (enabled) {
|
|
964
1097
|
const target = this.screenComponent;
|
|
965
|
-
if (target.style.pointerEvents === "none") {
|
|
966
|
-
target.style.pointerEvents = "auto";
|
|
967
|
-
}
|
|
968
1098
|
const onClick = () => {
|
|
969
1099
|
if (this.isDestroyed()) return;
|
|
970
1100
|
if (this.closeFn) {
|
|
@@ -987,6 +1117,11 @@ class ScrimController {
|
|
|
987
1117
|
this.detachScrimTap = null;
|
|
988
1118
|
this.scrimTapToCloseEnabled = false;
|
|
989
1119
|
}
|
|
1120
|
+
this.syncPointer();
|
|
1121
|
+
}
|
|
1122
|
+
syncPointer() {
|
|
1123
|
+
if (!this.screenComponent) return;
|
|
1124
|
+
this.screenComponent.style.pointerEvents = this.scrimInteractive || this.detachScrimTap ? "auto" : "none";
|
|
990
1125
|
}
|
|
991
1126
|
setScrimEnabled(enabled, applySize) {
|
|
992
1127
|
if (this.isDestroyed()) return;
|
|
@@ -1081,8 +1216,12 @@ class ScrimController {
|
|
|
1081
1216
|
const wrapper = screen.ownerDocument.createElement("div");
|
|
1082
1217
|
wrapper.className = "bs-scrim-overlay";
|
|
1083
1218
|
const ws = wrapper.style;
|
|
1084
|
-
ws.position = "
|
|
1085
|
-
|
|
1219
|
+
ws.position = "fixed";
|
|
1220
|
+
const place = () => {
|
|
1221
|
+
resetOverlayPosition(ws);
|
|
1222
|
+
applyOverlayPosition(ws, this.mode, position, inset);
|
|
1223
|
+
};
|
|
1224
|
+
place();
|
|
1086
1225
|
if (interactive) {
|
|
1087
1226
|
ws.pointerEvents = "auto";
|
|
1088
1227
|
}
|
|
@@ -1094,8 +1233,10 @@ class ScrimController {
|
|
|
1094
1233
|
};
|
|
1095
1234
|
}
|
|
1096
1235
|
host.appendChild(wrapper);
|
|
1236
|
+
this.placeOverlay = place;
|
|
1097
1237
|
const teardown = () => {
|
|
1098
1238
|
if (wrapper.parentNode) wrapper.parentNode.removeChild(wrapper);
|
|
1239
|
+
if (this.placeOverlay === place) this.placeOverlay = null;
|
|
1099
1240
|
if (this.scrimOverlayTeardown === teardown) {
|
|
1100
1241
|
this.scrimOverlayTeardown = null;
|
|
1101
1242
|
}
|
|
@@ -1119,6 +1260,7 @@ class ScrimController {
|
|
|
1119
1260
|
if (this.backdrop) {
|
|
1120
1261
|
this.backdrop.style.opacity = "";
|
|
1121
1262
|
this.backdrop.style.pointerEvents = "";
|
|
1263
|
+
this.backdrop.style.removeProperty(BACKDROP_COLOR_VAR);
|
|
1122
1264
|
}
|
|
1123
1265
|
this.invalidateOpacityCache();
|
|
1124
1266
|
this.lastBackdropPointer = "";
|
|
@@ -1143,13 +1285,13 @@ class ScrimController {
|
|
|
1143
1285
|
}
|
|
1144
1286
|
if (opts.interactive !== void 0) {
|
|
1145
1287
|
this.scrimInteractive = opts.interactive;
|
|
1146
|
-
|
|
1288
|
+
this.syncPointer();
|
|
1147
1289
|
}
|
|
1148
1290
|
}
|
|
1149
1291
|
applyAboveSheetInset() {
|
|
1150
1292
|
if (!this.screenComponent) return;
|
|
1151
1293
|
const insetByMode = {
|
|
1152
|
-
bottom: "0 0 var(--bs-size) 0",
|
|
1294
|
+
bottom: "0 0 calc(var(--bs-size) + var(--bs-keyboard-inset, 0px)) 0",
|
|
1153
1295
|
top: "var(--bs-size) 0 0 0",
|
|
1154
1296
|
left: "0 0 0 var(--bs-size)",
|
|
1155
1297
|
right: "0 var(--bs-size) 0 0"
|
|
@@ -1157,7 +1299,7 @@ class ScrimController {
|
|
|
1157
1299
|
const s = this.screenComponent.style;
|
|
1158
1300
|
s.position = "fixed";
|
|
1159
1301
|
s.inset = insetByMode[this.mode];
|
|
1160
|
-
|
|
1302
|
+
this.syncPointer();
|
|
1161
1303
|
}
|
|
1162
1304
|
}
|
|
1163
1305
|
const easeOutBack = (t) => {
|
|
@@ -1168,14 +1310,21 @@ const easeOutBack = (t) => {
|
|
|
1168
1310
|
const easeOutCubic = (t) => 1 - Math.pow(1 - t, 3);
|
|
1169
1311
|
const easeLinear = (t) => t;
|
|
1170
1312
|
const easeOutQuint = (t) => 1 - Math.pow(1 - t, 5);
|
|
1313
|
+
const MIN_RETARGET_MS = 120;
|
|
1171
1314
|
const tween = ({ from, to, duration, easing = easeOutCubic, onUpdate }) => {
|
|
1172
1315
|
let cancelled = false;
|
|
1316
|
+
let finished = false;
|
|
1173
1317
|
let rafId = 0;
|
|
1174
1318
|
let resolveFn = null;
|
|
1175
|
-
|
|
1319
|
+
let start = performance.now();
|
|
1320
|
+
let origin = from;
|
|
1321
|
+
let target = to;
|
|
1322
|
+
let span = duration;
|
|
1323
|
+
let last = from;
|
|
1176
1324
|
const promise = new Promise((resolve) => {
|
|
1177
1325
|
resolveFn = resolve;
|
|
1178
1326
|
if (duration <= 0) {
|
|
1327
|
+
finished = true;
|
|
1179
1328
|
onUpdate(to);
|
|
1180
1329
|
resolve();
|
|
1181
1330
|
return;
|
|
@@ -1183,12 +1332,13 @@ const tween = ({ from, to, duration, easing = easeOutCubic, onUpdate }) => {
|
|
|
1183
1332
|
const step = (now) => {
|
|
1184
1333
|
if (cancelled) return;
|
|
1185
1334
|
const elapsed = Math.max(0, now - start);
|
|
1186
|
-
const t = Math.min(elapsed /
|
|
1187
|
-
|
|
1188
|
-
onUpdate(
|
|
1335
|
+
const t = Math.min(elapsed / span, 1);
|
|
1336
|
+
last = origin + (target - origin) * easing(t);
|
|
1337
|
+
onUpdate(last);
|
|
1189
1338
|
if (t < 1) {
|
|
1190
1339
|
rafId = requestAnimationFrame(step);
|
|
1191
1340
|
} else {
|
|
1341
|
+
finished = true;
|
|
1192
1342
|
resolve();
|
|
1193
1343
|
}
|
|
1194
1344
|
};
|
|
@@ -1200,6 +1350,15 @@ const tween = ({ from, to, duration, easing = easeOutCubic, onUpdate }) => {
|
|
|
1200
1350
|
cancelAnimationFrame(rafId);
|
|
1201
1351
|
resolveFn?.();
|
|
1202
1352
|
},
|
|
1353
|
+
retarget: (next) => {
|
|
1354
|
+
if (cancelled || finished || next === target) return;
|
|
1355
|
+
const now = performance.now();
|
|
1356
|
+
const remaining = span - Math.max(0, now - start);
|
|
1357
|
+
origin = last;
|
|
1358
|
+
target = next;
|
|
1359
|
+
start = now;
|
|
1360
|
+
span = Math.max(remaining, MIN_RETARGET_MS);
|
|
1361
|
+
},
|
|
1203
1362
|
promise
|
|
1204
1363
|
};
|
|
1205
1364
|
};
|
|
@@ -1215,19 +1374,28 @@ const DEFAULT_SPRING = {
|
|
|
1215
1374
|
restSpeed: 0.5
|
|
1216
1375
|
};
|
|
1217
1376
|
const MAX_DT = 1 / 30;
|
|
1218
|
-
const
|
|
1377
|
+
const MAX_DURATION_MS = 3e3;
|
|
1378
|
+
const runSpring = ({ from, to, velocity = 0, config, maxDuration = MAX_DURATION_MS, onUpdate }) => {
|
|
1219
1379
|
const cfg = {
|
|
1220
1380
|
...DEFAULT_SPRING,
|
|
1221
1381
|
...config
|
|
1222
1382
|
};
|
|
1223
1383
|
let cancelled = false;
|
|
1384
|
+
let finished = false;
|
|
1224
1385
|
let rafId = 0;
|
|
1225
1386
|
let resolveFn = null;
|
|
1226
1387
|
let x = from;
|
|
1227
1388
|
let v = velocity;
|
|
1389
|
+
let target = to;
|
|
1228
1390
|
let lastTime = performance.now();
|
|
1391
|
+
let deadline = lastTime + maxDuration;
|
|
1229
1392
|
const promise = new Promise((resolve) => {
|
|
1230
1393
|
resolveFn = resolve;
|
|
1394
|
+
const land = () => {
|
|
1395
|
+
finished = true;
|
|
1396
|
+
onUpdate(target, 0);
|
|
1397
|
+
resolve();
|
|
1398
|
+
};
|
|
1231
1399
|
const step = (now) => {
|
|
1232
1400
|
if (cancelled) return;
|
|
1233
1401
|
const dt = Math.min(Math.max(0, now - lastTime) / 1e3, MAX_DT);
|
|
@@ -1236,21 +1404,19 @@ const runSpring = ({ from, to, velocity = 0, config, onUpdate }) => {
|
|
|
1236
1404
|
const subDt = dt / steps;
|
|
1237
1405
|
let stepsLeft = steps;
|
|
1238
1406
|
while (stepsLeft-- > 0) {
|
|
1239
|
-
const force = -cfg.stiffness * (x -
|
|
1407
|
+
const force = -cfg.stiffness * (x - target) - cfg.damping * v;
|
|
1240
1408
|
const accel = force / cfg.mass;
|
|
1241
1409
|
v += accel * subDt;
|
|
1242
1410
|
x += v * subDt;
|
|
1243
1411
|
}
|
|
1244
|
-
if (!Number.isFinite(x) || !Number.isFinite(v)) {
|
|
1245
|
-
|
|
1246
|
-
resolve();
|
|
1412
|
+
if (!Number.isFinite(x) || !Number.isFinite(v) || lastTime >= deadline) {
|
|
1413
|
+
land();
|
|
1247
1414
|
return;
|
|
1248
1415
|
}
|
|
1249
1416
|
onUpdate(x, v);
|
|
1250
|
-
const isAtRest = Math.abs(
|
|
1417
|
+
const isAtRest = Math.abs(target - x) < (cfg.restDelta ?? 0.5) && Math.abs(v) < (cfg.restSpeed ?? 0.5);
|
|
1251
1418
|
if (isAtRest) {
|
|
1252
|
-
|
|
1253
|
-
resolve();
|
|
1419
|
+
land();
|
|
1254
1420
|
} else {
|
|
1255
1421
|
rafId = requestAnimationFrame(step);
|
|
1256
1422
|
}
|
|
@@ -1263,6 +1429,11 @@ const runSpring = ({ from, to, velocity = 0, config, onUpdate }) => {
|
|
|
1263
1429
|
cancelAnimationFrame(rafId);
|
|
1264
1430
|
resolveFn?.();
|
|
1265
1431
|
},
|
|
1432
|
+
retarget: (next) => {
|
|
1433
|
+
if (cancelled || finished) return;
|
|
1434
|
+
target = next;
|
|
1435
|
+
deadline = performance.now() + maxDuration;
|
|
1436
|
+
},
|
|
1266
1437
|
promise
|
|
1267
1438
|
};
|
|
1268
1439
|
};
|
|
@@ -1436,21 +1607,40 @@ class AnimationRunner {
|
|
|
1436
1607
|
this.applySizeFn(size);
|
|
1437
1608
|
}
|
|
1438
1609
|
cancel() {
|
|
1439
|
-
this.currentTween
|
|
1440
|
-
this.currentSpring
|
|
1610
|
+
const tween2 = this.currentTween;
|
|
1611
|
+
const spring = this.currentSpring;
|
|
1612
|
+
this.currentTween = null;
|
|
1613
|
+
this.currentSpring = null;
|
|
1614
|
+
tween2?.cancel();
|
|
1615
|
+
spring?.cancel();
|
|
1441
1616
|
this.cancelWaapi();
|
|
1442
1617
|
}
|
|
1618
|
+
retarget(target) {
|
|
1619
|
+
if (this.currentSpring) {
|
|
1620
|
+
this.currentSpring.retarget(target);
|
|
1621
|
+
return true;
|
|
1622
|
+
}
|
|
1623
|
+
if (this.currentTween) {
|
|
1624
|
+
this.currentTween.retarget(target);
|
|
1625
|
+
return true;
|
|
1626
|
+
}
|
|
1627
|
+
if (this.currentWaapi) {
|
|
1628
|
+
this.currentWaapi.retarget(target);
|
|
1629
|
+
return true;
|
|
1630
|
+
}
|
|
1631
|
+
return false;
|
|
1632
|
+
}
|
|
1443
1633
|
async animateTo(target, velocityPxPerMs) {
|
|
1444
1634
|
if (target === this.getSize()) {
|
|
1445
|
-
if (
|
|
1635
|
+
if (this.isAnimating) this.cancel();
|
|
1636
|
+
if (!this.isDragging()) {
|
|
1446
1637
|
this.applySizeFn(target);
|
|
1638
|
+
this.getRootEl()?.removeAttribute("data-animating");
|
|
1447
1639
|
this.element.style.willChange = "";
|
|
1448
1640
|
}
|
|
1449
1641
|
return;
|
|
1450
1642
|
}
|
|
1451
|
-
this.
|
|
1452
|
-
this.currentSpring?.cancel();
|
|
1453
|
-
this.cancelWaapi();
|
|
1643
|
+
this.cancel();
|
|
1454
1644
|
this.getRootEl()?.setAttribute("data-animating", "true");
|
|
1455
1645
|
this.element.style.willChange = "transform";
|
|
1456
1646
|
if (this.reducedMotion) {
|
|
@@ -1460,9 +1650,12 @@ class AnimationRunner {
|
|
|
1460
1650
|
return;
|
|
1461
1651
|
}
|
|
1462
1652
|
if (this.settleWaapi && this.applyAux && this.getTransformFor && typeof this.element.animate === "function") {
|
|
1463
|
-
const samples = this.
|
|
1653
|
+
const samples = this.sampleSettle(this.getSize(), target, velocityPxPerMs * VELOCITY_PX_PER_S);
|
|
1464
1654
|
if (samples.values.length >= 2 && samples.durationMs > 0) {
|
|
1465
|
-
await this.runWaapiSettle(
|
|
1655
|
+
await this.runWaapiSettle({
|
|
1656
|
+
samples,
|
|
1657
|
+
target
|
|
1658
|
+
});
|
|
1466
1659
|
if (!this.isAnimating) {
|
|
1467
1660
|
this.getRootEl()?.removeAttribute("data-animating");
|
|
1468
1661
|
if (!this.isDragging()) this.element.style.willChange = "";
|
|
@@ -1504,7 +1697,10 @@ class AnimationRunner {
|
|
|
1504
1697
|
}
|
|
1505
1698
|
}
|
|
1506
1699
|
}
|
|
1507
|
-
|
|
1700
|
+
sampleSettle(from, to, velocityPxPerS) {
|
|
1701
|
+
return this.animationKind === "spring" ? sampleSpringSettle(from, to, velocityPxPerS, this.springConfig) : sampleTweenSettle(from, to, this.duration, this.easing);
|
|
1702
|
+
}
|
|
1703
|
+
startWaapiLeg(samples, onRetarget) {
|
|
1508
1704
|
const applyAux = this.applyAux;
|
|
1509
1705
|
const getTransformFor = this.getTransformFor;
|
|
1510
1706
|
const frames = samples.values.map((v) => ({
|
|
@@ -1519,13 +1715,20 @@ class AnimationRunner {
|
|
|
1519
1715
|
let stopped = false;
|
|
1520
1716
|
let auxRaf = 0;
|
|
1521
1717
|
const lastIdx = samples.values.length - 1;
|
|
1718
|
+
const cursor = () => Math.min((Number(anim.currentTime) || 0) / samples.stepMs, lastIdx);
|
|
1522
1719
|
const sizeNow = () => {
|
|
1523
|
-
const at =
|
|
1720
|
+
const at = cursor();
|
|
1524
1721
|
const idx = Math.floor(at);
|
|
1525
1722
|
const from = samples.values[idx];
|
|
1526
1723
|
const to = samples.values[Math.min(idx + 1, lastIdx)];
|
|
1527
1724
|
return from + (to - from) * (at - idx);
|
|
1528
1725
|
};
|
|
1726
|
+
const velocityNow = () => {
|
|
1727
|
+
const idx = Math.min(Math.floor(cursor()), Math.max(lastIdx - 1, 0));
|
|
1728
|
+
const from = samples.values[idx];
|
|
1729
|
+
const to = samples.values[Math.min(idx + 1, lastIdx)];
|
|
1730
|
+
return (to - from) / samples.stepMs * 1e3;
|
|
1731
|
+
};
|
|
1529
1732
|
const auxTick = () => {
|
|
1530
1733
|
if (stopped) return;
|
|
1531
1734
|
applyAux(sizeNow());
|
|
@@ -1538,22 +1741,55 @@ class AnimationRunner {
|
|
|
1538
1741
|
stopped = true;
|
|
1539
1742
|
cancelAnimationFrame(auxRaf);
|
|
1540
1743
|
},
|
|
1541
|
-
sizeNow
|
|
1744
|
+
sizeNow,
|
|
1745
|
+
velocityNow,
|
|
1746
|
+
retarget: (to) => onRetarget(entry, to)
|
|
1542
1747
|
};
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1748
|
+
return entry;
|
|
1749
|
+
}
|
|
1750
|
+
async runWaapiSettle(first) {
|
|
1751
|
+
let leg = first;
|
|
1752
|
+
for (; ; ) {
|
|
1753
|
+
let queued = null;
|
|
1754
|
+
const entry = this.startWaapiLeg(leg.samples, (running, to) => {
|
|
1755
|
+
const size = this.readShownSize?.() ?? running.sizeNow();
|
|
1756
|
+
queued = {
|
|
1757
|
+
samples: this.sampleSettle(size, to, running.velocityNow()),
|
|
1758
|
+
target: to
|
|
1759
|
+
};
|
|
1760
|
+
running.stop();
|
|
1761
|
+
try {
|
|
1762
|
+
running.anim.cancel();
|
|
1763
|
+
} catch {
|
|
1764
|
+
}
|
|
1765
|
+
this.applySizeFn(size);
|
|
1766
|
+
});
|
|
1767
|
+
this.currentWaapi = entry;
|
|
1553
1768
|
try {
|
|
1554
|
-
anim.
|
|
1769
|
+
await entry.anim.finished;
|
|
1555
1770
|
} catch {
|
|
1556
1771
|
}
|
|
1772
|
+
entry.stop();
|
|
1773
|
+
const wasCurrent = this.currentWaapi === entry;
|
|
1774
|
+
const next = queued;
|
|
1775
|
+
if (wasCurrent && next) {
|
|
1776
|
+
if (next.samples.values.length >= 2 && next.samples.durationMs > 0) {
|
|
1777
|
+
leg = next;
|
|
1778
|
+
continue;
|
|
1779
|
+
}
|
|
1780
|
+
this.currentWaapi = null;
|
|
1781
|
+
this.applySizeFn(next.target);
|
|
1782
|
+
return;
|
|
1783
|
+
}
|
|
1784
|
+
if (wasCurrent) this.currentWaapi = null;
|
|
1785
|
+
if (wasCurrent && entry.anim.playState === "finished") {
|
|
1786
|
+
this.applySizeFn(leg.target);
|
|
1787
|
+
try {
|
|
1788
|
+
entry.anim.cancel();
|
|
1789
|
+
} catch {
|
|
1790
|
+
}
|
|
1791
|
+
}
|
|
1792
|
+
return;
|
|
1557
1793
|
}
|
|
1558
1794
|
}
|
|
1559
1795
|
destroy() {
|
|
@@ -1607,27 +1843,51 @@ const collectFocusables = (root) => {
|
|
|
1607
1843
|
return out;
|
|
1608
1844
|
};
|
|
1609
1845
|
const focusables = (root) => collectFocusables(root).filter((el) => !el.hasAttribute("inert") && isVisible(el) && !el.matches("[aria-hidden='true']"));
|
|
1846
|
+
const findDeep = (root, selector) => {
|
|
1847
|
+
const direct = root.querySelector(selector);
|
|
1848
|
+
if (direct || typeof HTMLSlotElement === "undefined") return direct;
|
|
1849
|
+
for (const slot of Array.from(root.querySelectorAll("slot"))) {
|
|
1850
|
+
for (const assigned of slot.assignedElements()) {
|
|
1851
|
+
if (assigned.matches(selector)) return assigned;
|
|
1852
|
+
const inner = findDeep(assigned, selector);
|
|
1853
|
+
if (inner) return inner;
|
|
1854
|
+
}
|
|
1855
|
+
}
|
|
1856
|
+
return null;
|
|
1857
|
+
};
|
|
1858
|
+
const FOCUS_ALLOW_ATTR = "data-bs-focus-allow";
|
|
1859
|
+
const composedParent = (node) => {
|
|
1860
|
+
const slot = node.assignedSlot;
|
|
1861
|
+
if (slot) return slot;
|
|
1862
|
+
const parent = node.parentNode;
|
|
1863
|
+
return parent instanceof ShadowRoot ? parent.host : parent;
|
|
1864
|
+
};
|
|
1610
1865
|
const containsComposed = (container, node) => {
|
|
1611
|
-
let n = node;
|
|
1612
|
-
while (n) {
|
|
1866
|
+
for (let n = node; n; n = composedParent(n)) {
|
|
1613
1867
|
if (n === container) return true;
|
|
1614
|
-
const slot = n.assignedSlot;
|
|
1615
|
-
if (slot) {
|
|
1616
|
-
n = slot;
|
|
1617
|
-
continue;
|
|
1618
|
-
}
|
|
1619
|
-
const parent = n.parentNode;
|
|
1620
|
-
n = parent instanceof ShadowRoot ? parent.host : parent;
|
|
1621
1868
|
}
|
|
1622
1869
|
return false;
|
|
1623
1870
|
};
|
|
1624
|
-
const
|
|
1871
|
+
const isAllowedOutside = (node) => {
|
|
1872
|
+
for (let n = node; n; n = composedParent(n)) {
|
|
1873
|
+
if (n instanceof Element && n.hasAttribute(FOCUS_ALLOW_ATTR)) return true;
|
|
1874
|
+
}
|
|
1875
|
+
return false;
|
|
1876
|
+
};
|
|
1877
|
+
const deepActiveElement = () => {
|
|
1878
|
+
let active = document.activeElement;
|
|
1879
|
+
while (active?.shadowRoot?.activeElement) {
|
|
1880
|
+
active = active.shadowRoot.activeElement;
|
|
1881
|
+
}
|
|
1882
|
+
return active;
|
|
1883
|
+
};
|
|
1884
|
+
const trapStack = shared("focusTraps", () => []);
|
|
1625
1885
|
const installFocusTrap = (container, options = {}) => {
|
|
1626
1886
|
if (typeof document === "undefined") return () => {
|
|
1627
1887
|
};
|
|
1628
1888
|
const token = {};
|
|
1629
|
-
trapStack.push(token);
|
|
1630
|
-
const isActive = () => trapStack[trapStack.length - 1] === token;
|
|
1889
|
+
if (!options.isActive) trapStack.push(token);
|
|
1890
|
+
const isActive = options.isActive ?? (() => trapStack[trapStack.length - 1] === token);
|
|
1631
1891
|
const previouslyFocused = document.activeElement;
|
|
1632
1892
|
const focusInitial = () => {
|
|
1633
1893
|
const spec = options.initialFocus;
|
|
@@ -1638,12 +1898,13 @@ const installFocusTrap = (container, options = {}) => {
|
|
|
1638
1898
|
});
|
|
1639
1899
|
return;
|
|
1640
1900
|
}
|
|
1641
|
-
const initial = typeof spec === "string" ? container
|
|
1901
|
+
const initial = typeof spec === "string" ? findDeep(container, spec) : spec ?? focusables(container)[0] ?? container;
|
|
1642
1902
|
initial?.focus({
|
|
1643
1903
|
preventScroll: true
|
|
1644
1904
|
});
|
|
1645
1905
|
};
|
|
1646
|
-
focusInitial();
|
|
1906
|
+
if (!containsComposed(container, deepActiveElement())) focusInitial();
|
|
1907
|
+
let backwards = false;
|
|
1647
1908
|
const handleKey = (e) => {
|
|
1648
1909
|
if (!isActive()) return;
|
|
1649
1910
|
if (e.key === "Escape" && options.onEscape) {
|
|
@@ -1651,6 +1912,10 @@ const installFocusTrap = (container, options = {}) => {
|
|
|
1651
1912
|
return;
|
|
1652
1913
|
}
|
|
1653
1914
|
if (e.key !== "Tab") return;
|
|
1915
|
+
backwards = e.shiftKey;
|
|
1916
|
+
setTimeout(() => {
|
|
1917
|
+
backwards = false;
|
|
1918
|
+
}, 0);
|
|
1654
1919
|
const list = focusables(container);
|
|
1655
1920
|
if (list.length === 0) {
|
|
1656
1921
|
e.preventDefault();
|
|
@@ -1658,7 +1923,7 @@ const installFocusTrap = (container, options = {}) => {
|
|
|
1658
1923
|
}
|
|
1659
1924
|
const first = list[0];
|
|
1660
1925
|
const last = list[list.length - 1];
|
|
1661
|
-
const active =
|
|
1926
|
+
const active = deepActiveElement();
|
|
1662
1927
|
if (e.shiftKey && active === first) {
|
|
1663
1928
|
e.preventDefault();
|
|
1664
1929
|
last.focus();
|
|
@@ -1669,13 +1934,13 @@ const installFocusTrap = (container, options = {}) => {
|
|
|
1669
1934
|
};
|
|
1670
1935
|
const handleFocusIn = (e) => {
|
|
1671
1936
|
if (!isActive()) return;
|
|
1672
|
-
const target = e.target;
|
|
1673
|
-
if (target
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
}
|
|
1937
|
+
const target = e.composedPath()[0] ?? e.target;
|
|
1938
|
+
if (!target || containsComposed(container, target)) return;
|
|
1939
|
+
if (isAllowedOutside(target)) return;
|
|
1940
|
+
const list = focusables(container);
|
|
1941
|
+
list[backwards ? list.length - 1 : 0]?.focus({
|
|
1942
|
+
preventScroll: true
|
|
1943
|
+
});
|
|
1679
1944
|
};
|
|
1680
1945
|
document.addEventListener("keydown", handleKey, true);
|
|
1681
1946
|
document.addEventListener("focusin", handleFocusIn, true);
|
|
@@ -1699,21 +1964,25 @@ const installFocusTrap = (container, options = {}) => {
|
|
|
1699
1964
|
}
|
|
1700
1965
|
};
|
|
1701
1966
|
};
|
|
1702
|
-
|
|
1703
|
-
|
|
1967
|
+
const state$1 = shared("scrollLock", () => ({
|
|
1968
|
+
count: 0,
|
|
1969
|
+
saved: null
|
|
1970
|
+
}));
|
|
1704
1971
|
const lockBodyScroll = () => {
|
|
1705
1972
|
if (typeof document === "undefined") return () => {
|
|
1706
1973
|
};
|
|
1707
|
-
if (
|
|
1974
|
+
if (state$1.count === 0) {
|
|
1708
1975
|
const body = document.body;
|
|
1709
|
-
|
|
1976
|
+
const saved = {
|
|
1710
1977
|
overflow: body.style.overflow,
|
|
1711
1978
|
position: body.style.position,
|
|
1712
1979
|
top: body.style.top,
|
|
1713
1980
|
width: body.style.width,
|
|
1714
1981
|
paddingRight: body.style.paddingRight,
|
|
1982
|
+
scrollX: window.scrollX,
|
|
1715
1983
|
scrollY: window.scrollY
|
|
1716
1984
|
};
|
|
1985
|
+
state$1.saved = saved;
|
|
1717
1986
|
const scrollbarGap = window.innerWidth - document.documentElement.clientWidth;
|
|
1718
1987
|
if (scrollbarGap > 0) {
|
|
1719
1988
|
const current = parseFloat(getComputedStyle(body).paddingRight) || 0;
|
|
@@ -1721,56 +1990,76 @@ const lockBodyScroll = () => {
|
|
|
1721
1990
|
}
|
|
1722
1991
|
body.style.overflow = "hidden";
|
|
1723
1992
|
body.style.position = "fixed";
|
|
1724
|
-
body.style.top = `-${
|
|
1993
|
+
body.style.top = `-${saved.scrollY}px`;
|
|
1725
1994
|
body.style.width = "100%";
|
|
1726
1995
|
}
|
|
1727
|
-
|
|
1996
|
+
state$1.count++;
|
|
1728
1997
|
let released = false;
|
|
1729
1998
|
return () => {
|
|
1730
1999
|
if (released) return;
|
|
1731
2000
|
released = true;
|
|
1732
|
-
|
|
1733
|
-
if (
|
|
2001
|
+
state$1.count = Math.max(0, state$1.count - 1);
|
|
2002
|
+
if (state$1.count === 0 && state$1.saved) {
|
|
1734
2003
|
const body = document.body;
|
|
1735
|
-
|
|
1736
|
-
body.style.
|
|
1737
|
-
body.style.
|
|
1738
|
-
body.style.
|
|
1739
|
-
body.style.
|
|
1740
|
-
|
|
1741
|
-
|
|
2004
|
+
const saved = state$1.saved;
|
|
2005
|
+
body.style.overflow = saved.overflow;
|
|
2006
|
+
body.style.position = saved.position;
|
|
2007
|
+
body.style.top = saved.top;
|
|
2008
|
+
body.style.width = saved.width;
|
|
2009
|
+
body.style.paddingRight = saved.paddingRight;
|
|
2010
|
+
window.scrollTo({
|
|
2011
|
+
top: saved.scrollY,
|
|
2012
|
+
left: saved.scrollX,
|
|
2013
|
+
behavior: "instant"
|
|
2014
|
+
});
|
|
2015
|
+
state$1.saved = null;
|
|
1742
2016
|
}
|
|
1743
2017
|
};
|
|
1744
2018
|
};
|
|
2019
|
+
const OWN_ROOTS = ".bs-root, .ovl-root";
|
|
2020
|
+
const LAYER_CLASSES = [
|
|
2021
|
+
"bs-backdrop",
|
|
2022
|
+
"bs-screen",
|
|
2023
|
+
"bs-root",
|
|
2024
|
+
"ovl-backdrop",
|
|
2025
|
+
"ovl-root"
|
|
2026
|
+
];
|
|
2027
|
+
const isLayer = (el) => LAYER_CLASSES.some((name) => el.classList.contains(name));
|
|
1745
2028
|
function createInertSiblings(rootProvider) {
|
|
1746
2029
|
const tracked = [];
|
|
2030
|
+
const remove = () => {
|
|
2031
|
+
for (const el of tracked) el.removeAttribute("inert");
|
|
2032
|
+
tracked.length = 0;
|
|
2033
|
+
};
|
|
1747
2034
|
return {
|
|
1748
2035
|
apply() {
|
|
1749
2036
|
if (typeof document === "undefined") return;
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
if (child.classList.contains("bs-backdrop") || child.classList.contains("bs-screen") || child.classList.contains("bs-root")) {
|
|
2037
|
+
remove();
|
|
2038
|
+
const surface = rootProvider();
|
|
2039
|
+
let node = surface.closest(OWN_ROOTS) ?? surface;
|
|
2040
|
+
while (node && node !== document.body) {
|
|
2041
|
+
const parent = node.parentElement;
|
|
2042
|
+
if (!parent) {
|
|
2043
|
+
const root = node.getRootNode();
|
|
2044
|
+
node = typeof ShadowRoot !== "undefined" && root instanceof ShadowRoot ? root.host : null;
|
|
1759
2045
|
continue;
|
|
1760
2046
|
}
|
|
1761
|
-
|
|
1762
|
-
|
|
2047
|
+
for (const sibling of Array.from(parent.children)) {
|
|
2048
|
+
if (sibling === node) continue;
|
|
2049
|
+
if (sibling.hasAttribute("inert") || isLayer(sibling)) continue;
|
|
2050
|
+
sibling.setAttribute("inert", "");
|
|
2051
|
+
tracked.push(sibling);
|
|
2052
|
+
}
|
|
2053
|
+
node = parent;
|
|
1763
2054
|
}
|
|
1764
2055
|
},
|
|
1765
|
-
remove
|
|
1766
|
-
for (const el of tracked) el.removeAttribute("inert");
|
|
1767
|
-
tracked.length = 0;
|
|
1768
|
-
}
|
|
2056
|
+
remove
|
|
1769
2057
|
};
|
|
1770
2058
|
}
|
|
1771
2059
|
class LifecycleController {
|
|
1772
2060
|
constructor(deps, opts) {
|
|
1773
2061
|
__publicField(this, "element");
|
|
2062
|
+
__publicField(this, "isTop");
|
|
1774
2063
|
__publicField(this, "focusTrapEnabled");
|
|
1775
2064
|
__publicField(this, "initialFocus");
|
|
1776
2065
|
__publicField(this, "closeOnEscape");
|
|
@@ -1784,6 +2073,7 @@ class LifecycleController {
|
|
|
1784
2073
|
__publicField(this, "installed", false);
|
|
1785
2074
|
__publicField(this, "destroyed", false);
|
|
1786
2075
|
this.element = deps.element;
|
|
2076
|
+
this.isTop = deps.isTop;
|
|
1787
2077
|
this.focusTrapEnabled = opts.focusTrap ?? false;
|
|
1788
2078
|
this.initialFocus = opts.initialFocus;
|
|
1789
2079
|
this.closeOnEscape = opts.closeOnEscape ?? true;
|
|
@@ -1804,12 +2094,17 @@ class LifecycleController {
|
|
|
1804
2094
|
}
|
|
1805
2095
|
if (this.focusTrapEnabled && !this.releaseFocusTrap) {
|
|
1806
2096
|
this.releaseFocusTrap = installFocusTrap(this.element, {
|
|
1807
|
-
initialFocus: this.initialFocus
|
|
2097
|
+
initialFocus: this.initialFocus,
|
|
2098
|
+
isActive: this.isTop
|
|
1808
2099
|
});
|
|
1809
2100
|
}
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
2101
|
+
this.syncTop();
|
|
2102
|
+
}
|
|
2103
|
+
syncTop() {
|
|
2104
|
+
if (!this.installed || !this.inertSiblingsEnabled) return;
|
|
2105
|
+
if (!this.shouldApplyInertSiblings()) return;
|
|
2106
|
+
if (this.isTop?.() ?? true) this.inertSiblings.apply();
|
|
2107
|
+
else this.inertSiblings.remove();
|
|
1813
2108
|
}
|
|
1814
2109
|
setReturnFocus(target) {
|
|
1815
2110
|
if (this.destroyed) return;
|
|
@@ -1980,10 +2275,14 @@ const installGestures = (handle, mode, callbacks, options = {}) => {
|
|
|
1980
2275
|
if (wasPending) return;
|
|
1981
2276
|
callbacks.onCancel?.();
|
|
1982
2277
|
};
|
|
2278
|
+
const onLostCapture = (e) => {
|
|
2279
|
+
if (e.target === handle) onPointerCancel(e);
|
|
2280
|
+
};
|
|
1983
2281
|
handle.addEventListener("pointerdown", onPointerDown);
|
|
1984
2282
|
handle.addEventListener("pointermove", onPointerMove);
|
|
1985
2283
|
handle.addEventListener("pointerup", finishGesture);
|
|
1986
2284
|
handle.addEventListener("pointercancel", onPointerCancel);
|
|
2285
|
+
handle.addEventListener("lostpointercapture", onLostCapture);
|
|
1987
2286
|
const managesTouchAction = options.manageTouchAction !== false;
|
|
1988
2287
|
const prevTouchAction = handle.style.touchAction;
|
|
1989
2288
|
if (managesTouchAction) {
|
|
@@ -1994,6 +2293,7 @@ const installGestures = (handle, mode, callbacks, options = {}) => {
|
|
|
1994
2293
|
handle.removeEventListener("pointermove", onPointerMove);
|
|
1995
2294
|
handle.removeEventListener("pointerup", finishGesture);
|
|
1996
2295
|
handle.removeEventListener("pointercancel", onPointerCancel);
|
|
2296
|
+
handle.removeEventListener("lostpointercapture", onLostCapture);
|
|
1997
2297
|
if (managesTouchAction) handle.style.touchAction = prevTouchAction;
|
|
1998
2298
|
if (activePointerId !== null && handle.hasPointerCapture(activePointerId)) {
|
|
1999
2299
|
handle.releasePointerCapture(activePointerId);
|
|
@@ -2109,8 +2409,7 @@ class GestureController {
|
|
|
2109
2409
|
size: this.deps.getDragContext().size,
|
|
2110
2410
|
velocity: 0
|
|
2111
2411
|
});
|
|
2112
|
-
|
|
2113
|
-
void this.deps.animateTo(restoreTo, 0);
|
|
2412
|
+
this.deps.restoreAfterDrag();
|
|
2114
2413
|
}
|
|
2115
2414
|
}, this.deps.gestureOptions);
|
|
2116
2415
|
return this.detach;
|
|
@@ -2169,6 +2468,11 @@ const readDirection = (el) => {
|
|
|
2169
2468
|
}
|
|
2170
2469
|
return "ltr";
|
|
2171
2470
|
};
|
|
2471
|
+
const guessPhysicalMode = (mode) => {
|
|
2472
|
+
if (mode === "start") return "left";
|
|
2473
|
+
if (mode === "end") return "right";
|
|
2474
|
+
return mode ?? "bottom";
|
|
2475
|
+
};
|
|
2172
2476
|
const resolveMode = (mode, el) => {
|
|
2173
2477
|
if (!isLogicalMode(mode)) return mode;
|
|
2174
2478
|
const rtl = readDirection(el) === "rtl";
|
|
@@ -2215,22 +2519,24 @@ function createScrollCache(deps) {
|
|
|
2215
2519
|
return size < max / 2;
|
|
2216
2520
|
};
|
|
2217
2521
|
return {
|
|
2218
|
-
|
|
2522
|
+
leave(fromId, prevSize, nextSize) {
|
|
2219
2523
|
const container = deps.scrollContainer;
|
|
2220
2524
|
if (!container) return;
|
|
2221
|
-
if (
|
|
2222
|
-
|
|
2525
|
+
if (nextSize <= 0) {
|
|
2526
|
+
positions.clear();
|
|
2527
|
+
return;
|
|
2528
|
+
}
|
|
2529
|
+
if (isSmallSize(prevSize) || !isSmallSize(nextSize)) return;
|
|
2223
2530
|
positions.set(fromId, container.scrollTop);
|
|
2224
2531
|
},
|
|
2225
|
-
|
|
2532
|
+
enter(toId, prevSize, nextSize) {
|
|
2226
2533
|
const container = deps.scrollContainer;
|
|
2227
2534
|
if (!container) return;
|
|
2228
|
-
if (isSmallSize(nextSize)) return;
|
|
2229
|
-
if (!isSmallSize(prevSize)) return;
|
|
2535
|
+
if (isSmallSize(nextSize) || !isSmallSize(prevSize)) return;
|
|
2230
2536
|
const cached = positions.get(toId);
|
|
2231
2537
|
if (cached === void 0) return;
|
|
2232
|
-
container.scrollTop = cached;
|
|
2233
2538
|
positions.delete(toId);
|
|
2539
|
+
container.scrollTop = cached;
|
|
2234
2540
|
},
|
|
2235
2541
|
clear() {
|
|
2236
2542
|
positions.clear();
|
|
@@ -2400,17 +2706,18 @@ function attachAnchor(deps, opts) {
|
|
|
2400
2706
|
const isDock = position === "dock-bottom" || position === "dock-top";
|
|
2401
2707
|
const ws = wrapper.style;
|
|
2402
2708
|
ws.position = "fixed";
|
|
2403
|
-
|
|
2709
|
+
const place = () => {
|
|
2710
|
+
resetOverlayPosition(ws);
|
|
2711
|
+
if (!isDock) {
|
|
2712
|
+
applyOverlayPosition(ws, deps.getMode(), position, opts.inset ?? "16px");
|
|
2713
|
+
return;
|
|
2714
|
+
}
|
|
2404
2715
|
ws.left = "0";
|
|
2405
2716
|
ws.right = "0";
|
|
2406
|
-
if (position === "dock-bottom")
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
}
|
|
2411
|
-
} else {
|
|
2412
|
-
applyOverlayPosition(ws, deps.mode, position, opts.inset ?? "16px");
|
|
2413
|
-
}
|
|
2717
|
+
if (position === "dock-bottom") ws.bottom = "0";
|
|
2718
|
+
else ws.top = "0";
|
|
2719
|
+
};
|
|
2720
|
+
place();
|
|
2414
2721
|
if (opts.fadeRange) {
|
|
2415
2722
|
const [r0, r1] = opts.fadeRange;
|
|
2416
2723
|
const span = Math.max(r1 - r0, 1e-4);
|
|
@@ -2420,10 +2727,10 @@ function attachAnchor(deps, opts) {
|
|
|
2420
2727
|
deps.host.appendChild(wrapper);
|
|
2421
2728
|
let visible = null;
|
|
2422
2729
|
let inFlight = null;
|
|
2423
|
-
const shouldShow = (
|
|
2424
|
-
if (typeof opts.showOn === "function") return opts.showOn(
|
|
2425
|
-
if (Array.isArray(opts.showOn)) return opts.showOn.includes(
|
|
2426
|
-
return isDock ||
|
|
2730
|
+
const shouldShow = (state2) => {
|
|
2731
|
+
if (typeof opts.showOn === "function") return opts.showOn(state2);
|
|
2732
|
+
if (Array.isArray(opts.showOn)) return opts.showOn.includes(state2.activeId);
|
|
2733
|
+
return isDock || state2.size > 0;
|
|
2427
2734
|
};
|
|
2428
2735
|
const applyVisibility = (next, animate) => {
|
|
2429
2736
|
if (next === visible) return;
|
|
@@ -2470,7 +2777,8 @@ function attachAnchor(deps, opts) {
|
|
|
2470
2777
|
},
|
|
2471
2778
|
syncZ: (z) => {
|
|
2472
2779
|
wrapper.style.zIndex = String(z);
|
|
2473
|
-
}
|
|
2780
|
+
},
|
|
2781
|
+
reposition: place
|
|
2474
2782
|
};
|
|
2475
2783
|
}
|
|
2476
2784
|
const matchesId = (def, activeId) => {
|
|
@@ -2484,12 +2792,11 @@ const matchesRange = (def, progress) => {
|
|
|
2484
2792
|
};
|
|
2485
2793
|
function installScrimStages(deps, opts) {
|
|
2486
2794
|
const doc = deps.host.ownerDocument;
|
|
2487
|
-
const
|
|
2795
|
+
const entries = opts.stages.map((def) => {
|
|
2488
2796
|
const wrapper = doc.createElement("div");
|
|
2489
2797
|
wrapper.className = "bs-scrim-stage";
|
|
2490
2798
|
const ws = wrapper.style;
|
|
2491
|
-
ws.position = "
|
|
2492
|
-
applyOverlayPosition(ws, deps.mode, def.position ?? opts.position ?? "center", def.inset ?? opts.inset ?? "16px");
|
|
2799
|
+
ws.position = "fixed";
|
|
2493
2800
|
ws.visibility = "hidden";
|
|
2494
2801
|
ws.pointerEvents = "none";
|
|
2495
2802
|
wrapper.appendChild(def.element);
|
|
@@ -2500,13 +2807,21 @@ function installScrimStages(deps, opts) {
|
|
|
2500
2807
|
inFlight: null
|
|
2501
2808
|
};
|
|
2502
2809
|
});
|
|
2810
|
+
const place = () => {
|
|
2811
|
+
for (const entry of entries) {
|
|
2812
|
+
const ws = entry.wrapper.style;
|
|
2813
|
+
resetOverlayPosition(ws);
|
|
2814
|
+
applyOverlayPosition(ws, deps.getMode(), entry.def.position ?? opts.position ?? "center", entry.def.inset ?? opts.inset ?? "16px");
|
|
2815
|
+
}
|
|
2816
|
+
};
|
|
2817
|
+
place();
|
|
2503
2818
|
let active = null;
|
|
2504
2819
|
const resolveActive = () => {
|
|
2505
|
-
const
|
|
2506
|
-
if (
|
|
2507
|
-
return
|
|
2820
|
+
const state2 = deps.getState();
|
|
2821
|
+
if (state2.size === 0) {
|
|
2822
|
+
return entries.find((e) => matchesId(e.def, state2.activeId)) ?? null;
|
|
2508
2823
|
}
|
|
2509
|
-
return
|
|
2824
|
+
return entries.find((e) => matchesId(e.def, state2.activeId)) ?? entries.find((e) => matchesRange(e.def, state2.progress)) ?? null;
|
|
2510
2825
|
};
|
|
2511
2826
|
const hide = (entry, animate) => {
|
|
2512
2827
|
entry.inFlight?.cancel();
|
|
@@ -2547,20 +2862,23 @@ function installScrimStages(deps, opts) {
|
|
|
2547
2862
|
deps.on("open", () => update(true)),
|
|
2548
2863
|
deps.on("close", () => update(true))
|
|
2549
2864
|
];
|
|
2550
|
-
if (
|
|
2865
|
+
if (entries.some((e) => e.def.forRange)) {
|
|
2551
2866
|
offs.push(deps.on("progress", () => update(true)));
|
|
2552
2867
|
}
|
|
2553
2868
|
update(false);
|
|
2554
|
-
return
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
entry
|
|
2559
|
-
|
|
2560
|
-
entry.
|
|
2869
|
+
return {
|
|
2870
|
+
reposition: place,
|
|
2871
|
+
detach: () => {
|
|
2872
|
+
offs.forEach((off) => off());
|
|
2873
|
+
for (const entry of entries) {
|
|
2874
|
+
entry.inFlight?.cancel();
|
|
2875
|
+
entry.inFlight = null;
|
|
2876
|
+
if (entry.wrapper.parentNode) {
|
|
2877
|
+
entry.wrapper.parentNode.removeChild(entry.wrapper);
|
|
2878
|
+
}
|
|
2561
2879
|
}
|
|
2880
|
+
active = null;
|
|
2562
2881
|
}
|
|
2563
|
-
active = null;
|
|
2564
2882
|
};
|
|
2565
2883
|
}
|
|
2566
2884
|
const DEFAULT_FLICK_VELOCITY = 0.65;
|
|
@@ -2594,11 +2912,13 @@ function resolveEngineOptions(opts, extras) {
|
|
|
2594
2912
|
scrimMode: opts.scrimMode,
|
|
2595
2913
|
scrimColor: opts.scrimColor,
|
|
2596
2914
|
scrimBlur: opts.scrimBlur,
|
|
2597
|
-
scrimInteractive: opts.scrimInteractive
|
|
2915
|
+
scrimInteractive: opts.scrimInteractive,
|
|
2598
2916
|
scrimTapToClose: opts.scrimTapToClose,
|
|
2599
2917
|
scrimPreset: opts.scrimPreset,
|
|
2600
2918
|
screenRange: opts.screenRange,
|
|
2601
|
-
backdropRange: opts.backdropRange
|
|
2919
|
+
backdropRange: opts.backdropRange,
|
|
2920
|
+
backdropOpacity: opts.backdropOpacity,
|
|
2921
|
+
backdropColor: opts.backdropColor
|
|
2602
2922
|
},
|
|
2603
2923
|
animation: {
|
|
2604
2924
|
animation: opts.animation,
|
|
@@ -2673,6 +2993,7 @@ class BottomSheetCore {
|
|
|
2673
2993
|
__publicField(this, "fitContentToSnap");
|
|
2674
2994
|
__publicField(this, "settleAnimation");
|
|
2675
2995
|
__publicField(this, "persistent");
|
|
2996
|
+
__publicField(this, "keyboardInset", 0);
|
|
2676
2997
|
__publicField(this, "disableCloseFlag");
|
|
2677
2998
|
__publicField(this, "disableDragFlag");
|
|
2678
2999
|
__publicField(this, "closeOnRouteChange");
|
|
@@ -2687,6 +3008,7 @@ class BottomSheetCore {
|
|
|
2687
3008
|
__publicField(this, "detachSheetGesture", null);
|
|
2688
3009
|
__publicField(this, "detachSliderKeyboard", null);
|
|
2689
3010
|
__publicField(this, "rootEl", null);
|
|
3011
|
+
__publicField(this, "homeRoot", null);
|
|
2690
3012
|
__publicField(this, "destroyed", false);
|
|
2691
3013
|
__publicField(this, "restClosed", false);
|
|
2692
3014
|
__publicField(this, "currentViewTransition", null);
|
|
@@ -2694,8 +3016,13 @@ class BottomSheetCore {
|
|
|
2694
3016
|
__publicField(this, "sizeWriteSentinel", new WriteSentinel());
|
|
2695
3017
|
__publicField(this, "progressWriteSentinel", new WriteSentinel());
|
|
2696
3018
|
__publicField(this, "isTopSheet", true);
|
|
2697
|
-
__publicField(this, "
|
|
2698
|
-
__publicField(this, "
|
|
3019
|
+
__publicField(this, "phase", "closed");
|
|
3020
|
+
__publicField(this, "transition", null);
|
|
3021
|
+
__publicField(this, "inFlight", null);
|
|
3022
|
+
__publicField(this, "outbox", []);
|
|
3023
|
+
__publicField(this, "flushing", false);
|
|
3024
|
+
__publicField(this, "openPending", false);
|
|
3025
|
+
__publicField(this, "settleHolds", []);
|
|
2699
3026
|
__publicField(this, "allowOvershoot", false);
|
|
2700
3027
|
__publicField(this, "progressPayload", {
|
|
2701
3028
|
value: 0,
|
|
@@ -2719,6 +3046,7 @@ class BottomSheetCore {
|
|
|
2719
3046
|
__publicField(this, "anchorHost", null);
|
|
2720
3047
|
__publicField(this, "stackZ", 100);
|
|
2721
3048
|
__publicField(this, "detachScrimStages", null);
|
|
3049
|
+
__publicField(this, "placeScrimStages", null);
|
|
2722
3050
|
__publicField(this, "stackEffectEnabled", false);
|
|
2723
3051
|
__publicField(this, "stackEffectPrimed", false);
|
|
2724
3052
|
__publicField(this, "fitDeps");
|
|
@@ -2726,11 +3054,7 @@ class BottomSheetCore {
|
|
|
2726
3054
|
__publicField(this, "featureList", []);
|
|
2727
3055
|
__publicField(this, "featureCtx");
|
|
2728
3056
|
const resolved = resolveEngineOptions(opts, {
|
|
2729
|
-
shouldApplyInertSiblings: () =>
|
|
2730
|
-
if (typeof document === "undefined") return false;
|
|
2731
|
-
const bodyChildren = Array.from(document.body.children);
|
|
2732
|
-
return bodyChildren.some((c) => c === opts.element || c.contains(opts.element));
|
|
2733
|
-
}
|
|
3057
|
+
shouldApplyInertSiblings: () => opts.element.isConnected
|
|
2734
3058
|
});
|
|
2735
3059
|
this.element = opts.element;
|
|
2736
3060
|
this.handle = opts.handle ?? opts.element;
|
|
@@ -2758,7 +3082,6 @@ class BottomSheetCore {
|
|
|
2758
3082
|
void this.snapTo(id);
|
|
2759
3083
|
},
|
|
2760
3084
|
close: () => {
|
|
2761
|
-
if (!this.canDismiss()) return;
|
|
2762
3085
|
void this.close("backdrop");
|
|
2763
3086
|
}
|
|
2764
3087
|
}, resolved.scrim);
|
|
@@ -2782,7 +3105,8 @@ class BottomSheetCore {
|
|
|
2782
3105
|
}, resolved.animation);
|
|
2783
3106
|
this.lifecycle = new LifecycleController({
|
|
2784
3107
|
element: this.element,
|
|
2785
|
-
close: () => this.close()
|
|
3108
|
+
close: () => this.close(),
|
|
3109
|
+
isTop: () => this.isTopSheet
|
|
2786
3110
|
}, resolved.lifecycle);
|
|
2787
3111
|
this.closeOnBack = resolved.closeOnBack;
|
|
2788
3112
|
this.routedTo = opts.routedTo;
|
|
@@ -2807,6 +3131,7 @@ class BottomSheetCore {
|
|
|
2807
3131
|
auditVhUsage(this.snapPointsRaw);
|
|
2808
3132
|
this.auditDuplicateSnapIds(this.snapPointsRaw);
|
|
2809
3133
|
this.rootEl = this.element.closest(".bs-root");
|
|
3134
|
+
this.homeRoot = homeRootOf(this.rootEl);
|
|
2810
3135
|
this.maxHeightDeps = {
|
|
2811
3136
|
element: this.element,
|
|
2812
3137
|
mode: this.mode,
|
|
@@ -2828,7 +3153,9 @@ class BottomSheetCore {
|
|
|
2828
3153
|
});
|
|
2829
3154
|
const initial = this.snaps.findById(this.activeId);
|
|
2830
3155
|
if (initial) this.size = initial.size;
|
|
3156
|
+
this.phase = this.size > 0 ? "open" : "closed";
|
|
2831
3157
|
this.applySize(this.size);
|
|
3158
|
+
this.restClosed = this.element.getAttribute("data-bs-rest") === "closed";
|
|
2832
3159
|
this.setRestClosed(this.size === 0);
|
|
2833
3160
|
this.updateAriaSlider();
|
|
2834
3161
|
this.scrollCache = createScrollCache({
|
|
@@ -2839,12 +3166,11 @@ class BottomSheetCore {
|
|
|
2839
3166
|
this.attach();
|
|
2840
3167
|
this.registerInStack();
|
|
2841
3168
|
if (this.snaps.getMaxAxisSize() === 0 && typeof IntersectionObserver !== "undefined" && typeof document !== "undefined") {
|
|
2842
|
-
const io = new IntersectionObserver((
|
|
2843
|
-
for (const entry of
|
|
3169
|
+
const io = new IntersectionObserver((entries) => {
|
|
3170
|
+
for (const entry of entries) {
|
|
2844
3171
|
if (!entry.isIntersecting) continue;
|
|
2845
3172
|
if (this.destroyed) return;
|
|
2846
|
-
this.
|
|
2847
|
-
this.healActiveSnap();
|
|
3173
|
+
this.recompute();
|
|
2848
3174
|
io.disconnect();
|
|
2849
3175
|
return;
|
|
2850
3176
|
}
|
|
@@ -2853,6 +3179,7 @@ class BottomSheetCore {
|
|
|
2853
3179
|
this.teardowns.add(() => io.disconnect());
|
|
2854
3180
|
}
|
|
2855
3181
|
this.teardowns.add(installFitObserver({
|
|
3182
|
+
element: this.element,
|
|
2856
3183
|
handle: this.handle,
|
|
2857
3184
|
scrollContainer: this.scrollContainer,
|
|
2858
3185
|
hasFitSnap: () => this.snapPointsRaw.some((p) => p.size === "fit" || p.size === "content"),
|
|
@@ -2865,9 +3192,7 @@ class BottomSheetCore {
|
|
|
2865
3192
|
this.applyAutoAriaLabelledBy();
|
|
2866
3193
|
this.runFeatureStage("post");
|
|
2867
3194
|
this.warnOrphanFeatureOptions();
|
|
2868
|
-
if (this.
|
|
2869
|
-
this.handleOpen();
|
|
2870
|
-
}
|
|
3195
|
+
if (this.phase === "open") this.installLifecycle(true);
|
|
2871
3196
|
}
|
|
2872
3197
|
buildFeatureContext(autoCollapseAfter) {
|
|
2873
3198
|
return {
|
|
@@ -2895,21 +3220,27 @@ class BottomSheetCore {
|
|
|
2895
3220
|
getMaxAxisSize: () => this.snaps.getMaxAxisSize(),
|
|
2896
3221
|
resolveSnap: (id) => this.snaps.findById(id),
|
|
2897
3222
|
resolveActiveSnap: () => this.snaps.findById(this.activeId),
|
|
3223
|
+
getPhase: () => this.phase,
|
|
2898
3224
|
setSize: (size) => {
|
|
2899
3225
|
this.size = size;
|
|
2900
3226
|
},
|
|
2901
3227
|
setMaxAxisSize: (size) => {
|
|
2902
3228
|
this.snaps.setMaxAxisSize(size);
|
|
2903
3229
|
},
|
|
3230
|
+
setKeyboardInset: (px) => this.setKeyboardInset(px),
|
|
2904
3231
|
applySize: (size) => this.applySize(size),
|
|
2905
3232
|
recomputeSnaps: () => this.recomputeSnaps(),
|
|
3233
|
+
reseat: () => this.reseat(),
|
|
3234
|
+
holdSettle: (settled) => {
|
|
3235
|
+
this.settleHolds.push(settled);
|
|
3236
|
+
},
|
|
2906
3237
|
newCycle: () => {
|
|
2907
3238
|
this.newCycle();
|
|
2908
3239
|
},
|
|
2909
|
-
cancelInFlight: () =>
|
|
2910
|
-
|
|
3240
|
+
cancelInFlight: () => this.suspend(),
|
|
3241
|
+
resyncAfterResize: () => {
|
|
3242
|
+
if (!this.destroyed) this.land(false);
|
|
2911
3243
|
},
|
|
2912
|
-
resyncAfterResize: () => this.resyncAfterResize(),
|
|
2913
3244
|
snapTo: (id) => {
|
|
2914
3245
|
void this.snapTo(id);
|
|
2915
3246
|
},
|
|
@@ -2942,8 +3273,9 @@ class BottomSheetCore {
|
|
|
2942
3273
|
return {
|
|
2943
3274
|
size: this.size,
|
|
2944
3275
|
activeId: this.activeId,
|
|
3276
|
+
phase: this.phase,
|
|
2945
3277
|
isDragging: this.isDraggingAny(),
|
|
2946
|
-
isAnimating: this.animation.isAnimating,
|
|
3278
|
+
isAnimating: this.animation.isAnimating || this.currentViewTransition !== null,
|
|
2947
3279
|
progress: this.computeProgress(this.size)
|
|
2948
3280
|
};
|
|
2949
3281
|
}
|
|
@@ -2995,53 +3327,49 @@ class BottomSheetCore {
|
|
|
2995
3327
|
getResolvedSnaps() {
|
|
2996
3328
|
return this.snaps.getResolvedSnaps();
|
|
2997
3329
|
}
|
|
2998
|
-
|
|
2999
|
-
if (this.destroyed) return;
|
|
3330
|
+
snapTo(id, velocityOrOpts = 0, _skipBeforeSnap = false) {
|
|
3000
3331
|
const opts = typeof velocityOrOpts === "object" ? velocityOrOpts : {
|
|
3001
3332
|
velocity: velocityOrOpts
|
|
3002
3333
|
};
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3334
|
+
return this.transitionTo(id, opts.velocity ?? 0, _skipBeforeSnap, opts.signal);
|
|
3335
|
+
}
|
|
3336
|
+
transitionTo(id, velocityPxPerMs = 0, skipBeforeSnap = false, externalSignal) {
|
|
3337
|
+
if (this.destroyed || externalSignal?.aborted) return Promise.resolve();
|
|
3006
3338
|
const target = this.snaps.findById(id);
|
|
3007
3339
|
if (!target) {
|
|
3008
3340
|
devWarn(`[BottomSheet] unknown snap id: ${id}`);
|
|
3009
|
-
return;
|
|
3341
|
+
return Promise.resolve();
|
|
3010
3342
|
}
|
|
3011
3343
|
if (!this.snaps.getAllowedIds().includes(id)) {
|
|
3012
3344
|
devWarn(`[BottomSheet] snap "${id}" is not in allowed list`);
|
|
3013
|
-
return;
|
|
3345
|
+
return Promise.resolve();
|
|
3014
3346
|
}
|
|
3015
|
-
if (
|
|
3016
|
-
|
|
3347
|
+
if (target.size === 0 && this.closingBlocked()) return Promise.resolve();
|
|
3348
|
+
if (!externalSignal && this.inFlight?.id === id) return this.inFlight.done;
|
|
3349
|
+
if (!skipBeforeSnap && this.emitBeforeSnap(target, this.activeId)) {
|
|
3350
|
+
return Promise.resolve();
|
|
3017
3351
|
}
|
|
3018
|
-
const
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
this.animation.cancel();
|
|
3022
|
-
this.newCycle();
|
|
3352
|
+
const flight = {
|
|
3353
|
+
id,
|
|
3354
|
+
done: Promise.resolve()
|
|
3023
3355
|
};
|
|
3356
|
+
flight.done = this.runTransition(target, velocityPxPerMs, false, externalSignal, flight);
|
|
3357
|
+
return flight.done;
|
|
3358
|
+
}
|
|
3359
|
+
async runTransition(target, velocityPxPerMs, fromDrag, externalSignal, flight = null) {
|
|
3360
|
+
const signal = this.beginTransition(target);
|
|
3361
|
+
const transition = this.transition;
|
|
3362
|
+
if (signal.aborted || !transition) return;
|
|
3363
|
+
this.inFlight = flight;
|
|
3364
|
+
const onExternalAbort = () => this.suspend();
|
|
3024
3365
|
externalSignal?.addEventListener("abort", onExternalAbort, {
|
|
3025
3366
|
once: true
|
|
3026
3367
|
});
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
const previousSize = this.size;
|
|
3030
|
-
this.scrollCache.cache(previousId, previousSize, target.size);
|
|
3031
|
-
this.activeId = id;
|
|
3032
|
-
const rawTargetSize = this.snapPointsRaw.find((p) => p.id === id)?.size;
|
|
3033
|
-
const opensToRest = id === "closed" || rawTargetSize === 0;
|
|
3034
|
-
if (wasClosed && !opensToRest) {
|
|
3035
|
-
this.opening = true;
|
|
3036
|
-
if (!resumingOpen) {
|
|
3037
|
-
this.promotedForOpen = true;
|
|
3038
|
-
sheetStack.promote(this.id);
|
|
3039
|
-
}
|
|
3040
|
-
}
|
|
3041
|
-
if (this.animation.viewTransitionsAvailable) {
|
|
3368
|
+
this.allowOvershoot = fromDrag;
|
|
3369
|
+
if (!fromDrag && this.animation.viewTransitionsAvailable) {
|
|
3042
3370
|
this.currentViewTransition?.skipTransition?.();
|
|
3043
3371
|
const vt = document.startViewTransition(() => {
|
|
3044
|
-
this.applySize(
|
|
3372
|
+
if (!signal.aborted) this.applySize(transition.size);
|
|
3045
3373
|
});
|
|
3046
3374
|
vt.ready?.catch(() => {
|
|
3047
3375
|
});
|
|
@@ -3052,25 +3380,208 @@ class BottomSheetCore {
|
|
|
3052
3380
|
}
|
|
3053
3381
|
if (this.currentViewTransition === vt) this.currentViewTransition = null;
|
|
3054
3382
|
} else {
|
|
3055
|
-
await this.animation.animateTo(
|
|
3383
|
+
await this.animation.animateTo(transition.size, velocityPxPerMs);
|
|
3056
3384
|
}
|
|
3057
3385
|
externalSignal?.removeEventListener("abort", onExternalAbort);
|
|
3058
3386
|
if (signal.aborted) return;
|
|
3059
|
-
this.
|
|
3060
|
-
this.
|
|
3387
|
+
if (this.size !== transition.size) this.applySize(transition.size);
|
|
3388
|
+
this.land(fromDrag);
|
|
3389
|
+
if (this.settleHolds.length > 0) {
|
|
3390
|
+
await Promise.allSettled(this.settleHolds.splice(0));
|
|
3391
|
+
}
|
|
3392
|
+
}
|
|
3393
|
+
beginTransition(target) {
|
|
3394
|
+
const signal = this.newCycle();
|
|
3395
|
+
const cap = this.snaps.getMaxAxisSize();
|
|
3396
|
+
const fromId = this.activeId;
|
|
3397
|
+
const fromSize = this.snaps.findById(fromId)?.size ?? this.size;
|
|
3398
|
+
this.scrollCache.leave(fromId, fromSize, target.size);
|
|
3399
|
+
this.scrollCache.enter(target.id, fromSize, target.size);
|
|
3400
|
+
this.activeId = target.id;
|
|
3401
|
+
this.transition = {
|
|
3402
|
+
size: cap > 0 ? Math.min(target.size, cap) : target.size,
|
|
3403
|
+
cap
|
|
3404
|
+
};
|
|
3405
|
+
if (target.size > 0) {
|
|
3406
|
+
this.enterOpening(target.id);
|
|
3407
|
+
} else {
|
|
3408
|
+
if (this.phase === "closed" && !this.isClosedSnap(target.id)) {
|
|
3409
|
+
sheetStack.promote(this.id);
|
|
3410
|
+
}
|
|
3411
|
+
this.enterClosing();
|
|
3412
|
+
}
|
|
3413
|
+
this.flush();
|
|
3414
|
+
return signal;
|
|
3415
|
+
}
|
|
3416
|
+
enterOpening(id) {
|
|
3417
|
+
if (this.phase === "open" || this.phase === "opening") return;
|
|
3418
|
+
const fresh = this.phase === "closed";
|
|
3419
|
+
this.phase = "opening";
|
|
3420
|
+
this.setRestClosed(false);
|
|
3421
|
+
if (!this.installLifecycle(fresh)) return;
|
|
3422
|
+
this.post("open", {
|
|
3423
|
+
id
|
|
3424
|
+
});
|
|
3425
|
+
this.outbox.push(() => {
|
|
3426
|
+
if (this.phase !== "closed") {
|
|
3427
|
+
notifyLinkedSheets(this.linkedSheets, this);
|
|
3428
|
+
}
|
|
3429
|
+
});
|
|
3061
3430
|
}
|
|
3062
|
-
|
|
3063
|
-
this.
|
|
3431
|
+
enterClosing() {
|
|
3432
|
+
if (this.phase === "closed" || this.phase === "closing") return;
|
|
3433
|
+
this.phase = "closing";
|
|
3434
|
+
this.post("close", void 0);
|
|
3435
|
+
}
|
|
3436
|
+
settlePhase(heal) {
|
|
3437
|
+
if (this.size > 0) {
|
|
3438
|
+
this.enterOpening(this.activeId);
|
|
3439
|
+
if (this.phase === "opening") {
|
|
3440
|
+
this.phase = "open";
|
|
3441
|
+
this.post("opened", {
|
|
3442
|
+
id: this.activeId
|
|
3443
|
+
});
|
|
3444
|
+
}
|
|
3445
|
+
return;
|
|
3446
|
+
}
|
|
3447
|
+
if (heal && this.phase !== "closing") return;
|
|
3448
|
+
this.enterClosing();
|
|
3449
|
+
if (this.phase === "closing") {
|
|
3450
|
+
this.phase = "closed";
|
|
3451
|
+
this.setRestClosed(true);
|
|
3452
|
+
this.lifecycle.release();
|
|
3453
|
+
sheetStack.update();
|
|
3454
|
+
this.post("closed", void 0);
|
|
3455
|
+
}
|
|
3456
|
+
}
|
|
3457
|
+
land(haptic) {
|
|
3458
|
+
this.transition = null;
|
|
3459
|
+
this.inFlight = null;
|
|
3460
|
+
this.allowOvershoot = false;
|
|
3461
|
+
this.openPending = this.size === 0 && !this.isClosedSnap(this.activeId);
|
|
3064
3462
|
this.updateAriaSlider();
|
|
3065
|
-
this.
|
|
3066
|
-
|
|
3463
|
+
this.setRestClosed(this.size === 0);
|
|
3464
|
+
this.post("snap", {
|
|
3465
|
+
id: this.activeId,
|
|
3067
3466
|
size: this.size,
|
|
3068
3467
|
progress: this.computeProgress(this.size)
|
|
3069
3468
|
});
|
|
3070
|
-
|
|
3071
|
-
this.
|
|
3072
|
-
|
|
3073
|
-
|
|
3469
|
+
this.settlePhase(false);
|
|
3470
|
+
if (haptic) this.haptic();
|
|
3471
|
+
this.flush();
|
|
3472
|
+
}
|
|
3473
|
+
suspend() {
|
|
3474
|
+
this.animation.cancel();
|
|
3475
|
+
this.currentViewTransition?.skipTransition?.();
|
|
3476
|
+
this.newCycle();
|
|
3477
|
+
}
|
|
3478
|
+
landNow() {
|
|
3479
|
+
const transition = this.transition;
|
|
3480
|
+
if (this.destroyed || !transition || this.isDraggingAny()) return;
|
|
3481
|
+
this.animation.cancel();
|
|
3482
|
+
this.currentViewTransition?.skipTransition?.();
|
|
3483
|
+
this.newCycle();
|
|
3484
|
+
this.applySize(transition.size);
|
|
3485
|
+
this.land(false);
|
|
3486
|
+
}
|
|
3487
|
+
reseat() {
|
|
3488
|
+
if (this.destroyed || this.isDraggingAny()) return;
|
|
3489
|
+
const active = this.snaps.findById(this.activeId);
|
|
3490
|
+
if (!active) return;
|
|
3491
|
+
const cap = this.snaps.getMaxAxisSize();
|
|
3492
|
+
const target = cap > 0 ? Math.min(active.size, cap) : active.size;
|
|
3493
|
+
this.updateAriaSlider();
|
|
3494
|
+
const transition = this.transition;
|
|
3495
|
+
if (transition) {
|
|
3496
|
+
if (Math.abs(target - transition.size) < SIZE_WRITE_EPSILON && Math.abs(cap - transition.cap) < SIZE_WRITE_EPSILON) {
|
|
3497
|
+
return;
|
|
3498
|
+
}
|
|
3499
|
+
transition.size = target;
|
|
3500
|
+
transition.cap = cap;
|
|
3501
|
+
this.applySize(this.animation.retarget(target) ? this.size : target);
|
|
3502
|
+
return;
|
|
3503
|
+
}
|
|
3504
|
+
if (this.openPending && target > 0 && this.phase === "closed") {
|
|
3505
|
+
void this.runTransition(active, 0, false);
|
|
3506
|
+
return;
|
|
3507
|
+
}
|
|
3508
|
+
this.applySize(target);
|
|
3509
|
+
this.settlePhase(true);
|
|
3510
|
+
this.flush();
|
|
3511
|
+
}
|
|
3512
|
+
installLifecycle(promote) {
|
|
3513
|
+
if (promote) sheetStack.promote(this.id);
|
|
3514
|
+
if (this.lifecycle.isInstalled) return true;
|
|
3515
|
+
try {
|
|
3516
|
+
this.lifecycle.install();
|
|
3517
|
+
return true;
|
|
3518
|
+
} catch (err) {
|
|
3519
|
+
this.abortOpen();
|
|
3520
|
+
queueMicrotask(() => {
|
|
3521
|
+
throw err;
|
|
3522
|
+
});
|
|
3523
|
+
return false;
|
|
3524
|
+
}
|
|
3525
|
+
}
|
|
3526
|
+
abortOpen() {
|
|
3527
|
+
this.animation.cancel();
|
|
3528
|
+
if (!this.destroyed) this.newCycle();
|
|
3529
|
+
this.phase = "closed";
|
|
3530
|
+
this.openPending = false;
|
|
3531
|
+
this.lifecycle.release();
|
|
3532
|
+
sheetStack.update();
|
|
3533
|
+
this.activeId = this.zeroSnapId() ?? this.activeId;
|
|
3534
|
+
this.applySize(0);
|
|
3535
|
+
this.setRestClosed(true);
|
|
3536
|
+
this.updateAriaSlider();
|
|
3537
|
+
}
|
|
3538
|
+
zeroSnapId() {
|
|
3539
|
+
return this.snapPointsRaw.find((p) => p.id === "closed")?.id ?? this.snaps.getAllowedIds().find((a) => this.snaps.findById(a)?.size === 0);
|
|
3540
|
+
}
|
|
3541
|
+
isClosedSnap(id) {
|
|
3542
|
+
if (id === "closed") return true;
|
|
3543
|
+
return this.snapPointsRaw.find((p) => p.id === id)?.size === 0;
|
|
3544
|
+
}
|
|
3545
|
+
closingBlocked() {
|
|
3546
|
+
return this.disableCloseFlag && this.phase !== "closed";
|
|
3547
|
+
}
|
|
3548
|
+
setKeyboardInset(px) {
|
|
3549
|
+
if (px === this.keyboardInset) return;
|
|
3550
|
+
this.keyboardInset = px;
|
|
3551
|
+
for (const host of this.varHosts()) {
|
|
3552
|
+
host.style.setProperty("--bs-keyboard-inset", `${px}px`);
|
|
3553
|
+
}
|
|
3554
|
+
}
|
|
3555
|
+
varHosts() {
|
|
3556
|
+
const hosts = /* @__PURE__ */ new Set([
|
|
3557
|
+
this.element
|
|
3558
|
+
]);
|
|
3559
|
+
for (const host of [
|
|
3560
|
+
this.anchorHost,
|
|
3561
|
+
this.scrimParent,
|
|
3562
|
+
this.rootEl,
|
|
3563
|
+
this.homeRoot
|
|
3564
|
+
]) {
|
|
3565
|
+
if (host) hosts.add(host);
|
|
3566
|
+
}
|
|
3567
|
+
return hosts;
|
|
3568
|
+
}
|
|
3569
|
+
dismissBlocked() {
|
|
3570
|
+
return (this.disableCloseFlag || this.persistent) && this.phase !== "closed";
|
|
3571
|
+
}
|
|
3572
|
+
post(event, payload) {
|
|
3573
|
+
this.outbox.push(() => this.bus.emit(event, payload));
|
|
3574
|
+
}
|
|
3575
|
+
flush() {
|
|
3576
|
+
if (this.flushing) return;
|
|
3577
|
+
this.flushing = true;
|
|
3578
|
+
try {
|
|
3579
|
+
for (let next = this.outbox.shift(); next; next = this.outbox.shift()) {
|
|
3580
|
+
next();
|
|
3581
|
+
}
|
|
3582
|
+
} finally {
|
|
3583
|
+
this.flushing = false;
|
|
3584
|
+
}
|
|
3074
3585
|
}
|
|
3075
3586
|
setRestClosed(closed) {
|
|
3076
3587
|
if (closed === this.restClosed) return;
|
|
@@ -3078,21 +3589,6 @@ class BottomSheetCore {
|
|
|
3078
3589
|
if (closed) this.element.setAttribute("data-bs-rest", "closed");
|
|
3079
3590
|
else this.element.removeAttribute("data-bs-rest");
|
|
3080
3591
|
}
|
|
3081
|
-
emitOpenSequence(id) {
|
|
3082
|
-
this.emit("open", {
|
|
3083
|
-
id
|
|
3084
|
-
});
|
|
3085
|
-
this.handleOpen();
|
|
3086
|
-
notifyLinkedSheets(this.linkedSheets, this);
|
|
3087
|
-
this.emit("opened", {
|
|
3088
|
-
id
|
|
3089
|
-
});
|
|
3090
|
-
}
|
|
3091
|
-
emitCloseSequence() {
|
|
3092
|
-
this.emit("close", void 0);
|
|
3093
|
-
this.handleClose();
|
|
3094
|
-
this.emit("closed", void 0);
|
|
3095
|
-
}
|
|
3096
3592
|
async dragTo(targetSize, velocityOrOpts = 0) {
|
|
3097
3593
|
if (this.destroyed) return;
|
|
3098
3594
|
const opts = typeof velocityOrOpts === "object" ? velocityOrOpts : {
|
|
@@ -3102,29 +3598,33 @@ class BottomSheetCore {
|
|
|
3102
3598
|
const externalSignal = opts.signal;
|
|
3103
3599
|
if (externalSignal?.aborted) return;
|
|
3104
3600
|
this.newCycle();
|
|
3105
|
-
const onExternalAbort = () =>
|
|
3106
|
-
this.animation.cancel();
|
|
3107
|
-
this.newCycle();
|
|
3108
|
-
};
|
|
3601
|
+
const onExternalAbort = () => this.suspend();
|
|
3109
3602
|
externalSignal?.addEventListener("abort", onExternalAbort, {
|
|
3110
3603
|
once: true
|
|
3111
3604
|
});
|
|
3112
3605
|
const clamped = Math.max(0, Math.min(targetSize, this.snaps.getMaxAxisSize()));
|
|
3113
3606
|
await this.animation.animateTo(clamped, velocityPxPerMs);
|
|
3114
3607
|
externalSignal?.removeEventListener("abort", onExternalAbort);
|
|
3115
|
-
if (this.destroyed || externalSignal?.aborted) return;
|
|
3116
3608
|
}
|
|
3117
3609
|
open(id) {
|
|
3118
3610
|
if (this.destroyed) return Promise.resolve();
|
|
3611
|
+
if (!id && (this.phase === "open" || this.phase === "opening")) {
|
|
3612
|
+
return Promise.resolve();
|
|
3613
|
+
}
|
|
3119
3614
|
const target = id ?? this.snaps.getAllowedIds().find((a) => (this.snaps.findById(a)?.size ?? 0) > 0) ?? this.activeId;
|
|
3120
3615
|
return this.snapTo(target);
|
|
3121
3616
|
}
|
|
3122
3617
|
close(reason = "programmatic") {
|
|
3123
|
-
if (this.destroyed) return Promise.resolve();
|
|
3124
|
-
if (this.
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
|
|
3618
|
+
if (this.destroyed || this.disableCloseFlag) return Promise.resolve();
|
|
3619
|
+
if (this.persistent && reason !== "programmatic") return Promise.resolve();
|
|
3620
|
+
const target = this.zeroSnapId() ?? this.allowedIdsBySize()[0];
|
|
3621
|
+
if (target === void 0) return Promise.resolve();
|
|
3622
|
+
if (this.phase === "closed" && this.activeId === target) {
|
|
3623
|
+
return Promise.resolve();
|
|
3624
|
+
}
|
|
3625
|
+
const visible = this.phase === "open" || this.phase === "opening";
|
|
3626
|
+
if (visible && this.emitBeforeClose(reason)) return Promise.resolve();
|
|
3627
|
+
return this.snapTo(target);
|
|
3128
3628
|
}
|
|
3129
3629
|
canDismiss() {
|
|
3130
3630
|
return !this.persistent && !this.disableCloseFlag && !this.destroyed;
|
|
@@ -3147,10 +3647,12 @@ class BottomSheetCore {
|
|
|
3147
3647
|
}
|
|
3148
3648
|
setDragFrom(mode) {
|
|
3149
3649
|
if (this.destroyed || mode === this.dragFromMode) return;
|
|
3650
|
+
const wasDragging = this.gesture?.isDragging ?? false;
|
|
3150
3651
|
this.gesture?.forceClearDragState();
|
|
3151
3652
|
this.detachSheetGesture?.();
|
|
3152
3653
|
this.dragFromMode = mode;
|
|
3153
3654
|
this.mountSheetGesture();
|
|
3655
|
+
if (wasDragging) this.restoreAfterDrag();
|
|
3154
3656
|
}
|
|
3155
3657
|
getDragFrom() {
|
|
3156
3658
|
return this.dragFromMode;
|
|
@@ -3163,6 +3665,7 @@ class BottomSheetCore {
|
|
|
3163
3665
|
const nowVertical = next === "bottom" || next === "top";
|
|
3164
3666
|
this.gesture?.forceClearDragState();
|
|
3165
3667
|
this.detachSheetGesture?.();
|
|
3668
|
+
this.landNow();
|
|
3166
3669
|
this.animation.cancel();
|
|
3167
3670
|
this.element.style.removeProperty(layoutAxis(this.mode));
|
|
3168
3671
|
this.mode = next;
|
|
@@ -3178,9 +3681,12 @@ class BottomSheetCore {
|
|
|
3178
3681
|
this.detachSliderKeyboard?.();
|
|
3179
3682
|
this.mountSliderKeyboard();
|
|
3180
3683
|
this.mountSheetGesture();
|
|
3684
|
+
for (const anchor of this.anchors) anchor.reposition();
|
|
3685
|
+
this.placeScrimStages?.();
|
|
3686
|
+
if (this.stackEffectPrimed) {
|
|
3687
|
+
this.element.style.transformOrigin = nowVertical ? "50% 100%" : "0% 50%";
|
|
3688
|
+
}
|
|
3181
3689
|
this.recompute();
|
|
3182
|
-
const active = this.snaps.findById(this.activeId);
|
|
3183
|
-
if (active) this.applySize(active.size);
|
|
3184
3690
|
this.updateAriaSlider();
|
|
3185
3691
|
}
|
|
3186
3692
|
getMode() {
|
|
@@ -3222,13 +3728,22 @@ class BottomSheetCore {
|
|
|
3222
3728
|
if (snap && ids.includes(snap)) {
|
|
3223
3729
|
void this.snapTo(snap, 0, true);
|
|
3224
3730
|
} else if (!ids.includes(this.activeId)) {
|
|
3225
|
-
const fallback =
|
|
3226
|
-
if (fallback) void this.snapTo(fallback, 0, true);
|
|
3731
|
+
const fallback = this.fallbackSnap(this.snaps.findById(this.activeId)?.size ?? this.size);
|
|
3732
|
+
if (fallback) void this.snapTo(fallback.id, 0, true);
|
|
3227
3733
|
}
|
|
3228
3734
|
}
|
|
3735
|
+
fallbackSnap(from) {
|
|
3736
|
+
return (from > 0 ? this.snaps.nearest(from, true) : null) ?? this.snaps.nearest(from, false);
|
|
3737
|
+
}
|
|
3229
3738
|
setBackdropRange(range) {
|
|
3230
3739
|
this.scrim.setBackdropRange(range, () => this.applySize(this.size));
|
|
3231
3740
|
}
|
|
3741
|
+
setBackdropOpacity(value) {
|
|
3742
|
+
this.scrim.setBackdropOpacity(value, () => this.applySize(this.size));
|
|
3743
|
+
}
|
|
3744
|
+
setBackdropColor(color) {
|
|
3745
|
+
this.scrim.setBackdropColor(color);
|
|
3746
|
+
}
|
|
3232
3747
|
setScreenRange(range) {
|
|
3233
3748
|
this.scrim.setScreenRange(range, () => this.applySize(this.size));
|
|
3234
3749
|
}
|
|
@@ -3265,7 +3780,7 @@ class BottomSheetCore {
|
|
|
3265
3780
|
this.anchorHost.style.setProperty("--bs-progress", String(this.computeProgress(this.size)));
|
|
3266
3781
|
}
|
|
3267
3782
|
const handle = attachAnchor({
|
|
3268
|
-
|
|
3783
|
+
getMode: () => this.mode,
|
|
3269
3784
|
host: this.anchorHost,
|
|
3270
3785
|
getState: () => ({
|
|
3271
3786
|
activeId: this.activeId,
|
|
@@ -3299,8 +3814,8 @@ class BottomSheetCore {
|
|
|
3299
3814
|
return () => {
|
|
3300
3815
|
};
|
|
3301
3816
|
}
|
|
3302
|
-
const
|
|
3303
|
-
|
|
3817
|
+
const stages = installScrimStages({
|
|
3818
|
+
getMode: () => this.mode,
|
|
3304
3819
|
host,
|
|
3305
3820
|
getState: () => ({
|
|
3306
3821
|
activeId: this.activeId,
|
|
@@ -3311,10 +3826,14 @@ class BottomSheetCore {
|
|
|
3311
3826
|
isDestroyed: () => this.destroyed
|
|
3312
3827
|
}, opts);
|
|
3313
3828
|
const detach = () => {
|
|
3314
|
-
if (this.detachScrimStages === detach)
|
|
3315
|
-
|
|
3829
|
+
if (this.detachScrimStages === detach) {
|
|
3830
|
+
this.detachScrimStages = null;
|
|
3831
|
+
this.placeScrimStages = null;
|
|
3832
|
+
}
|
|
3833
|
+
stages.detach();
|
|
3316
3834
|
};
|
|
3317
3835
|
this.detachScrimStages = detach;
|
|
3836
|
+
this.placeScrimStages = stages.reposition;
|
|
3318
3837
|
this.teardowns.add(() => this.detachScrimStages?.());
|
|
3319
3838
|
return detach;
|
|
3320
3839
|
}
|
|
@@ -3326,32 +3845,29 @@ class BottomSheetCore {
|
|
|
3326
3845
|
}
|
|
3327
3846
|
setSnapPoints(points, allowed) {
|
|
3328
3847
|
if (this.destroyed) return;
|
|
3329
|
-
this.
|
|
3330
|
-
this.
|
|
3848
|
+
const from = this.snaps.findById(this.activeId)?.size ?? this.size;
|
|
3849
|
+
const restricted = this.snaps.getResolvedSnaps().some((s) => !this.snaps.getAllowedIds().includes(s.id));
|
|
3331
3850
|
this.snapPointsRaw = points;
|
|
3332
3851
|
auditVhUsage(points);
|
|
3333
3852
|
this.auditDuplicateSnapIds(points);
|
|
3853
|
+
this.maxHeight.resolveCap();
|
|
3334
3854
|
this.snaps.setRaw(points);
|
|
3855
|
+
this.maxHeight.clampTo();
|
|
3335
3856
|
if (allowed) {
|
|
3336
3857
|
this.snaps.setAllowedIds(allowed);
|
|
3337
3858
|
} else {
|
|
3338
3859
|
const present = this.snaps.getResolvedSnaps().map((s) => s.id);
|
|
3339
|
-
const kept = this.snaps.getAllowedIds().filter((id) => present.includes(id));
|
|
3860
|
+
const kept = restricted ? this.snaps.getAllowedIds().filter((id) => present.includes(id)) : [];
|
|
3340
3861
|
this.snaps.setAllowedIds(kept.length ? kept : present);
|
|
3341
3862
|
}
|
|
3342
3863
|
this.scrollCache.clear();
|
|
3343
3864
|
this.scrim.invalidateOpacityCache();
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
} else {
|
|
3348
|
-
const fallback = this.snaps.getResolvedSnaps().find((s) => this.snaps.getAllowedIds().includes(s.id)) ?? this.snaps.getResolvedSnaps()[0];
|
|
3349
|
-
if (fallback) {
|
|
3350
|
-
this.activeId = fallback.id;
|
|
3351
|
-
this.applySize(fallback.size);
|
|
3352
|
-
}
|
|
3865
|
+
if (this.snaps.findById(this.activeId)) {
|
|
3866
|
+
this.reseat();
|
|
3867
|
+
return;
|
|
3353
3868
|
}
|
|
3354
|
-
this.
|
|
3869
|
+
const fallback = this.fallbackSnap(from) ?? this.snaps.getResolvedSnaps()[0];
|
|
3870
|
+
if (fallback) void this.transitionTo(fallback.id, 0, true);
|
|
3355
3871
|
}
|
|
3356
3872
|
recompute() {
|
|
3357
3873
|
if (this.destroyed) return;
|
|
@@ -3359,22 +3875,11 @@ class BottomSheetCore {
|
|
|
3359
3875
|
this.snaps.recompute();
|
|
3360
3876
|
this.maxHeight.clampTo();
|
|
3361
3877
|
this.scrim.invalidateOpacityCache();
|
|
3362
|
-
|
|
3363
|
-
this.healActiveSnap();
|
|
3364
|
-
}
|
|
3365
|
-
healActiveSnap() {
|
|
3366
|
-
const current = this.snaps.findById(this.activeId);
|
|
3367
|
-
if (!current) return;
|
|
3368
|
-
this.size = current.size;
|
|
3369
|
-
this.applySize(this.size);
|
|
3370
|
-
this.updateAriaSlider();
|
|
3371
|
-
if (this.size > 0 && !this.lifecycle.isInstalled && !this.opening && !this.animation.isAnimating) {
|
|
3372
|
-
this.emitOpenSequence(this.activeId);
|
|
3373
|
-
}
|
|
3878
|
+
this.reseat();
|
|
3374
3879
|
}
|
|
3375
3880
|
destroy() {
|
|
3376
3881
|
this.destroyed = true;
|
|
3377
|
-
this.
|
|
3882
|
+
this.outbox.length = 0;
|
|
3378
3883
|
this.currentAbort.abort();
|
|
3379
3884
|
this.currentViewTransition?.skipTransition?.();
|
|
3380
3885
|
this.currentViewTransition = null;
|
|
@@ -3394,12 +3899,16 @@ class BottomSheetCore {
|
|
|
3394
3899
|
for (const host of [
|
|
3395
3900
|
this.anchorHost,
|
|
3396
3901
|
this.scrimParent,
|
|
3397
|
-
this.rootEl
|
|
3902
|
+
this.rootEl,
|
|
3903
|
+
this.homeRoot
|
|
3398
3904
|
]) {
|
|
3399
3905
|
if (!host) continue;
|
|
3400
3906
|
host.style.removeProperty("--bs-size");
|
|
3401
3907
|
host.style.removeProperty("--bs-progress");
|
|
3908
|
+
host.style.removeProperty("--bs-z-sheet");
|
|
3909
|
+
host.style.removeProperty("--bs-keyboard-inset");
|
|
3402
3910
|
}
|
|
3911
|
+
this.element.style.removeProperty("--bs-keyboard-inset");
|
|
3403
3912
|
if (this.screenComponent) {
|
|
3404
3913
|
this.screenComponent.style.opacity = "";
|
|
3405
3914
|
this.screenComponent.style.display = "";
|
|
@@ -3412,7 +3921,8 @@ class BottomSheetCore {
|
|
|
3412
3921
|
}
|
|
3413
3922
|
newCycle() {
|
|
3414
3923
|
this.allowOvershoot = false;
|
|
3415
|
-
this.
|
|
3924
|
+
this.transition = null;
|
|
3925
|
+
this.inFlight = null;
|
|
3416
3926
|
this.currentAbort.abort();
|
|
3417
3927
|
this.currentAbort = new AbortController();
|
|
3418
3928
|
return this.currentAbort.signal;
|
|
@@ -3433,8 +3943,9 @@ class BottomSheetCore {
|
|
|
3433
3943
|
if (typeof document === "undefined") return;
|
|
3434
3944
|
if (!this.lifecycle.focusTrapEnabled) return;
|
|
3435
3945
|
if (this.element.getAttribute("aria-labelledby")) return;
|
|
3436
|
-
const
|
|
3437
|
-
const
|
|
3946
|
+
const HEADING = "h1,h2,h3,h4,h5,h6";
|
|
3947
|
+
const header = this.element.querySelector(".bs-header");
|
|
3948
|
+
const titled = this.element.querySelector("[data-bs-title]") ?? this.handle.querySelector(HEADING) ?? header?.querySelector(HEADING);
|
|
3438
3949
|
if (!titled) return;
|
|
3439
3950
|
if (!titled.id) {
|
|
3440
3951
|
titled.id = nextInstanceId("bs-title");
|
|
@@ -3472,12 +3983,16 @@ class BottomSheetCore {
|
|
|
3472
3983
|
this.stackZ = z;
|
|
3473
3984
|
this.element.style.zIndex = String(z);
|
|
3474
3985
|
if (this.backdrop) this.backdrop.style.zIndex = String(z - 1);
|
|
3986
|
+
this.rootEl?.style.setProperty("--bs-z-sheet", String(z));
|
|
3987
|
+
this.homeRoot?.style.setProperty("--bs-z-sheet", String(z));
|
|
3475
3988
|
for (const anchor of this.anchors) anchor.syncZ(z + 1);
|
|
3476
3989
|
},
|
|
3477
3990
|
setIsTop: (isTop) => {
|
|
3991
|
+
if (isTop === this.isTopSheet) return;
|
|
3478
3992
|
this.isTopSheet = isTop;
|
|
3993
|
+
this.lifecycle.syncTop();
|
|
3479
3994
|
},
|
|
3480
|
-
isOpen: () => this.
|
|
3995
|
+
isOpen: () => this.phase !== "closed",
|
|
3481
3996
|
setDepth: (depth) => this.applyStackDepth(depth)
|
|
3482
3997
|
}));
|
|
3483
3998
|
}
|
|
@@ -3505,15 +4020,15 @@ class BottomSheetCore {
|
|
|
3505
4020
|
const r = this.getAllowedRange();
|
|
3506
4021
|
buf.size = this.size;
|
|
3507
4022
|
buf.maxAxisSize = this.snaps.getMaxAxisSize();
|
|
3508
|
-
buf.range.min = r.min;
|
|
4023
|
+
buf.range.min = this.dismissBlocked() ? Math.max(r.min, this.smallestOpenSize()) : r.min;
|
|
3509
4024
|
buf.range.max = r.max;
|
|
3510
4025
|
buf.rubberBandEnabled = this.rubberBandEnabled;
|
|
3511
4026
|
return buf;
|
|
3512
4027
|
},
|
|
3513
4028
|
getDisableDrag: () => this.disableDragFlag,
|
|
3514
|
-
cancelAnimation: () => this.
|
|
4029
|
+
cancelAnimation: () => this.suspend(),
|
|
3515
4030
|
applySize: (size) => this.applySize(size),
|
|
3516
|
-
|
|
4031
|
+
restoreAfterDrag: () => this.restoreAfterDrag(),
|
|
3517
4032
|
settleAfterDrag: (delta, velocity, kind) => this.settleAfterDrag(delta, velocity, kind),
|
|
3518
4033
|
emit: (event, payload) => this.emit(event, payload),
|
|
3519
4034
|
listenerCount: (event) => this.bus.listenerCount(event)
|
|
@@ -3630,32 +4145,19 @@ class BottomSheetCore {
|
|
|
3630
4145
|
element: this.element,
|
|
3631
4146
|
getMode: () => this.mode,
|
|
3632
4147
|
isDestroyed: () => this.destroyed,
|
|
3633
|
-
isDragging: () => this.isDraggingAny(),
|
|
3634
4148
|
resolveActiveSnap: () => this.snaps.findById(this.activeId),
|
|
3635
4149
|
getMaxAxisSize: () => this.snaps.getMaxAxisSize(),
|
|
3636
|
-
getSize: () => this.size,
|
|
3637
4150
|
setMaxAxisSize: (size) => {
|
|
3638
4151
|
this.snaps.setMaxAxisSize(size);
|
|
3639
4152
|
},
|
|
3640
|
-
setSize: (size) => {
|
|
3641
|
-
this.size = size;
|
|
3642
|
-
},
|
|
3643
4153
|
recomputeSnaps: () => this.recomputeSnaps(),
|
|
3644
|
-
|
|
3645
|
-
|
|
3646
|
-
this.animation.cancel();
|
|
3647
|
-
},
|
|
3648
|
-
newCycle: () => {
|
|
3649
|
-
this.newCycle();
|
|
3650
|
-
},
|
|
3651
|
-
isAnimating: () => this.animation.isAnimating,
|
|
3652
|
-
resyncAfterCancel: () => this.resyncAfterResize()
|
|
4154
|
+
reseat: () => this.reseat(),
|
|
4155
|
+
landNow: () => this.landNow()
|
|
3653
4156
|
}));
|
|
3654
4157
|
if (this.lifecycle.closeOnEscape) {
|
|
3655
4158
|
const onKey = (e) => {
|
|
3656
4159
|
if (this.destroyed || e.defaultPrevented) return;
|
|
3657
|
-
if (
|
|
3658
|
-
if (e.key === "Escape" && this.isTopSheet && this.size > 0) {
|
|
4160
|
+
if (e.key === "Escape" && this.isTopSheet) {
|
|
3659
4161
|
void this.close("escape");
|
|
3660
4162
|
}
|
|
3661
4163
|
};
|
|
@@ -3671,7 +4173,10 @@ class BottomSheetCore {
|
|
|
3671
4173
|
handle: this.handle,
|
|
3672
4174
|
mode: this.mode,
|
|
3673
4175
|
isDestroyed: () => this.destroyed,
|
|
3674
|
-
getAllowedIds: () =>
|
|
4176
|
+
getAllowedIds: () => {
|
|
4177
|
+
const ids = this.allowedIdsBySize();
|
|
4178
|
+
return this.dismissBlocked() ? ids.filter((id) => (this.snaps.findById(id)?.size ?? 0) > 0) : ids;
|
|
4179
|
+
},
|
|
3675
4180
|
getActiveId: () => this.activeId,
|
|
3676
4181
|
snapTo: (id) => {
|
|
3677
4182
|
void this.snapTo(id);
|
|
@@ -3684,7 +4189,6 @@ class BottomSheetCore {
|
|
|
3684
4189
|
});
|
|
3685
4190
|
}
|
|
3686
4191
|
settleAfterDrag(delta, velocity, kind = "touch") {
|
|
3687
|
-
const signal = this.newCycle();
|
|
3688
4192
|
const target = this.snaps.findDragSettleTarget({
|
|
3689
4193
|
delta,
|
|
3690
4194
|
velocity,
|
|
@@ -3693,41 +4197,35 @@ class BottomSheetCore {
|
|
|
3693
4197
|
activeId: this.activeId,
|
|
3694
4198
|
flickVelocity: this.flickVelocity,
|
|
3695
4199
|
dragThreshold: this.dragThreshold
|
|
3696
|
-
});
|
|
4200
|
+
}, this.dismissBlocked());
|
|
3697
4201
|
if (!target) {
|
|
3698
4202
|
this.clearWillChangeIfIdle();
|
|
3699
4203
|
return;
|
|
3700
4204
|
}
|
|
3701
4205
|
const previousId = this.activeId;
|
|
3702
4206
|
if (target.id === previousId && target.size === this.size) {
|
|
4207
|
+
if (this.phase === "opening" || this.phase === "closing") {
|
|
4208
|
+
this.land(false);
|
|
4209
|
+
}
|
|
3703
4210
|
this.clearWillChangeIfIdle();
|
|
3704
4211
|
return;
|
|
3705
4212
|
}
|
|
3706
4213
|
if (this.emitBeforeSnap(target, previousId)) {
|
|
3707
|
-
|
|
3708
|
-
if (restore2) {
|
|
3709
|
-
void this.animation.animateTo(restore2.size, 0);
|
|
3710
|
-
}
|
|
4214
|
+
this.restoreAfterDrag();
|
|
3711
4215
|
return;
|
|
3712
4216
|
}
|
|
3713
|
-
|
|
3714
|
-
|
|
3715
|
-
|
|
3716
|
-
|
|
3717
|
-
if (
|
|
3718
|
-
|
|
3719
|
-
|
|
3720
|
-
|
|
3721
|
-
|
|
3722
|
-
|
|
3723
|
-
|
|
3724
|
-
|
|
3725
|
-
void this.animation.animateTo(settleSize, velocity).then(() => {
|
|
3726
|
-
if (signal.aborted) return;
|
|
3727
|
-
this.allowOvershoot = false;
|
|
3728
|
-
this.opening = false;
|
|
3729
|
-
this.completeSnap(target.id, target.size, previousSize, previousSnapSize === 0, true);
|
|
3730
|
-
});
|
|
4217
|
+
void this.runTransition(target, velocity, true);
|
|
4218
|
+
}
|
|
4219
|
+
restoreAfterDrag() {
|
|
4220
|
+
const active = this.snaps.findById(this.activeId);
|
|
4221
|
+
if (active) void this.runTransition(active, 0, false);
|
|
4222
|
+
}
|
|
4223
|
+
smallestOpenSize() {
|
|
4224
|
+
const allowed = this.snaps.getAllowedIds();
|
|
4225
|
+
for (const snap of this.snaps.getResolvedSnaps()) {
|
|
4226
|
+
if (snap.size > 0 && allowed.includes(snap.id)) return snap.size;
|
|
4227
|
+
}
|
|
4228
|
+
return 0;
|
|
3731
4229
|
}
|
|
3732
4230
|
isDraggingAny() {
|
|
3733
4231
|
return (this.gesture?.isDragging ?? false) || (this.contentGesture?.isDragging ?? false);
|
|
@@ -3752,7 +4250,8 @@ class BottomSheetCore {
|
|
|
3752
4250
|
const offset = cap - clamped;
|
|
3753
4251
|
const style = this.element.style;
|
|
3754
4252
|
if (!skipTransform) style.transform = this.transformTemplate(offset);
|
|
3755
|
-
const
|
|
4253
|
+
const moving = this.animation.isAnimating || this.isDraggingAny();
|
|
4254
|
+
const sizeChanged = this.sizeWriteSentinel.shouldWrite(clamped, moving ? SIZE_WRITE_EPSILON : 0);
|
|
3756
4255
|
if (sizeChanged) {
|
|
3757
4256
|
style.setProperty("--bs-size", `${clamped}px`);
|
|
3758
4257
|
if (this.scrimParent) {
|
|
@@ -3764,9 +4263,11 @@ class BottomSheetCore {
|
|
|
3764
4263
|
if (this.rootEl && this.rootEl !== this.scrimParent && this.rootEl !== this.anchorHost) {
|
|
3765
4264
|
this.rootEl.style.setProperty("--bs-size", `${clamped}px`);
|
|
3766
4265
|
}
|
|
4266
|
+
this.homeRoot?.style.setProperty("--bs-size", `${clamped}px`);
|
|
3767
4267
|
}
|
|
3768
4268
|
const progress = this.computeProgress(clamped);
|
|
3769
|
-
const
|
|
4269
|
+
const opacityEpsilon = moving ? OPACITY_WRITE_EPSILON : 0;
|
|
4270
|
+
const progressChanged = this.progressWriteSentinel.shouldWrite(progress, opacityEpsilon);
|
|
3770
4271
|
if (progressChanged) {
|
|
3771
4272
|
style.setProperty("--bs-progress", String(progress));
|
|
3772
4273
|
if (this.anchorHost) {
|
|
@@ -3775,8 +4276,9 @@ class BottomSheetCore {
|
|
|
3775
4276
|
if (this.rootEl && this.rootEl !== this.anchorHost) {
|
|
3776
4277
|
this.rootEl.style.setProperty("--bs-progress", String(progress));
|
|
3777
4278
|
}
|
|
4279
|
+
this.homeRoot?.style.setProperty("--bs-progress", String(progress));
|
|
3778
4280
|
}
|
|
3779
|
-
this.scrim.applyOpacity(progress, progressChanged);
|
|
4281
|
+
this.scrim.applyOpacity(progress, progressChanged, opacityEpsilon);
|
|
3780
4282
|
if ((progressChanged || sizeChanged) && this.bus.listenerCount("progress") > 0) {
|
|
3781
4283
|
this.progressPayload.value = progress;
|
|
3782
4284
|
this.progressPayload.size = clamped;
|
|
@@ -3789,236 +4291,328 @@ class BottomSheetCore {
|
|
|
3789
4291
|
if (reachableMax <= min) return 0;
|
|
3790
4292
|
return Math.min(Math.max((size - min) / (reachableMax - min), 0), 1);
|
|
3791
4293
|
}
|
|
3792
|
-
handleOpen() {
|
|
3793
|
-
if (this.promotedForOpen) this.promotedForOpen = false;
|
|
3794
|
-
else sheetStack.promote(this.id);
|
|
3795
|
-
try {
|
|
3796
|
-
this.lifecycle.install();
|
|
3797
|
-
} catch (err) {
|
|
3798
|
-
if (!this.destroyed) this.newCycle();
|
|
3799
|
-
this.handleClose();
|
|
3800
|
-
this.applySize(0);
|
|
3801
|
-
this.activeId = this.snapPointsRaw.find((p) => p.id === "closed")?.id ?? this.activeId;
|
|
3802
|
-
this.size = 0;
|
|
3803
|
-
queueMicrotask(() => {
|
|
3804
|
-
throw err;
|
|
3805
|
-
});
|
|
3806
|
-
}
|
|
3807
|
-
}
|
|
3808
|
-
resyncAfterResize() {
|
|
3809
|
-
if (this.destroyed) return;
|
|
3810
|
-
const target = this.snaps.findById(this.activeId);
|
|
3811
|
-
if (!target) return;
|
|
3812
|
-
this.updateAriaSlider();
|
|
3813
|
-
this.emit("snap", {
|
|
3814
|
-
id: target.id,
|
|
3815
|
-
size: this.size,
|
|
3816
|
-
progress: this.computeProgress(this.size)
|
|
3817
|
-
});
|
|
3818
|
-
if (target.size > 0 && !this.lifecycle.isInstalled) {
|
|
3819
|
-
this.emitOpenSequence(target.id);
|
|
3820
|
-
} else if (target.size === 0 && this.lifecycle.isInstalled) {
|
|
3821
|
-
this.emitCloseSequence();
|
|
3822
|
-
}
|
|
3823
|
-
}
|
|
3824
|
-
handleClose() {
|
|
3825
|
-
this.opening = false;
|
|
3826
|
-
this.promotedForOpen = false;
|
|
3827
|
-
this.lifecycle.release();
|
|
3828
|
-
sheetStack.update();
|
|
3829
|
-
}
|
|
3830
4294
|
}
|
|
3831
|
-
const
|
|
3832
|
-
const
|
|
3833
|
-
|
|
3834
|
-
|
|
3835
|
-
const
|
|
3836
|
-
|
|
3837
|
-
|
|
3838
|
-
|
|
3839
|
-
|
|
3840
|
-
|
|
3841
|
-
|
|
3842
|
-
|
|
3843
|
-
|
|
3844
|
-
|
|
4295
|
+
const MARKER = "__bs";
|
|
4296
|
+
const STACK = "__bsStack";
|
|
4297
|
+
const DEPTH = "__bsDepth";
|
|
4298
|
+
const ROUTED = "__bsRouted";
|
|
4299
|
+
const SETTLE_TIMEOUT_MS = 1e3;
|
|
4300
|
+
const state = shared("history", () => ({
|
|
4301
|
+
live: [],
|
|
4302
|
+
stackId: void 0,
|
|
4303
|
+
baseUrl: void 0,
|
|
4304
|
+
position: null,
|
|
4305
|
+
knownLength: 0,
|
|
4306
|
+
href: "",
|
|
4307
|
+
subscribers: /* @__PURE__ */ new Set(),
|
|
4308
|
+
internal: 0,
|
|
4309
|
+
pending: [],
|
|
4310
|
+
deferred: [],
|
|
4311
|
+
waiters: [],
|
|
4312
|
+
timer: null,
|
|
4313
|
+
listening: false,
|
|
4314
|
+
leftovers: false,
|
|
4315
|
+
orphanChecked: false,
|
|
4316
|
+
push: null,
|
|
4317
|
+
replace: null
|
|
4318
|
+
}));
|
|
4319
|
+
const hasHistory = () => typeof window !== "undefined" && typeof history !== "undefined";
|
|
4320
|
+
const plain = (value) => value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
4321
|
+
const depthOf = (value) => {
|
|
4322
|
+
const depth = value?.[DEPTH];
|
|
4323
|
+
return typeof depth === "number" ? depth : null;
|
|
4324
|
+
};
|
|
4325
|
+
const isMarker = (value) => value?.[MARKER] === true;
|
|
4326
|
+
const inStack = (value) => value !== null && state.stackId !== void 0 && value[STACK] === state.stackId && depthOf(value) !== null;
|
|
4327
|
+
const foreignKeys = (value) => {
|
|
4328
|
+
const out = {};
|
|
4329
|
+
const source = plain(value);
|
|
4330
|
+
if (!source) return out;
|
|
4331
|
+
for (const key of Object.keys(source)) {
|
|
4332
|
+
if (!key.startsWith(MARKER)) out[key] = source[key];
|
|
4333
|
+
}
|
|
4334
|
+
return out;
|
|
4335
|
+
};
|
|
4336
|
+
const markerFor = (surface, depth) => ({
|
|
4337
|
+
...foreignKeys(history.state),
|
|
3845
4338
|
...surface.markerState(),
|
|
3846
|
-
|
|
4339
|
+
[MARKER]: true,
|
|
4340
|
+
[STACK]: state.stackId,
|
|
4341
|
+
[DEPTH]: depth
|
|
3847
4342
|
});
|
|
4343
|
+
const urlForDepth = (depth) => {
|
|
4344
|
+
for (let i = depth - 1; i >= 0; i -= 1) {
|
|
4345
|
+
const url = state.live[i]?.surface.url;
|
|
4346
|
+
if (url !== void 0) return url;
|
|
4347
|
+
}
|
|
4348
|
+
return state.baseUrl;
|
|
4349
|
+
};
|
|
3848
4350
|
const runInternal = (fn) => {
|
|
3849
|
-
|
|
4351
|
+
state.internal += 1;
|
|
3850
4352
|
try {
|
|
3851
4353
|
fn();
|
|
4354
|
+
return true;
|
|
4355
|
+
} catch {
|
|
4356
|
+
return false;
|
|
3852
4357
|
} finally {
|
|
3853
|
-
|
|
4358
|
+
state.internal -= 1;
|
|
3854
4359
|
}
|
|
3855
4360
|
};
|
|
3856
4361
|
const notifyRouteChange = () => {
|
|
3857
|
-
const
|
|
3858
|
-
|
|
4362
|
+
for (const fn of Array.from(state.subscribers)) {
|
|
4363
|
+
try {
|
|
4364
|
+
fn();
|
|
4365
|
+
} catch (err) {
|
|
4366
|
+
queueMicrotask(() => {
|
|
4367
|
+
throw err;
|
|
4368
|
+
});
|
|
4369
|
+
}
|
|
4370
|
+
}
|
|
3859
4371
|
};
|
|
3860
4372
|
const ensureListener = () => {
|
|
3861
|
-
if (
|
|
4373
|
+
if (state.listening || !hasHistory()) return;
|
|
3862
4374
|
window.addEventListener("popstate", onPopState);
|
|
3863
|
-
|
|
4375
|
+
state.listening = true;
|
|
3864
4376
|
};
|
|
3865
4377
|
const maybeTeardownListener = () => {
|
|
3866
|
-
if (!
|
|
3867
|
-
if (
|
|
3868
|
-
if (hasWindow()) window.removeEventListener("popstate", onPopState);
|
|
3869
|
-
listenerInstalled = false;
|
|
3870
|
-
};
|
|
3871
|
-
const installPatch = () => {
|
|
3872
|
-
if (patchInstalled || !hasHistory()) return;
|
|
3873
|
-
origPushState = history.pushState;
|
|
3874
|
-
origReplaceState = history.replaceState;
|
|
3875
|
-
patchedPushState = function(...args) {
|
|
3876
|
-
origPushState.apply(this, args);
|
|
3877
|
-
if (internalDepth === 0) notifyRouteChange();
|
|
3878
|
-
};
|
|
3879
|
-
patchedReplaceState = function(...args) {
|
|
3880
|
-
origReplaceState.apply(this, args);
|
|
3881
|
-
if (internalDepth === 0) notifyRouteChange();
|
|
3882
|
-
};
|
|
3883
|
-
history.pushState = patchedPushState;
|
|
3884
|
-
history.replaceState = patchedReplaceState;
|
|
3885
|
-
patchInstalled = true;
|
|
3886
|
-
};
|
|
3887
|
-
const removePatch = () => {
|
|
3888
|
-
if (!patchInstalled) return;
|
|
3889
|
-
if (history.pushState === patchedPushState && origPushState) {
|
|
3890
|
-
history.pushState = origPushState;
|
|
3891
|
-
}
|
|
3892
|
-
if (history.replaceState === patchedReplaceState && origReplaceState) {
|
|
3893
|
-
history.replaceState = origReplaceState;
|
|
3894
|
-
}
|
|
3895
|
-
origPushState = null;
|
|
3896
|
-
origReplaceState = null;
|
|
3897
|
-
patchedPushState = null;
|
|
3898
|
-
patchedReplaceState = null;
|
|
3899
|
-
patchInstalled = false;
|
|
3900
|
-
};
|
|
3901
|
-
function onPopState() {
|
|
3902
|
-
if (suppress > 0) {
|
|
3903
|
-
suppress -= 1;
|
|
3904
|
-
const rebrand = pendingRebrands.shift();
|
|
3905
|
-
if (rebrand) rebrand();
|
|
3906
|
-
maybeTeardownListener();
|
|
4378
|
+
if (!state.listening) return;
|
|
4379
|
+
if (state.live.length > 0 || state.subscribers.size > 0 || state.pending.length > 0 || state.leftovers) {
|
|
3907
4380
|
return;
|
|
3908
4381
|
}
|
|
3909
|
-
if (
|
|
3910
|
-
|
|
3911
|
-
|
|
3912
|
-
|
|
3913
|
-
|
|
3914
|
-
|
|
3915
|
-
|
|
3916
|
-
|
|
3917
|
-
|
|
3918
|
-
|
|
3919
|
-
|
|
3920
|
-
|
|
3921
|
-
|
|
3922
|
-
|
|
3923
|
-
|
|
3924
|
-
|
|
3925
|
-
|
|
3926
|
-
|
|
3927
|
-
|
|
3928
|
-
}
|
|
3929
|
-
if (!target) {
|
|
3930
|
-
const removed = entries.pop();
|
|
3931
|
-
if (removed) removed.live = false;
|
|
4382
|
+
if (hasHistory()) window.removeEventListener("popstate", onPopState);
|
|
4383
|
+
state.listening = false;
|
|
4384
|
+
};
|
|
4385
|
+
const settleIfIdle = () => {
|
|
4386
|
+
if (state.pending.length > 0) return;
|
|
4387
|
+
if (state.timer !== null) {
|
|
4388
|
+
clearTimeout(state.timer);
|
|
4389
|
+
state.timer = null;
|
|
4390
|
+
}
|
|
4391
|
+
for (const entry of state.deferred.splice(0)) pushEntry(entry);
|
|
4392
|
+
for (const resolve of state.waiters.splice(0)) resolve();
|
|
4393
|
+
};
|
|
4394
|
+
const traverse = (delta, kind) => {
|
|
4395
|
+
state.pending.push(kind);
|
|
4396
|
+
if (state.timer !== null) clearTimeout(state.timer);
|
|
4397
|
+
state.timer = setTimeout(() => {
|
|
4398
|
+
state.timer = null;
|
|
4399
|
+
state.pending.length = 0;
|
|
4400
|
+
settleIfIdle();
|
|
3932
4401
|
maybeTeardownListener();
|
|
3933
|
-
|
|
4402
|
+
}, SETTLE_TIMEOUT_MS);
|
|
4403
|
+
ensureListener();
|
|
4404
|
+
const moved = runInternal(() => {
|
|
4405
|
+
if (delta < 0) history.back();
|
|
4406
|
+
else history.forward();
|
|
4407
|
+
});
|
|
4408
|
+
if (!moved) {
|
|
4409
|
+
state.pending.pop();
|
|
4410
|
+
settleIfIdle();
|
|
3934
4411
|
}
|
|
3935
|
-
|
|
3936
|
-
|
|
3937
|
-
|
|
3938
|
-
|
|
3939
|
-
|
|
4412
|
+
};
|
|
4413
|
+
const newStackId = () => `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
4414
|
+
const startStack = () => {
|
|
4415
|
+
state.stackId = newStackId();
|
|
4416
|
+
const current = history.state;
|
|
4417
|
+
const leftover = plain(current);
|
|
4418
|
+
state.baseUrl = isMarker(leftover) && leftover?.[ROUTED] !== void 0 ? void 0 : location.href;
|
|
4419
|
+
if (isMarker(leftover)) return;
|
|
4420
|
+
if (current !== null && current !== void 0 && !leftover) return;
|
|
4421
|
+
runInternal(() => {
|
|
4422
|
+
history.replaceState({
|
|
4423
|
+
...foreignKeys(current),
|
|
4424
|
+
[STACK]: state.stackId,
|
|
4425
|
+
[DEPTH]: 0
|
|
4426
|
+
}, "", location.href);
|
|
3940
4427
|
});
|
|
3941
|
-
|
|
4428
|
+
};
|
|
4429
|
+
function pushEntry(entry) {
|
|
4430
|
+
const depth = state.live.length + 1;
|
|
4431
|
+
if (state.live.length === 0) startStack();
|
|
4432
|
+
const written = runInternal(() => {
|
|
4433
|
+
history.pushState(markerFor(entry.surface, depth), "", entry.surface.url);
|
|
4434
|
+
});
|
|
4435
|
+
if (!written) return false;
|
|
4436
|
+
state.live.push(entry);
|
|
4437
|
+
state.position = depth;
|
|
4438
|
+
state.knownLength = history.length;
|
|
4439
|
+
state.href = location.href;
|
|
4440
|
+
ensureListener();
|
|
4441
|
+
return true;
|
|
3942
4442
|
}
|
|
3943
|
-
|
|
3944
|
-
if (
|
|
3945
|
-
entry
|
|
4443
|
+
const enlist = (entry) => {
|
|
4444
|
+
if (state.pending.length > 0) state.deferred.push(entry);
|
|
4445
|
+
else pushEntry(entry);
|
|
4446
|
+
};
|
|
4447
|
+
const sameBrand = (a, b) => {
|
|
4448
|
+
for (const key of /* @__PURE__ */ new Set([
|
|
4449
|
+
...Object.keys(a),
|
|
4450
|
+
...Object.keys(b)
|
|
4451
|
+
])) {
|
|
4452
|
+
if (key.startsWith(MARKER) && a[key] !== b[key]) return false;
|
|
4453
|
+
}
|
|
4454
|
+
return true;
|
|
4455
|
+
};
|
|
4456
|
+
const rebrand = (depth) => {
|
|
4457
|
+
const entry = state.live[depth - 1];
|
|
4458
|
+
if (!entry) return;
|
|
4459
|
+
const url = urlForDepth(depth);
|
|
4460
|
+
const marker = markerFor(entry.surface, depth);
|
|
4461
|
+
const atUrl = url === void 0 || new URL(url, location.href).href === location.href;
|
|
4462
|
+
if (atUrl && sameBrand(plain(history.state) ?? {}, marker)) return;
|
|
3946
4463
|
runInternal(() => {
|
|
4464
|
+
history.replaceState(marker, "", url);
|
|
4465
|
+
});
|
|
4466
|
+
state.href = location.href;
|
|
4467
|
+
};
|
|
4468
|
+
const closeAbove = (depth) => {
|
|
4469
|
+
const dropped = state.live.splice(depth);
|
|
4470
|
+
for (let i = dropped.length - 1; i >= 0; i -= 1) {
|
|
4471
|
+
const entry = dropped[i];
|
|
4472
|
+
let closing = void 0;
|
|
3947
4473
|
try {
|
|
3948
|
-
|
|
3949
|
-
} catch {
|
|
3950
|
-
|
|
4474
|
+
closing = entry.surface.close();
|
|
4475
|
+
} catch (err) {
|
|
4476
|
+
queueMicrotask(() => {
|
|
4477
|
+
throw err;
|
|
4478
|
+
});
|
|
3951
4479
|
}
|
|
3952
|
-
|
|
3953
|
-
|
|
3954
|
-
|
|
3955
|
-
|
|
4480
|
+
void Promise.resolve(closing).then(() => {
|
|
4481
|
+
if (!entry.surface.isOpen()) return;
|
|
4482
|
+
const known = (e) => e.surface === entry.surface;
|
|
4483
|
+
if (state.live.some(known) || state.deferred.some(known)) return;
|
|
4484
|
+
enlist(entry);
|
|
4485
|
+
});
|
|
3956
4486
|
}
|
|
4487
|
+
};
|
|
4488
|
+
function onPopState(event) {
|
|
4489
|
+
const kind = state.pending.shift();
|
|
4490
|
+
const byUser = kind !== "pop";
|
|
4491
|
+
const landed = plain(event.state);
|
|
4492
|
+
const depth = depthOf(landed);
|
|
4493
|
+
const from = state.position;
|
|
4494
|
+
const liveBefore = state.live.length;
|
|
4495
|
+
const grew = history.length > state.knownLength;
|
|
4496
|
+
state.knownLength = history.length;
|
|
4497
|
+
const within = inStack(landed);
|
|
4498
|
+
if (within && depth !== null) {
|
|
4499
|
+
state.position = depth;
|
|
4500
|
+
if (depth > state.live.length) {
|
|
4501
|
+
const forward = from !== null && from < depth;
|
|
4502
|
+
traverse(forward ? 1 : -1, byUser ? "skip" : "pop");
|
|
4503
|
+
} else if (depth < state.live.length) {
|
|
4504
|
+
if (byUser) closeAbove(depth);
|
|
4505
|
+
} else {
|
|
4506
|
+
rebrand(depth);
|
|
4507
|
+
}
|
|
4508
|
+
} else if (isMarker(landed)) {
|
|
4509
|
+
state.position = null;
|
|
4510
|
+
traverse(-1, byUser ? "skip" : "pop");
|
|
4511
|
+
} else {
|
|
4512
|
+
state.position = null;
|
|
4513
|
+
if (byUser && !grew && state.live.length > 0) {
|
|
4514
|
+
closeAbove(state.live.length - 1);
|
|
4515
|
+
}
|
|
4516
|
+
}
|
|
4517
|
+
const moved = location.href !== state.href;
|
|
4518
|
+
state.href = location.href;
|
|
4519
|
+
if (kind === void 0 && moved && (liveBefore === 0 || !within)) {
|
|
4520
|
+
notifyRouteChange();
|
|
4521
|
+
}
|
|
4522
|
+
settleIfIdle();
|
|
4523
|
+
maybeTeardownListener();
|
|
3957
4524
|
}
|
|
3958
4525
|
function pushBackMarker(surface) {
|
|
3959
4526
|
const entry = {
|
|
3960
|
-
surface
|
|
3961
|
-
priorUrl: void 0,
|
|
3962
|
-
live: false
|
|
4527
|
+
surface
|
|
3963
4528
|
};
|
|
3964
|
-
if (
|
|
3965
|
-
return entry;
|
|
3966
|
-
}
|
|
3967
|
-
entry.priorUrl = surface.url !== void 0 ? location.href : void 0;
|
|
3968
|
-
runInternal(() => {
|
|
3969
|
-
try {
|
|
3970
|
-
history.pushState(brandMarker(surface), "", surface.url);
|
|
3971
|
-
entry.live = true;
|
|
3972
|
-
} catch {
|
|
3973
|
-
entry.live = false;
|
|
3974
|
-
}
|
|
3975
|
-
});
|
|
3976
|
-
if (entry.live) {
|
|
3977
|
-
entries.push(entry);
|
|
3978
|
-
ensureListener();
|
|
3979
|
-
}
|
|
4529
|
+
if (hasHistory()) enlist(entry);
|
|
3980
4530
|
return entry;
|
|
3981
4531
|
}
|
|
3982
4532
|
function popBackMarker(handle) {
|
|
3983
|
-
if (!
|
|
4533
|
+
if (!hasHistory()) return Promise.resolve();
|
|
3984
4534
|
const entry = handle;
|
|
3985
|
-
const
|
|
3986
|
-
if (
|
|
3987
|
-
const
|
|
3988
|
-
|
|
3989
|
-
|
|
3990
|
-
|
|
3991
|
-
|
|
3992
|
-
|
|
3993
|
-
|
|
3994
|
-
|
|
3995
|
-
|
|
3996
|
-
|
|
3997
|
-
|
|
3998
|
-
};
|
|
4535
|
+
const waiting = state.deferred.indexOf(entry);
|
|
4536
|
+
if (waiting !== -1) state.deferred.splice(waiting, 1);
|
|
4537
|
+
const idx = state.live.indexOf(entry);
|
|
4538
|
+
if (idx === -1) return historySettled();
|
|
4539
|
+
const top = state.live.length;
|
|
4540
|
+
state.live.splice(idx, 1);
|
|
4541
|
+
const current = plain(history.state);
|
|
4542
|
+
const onTop = isMarker(current) && inStack(current) && depthOf(current) === top;
|
|
4543
|
+
if (onTop && state.pending.length === 0) {
|
|
4544
|
+
traverse(-1, "pop");
|
|
4545
|
+
} else {
|
|
4546
|
+
state.leftovers = true;
|
|
4547
|
+
ensureListener();
|
|
3999
4548
|
}
|
|
4000
|
-
pendingRebrands.push(rebrand);
|
|
4001
|
-
suppress += 1;
|
|
4002
|
-
runInternal(() => {
|
|
4003
|
-
try {
|
|
4004
|
-
history.back();
|
|
4005
|
-
} catch {
|
|
4006
|
-
suppress = Math.max(0, suppress - 1);
|
|
4007
|
-
pendingRebrands.pop();
|
|
4008
|
-
}
|
|
4009
|
-
});
|
|
4010
4549
|
maybeTeardownListener();
|
|
4550
|
+
return historySettled();
|
|
4011
4551
|
}
|
|
4552
|
+
function releaseOrphanMarker() {
|
|
4553
|
+
if (!hasHistory() || state.orphanChecked) return;
|
|
4554
|
+
state.orphanChecked = true;
|
|
4555
|
+
if (state.live.length > 0 || state.pending.length > 0) return;
|
|
4556
|
+
if (!isMarker(plain(history.state))) return;
|
|
4557
|
+
state.leftovers = true;
|
|
4558
|
+
traverse(-1, "pop");
|
|
4559
|
+
}
|
|
4560
|
+
function historySettled() {
|
|
4561
|
+
if (state.pending.length === 0) return Promise.resolve();
|
|
4562
|
+
return new Promise((resolve) => {
|
|
4563
|
+
state.waiters.push(resolve);
|
|
4564
|
+
});
|
|
4565
|
+
}
|
|
4566
|
+
const wrap = (original) => function(...args) {
|
|
4567
|
+
original.apply(this, args);
|
|
4568
|
+
state.knownLength = history.length;
|
|
4569
|
+
if (location.href === state.href) return;
|
|
4570
|
+
state.href = location.href;
|
|
4571
|
+
if (state.internal === 0 && state.subscribers.size > 0) {
|
|
4572
|
+
notifyRouteChange();
|
|
4573
|
+
}
|
|
4574
|
+
};
|
|
4575
|
+
const installPatch = () => {
|
|
4576
|
+
if (!state.push || history.pushState === state.push.original) {
|
|
4577
|
+
const original = history.pushState;
|
|
4578
|
+
const wrapper = wrap(original);
|
|
4579
|
+
history.pushState = wrapper;
|
|
4580
|
+
state.push = {
|
|
4581
|
+
wrapper,
|
|
4582
|
+
original
|
|
4583
|
+
};
|
|
4584
|
+
}
|
|
4585
|
+
if (!state.replace || history.replaceState === state.replace.original) {
|
|
4586
|
+
const original = history.replaceState;
|
|
4587
|
+
const wrapper = wrap(original);
|
|
4588
|
+
history.replaceState = wrapper;
|
|
4589
|
+
state.replace = {
|
|
4590
|
+
wrapper,
|
|
4591
|
+
original
|
|
4592
|
+
};
|
|
4593
|
+
}
|
|
4594
|
+
};
|
|
4595
|
+
const removePatch = () => {
|
|
4596
|
+
if (state.push && history.pushState === state.push.wrapper) {
|
|
4597
|
+
history.pushState = state.push.original;
|
|
4598
|
+
state.push = null;
|
|
4599
|
+
}
|
|
4600
|
+
if (state.replace && history.replaceState === state.replace.wrapper) {
|
|
4601
|
+
history.replaceState = state.replace.original;
|
|
4602
|
+
state.replace = null;
|
|
4603
|
+
}
|
|
4604
|
+
};
|
|
4012
4605
|
function subscribeRouteChange(fn) {
|
|
4013
|
-
if (!
|
|
4606
|
+
if (!hasHistory()) return () => {
|
|
4014
4607
|
};
|
|
4015
|
-
subscribers.add(fn);
|
|
4016
|
-
|
|
4608
|
+
state.subscribers.add(fn);
|
|
4609
|
+
state.href = location.href;
|
|
4610
|
+
state.knownLength = history.length;
|
|
4611
|
+
installPatch();
|
|
4017
4612
|
ensureListener();
|
|
4018
4613
|
return () => {
|
|
4019
|
-
if (!subscribers.
|
|
4020
|
-
subscribers.
|
|
4021
|
-
if (subscribers.size === 0) removePatch();
|
|
4614
|
+
if (!state.subscribers.delete(fn)) return;
|
|
4615
|
+
if (state.subscribers.size === 0) removePatch();
|
|
4022
4616
|
maybeTeardownListener();
|
|
4023
4617
|
};
|
|
4024
4618
|
}
|
|
@@ -4032,40 +4626,41 @@ function installRoute(deps) {
|
|
|
4032
4626
|
};
|
|
4033
4627
|
}
|
|
4034
4628
|
let handle = null;
|
|
4629
|
+
const surface = {
|
|
4630
|
+
isOpen: () => !deps.isDestroyed() && deps.isOpen(),
|
|
4631
|
+
close: deps.close,
|
|
4632
|
+
markerState: () => deps.routedTo !== void 0 ? {
|
|
4633
|
+
__bsRouted: deps.sheetId
|
|
4634
|
+
} : {
|
|
4635
|
+
__bsSheet: deps.sheetId
|
|
4636
|
+
},
|
|
4637
|
+
url: deps.routedTo
|
|
4638
|
+
};
|
|
4035
4639
|
const onOpen = () => {
|
|
4036
4640
|
if (handle) return;
|
|
4037
|
-
handle = pushBackMarker(
|
|
4038
|
-
isOpen: () => !deps.isDestroyed() && deps.getSize() > 0,
|
|
4039
|
-
isTop: deps.isTopSheet,
|
|
4040
|
-
close: deps.close,
|
|
4041
|
-
markerState: () => deps.routedTo !== void 0 ? {
|
|
4042
|
-
__bsRouted: deps.sheetId
|
|
4043
|
-
} : {
|
|
4044
|
-
__bsSheet: deps.sheetId
|
|
4045
|
-
},
|
|
4046
|
-
url: deps.routedTo
|
|
4047
|
-
});
|
|
4641
|
+
handle = pushBackMarker(surface);
|
|
4048
4642
|
};
|
|
4049
4643
|
const onClose = () => {
|
|
4050
4644
|
if (!handle) return;
|
|
4051
|
-
popBackMarker(handle);
|
|
4645
|
+
deps.hold(popBackMarker(handle));
|
|
4052
4646
|
handle = null;
|
|
4053
4647
|
};
|
|
4054
4648
|
const unsubscribeOpen = deps.on("open", onOpen);
|
|
4055
4649
|
const unsubscribeClose = deps.on("close", onClose);
|
|
4056
|
-
if (deps.
|
|
4650
|
+
if (deps.isOpen()) onOpen();
|
|
4651
|
+
else releaseOrphanMarker();
|
|
4057
4652
|
return () => {
|
|
4058
4653
|
unsubscribeOpen();
|
|
4059
4654
|
unsubscribeClose();
|
|
4060
4655
|
if (handle) {
|
|
4061
|
-
popBackMarker(handle);
|
|
4656
|
+
void popBackMarker(handle);
|
|
4062
4657
|
handle = null;
|
|
4063
4658
|
}
|
|
4064
4659
|
};
|
|
4065
4660
|
}
|
|
4066
4661
|
function installRouteChange(deps) {
|
|
4067
4662
|
return subscribeRouteChange(() => {
|
|
4068
|
-
if (deps.isDestroyed() || deps.
|
|
4663
|
+
if (deps.isDestroyed() || !deps.isOpen()) return;
|
|
4069
4664
|
void deps.close();
|
|
4070
4665
|
});
|
|
4071
4666
|
}
|
|
@@ -4095,7 +4690,10 @@ function installAutoCollapse(deps) {
|
|
|
4095
4690
|
};
|
|
4096
4691
|
const fire = () => {
|
|
4097
4692
|
if (deps.isDestroyed()) return;
|
|
4098
|
-
if (deps.isDragging())
|
|
4693
|
+
if (deps.isDragging() || deps.isAnimating()) {
|
|
4694
|
+
reset();
|
|
4695
|
+
return;
|
|
4696
|
+
}
|
|
4099
4697
|
const active = deps.resolveSnap(deps.getActiveId());
|
|
4100
4698
|
if (!active || active.size === 0) return;
|
|
4101
4699
|
let target = null;
|
|
@@ -4128,6 +4726,9 @@ function installContentDrag(deps) {
|
|
|
4128
4726
|
return () => detach?.();
|
|
4129
4727
|
}
|
|
4130
4728
|
const SAFETY_PAD = 8;
|
|
4729
|
+
const KEYBOARD_MIN_INSET = 1;
|
|
4730
|
+
const KEYBOARD_MIN_COVER = 60;
|
|
4731
|
+
const ZOOMED = 1.01;
|
|
4131
4732
|
function installVisualViewport(deps) {
|
|
4132
4733
|
if (typeof window === "undefined" || !window.visualViewport) {
|
|
4133
4734
|
return () => {
|
|
@@ -4135,36 +4736,36 @@ function installVisualViewport(deps) {
|
|
|
4135
4736
|
}
|
|
4136
4737
|
const vv = window.visualViewport;
|
|
4137
4738
|
let rafId = null;
|
|
4739
|
+
const coveredByKeyboard = () => {
|
|
4740
|
+
if ((vv.scale || 1) > ZOOMED) return 0;
|
|
4741
|
+
const covered = window.innerHeight - ((vv.offsetTop || 0) + vv.height);
|
|
4742
|
+
return covered >= KEYBOARD_MIN_COVER ? Math.round(covered) : 0;
|
|
4743
|
+
};
|
|
4138
4744
|
const onResize = () => {
|
|
4139
4745
|
if (rafId !== null) return;
|
|
4140
4746
|
rafId = requestAnimationFrame(() => {
|
|
4141
4747
|
rafId = null;
|
|
4142
4748
|
if (deps.isDestroyed()) return;
|
|
4749
|
+
deps.setKeyboardInset(coveredByKeyboard());
|
|
4750
|
+
const before = seatOf(deps);
|
|
4143
4751
|
deps.recomputeSnaps();
|
|
4144
4752
|
const isVertical = deps.isVerticalAxis();
|
|
4145
4753
|
const visible = isVertical ? vv.height : vv.width;
|
|
4146
4754
|
const windowSize = isVertical ? window.innerHeight : window.innerWidth;
|
|
4147
|
-
const
|
|
4755
|
+
const pad = windowSize - visible > KEYBOARD_MIN_INSET ? SAFETY_PAD : 0;
|
|
4756
|
+
const clamp = Math.max(0, Math.min(windowSize, visible) - pad);
|
|
4148
4757
|
if (clamp < deps.getMaxAxisSize()) {
|
|
4149
4758
|
deps.setMaxAxisSize(clamp);
|
|
4150
4759
|
}
|
|
4151
|
-
|
|
4152
|
-
deps.
|
|
4153
|
-
deps.newCycle();
|
|
4154
|
-
const max = deps.getMaxAxisSize();
|
|
4155
|
-
deps.setSize(Math.min(deps.getSize(), max));
|
|
4156
|
-
const current = deps.resolveActiveSnap();
|
|
4157
|
-
if (current && !deps.isDragging()) {
|
|
4158
|
-
deps.applySize(Math.min(current.size, max));
|
|
4159
|
-
if (wasAnimating) deps.resyncAfterCancel?.();
|
|
4160
|
-
} else {
|
|
4161
|
-
deps.applySize(deps.getSize());
|
|
4162
|
-
}
|
|
4760
|
+
if (sameSeat(before, seatOf(deps))) return;
|
|
4761
|
+
deps.reseat();
|
|
4163
4762
|
});
|
|
4164
4763
|
};
|
|
4165
4764
|
vv.addEventListener("resize", onResize);
|
|
4765
|
+
vv.addEventListener("scroll", onResize);
|
|
4166
4766
|
return () => {
|
|
4167
4767
|
vv.removeEventListener("resize", onResize);
|
|
4768
|
+
vv.removeEventListener("scroll", onResize);
|
|
4168
4769
|
if (rafId !== null) cancelAnimationFrame(rafId);
|
|
4169
4770
|
};
|
|
4170
4771
|
}
|
|
@@ -4176,17 +4777,17 @@ function routeFeature() {
|
|
|
4176
4777
|
if (ctx.options.closeOnRouteChange) {
|
|
4177
4778
|
teardowns.add(installRouteChange({
|
|
4178
4779
|
isDestroyed: ctx.isDestroyed,
|
|
4179
|
-
|
|
4780
|
+
isOpen: () => ctx.getPhase() !== "closed",
|
|
4180
4781
|
close: () => ctx.close()
|
|
4181
4782
|
}));
|
|
4182
4783
|
}
|
|
4183
4784
|
teardowns.add(installRoute({
|
|
4184
4785
|
routedTo: ctx.options.routedTo,
|
|
4185
4786
|
closeOnBack: ctx.options.closeOnBack,
|
|
4186
|
-
|
|
4187
|
-
getSize: ctx.getSize,
|
|
4787
|
+
isOpen: () => ctx.getPhase() !== "closed",
|
|
4188
4788
|
isDestroyed: ctx.isDestroyed,
|
|
4189
4789
|
close: () => ctx.close("back"),
|
|
4790
|
+
hold: ctx.holdSettle,
|
|
4190
4791
|
on: ctx.on,
|
|
4191
4792
|
sheetId: ctx.sheetId
|
|
4192
4793
|
}));
|
|
@@ -4213,6 +4814,7 @@ function autoCollapseFeature() {
|
|
|
4213
4814
|
ms: ctx.options.autoCollapseAfter,
|
|
4214
4815
|
isDestroyed: ctx.isDestroyed,
|
|
4215
4816
|
isDragging: ctx.isDragging,
|
|
4817
|
+
isAnimating: ctx.isAnimating,
|
|
4216
4818
|
getAllowedIds: ctx.getAllowedIds,
|
|
4217
4819
|
getActiveId: ctx.getActiveId,
|
|
4218
4820
|
resolveSnap: ctx.resolveSnap,
|
|
@@ -4240,21 +4842,14 @@ function visualViewportFeature() {
|
|
|
4240
4842
|
install: (ctx) => {
|
|
4241
4843
|
if (typeof window === "undefined") return;
|
|
4242
4844
|
return installVisualViewport({
|
|
4243
|
-
element: ctx.element,
|
|
4244
4845
|
isVerticalAxis: ctx.isVerticalAxis,
|
|
4245
4846
|
isDestroyed: ctx.isDestroyed,
|
|
4246
|
-
isDragging: ctx.isDragging,
|
|
4247
4847
|
recomputeSnaps: ctx.recomputeSnaps,
|
|
4248
4848
|
resolveActiveSnap: ctx.resolveActiveSnap,
|
|
4249
4849
|
getMaxAxisSize: ctx.getMaxAxisSize,
|
|
4250
|
-
getSize: ctx.getSize,
|
|
4251
4850
|
setMaxAxisSize: ctx.setMaxAxisSize,
|
|
4252
|
-
|
|
4253
|
-
|
|
4254
|
-
cancelInFlight: ctx.cancelInFlight,
|
|
4255
|
-
newCycle: ctx.newCycle,
|
|
4256
|
-
isAnimating: ctx.isAnimating,
|
|
4257
|
-
resyncAfterCancel: ctx.resyncAfterResize
|
|
4851
|
+
setKeyboardInset: ctx.setKeyboardInset,
|
|
4852
|
+
reseat: ctx.reseat
|
|
4258
4853
|
});
|
|
4259
4854
|
}
|
|
4260
4855
|
};
|
|
@@ -4409,39 +5004,68 @@ class BottomSheetEngine extends BottomSheetCore {
|
|
|
4409
5004
|
});
|
|
4410
5005
|
}
|
|
4411
5006
|
}
|
|
4412
|
-
const
|
|
4413
|
-
|
|
4414
|
-
|
|
4415
|
-
|
|
4416
|
-
|
|
4417
|
-
|
|
4418
|
-
|
|
4419
|
-
|
|
4420
|
-
|
|
4421
|
-
|
|
4422
|
-
|
|
4423
|
-
|
|
4424
|
-
|
|
4425
|
-
|
|
4426
|
-
|
|
4427
|
-
|
|
4428
|
-
|
|
5007
|
+
const ENGINE_OPTION_KEYS = [
|
|
5008
|
+
"mode",
|
|
5009
|
+
"snapPoints",
|
|
5010
|
+
"allowed",
|
|
5011
|
+
"initial",
|
|
5012
|
+
"duration",
|
|
5013
|
+
"easing",
|
|
5014
|
+
"respectReducedMotion",
|
|
5015
|
+
"flickVelocity",
|
|
5016
|
+
"dragThreshold",
|
|
5017
|
+
"dragFrom",
|
|
5018
|
+
"dragFromContent",
|
|
5019
|
+
"fitContentToSnap",
|
|
5020
|
+
"rubberBand",
|
|
5021
|
+
"backdropRange",
|
|
5022
|
+
"backdropOpacity",
|
|
5023
|
+
"backdropColor",
|
|
5024
|
+
"screenRange",
|
|
5025
|
+
"scrimMode",
|
|
5026
|
+
"scrimColor",
|
|
5027
|
+
"scrimBlur",
|
|
5028
|
+
"scrimInteractive",
|
|
5029
|
+
"scrimTapToClose",
|
|
5030
|
+
"scrimPreset",
|
|
5031
|
+
"animation",
|
|
5032
|
+
"settleAnimation",
|
|
5033
|
+
"spring",
|
|
5034
|
+
"focusTrap",
|
|
5035
|
+
"initialFocus",
|
|
5036
|
+
"closeOnEscape",
|
|
5037
|
+
"lockBodyScroll",
|
|
5038
|
+
"closeOnBack",
|
|
5039
|
+
"routedTo",
|
|
5040
|
+
"inertSiblings",
|
|
5041
|
+
"persistent",
|
|
5042
|
+
"disableClose",
|
|
5043
|
+
"disableDrag",
|
|
5044
|
+
"closeOnRouteChange",
|
|
5045
|
+
"radius",
|
|
5046
|
+
"maxHeight",
|
|
5047
|
+
"returnFocusTo",
|
|
5048
|
+
"persistKey",
|
|
5049
|
+
"autoCollapseAfter",
|
|
5050
|
+
"linkedSheets",
|
|
5051
|
+
"viewTransitions",
|
|
5052
|
+
"stackEffect",
|
|
5053
|
+
"features"
|
|
5054
|
+
];
|
|
5055
|
+
const pickEngineOptions = (source) => {
|
|
5056
|
+
const out = {};
|
|
5057
|
+
for (const key of ENGINE_OPTION_KEYS) {
|
|
5058
|
+
const value = source[key];
|
|
5059
|
+
if (value !== void 0) out[key] = value;
|
|
4429
5060
|
}
|
|
4430
|
-
return
|
|
4431
|
-
|
|
4432
|
-
|
|
4433
|
-
|
|
4434
|
-
|
|
4435
|
-
|
|
4436
|
-
|
|
4437
|
-
|
|
4438
|
-
el.parentNode?.removeChild(el);
|
|
4439
|
-
}
|
|
4440
|
-
} else {
|
|
4441
|
-
el.parentNode?.removeChild(el);
|
|
4442
|
-
}
|
|
4443
|
-
}
|
|
4444
|
-
};
|
|
5061
|
+
return out;
|
|
5062
|
+
};
|
|
5063
|
+
const closedSnapId = (points) => points.find((point) => point.size === 0)?.id;
|
|
5064
|
+
const syncOpen = (engine, open) => {
|
|
5065
|
+
const phase = engine.state.phase;
|
|
5066
|
+
const showing = phase === "open" || phase === "opening";
|
|
5067
|
+
if (open && !showing) void engine.open();
|
|
5068
|
+
else if (!open && showing) void engine.close();
|
|
4445
5069
|
};
|
|
4446
5070
|
const BottomSheet = qwik.component$((props) => {
|
|
4447
5071
|
const sheetRef = qwik.useSignal();
|
|
@@ -4453,10 +5077,12 @@ const BottomSheet = qwik.component$((props) => {
|
|
|
4453
5077
|
const footerRef = qwik.useSignal();
|
|
4454
5078
|
const leftBtnRef = qwik.useSignal();
|
|
4455
5079
|
const rightBtnRef = qwik.useSignal();
|
|
4456
|
-
const
|
|
4457
|
-
const
|
|
5080
|
+
const initialSnap = props.initial ?? (props.open === false ? closedSnapId(props.snapPoints) : void 0) ?? props.snap;
|
|
5081
|
+
const initialActive = initialSnap ?? props.snapPoints[0]?.id ?? "default";
|
|
5082
|
+
const state2 = qwik.useStore({
|
|
4458
5083
|
size: 0,
|
|
4459
5084
|
activeId: initialActive,
|
|
5085
|
+
phase: "closed",
|
|
4460
5086
|
isDragging: false,
|
|
4461
5087
|
isAnimating: false,
|
|
4462
5088
|
progress: 0
|
|
@@ -4464,12 +5090,15 @@ const BottomSheet = qwik.component$((props) => {
|
|
|
4464
5090
|
const engineStore = qwik.useStore({
|
|
4465
5091
|
engine: void 0
|
|
4466
5092
|
});
|
|
5093
|
+
const physicalMode = qwik.useSignal(guessPhysicalMode(props.mode));
|
|
5094
|
+
const restAtStart = startsClosed(props.snapPoints, initialSnap, props.allowed) ? "closed" : void 0;
|
|
4467
5095
|
qwik.useVisibleTask$(({ cleanup }) => {
|
|
4468
5096
|
if (!sheetRef.value) return;
|
|
4469
5097
|
if (!handleRef.value || !contentRef.value) {
|
|
4470
5098
|
devWarn("[BottomSheet/qwik] handle or content ref missing at attach time — drag and content-swipe disabled. Make sure ref bindings render before useVisibleTask$ fires.");
|
|
4471
5099
|
}
|
|
4472
5100
|
const engineOpts = {
|
|
5101
|
+
...pickEngineOptions(props),
|
|
4473
5102
|
element: sheetRef.value,
|
|
4474
5103
|
handle: handleRef.value,
|
|
4475
5104
|
scrollContainer: contentRef.value,
|
|
@@ -4477,43 +5106,25 @@ const BottomSheet = qwik.component$((props) => {
|
|
|
4477
5106
|
scrim: scrimRef.value,
|
|
4478
5107
|
mode: props.mode ?? "bottom",
|
|
4479
5108
|
snapPoints: props.snapPoints,
|
|
4480
|
-
|
|
4481
|
-
initial: props.initial,
|
|
4482
|
-
animation: props.animation,
|
|
4483
|
-
spring: props.spring,
|
|
4484
|
-
focusTrap: props.focusTrap,
|
|
4485
|
-
closeOnEscape: props.closeOnEscape,
|
|
4486
|
-
closeOnBack: props.closeOnBack,
|
|
4487
|
-
lockBodyScroll: props.lockBodyScroll,
|
|
4488
|
-
rubberBand: props.rubberBand,
|
|
4489
|
-
backdropRange: props.backdropRange,
|
|
4490
|
-
persistent: props.persistent,
|
|
4491
|
-
disableClose: props.disableClose,
|
|
4492
|
-
disableDrag: props.disableDrag,
|
|
4493
|
-
dragFrom: props.dragFrom,
|
|
4494
|
-
dragFromContent: props.dragFromContent,
|
|
4495
|
-
fitContentToSnap: props.fitContentToSnap,
|
|
4496
|
-
closeOnRouteChange: props.closeOnRouteChange,
|
|
4497
|
-
stackEffect: props.stackEffect,
|
|
4498
|
-
returnFocusTo: props.returnFocusTo,
|
|
4499
|
-
radius: props.radius,
|
|
4500
|
-
maxHeight: props.maxHeight
|
|
5109
|
+
initial: initialSnap
|
|
4501
5110
|
};
|
|
4502
|
-
const engine = new BottomSheetEngine(engineOpts);
|
|
4503
|
-
engineStore.engine = qwik.noSerialize(engine);
|
|
4504
5111
|
const teleportTarget = props.teleport === false ? null : resolveTeleportTarget(props.teleportTo);
|
|
4505
5112
|
const restoreTeleport = teleportTarget ? teleportElements([
|
|
4506
5113
|
backdropRef.value,
|
|
4507
5114
|
scrimRef.value,
|
|
4508
5115
|
sheetRef.value
|
|
4509
5116
|
], teleportTarget) : null;
|
|
5117
|
+
const engine = new BottomSheetEngine(engineOpts);
|
|
5118
|
+
engineStore.engine = qwik.noSerialize(engine);
|
|
5119
|
+
physicalMode.value = engine.getMode();
|
|
4510
5120
|
const sync = () => {
|
|
4511
5121
|
const s = engine.state;
|
|
4512
|
-
|
|
4513
|
-
|
|
4514
|
-
|
|
4515
|
-
|
|
4516
|
-
|
|
5122
|
+
state2.size = s.size;
|
|
5123
|
+
state2.activeId = s.activeId;
|
|
5124
|
+
state2.isDragging = s.isDragging;
|
|
5125
|
+
state2.phase = s.phase;
|
|
5126
|
+
state2.isAnimating = s.isAnimating;
|
|
5127
|
+
state2.progress = s.progress;
|
|
4517
5128
|
props.onChange$?.(s);
|
|
4518
5129
|
};
|
|
4519
5130
|
sync();
|
|
@@ -4521,8 +5132,15 @@ const BottomSheet = qwik.component$((props) => {
|
|
|
4521
5132
|
sync();
|
|
4522
5133
|
props.onSnap$?.(payload.id);
|
|
4523
5134
|
});
|
|
4524
|
-
engine.on("open", (payload) =>
|
|
4525
|
-
|
|
5135
|
+
engine.on("open", (payload) => {
|
|
5136
|
+
props.onOpen$?.(payload.id);
|
|
5137
|
+
props.onOpenChange$?.(true);
|
|
5138
|
+
});
|
|
5139
|
+
engine.on("close", () => {
|
|
5140
|
+
props.onClose$?.();
|
|
5141
|
+
props.onOpenChange$?.(false);
|
|
5142
|
+
});
|
|
5143
|
+
if (props.open !== void 0) syncOpen(engine, props.open);
|
|
4526
5144
|
engine.on("opened", (payload) => props.onOpened$?.(payload.id));
|
|
4527
5145
|
engine.on("closed", () => props.onClosed$?.());
|
|
4528
5146
|
engine.on("dragstart", (payload) => {
|
|
@@ -4580,6 +5198,8 @@ const BottomSheet = qwik.component$((props) => {
|
|
|
4580
5198
|
engineStore.engine = void 0;
|
|
4581
5199
|
engine.destroy();
|
|
4582
5200
|
});
|
|
5201
|
+
}, {
|
|
5202
|
+
strategy: "document-ready"
|
|
4583
5203
|
});
|
|
4584
5204
|
qwik.useTask$(({ track }) => {
|
|
4585
5205
|
const points = track(() => props.snapPoints);
|
|
@@ -4612,14 +5232,25 @@ const BottomSheet = qwik.component$((props) => {
|
|
|
4612
5232
|
}
|
|
4613
5233
|
if (dragFrom !== void 0) engine.setDragFrom(dragFrom);
|
|
4614
5234
|
});
|
|
5235
|
+
qwik.useTask$(({ track }) => {
|
|
5236
|
+
const open = track(() => props.open);
|
|
5237
|
+
const engine = engineStore.engine;
|
|
5238
|
+
if (engine && open !== void 0) syncOpen(engine, open);
|
|
5239
|
+
});
|
|
5240
|
+
qwik.useTask$(({ track }) => {
|
|
5241
|
+
const snap = track(() => props.snap);
|
|
5242
|
+
const engine = engineStore.engine;
|
|
5243
|
+
if (!engine || snap === void 0 || snap === engine.state.activeId) return;
|
|
5244
|
+
void engine.snapTo(snap);
|
|
5245
|
+
});
|
|
4615
5246
|
qwik.useTask$(({ track }) => {
|
|
4616
5247
|
const nextMode = track(() => props.mode);
|
|
4617
5248
|
const engine = engineStore.engine;
|
|
4618
5249
|
if (!engine || nextMode === void 0) return;
|
|
4619
5250
|
engine.setMode(nextMode);
|
|
5251
|
+
physicalMode.value = engine.getMode();
|
|
4620
5252
|
});
|
|
4621
5253
|
const showBackdrop = props.backdrop !== false;
|
|
4622
|
-
const mode = props.mode ?? "bottom";
|
|
4623
5254
|
const ariaLabel = props.ariaLabel ?? "Bottom sheet";
|
|
4624
5255
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", {
|
|
4625
5256
|
class: "bs-root",
|
|
@@ -4638,8 +5269,9 @@ const BottomSheet = qwik.component$((props) => {
|
|
|
4638
5269
|
/* @__PURE__ */ jsxRuntime.jsxs("section", {
|
|
4639
5270
|
class: "bs-sheet",
|
|
4640
5271
|
ref: sheetRef,
|
|
4641
|
-
"data-mode":
|
|
4642
|
-
"data-
|
|
5272
|
+
"data-mode": physicalMode.value,
|
|
5273
|
+
"data-bs-rest": restAtStart,
|
|
5274
|
+
"data-active": state2.activeId,
|
|
4643
5275
|
role: "dialog",
|
|
4644
5276
|
"aria-modal": props.focusTrap ? "true" : void 0,
|
|
4645
5277
|
"aria-label": ariaLabel,
|
|
@@ -4649,7 +5281,7 @@ const BottomSheet = qwik.component$((props) => {
|
|
|
4649
5281
|
ref: handleRef,
|
|
4650
5282
|
role: "slider",
|
|
4651
5283
|
tabIndex: 0,
|
|
4652
|
-
"aria-label": "Resize sheet"
|
|
5284
|
+
"aria-label": props.handleLabel ?? "Resize sheet"
|
|
4653
5285
|
}),
|
|
4654
5286
|
/* @__PURE__ */ jsxRuntime.jsx("div", {
|
|
4655
5287
|
class: "bs-header",
|
|
@@ -4661,6 +5293,9 @@ const BottomSheet = qwik.component$((props) => {
|
|
|
4661
5293
|
/* @__PURE__ */ jsxRuntime.jsx("div", {
|
|
4662
5294
|
class: "bs-content",
|
|
4663
5295
|
ref: contentRef,
|
|
5296
|
+
tabIndex: 0,
|
|
5297
|
+
role: "region",
|
|
5298
|
+
"aria-label": props.contentLabel ?? "Sheet content",
|
|
4664
5299
|
children: /* @__PURE__ */ jsxRuntime.jsx(qwik.Slot, {})
|
|
4665
5300
|
}),
|
|
4666
5301
|
/* @__PURE__ */ jsxRuntime.jsx("div", {
|
|
@@ -4674,14 +5309,14 @@ const BottomSheet = qwik.component$((props) => {
|
|
|
4674
5309
|
class: "bs-sr-only",
|
|
4675
5310
|
role: "status",
|
|
4676
5311
|
"aria-live": "polite",
|
|
4677
|
-
children:
|
|
5312
|
+
children: state2.activeId
|
|
4678
5313
|
})
|
|
4679
5314
|
]
|
|
4680
5315
|
}),
|
|
4681
5316
|
/* @__PURE__ */ jsxRuntime.jsx("div", {
|
|
4682
5317
|
class: "bs-button-slot",
|
|
4683
5318
|
"data-side": "left",
|
|
4684
|
-
"data-mode":
|
|
5319
|
+
"data-mode": physicalMode.value,
|
|
4685
5320
|
ref: leftBtnRef,
|
|
4686
5321
|
children: /* @__PURE__ */ jsxRuntime.jsx(qwik.Slot, {
|
|
4687
5322
|
name: "leftButton"
|
|
@@ -4690,7 +5325,7 @@ const BottomSheet = qwik.component$((props) => {
|
|
|
4690
5325
|
/* @__PURE__ */ jsxRuntime.jsx("div", {
|
|
4691
5326
|
class: "bs-button-slot",
|
|
4692
5327
|
"data-side": "right",
|
|
4693
|
-
"data-mode":
|
|
5328
|
+
"data-mode": physicalMode.value,
|
|
4694
5329
|
ref: rightBtnRef,
|
|
4695
5330
|
children: /* @__PURE__ */ jsxRuntime.jsx(qwik.Slot, {
|
|
4696
5331
|
name: "rightButton"
|