@surdeddd/bottom-sheet 0.1.0 → 0.2.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 +6 -0
- package/dist/BottomSheetEngine-CIT9Htti.d.cts +219 -0
- package/dist/BottomSheetEngine-Df9MwBbm.d.ts +219 -0
- package/dist/element.cjs +95 -440
- package/dist/element.d.cts +3 -56
- package/dist/element.d.ts +3 -56
- package/dist/element.iife.global.js +2 -2
- package/dist/element.js +95 -440
- package/dist/index.cjs +84 -494
- package/dist/index.d.cts +3 -84
- package/dist/index.d.ts +3 -84
- package/dist/index.js +84 -494
- package/dist/integrations/formik.d.cts +2 -8
- package/dist/integrations/formik.d.ts +2 -8
- package/dist/integrations/react-hook-form.d.cts +2 -11
- package/dist/integrations/react-hook-form.d.ts +2 -11
- package/dist/overlay.cjs +0 -87
- package/dist/overlay.d.cts +1 -137
- package/dist/overlay.d.ts +1 -137
- package/dist/overlay.js +0 -87
- package/dist/preact.d.cts +2 -2
- package/dist/preact.d.ts +2 -2
- package/dist/preact.js +0 -1
- package/dist/qwik.cjs +87 -439
- package/dist/qwik.d.cts +3 -24
- package/dist/qwik.d.ts +3 -24
- package/dist/qwik.js +87 -439
- package/dist/react.cjs +91 -496
- package/dist/react.d.cts +16 -158
- package/dist/react.d.ts +16 -158
- package/dist/react.js +91 -496
- package/dist/solid.cjs +87 -439
- package/dist/solid.d.cts +4 -31
- package/dist/solid.d.ts +4 -31
- package/dist/solid.js +87 -439
- package/dist/styles.css +27 -102
- package/dist/svelte.cjs +139 -462
- package/dist/svelte.d.ts +9 -2
- package/dist/svelte.js +139 -462
- package/dist/themes/ios.css +0 -3
- package/dist/themes/material.css +0 -3
- package/dist/themes/vercel.css +0 -3
- package/dist/{transform-Brkf-wzo.d.cts → transform-jVfAikE9.d.cts} +0 -1
- package/dist/{transform-Brkf-wzo.d.ts → transform-jVfAikE9.d.ts} +0 -1
- package/dist/vue.cjs +104 -446
- package/dist/vue.d.ts +7 -1
- package/dist/vue.js +105 -447
- package/package.json +3 -3
- package/dist/BottomSheetEngine-CvSVbo6c.d.cts +0 -704
- package/dist/BottomSheetEngine-DbO8rW_3.d.ts +0 -704
package/dist/element.js
CHANGED
|
@@ -270,11 +270,6 @@ var init_snap_resolver = __esm({
|
|
|
270
270
|
this.allowedIds = allowed ?? raw.map((p) => p.id);
|
|
271
271
|
this.recompute();
|
|
272
272
|
}
|
|
273
|
-
/**
|
|
274
|
-
* Re-resolve raw → resolved against the current viewport / fit-measure,
|
|
275
|
-
* recompute maxAxisSize, invalidate range cache, notify engine. Called on
|
|
276
|
-
* resize, orientationchange, visualViewport changes, and snap-list swaps.
|
|
277
|
-
*/
|
|
278
273
|
recompute() {
|
|
279
274
|
this.resolved = resolveSnapList(this.raw, this.mode, this.measureFit);
|
|
280
275
|
this.maxAxisSize = this.resolved.reduce(
|
|
@@ -284,15 +279,10 @@ var init_snap_resolver = __esm({
|
|
|
284
279
|
this.rangeCache = null;
|
|
285
280
|
this.onMaxAxisSizeChange?.(this.maxAxisSize);
|
|
286
281
|
}
|
|
287
|
-
/** Replace the raw snap list and recompute. Engine calls on `setSnapPoints`. */
|
|
288
282
|
setRaw(raw) {
|
|
289
283
|
this.raw = raw;
|
|
290
284
|
this.recompute();
|
|
291
285
|
}
|
|
292
|
-
/**
|
|
293
|
-
* Replace the allow-list. Range cache depends on `(resolvedSnaps ×
|
|
294
|
-
* allowedIds)` so flipping ids alone invalidates without a full recompute.
|
|
295
|
-
*/
|
|
296
286
|
setAllowedIds(ids) {
|
|
297
287
|
this.allowedIds = ids;
|
|
298
288
|
this.rangeCache = null;
|
|
@@ -300,11 +290,6 @@ var init_snap_resolver = __esm({
|
|
|
300
290
|
findById(id) {
|
|
301
291
|
return findById(id, this.resolved);
|
|
302
292
|
}
|
|
303
|
-
/**
|
|
304
|
-
* Pure drag-settle target resolution. Engine passes the gesture-specific
|
|
305
|
-
* fields (delta, velocity, pointerKind, flickVelocity, dragThreshold) plus
|
|
306
|
-
* `size`/`activeId` since those are still engine-owned.
|
|
307
|
-
*/
|
|
308
293
|
findDragSettleTarget(args) {
|
|
309
294
|
return findDragSettleTarget({
|
|
310
295
|
...args,
|
|
@@ -313,18 +298,9 @@ var init_snap_resolver = __esm({
|
|
|
313
298
|
maxAxisSize: this.maxAxisSize
|
|
314
299
|
});
|
|
315
300
|
}
|
|
316
|
-
/**
|
|
317
|
-
* Memoised allowed-range query. Twice-per-drag-frame (gesture onMove +
|
|
318
|
-
* applySize→computeProgress); cache collapses 2× iteration of resolvedSnaps
|
|
319
|
-
* to one recompute per geometry/allow-list change.
|
|
320
|
-
*/
|
|
321
301
|
getAllowedRange() {
|
|
322
302
|
return this.rangeCache ?? (this.rangeCache = allowedRange(this.resolved, this.allowedIds));
|
|
323
303
|
}
|
|
324
|
-
/**
|
|
325
|
-
* Read-only view of resolved snaps. Returned as `readonly` to discourage
|
|
326
|
-
* accidental mutation by feature install sites that close over this list.
|
|
327
|
-
*/
|
|
328
304
|
getResolvedSnaps() {
|
|
329
305
|
return this.resolved;
|
|
330
306
|
}
|
|
@@ -334,18 +310,6 @@ var init_snap_resolver = __esm({
|
|
|
334
310
|
getMaxAxisSize() {
|
|
335
311
|
return this.maxAxisSize;
|
|
336
312
|
}
|
|
337
|
-
/**
|
|
338
|
-
* External clamp override. The resize-observer feature compares
|
|
339
|
-
* `getMaxAxisSize()` against the live viewport and shrinks if the largest
|
|
340
|
-
* resolved snap exceeds it (mobile address-bar collapse / soft-keyboard
|
|
341
|
-
* window resize). The next `recompute()` overwrites this clamp from the
|
|
342
|
-
* resolved-snap reduction.
|
|
343
|
-
*
|
|
344
|
-
* Does NOT invalidate the range cache — viewport clamping doesn't change
|
|
345
|
-
* `(resolvedSnaps × allowedIds) → range`. DOES fire `onMaxAxisSizeChange`
|
|
346
|
-
* so the resolver owns the layout-axis style write end-to-end (symmetric
|
|
347
|
-
* with `recompute()` — feature call sites no longer duplicate the write).
|
|
348
|
-
*/
|
|
349
313
|
setMaxAxisSize(n) {
|
|
350
314
|
this.maxAxisSize = n;
|
|
351
315
|
this.onMaxAxisSizeChange?.(n);
|
|
@@ -769,36 +733,17 @@ var init_opacity_dedup = __esm({
|
|
|
769
733
|
constructor() {
|
|
770
734
|
__publicField(this, "last", -1);
|
|
771
735
|
}
|
|
772
|
-
/**
|
|
773
|
-
* Returns `true` (and updates the cached value) if `next` differs from the
|
|
774
|
-
* cached `last` by more than `epsilon`. Returns `false` (and leaves the
|
|
775
|
-
* cache untouched) when the delta is within epsilon — caller skips the
|
|
776
|
-
* CSSOM write.
|
|
777
|
-
*/
|
|
778
736
|
shouldWrite(next, epsilon) {
|
|
779
737
|
if (Math.abs(next - this.last) <= epsilon) return false;
|
|
780
738
|
this.last = next;
|
|
781
739
|
return true;
|
|
782
740
|
}
|
|
783
|
-
/**
|
|
784
|
-
* Force the next `shouldWrite` to pass. Resets the cache to `-1` so any
|
|
785
|
-
* non-negative `next` exceeds the epsilon comparison. Called from setters
|
|
786
|
-
* that mutate state under the cache (range/mode/enabled flips that change
|
|
787
|
-
* the progress→opacity mapping but don't move `progress` itself).
|
|
788
|
-
*/
|
|
789
741
|
invalidate() {
|
|
790
742
|
this.last = -1;
|
|
791
743
|
}
|
|
792
|
-
/**
|
|
793
|
-
* Record `value` as the last-written without performing a write. Used
|
|
794
|
-
* when a setter writes a literal value through a different path (e.g.
|
|
795
|
-
* `setScrimMode("off")` writes `opacity: "0"` inline) and wants future
|
|
796
|
-
* `shouldWrite` calls to short-circuit against that known cached state.
|
|
797
|
-
*/
|
|
798
744
|
setLastWritten(value) {
|
|
799
745
|
this.last = value;
|
|
800
746
|
}
|
|
801
|
-
/** Read-only accessor for diagnostic / dedup-aware peek. */
|
|
802
747
|
get value() {
|
|
803
748
|
return this.last;
|
|
804
749
|
}
|
|
@@ -806,45 +751,74 @@ var init_opacity_dedup = __esm({
|
|
|
806
751
|
}
|
|
807
752
|
});
|
|
808
753
|
|
|
754
|
+
// src/core/primitives/devWarn.ts
|
|
755
|
+
function devWarn(...args) {
|
|
756
|
+
if (typeof process !== "undefined" && process.env && process.env.NODE_ENV !== "production" && typeof console !== "undefined") {
|
|
757
|
+
console.warn(...args);
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
var init_devWarn = __esm({
|
|
761
|
+
"src/core/primitives/devWarn.ts"() {
|
|
762
|
+
}
|
|
763
|
+
});
|
|
764
|
+
|
|
809
765
|
// src/core/controllers/scrim-controller.ts
|
|
810
|
-
|
|
766
|
+
function resolveSheetAnchoredStyle(mode, position, inset) {
|
|
767
|
+
const sizeOffset = `calc(var(--bs-size, 0px) + ${inset})`;
|
|
768
|
+
switch (mode) {
|
|
769
|
+
case "bottom":
|
|
770
|
+
if (position === "sheet-top-left") return { bottom: sizeOffset, left: inset };
|
|
771
|
+
if (position === "sheet-top-right") return { bottom: sizeOffset, right: inset };
|
|
772
|
+
return { bottom: sizeOffset, left: "50%", transform: "translateX(-50%)" };
|
|
773
|
+
case "top":
|
|
774
|
+
if (position === "sheet-top-left") return { top: sizeOffset, left: inset };
|
|
775
|
+
if (position === "sheet-top-right") return { top: sizeOffset, right: inset };
|
|
776
|
+
return { top: sizeOffset, left: "50%", transform: "translateX(-50%)" };
|
|
777
|
+
case "left":
|
|
778
|
+
if (position === "sheet-top-left") return { left: sizeOffset, top: inset };
|
|
779
|
+
if (position === "sheet-top-right") return { left: sizeOffset, bottom: inset };
|
|
780
|
+
return { left: sizeOffset, top: "50%", transform: "translateY(-50%)" };
|
|
781
|
+
case "right":
|
|
782
|
+
if (position === "sheet-top-left") return { right: sizeOffset, top: inset };
|
|
783
|
+
if (position === "sheet-top-right") return { right: sizeOffset, bottom: inset };
|
|
784
|
+
return { right: sizeOffset, top: "50%", transform: "translateY(-50%)" };
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
function applySheetAnchoredPosition(ws, mode, position, inset) {
|
|
788
|
+
const style = resolveSheetAnchoredStyle(mode, position, inset);
|
|
789
|
+
if (style.top !== void 0) ws.top = style.top;
|
|
790
|
+
if (style.bottom !== void 0) ws.bottom = style.bottom;
|
|
791
|
+
if (style.left !== void 0) ws.left = style.left;
|
|
792
|
+
if (style.right !== void 0) ws.right = style.right;
|
|
793
|
+
if (style.transform !== void 0) ws.transform = style.transform;
|
|
794
|
+
}
|
|
795
|
+
var VALID_CSS_LENGTH, ScrimController;
|
|
811
796
|
var init_scrim_controller = __esm({
|
|
812
797
|
"src/core/controllers/scrim-controller.ts"() {
|
|
813
798
|
init_types();
|
|
814
799
|
init_snap_points();
|
|
815
800
|
init_hot_path_thresholds();
|
|
816
801
|
init_opacity_dedup();
|
|
802
|
+
init_devWarn();
|
|
803
|
+
VALID_CSS_LENGTH = /^-?\d+(?:\.\d+)?(?:px|em|rem|%)$/;
|
|
817
804
|
ScrimController = class {
|
|
818
805
|
constructor(deps, opts) {
|
|
819
|
-
// ── DOM refs (mirror engine's; cached for hot path) ─────────────────
|
|
820
806
|
__publicField(this, "screenComponent");
|
|
821
807
|
__publicField(this, "backdrop");
|
|
822
808
|
__publicField(this, "mode");
|
|
823
|
-
// ── Engine callbacks ────────────────────────────────────────────────
|
|
824
809
|
__publicField(this, "isDestroyed");
|
|
825
810
|
__publicField(this, "isTopSheet");
|
|
826
811
|
__publicField(this, "getAllowedIds");
|
|
827
812
|
__publicField(this, "getResolvedSnaps");
|
|
828
813
|
__publicField(this, "snapToFn");
|
|
829
|
-
// ── Mode + state ────────────────────────────────────────────────────
|
|
830
814
|
__publicField(this, "scrimMode");
|
|
831
815
|
__publicField(this, "backdropRange");
|
|
832
816
|
__publicField(this, "screenRange");
|
|
833
|
-
// setScrimEnabled toggle — gated through `scrimEnabled` rather than nuking
|
|
834
|
-
// ranges so re-enable can restore prior values without a remount. Public
|
|
835
|
-
// so tests / introspection can read it without an `as any` cast.
|
|
836
817
|
__publicField(this, "scrimEnabled", true);
|
|
837
818
|
__publicField(this, "savedScrimRanges", null);
|
|
838
|
-
// ── Tap-to-close ────────────────────────────────────────────────────
|
|
839
819
|
__publicField(this, "scrimTapToCloseEnabled", false);
|
|
840
820
|
__publicField(this, "detachScrimTap", null);
|
|
841
|
-
// ── Scrim overlay slot (positioned floating element) ────────────────
|
|
842
821
|
__publicField(this, "scrimOverlayTeardown", null);
|
|
843
|
-
// ── Hot-path opacity dedup caches (per-frame writes) ────────────────
|
|
844
|
-
// Numeric sentinels migrated to WriteSentinel primitive — single
|
|
845
|
-
// invalidation surface, shared with the engine's size/progress sentinels.
|
|
846
|
-
// The two string-typed sentinels (`Pointer`, `Display`) keep their inline
|
|
847
|
-
// pattern: equality on string union, no epsilon, different reset semantics.
|
|
848
822
|
__publicField(this, "backdropOpacitySentinel", new WriteSentinel());
|
|
849
823
|
__publicField(this, "screenOpacitySentinel", new WriteSentinel());
|
|
850
824
|
__publicField(this, "lastBackdropPointer", "");
|
|
@@ -879,41 +853,15 @@ var init_scrim_controller = __esm({
|
|
|
879
853
|
}
|
|
880
854
|
}
|
|
881
855
|
}
|
|
882
|
-
/**
|
|
883
|
-
* Invalidate the opacity dedup caches. Called from any setter that mutates
|
|
884
|
-
* range/mode/enabled — opacity is a pure function of (progress, range,
|
|
885
|
-
* enabled), so a config change makes the cached values stale even if
|
|
886
|
-
* `progress` itself didn't move. Next `applyOpacity(progress, false)` call
|
|
887
|
-
* sees the -1 sentinel and re-runs the math instead of short-circuiting.
|
|
888
|
-
*
|
|
889
|
-
* Public for the engine: `setSnapPoints` mutates resolved geometry which
|
|
890
|
-
* shifts `progress→opacity` mapping under the cache; engine calls this to
|
|
891
|
-
* keep the next render frame correct on a static sheet.
|
|
892
|
-
* @internal
|
|
893
|
-
*/
|
|
894
856
|
invalidateOpacityCache() {
|
|
895
857
|
this.backdropOpacitySentinel.invalidate();
|
|
896
858
|
this.screenOpacitySentinel.invalidate();
|
|
897
859
|
}
|
|
898
|
-
/** Engine calls this when its `attach()` runs — installs scrim-tap-click if requested. */
|
|
899
860
|
attach() {
|
|
900
861
|
if (this.scrimTapToCloseEnabled) {
|
|
901
862
|
this.setScrimTapToClose(true);
|
|
902
863
|
}
|
|
903
864
|
}
|
|
904
|
-
// ── Hot-path: opacity computation called per-frame from engine.applySize ──
|
|
905
|
-
/**
|
|
906
|
-
* Per-frame opacity writer. Computes backdrop + screen opacity from the
|
|
907
|
-
* sheet's progress (0..1 within allowed range), gated by sub-pixel dedup
|
|
908
|
-
* caches so steady-state frames don't trigger style recalc.
|
|
909
|
-
*
|
|
910
|
-
* `progressChanged` is the engine's already-computed dedup gate — when
|
|
911
|
-
* `false`, opacity is by construction a pure function of `progress` so
|
|
912
|
-
* cached values are still valid; we short-circuit the Math.min/max +
|
|
913
|
-
* division work entirely. Setters that mutate ranges/mode/enabled
|
|
914
|
-
* invalidate the cache by writing -1 sentinels so the next call re-runs
|
|
915
|
-
* the math.
|
|
916
|
-
*/
|
|
917
865
|
applyOpacity(progress, progressChanged) {
|
|
918
866
|
if (!progressChanged && this.backdropOpacitySentinel.value !== -1 && this.screenOpacitySentinel.value !== -1) {
|
|
919
867
|
return;
|
|
@@ -959,80 +907,30 @@ var init_scrim_controller = __esm({
|
|
|
959
907
|
}
|
|
960
908
|
}
|
|
961
909
|
}
|
|
962
|
-
// ── Public setters (engine forwards these 1:1) ─────────────────────
|
|
963
|
-
/**
|
|
964
|
-
* Replace the [start, end] progress window in which the backdrop fades 0→1.
|
|
965
|
-
* @param range - Tuple of two progress values in 0..1 (start <= end).
|
|
966
|
-
* @param applySize - Engine-supplied recompute hook; runs one applyOpacity pass.
|
|
967
|
-
* @example
|
|
968
|
-
* // Backdrop only starts darkening after the sheet crosses 30% open.
|
|
969
|
-
* engine.setBackdropRange([0.3, 1]);
|
|
970
|
-
*/
|
|
971
910
|
setBackdropRange(range, applySize) {
|
|
972
911
|
if (this.isDestroyed()) return;
|
|
973
912
|
this.backdropRange = range;
|
|
974
913
|
this.invalidateOpacityCache();
|
|
975
914
|
applySize();
|
|
976
915
|
}
|
|
977
|
-
/**
|
|
978
|
-
* Replace the [start, end] progress window in which the screen scrim fades 0→1.
|
|
979
|
-
* @param range - Tuple of two progress values in 0..1 (start <= end).
|
|
980
|
-
* @param applySize - Engine-supplied recompute hook; runs one applyOpacity pass.
|
|
981
|
-
* @example
|
|
982
|
-
* // Scrim is fully opaque only when the sheet is past 50% — softer feel.
|
|
983
|
-
* engine.setScreenRange([0, 0.5]);
|
|
984
|
-
*/
|
|
985
916
|
setScreenRange(range, applySize) {
|
|
986
917
|
if (this.isDestroyed()) return;
|
|
987
918
|
this.screenRange = range;
|
|
988
919
|
this.invalidateOpacityCache();
|
|
989
920
|
applySize();
|
|
990
921
|
}
|
|
991
|
-
/**
|
|
992
|
-
* Set the scrim background color. Pass `null`/`undefined` to clear the
|
|
993
|
-
* inline write and let consumer CSS take over.
|
|
994
|
-
* @param color - Any valid CSS color string, or `null`/`undefined` to clear.
|
|
995
|
-
* @example
|
|
996
|
-
* engine.setScrimColor("rgba(0, 0, 0, 0.6)");
|
|
997
|
-
* engine.setScrimColor(null); // hand back to consumer CSS
|
|
998
|
-
*/
|
|
999
922
|
setScrimColor(color) {
|
|
1000
923
|
if (this.isDestroyed()) return;
|
|
1001
924
|
this.applyScrimStyles({ color: color === void 0 ? null : color });
|
|
1002
925
|
}
|
|
1003
|
-
/**
|
|
1004
|
-
* Set the scrim backdrop-filter blur radius. Pass `null`/`undefined` to clear.
|
|
1005
|
-
* @param blur - CSS length (e.g. `"8px"`) consumed as `blur(<value>)`, or
|
|
1006
|
-
* `null`/`undefined` to remove the filter.
|
|
1007
|
-
* @example
|
|
1008
|
-
* engine.setScrimBlur("12px"); // frosted-glass effect
|
|
1009
|
-
* engine.setScrimBlur(null); // disable blur
|
|
1010
|
-
*/
|
|
1011
926
|
setScrimBlur(blur) {
|
|
1012
927
|
if (this.isDestroyed()) return;
|
|
1013
928
|
this.applyScrimStyles({ blur: blur === void 0 ? null : blur });
|
|
1014
929
|
}
|
|
1015
|
-
/**
|
|
1016
|
-
* Toggle whether the scrim layer captures pointer events.
|
|
1017
|
-
* @param interactive - `true` → `pointer-events: auto`; `false` → `none`.
|
|
1018
|
-
* @example
|
|
1019
|
-
* engine.setScrimInteractive(true); // scrim swallows clicks
|
|
1020
|
-
* engine.setScrimInteractive(false); // clicks pass through to content below
|
|
1021
|
-
*/
|
|
1022
930
|
setScrimInteractive(interactive) {
|
|
1023
931
|
if (this.isDestroyed()) return;
|
|
1024
932
|
this.applyScrimStyles({ interactive });
|
|
1025
933
|
}
|
|
1026
|
-
/**
|
|
1027
|
-
* Switch scrim positioning at runtime.
|
|
1028
|
-
* @param mode - `"full"` (consumer CSS), `"above-sheet"` (engine-pinned inset
|
|
1029
|
-
* so only the area NOT covered by the sheet is dimmed), or
|
|
1030
|
-
* `"off"` (display:none + opacity:0 — no remount needed).
|
|
1031
|
-
* @param applySize - Engine-supplied recompute hook; runs one applyOpacity pass.
|
|
1032
|
-
* @example
|
|
1033
|
-
* engine.setScrimMode("above-sheet"); // dim only the area above the sheet
|
|
1034
|
-
* engine.setScrimMode("off"); // disable scrim layer
|
|
1035
|
-
*/
|
|
1036
934
|
setScrimMode(mode, applySize) {
|
|
1037
935
|
if (this.isDestroyed()) return;
|
|
1038
936
|
if (mode === this.scrimMode) return;
|
|
@@ -1062,15 +960,6 @@ var init_scrim_controller = __esm({
|
|
|
1062
960
|
}
|
|
1063
961
|
applySize();
|
|
1064
962
|
}
|
|
1065
|
-
/**
|
|
1066
|
-
* Enable or disable click-on-scrim → snap to first non-zero allowed snap.
|
|
1067
|
-
* Auto-promotes `pointer-events: auto` when scrim is non-interactive so the
|
|
1068
|
-
* click listener actually fires.
|
|
1069
|
-
* @param enabled - `true` installs the click listener; `false` removes it.
|
|
1070
|
-
* @example
|
|
1071
|
-
* engine.setScrimTapToClose(true); // tap outside sheet collapses it
|
|
1072
|
-
* engine.setScrimTapToClose(false); // require explicit close button
|
|
1073
|
-
*/
|
|
1074
963
|
setScrimTapToClose(enabled) {
|
|
1075
964
|
if (this.isDestroyed()) return;
|
|
1076
965
|
if (!this.screenComponent) return;
|
|
@@ -1100,16 +989,6 @@ var init_scrim_controller = __esm({
|
|
|
1100
989
|
this.scrimTapToCloseEnabled = false;
|
|
1101
990
|
}
|
|
1102
991
|
}
|
|
1103
|
-
/**
|
|
1104
|
-
* Toggle the scrim layer without remounting. Disabling stashes current
|
|
1105
|
-
* `screenRange`/`backdropRange` and degenerates them to `[1, 1]` (opacity
|
|
1106
|
-
* formula → 0 across the whole range); re-enabling restores the saved values.
|
|
1107
|
-
* @param enabled - `false` hides scrim, `true` restores prior ranges.
|
|
1108
|
-
* @param applySize - Engine-supplied recompute hook; runs one applyOpacity pass.
|
|
1109
|
-
* @example
|
|
1110
|
-
* engine.setScrimEnabled(false); // hide scrim, ranges remembered
|
|
1111
|
-
* engine.setScrimEnabled(true); // restore prior ranges (no remount)
|
|
1112
|
-
*/
|
|
1113
992
|
setScrimEnabled(enabled, applySize) {
|
|
1114
993
|
if (this.isDestroyed()) return;
|
|
1115
994
|
if (enabled === this.scrimEnabled) return;
|
|
@@ -1128,20 +1007,6 @@ var init_scrim_controller = __esm({
|
|
|
1128
1007
|
}
|
|
1129
1008
|
applySize();
|
|
1130
1009
|
}
|
|
1131
|
-
/**
|
|
1132
|
-
* Batch-update multiple scrim fields with a single applySize() at the end.
|
|
1133
|
-
* If `preset` is set, it seeds color/blur/interactive/range first; explicit
|
|
1134
|
-
* fields override.
|
|
1135
|
-
* @param opts - Partial scrim config: preset, mode, enabled, tapToClose,
|
|
1136
|
-
* color, blur, interactive, range.
|
|
1137
|
-
* @param applySize - Engine-supplied recompute hook; runs ONCE per call.
|
|
1138
|
-
* @example
|
|
1139
|
-
* engine.setScrim({
|
|
1140
|
-
* preset: "frosted",
|
|
1141
|
-
* mode: "above-sheet",
|
|
1142
|
-
* tapToClose: true,
|
|
1143
|
-
* });
|
|
1144
|
-
*/
|
|
1145
1010
|
setScrim(opts, applySize) {
|
|
1146
1011
|
if (this.isDestroyed()) return;
|
|
1147
1012
|
if (opts.preset) {
|
|
@@ -1164,27 +1029,18 @@ var init_scrim_controller = __esm({
|
|
|
1164
1029
|
interactive: opts.interactive
|
|
1165
1030
|
});
|
|
1166
1031
|
if (opts.range !== void 0) {
|
|
1167
|
-
this.
|
|
1032
|
+
if (!this.scrimEnabled && this.savedScrimRanges) {
|
|
1033
|
+
this.savedScrimRanges = {
|
|
1034
|
+
screen: opts.range,
|
|
1035
|
+
backdrop: this.savedScrimRanges.backdrop
|
|
1036
|
+
};
|
|
1037
|
+
} else {
|
|
1038
|
+
this.screenRange = opts.range;
|
|
1039
|
+
}
|
|
1168
1040
|
}
|
|
1169
1041
|
this.invalidateOpacityCache();
|
|
1170
1042
|
applySize();
|
|
1171
1043
|
}
|
|
1172
|
-
/**
|
|
1173
|
-
* Inject a positioned floating element into the scrim layer (e.g. a close
|
|
1174
|
-
* button anchored top-right). Replaces any prior overlay so repeated calls
|
|
1175
|
-
* (reactive effects re-running) don't accumulate wrappers.
|
|
1176
|
-
* @param opts - Children element, optional `inset` (default `"16px"`),
|
|
1177
|
-
* `position` (9-way grid, default `"top-right"`), and
|
|
1178
|
-
* `interactive` flag (default `true`).
|
|
1179
|
-
* @returns Teardown function that removes the wrapper from the DOM.
|
|
1180
|
-
* @example
|
|
1181
|
-
* const teardown = engine.setScrimOverlay({
|
|
1182
|
-
* children: closeBtn,
|
|
1183
|
-
* position: "top-right",
|
|
1184
|
-
* inset: "20px",
|
|
1185
|
-
* });
|
|
1186
|
-
* // later: teardown(); // remove the floating button
|
|
1187
|
-
*/
|
|
1188
1044
|
setScrimOverlay(opts) {
|
|
1189
1045
|
if (this.isDestroyed()) return () => {
|
|
1190
1046
|
};
|
|
@@ -1192,7 +1048,18 @@ var init_scrim_controller = __esm({
|
|
|
1192
1048
|
};
|
|
1193
1049
|
this.scrimOverlayTeardown?.();
|
|
1194
1050
|
const screen = this.screenComponent;
|
|
1195
|
-
const
|
|
1051
|
+
const insetRaw = opts.inset ?? "16px";
|
|
1052
|
+
const inset = VALID_CSS_LENGTH.test(insetRaw) ? insetRaw : "16px";
|
|
1053
|
+
if (inset !== insetRaw) {
|
|
1054
|
+
devWarn(
|
|
1055
|
+
`[bottom-sheet] setScrimOverlay: invalid inset ${JSON.stringify(insetRaw)}; expected a CSS length like "16px" / "1rem" / "5%". Falling back to "16px".`
|
|
1056
|
+
);
|
|
1057
|
+
}
|
|
1058
|
+
if (opts.children.ownerDocument && opts.children.ownerDocument !== screen.ownerDocument) {
|
|
1059
|
+
devWarn(
|
|
1060
|
+
"[bottom-sheet] setScrimOverlay: children belong to a different document than the scrim. Cross-document adoption can drop event listeners; construct children via the same document as the sheet root."
|
|
1061
|
+
);
|
|
1062
|
+
}
|
|
1196
1063
|
const position = opts.position ?? "top-right";
|
|
1197
1064
|
const interactive = opts.interactive ?? true;
|
|
1198
1065
|
const wrapper = screen.ownerDocument.createElement("div");
|
|
@@ -1241,12 +1108,30 @@ var init_scrim_controller = __esm({
|
|
|
1241
1108
|
ws.bottom = inset;
|
|
1242
1109
|
ws.right = inset;
|
|
1243
1110
|
break;
|
|
1111
|
+
case "sheet-top-left":
|
|
1112
|
+
case "sheet-top-center":
|
|
1113
|
+
case "sheet-top-right":
|
|
1114
|
+
applySheetAnchoredPosition(
|
|
1115
|
+
ws,
|
|
1116
|
+
this.mode,
|
|
1117
|
+
position,
|
|
1118
|
+
inset
|
|
1119
|
+
);
|
|
1120
|
+
break;
|
|
1244
1121
|
}
|
|
1245
1122
|
if (interactive) {
|
|
1246
1123
|
ws.pointerEvents = "auto";
|
|
1247
1124
|
}
|
|
1248
1125
|
wrapper.appendChild(opts.children);
|
|
1249
|
-
screen.
|
|
1126
|
+
const host = screen.parentElement;
|
|
1127
|
+
if (!host) {
|
|
1128
|
+
devWarn(
|
|
1129
|
+
"[bottom-sheet] setScrimOverlay: scrim element has no parent, skipping overlay injection. Mount the sheet root before calling setScrimOverlay."
|
|
1130
|
+
);
|
|
1131
|
+
return () => {
|
|
1132
|
+
};
|
|
1133
|
+
}
|
|
1134
|
+
host.appendChild(wrapper);
|
|
1250
1135
|
const teardown = () => {
|
|
1251
1136
|
if (wrapper.parentNode) wrapper.parentNode.removeChild(wrapper);
|
|
1252
1137
|
if (this.scrimOverlayTeardown === teardown) {
|
|
@@ -1256,7 +1141,6 @@ var init_scrim_controller = __esm({
|
|
|
1256
1141
|
this.scrimOverlayTeardown = teardown;
|
|
1257
1142
|
return teardown;
|
|
1258
1143
|
}
|
|
1259
|
-
/** Tear down toggle-state listeners + remove any injected overlay wrapper. */
|
|
1260
1144
|
destroy() {
|
|
1261
1145
|
this.detachScrimTap?.();
|
|
1262
1146
|
this.detachScrimTap = null;
|
|
@@ -1275,8 +1159,6 @@ var init_scrim_controller = __esm({
|
|
|
1275
1159
|
this.lastBackdropPointer = "";
|
|
1276
1160
|
this.lastScreenDisplay = "";
|
|
1277
1161
|
}
|
|
1278
|
-
// ── Private helpers ────────────────────────────────────────────────
|
|
1279
|
-
/** Centralized scrim style writer — atomic 3-property write across all setters. */
|
|
1280
1162
|
applyScrimStyles(opts) {
|
|
1281
1163
|
if (!this.screenComponent) return;
|
|
1282
1164
|
const s = this.screenComponent.style;
|
|
@@ -1298,7 +1180,6 @@ var init_scrim_controller = __esm({
|
|
|
1298
1180
|
s.pointerEvents = opts.interactive ? "auto" : "none";
|
|
1299
1181
|
}
|
|
1300
1182
|
}
|
|
1301
|
-
/** Pin the screen overlay to the area NOT occupied by the sheet. */
|
|
1302
1183
|
applyAboveSheetInset() {
|
|
1303
1184
|
if (!this.screenComponent) return;
|
|
1304
1185
|
const insetByMode = {
|
|
@@ -1489,13 +1370,9 @@ var init_animation_runner = __esm({
|
|
|
1489
1370
|
__publicField(this, "duration");
|
|
1490
1371
|
__publicField(this, "easing");
|
|
1491
1372
|
__publicField(this, "respectReducedMotion");
|
|
1492
|
-
/** Live-tracked via mq listener so animateTo skips matchMedia per snap. */
|
|
1493
1373
|
__publicField(this, "reducedMotion", false);
|
|
1494
|
-
/** Disposes the matchMedia change listener — drained from destroy(). */
|
|
1495
1374
|
__publicField(this, "detachReducedMotion", null);
|
|
1496
|
-
/** Computed once — both inputs (option + API presence) stable for life. */
|
|
1497
1375
|
__publicField(this, "viewTransitionsAvailable");
|
|
1498
|
-
/** In-flight handles. Public for tests / debugging only — engine drives via cancel(). */
|
|
1499
1376
|
__publicField(this, "currentTween", null);
|
|
1500
1377
|
__publicField(this, "currentSpring", null);
|
|
1501
1378
|
this.element = deps.element;
|
|
@@ -1526,26 +1403,13 @@ var init_animation_runner = __esm({
|
|
|
1526
1403
|
}
|
|
1527
1404
|
}
|
|
1528
1405
|
}
|
|
1529
|
-
/**
|
|
1530
|
-
* Live derived flag — `true` whenever a spring/tween handle is in flight.
|
|
1531
|
-
* Reading the canonical handles (instead of mirroring into a separate
|
|
1532
|
-
* boolean) eliminates the reduced-motion early-return latent bug where
|
|
1533
|
-
* the flag stayed true forever, and removes the cross-controller
|
|
1534
|
-
* setIsAnimating callback.
|
|
1535
|
-
*/
|
|
1536
1406
|
get isAnimating() {
|
|
1537
1407
|
return this.currentTween !== null || this.currentSpring !== null;
|
|
1538
1408
|
}
|
|
1539
|
-
/** Cancel any in-flight tween/spring without touching engine state. */
|
|
1540
1409
|
cancel() {
|
|
1541
1410
|
this.currentTween?.cancel();
|
|
1542
1411
|
this.currentSpring?.cancel();
|
|
1543
1412
|
}
|
|
1544
|
-
/**
|
|
1545
|
-
* Animate from current size to `target`. Resolves when the animation
|
|
1546
|
-
* completes; resolves early if cancelled mid-flight (caller checks an
|
|
1547
|
-
* abort signal post-await for cycle-invariant correctness).
|
|
1548
|
-
*/
|
|
1549
1413
|
async animateTo(target, velocityPxPerMs) {
|
|
1550
1414
|
if (target === this.getSize()) return;
|
|
1551
1415
|
this.currentTween?.cancel();
|
|
@@ -1586,7 +1450,6 @@ var init_animation_runner = __esm({
|
|
|
1586
1450
|
if (!this.isDragging()) this.element.style.willChange = "auto";
|
|
1587
1451
|
}
|
|
1588
1452
|
}
|
|
1589
|
-
/** Tear down the matchMedia listener. Engine calls from destroy(). */
|
|
1590
1453
|
destroy() {
|
|
1591
1454
|
this.detachReducedMotion?.();
|
|
1592
1455
|
this.detachReducedMotion = null;
|
|
@@ -1768,12 +1631,8 @@ var init_lifecycle_controller = __esm({
|
|
|
1768
1631
|
__publicField(this, "inertSiblings");
|
|
1769
1632
|
__publicField(this, "shouldApplyInertSiblings");
|
|
1770
1633
|
__publicField(this, "returnFocus");
|
|
1771
|
-
/** Toggle-state teardowns — fire on close, NOT in destroy-only stack. */
|
|
1772
1634
|
__publicField(this, "releaseFocusTrap", null);
|
|
1773
1635
|
__publicField(this, "releaseScrollLock", null);
|
|
1774
|
-
/** True between install() and release(). Guards release()/destroy() from
|
|
1775
|
-
* re-running side effects (notably `returnFocus.focus()`) on already-
|
|
1776
|
-
* released or never-installed instances. */
|
|
1777
1636
|
__publicField(this, "installed", false);
|
|
1778
1637
|
__publicField(this, "destroyed", false);
|
|
1779
1638
|
this.element = deps.element;
|
|
@@ -1787,14 +1646,6 @@ var init_lifecycle_controller = __esm({
|
|
|
1787
1646
|
this.returnFocus = opts.returnFocus;
|
|
1788
1647
|
this.inertSiblings = createInertSiblings(() => this.element);
|
|
1789
1648
|
}
|
|
1790
|
-
/**
|
|
1791
|
-
* Run the open-time install steps. Idempotent: each step checks its
|
|
1792
|
-
* existing teardown ref so a re-open during a half-cancelled close
|
|
1793
|
-
* doesn't double-install. Sets `installed=true` BEFORE the first side
|
|
1794
|
-
* effect so a partial throw (detached / shadow-DOM target) leaves the
|
|
1795
|
-
* caller's `release()` rollback path armed to undo whatever did succeed.
|
|
1796
|
-
* No-op when destroyed.
|
|
1797
|
-
*/
|
|
1798
1649
|
install() {
|
|
1799
1650
|
if (this.destroyed) return;
|
|
1800
1651
|
this.installed = true;
|
|
@@ -1811,22 +1662,10 @@ var init_lifecycle_controller = __esm({
|
|
|
1811
1662
|
this.inertSiblings.apply();
|
|
1812
1663
|
}
|
|
1813
1664
|
}
|
|
1814
|
-
/**
|
|
1815
|
-
* Update the post-release focus target. Overlay re-binds this when the
|
|
1816
|
-
* consumer changes `returnFocus` after construction; the new value applies
|
|
1817
|
-
* on the next `release()`. No-op when destroyed.
|
|
1818
|
-
*/
|
|
1819
1665
|
setReturnFocus(target) {
|
|
1820
1666
|
if (this.destroyed) return;
|
|
1821
1667
|
this.returnFocus = target;
|
|
1822
1668
|
}
|
|
1823
|
-
/**
|
|
1824
|
-
* Release all install-time teardowns. Short-circuits when not installed,
|
|
1825
|
-
* so `close() → destroy()` (each routing through here) only restores
|
|
1826
|
-
* focus once. The `installed` guard lets `inertSiblings.remove()` and
|
|
1827
|
-
* the focus-trap/scroll-lock teardown nullings stay simple — they were
|
|
1828
|
-
* already idempotent, but `returnFocus.focus()` was firing on every call.
|
|
1829
|
-
*/
|
|
1830
1669
|
release() {
|
|
1831
1670
|
if (!this.installed) return;
|
|
1832
1671
|
this.installed = false;
|
|
@@ -1840,12 +1679,6 @@ var init_lifecycle_controller = __esm({
|
|
|
1840
1679
|
target?.focus?.();
|
|
1841
1680
|
}
|
|
1842
1681
|
}
|
|
1843
|
-
/**
|
|
1844
|
-
* Final teardown — releases any still-installed listeners and seals the
|
|
1845
|
-
* controller. After destroy(), install() is a no-op and setReturnFocus()
|
|
1846
|
-
* is rejected, so post-destroy mutations can't queue up a stale focus
|
|
1847
|
-
* restore.
|
|
1848
|
-
*/
|
|
1849
1682
|
destroy() {
|
|
1850
1683
|
this.release();
|
|
1851
1684
|
this.destroyed = true;
|
|
@@ -1860,12 +1693,10 @@ var init_gestures = __esm({
|
|
|
1860
1693
|
"src/core/gestures.ts"() {
|
|
1861
1694
|
isAxisVertical = (mode) => mode === "bottom" || mode === "top";
|
|
1862
1695
|
SampleRing = class {
|
|
1863
|
-
// current count, ≤ capacity
|
|
1864
1696
|
constructor(capacity) {
|
|
1865
1697
|
__publicField(this, "slots");
|
|
1866
1698
|
__publicField(this, "capacity");
|
|
1867
1699
|
__publicField(this, "head", 0);
|
|
1868
|
-
// next write index
|
|
1869
1700
|
__publicField(this, "size", 0);
|
|
1870
1701
|
this.capacity = capacity;
|
|
1871
1702
|
this.slots = new Array(capacity);
|
|
@@ -1878,12 +1709,6 @@ var init_gestures = __esm({
|
|
|
1878
1709
|
this.head = (this.head + 1) % this.capacity;
|
|
1879
1710
|
if (this.size < this.capacity) this.size++;
|
|
1880
1711
|
}
|
|
1881
|
-
/**
|
|
1882
|
-
* Drop oldest entries whose timestamp is below `cutoff`, but never shrink
|
|
1883
|
-
* below `minKeep`. Mirrors the original
|
|
1884
|
-
* `while (samples.length > minKeep && samples[0].t < cutoff) samples.shift()`
|
|
1885
|
-
* but without copying — just advances the logical tail.
|
|
1886
|
-
*/
|
|
1887
1712
|
pruneBefore(cutoff, minKeep) {
|
|
1888
1713
|
while (this.size > minKeep) {
|
|
1889
1714
|
const oldestIdx = (this.head - this.size + this.capacity) % this.capacity;
|
|
@@ -2036,28 +1861,14 @@ var init_gesture_controller = __esm({
|
|
|
2036
1861
|
__publicField(this, "detach", null);
|
|
2037
1862
|
__publicField(this, "isDragging_", false);
|
|
2038
1863
|
__publicField(this, "dragStartSize", 0);
|
|
2039
|
-
// Only "touch" gestures are eligible for soft-keyboard dismissal —
|
|
2040
|
-
// mouse/trackpad users don't have a keyboard to dismiss.
|
|
2041
1864
|
__publicField(this, "currentPointerKind", "touch");
|
|
2042
|
-
// One blur per drag — flipping focus every move event races the keyboard's
|
|
2043
|
-
// own animations on iOS and makes the page jitter.
|
|
2044
1865
|
__publicField(this, "keyboardDismissed", false);
|
|
2045
|
-
// Reused payload object for the "drag" event — mutated each onMove instead
|
|
2046
|
-
// of allocating a fresh `{size, delta}` per frame. At 60-120Hz a long drag
|
|
2047
|
-
// would otherwise churn tens of KB through the GC. Mirrors browser
|
|
2048
|
-
// PointerEvent semantics: consumers must NOT retain the reference across
|
|
2049
|
-
// frames (clone if needed). See SheetEventMap.drag JSDoc.
|
|
2050
1866
|
__publicField(this, "dragPayload", { size: 0, delta: 0 });
|
|
2051
1867
|
this.deps = deps;
|
|
2052
1868
|
}
|
|
2053
|
-
/** True between `dragstart` and `dragend`/`onCancel`. */
|
|
2054
1869
|
get isDragging() {
|
|
2055
1870
|
return this.isDragging_;
|
|
2056
1871
|
}
|
|
2057
|
-
/**
|
|
2058
|
-
* Bind pointer listeners on the handle and return a teardown. Engine pushes
|
|
2059
|
-
* the teardown into its TeardownStack so destroy() drains it once.
|
|
2060
|
-
*/
|
|
2061
1872
|
install() {
|
|
2062
1873
|
if (this.detach) return this.detach;
|
|
2063
1874
|
this.detach = installGestures(this.deps.handle, this.deps.mode, {
|
|
@@ -2114,11 +1925,6 @@ var init_gesture_controller = __esm({
|
|
|
2114
1925
|
});
|
|
2115
1926
|
return this.detach;
|
|
2116
1927
|
}
|
|
2117
|
-
/**
|
|
2118
|
-
* Force-clear drag visual state. Engine calls from destroy() when destroyed
|
|
2119
|
-
* mid-drag — gesture detach won't synthesize an onCancel, so we have to
|
|
2120
|
-
* roll back the data-attribute + will-change ourselves.
|
|
2121
|
-
*/
|
|
2122
1928
|
forceClearDragState() {
|
|
2123
1929
|
if (!this.isDragging_) return;
|
|
2124
1930
|
this.isDragging_ = false;
|
|
@@ -2142,11 +1948,6 @@ var init_aria_slider_writer = __esm({
|
|
|
2142
1948
|
mode === "bottom" || mode === "top" ? "vertical" : "horizontal"
|
|
2143
1949
|
);
|
|
2144
1950
|
}
|
|
2145
|
-
/**
|
|
2146
|
-
* Update slider position. `allowedIds` length determines `aria-valuemax`;
|
|
2147
|
-
* `activeId` indexes into it for `aria-valuenow` + `aria-valuetext`.
|
|
2148
|
-
* Empty list → strip every dynamic attr so AT skips the handle entirely.
|
|
2149
|
-
*/
|
|
2150
1951
|
setValue(allowedIds, activeId) {
|
|
2151
1952
|
if (allowedIds.length === 0) {
|
|
2152
1953
|
this.handle.removeAttribute("aria-valuemin");
|
|
@@ -2224,9 +2025,6 @@ function resolveEngineOptions(opts, extras) {
|
|
|
2224
2025
|
scrimMode: opts.scrimMode,
|
|
2225
2026
|
scrimColor: opts.scrimColor,
|
|
2226
2027
|
scrimBlur: opts.scrimBlur,
|
|
2227
|
-
// Auto-promote pointer-events when tap-to-close is on so the click
|
|
2228
|
-
// listener actually receives events. Caller can still force `false`
|
|
2229
|
-
// explicitly to opt out — `??` only kicks in for `undefined`.
|
|
2230
2028
|
scrimInteractive: opts.scrimInteractive ?? (opts.scrimTapToClose ? true : void 0),
|
|
2231
2029
|
scrimTapToClose: opts.scrimTapToClose,
|
|
2232
2030
|
scrimPreset: opts.scrimPreset,
|
|
@@ -2247,10 +2045,6 @@ function resolveEngineOptions(opts, extras) {
|
|
|
2247
2045
|
closeOnEscape: opts.closeOnEscape,
|
|
2248
2046
|
lockBodyScroll: opts.lockBodyScroll,
|
|
2249
2047
|
inertSiblings: opts.inertSiblings,
|
|
2250
|
-
// Folded in from `extras` so the lifecycle bag is fully assembled at
|
|
2251
|
-
// the call site — engine no longer needs a spread+override at
|
|
2252
|
-
// controller construction. When `extras` is omitted, the field stays
|
|
2253
|
-
// undefined and the controller uses its own default predicate.
|
|
2254
2048
|
shouldApplyInertSiblings: extras?.shouldApplyInertSiblings
|
|
2255
2049
|
}
|
|
2256
2050
|
};
|
|
@@ -2319,6 +2113,7 @@ var init_BottomSheetEngine = __esm({
|
|
|
2319
2113
|
__publicField(this, "scrollContainer");
|
|
2320
2114
|
__publicField(this, "backdrop");
|
|
2321
2115
|
__publicField(this, "screenComponent");
|
|
2116
|
+
__publicField(this, "scrimParent", null);
|
|
2322
2117
|
__publicField(this, "mode");
|
|
2323
2118
|
__publicField(this, "flickVelocity");
|
|
2324
2119
|
__publicField(this, "dragThreshold");
|
|
@@ -2329,40 +2124,22 @@ var init_BottomSheetEngine = __esm({
|
|
|
2329
2124
|
__publicField(this, "lifecycle");
|
|
2330
2125
|
__publicField(this, "closeOnBack");
|
|
2331
2126
|
__publicField(this, "routedTo");
|
|
2332
|
-
// Engine retains `snapPointsRaw` for the "find a closed-id" query in
|
|
2333
|
-
// close() (raw input, not resolved geometry). Resolver owns geometry.
|
|
2334
2127
|
__publicField(this, "snapPointsRaw");
|
|
2335
2128
|
__publicField(this, "snaps");
|
|
2336
2129
|
__publicField(this, "activeId");
|
|
2337
2130
|
__publicField(this, "size", 0);
|
|
2338
|
-
// Constructed in attach(); a plugin's install() could read `state` before
|
|
2339
|
-
// attach completes if the constructor throws partway through. State getter
|
|
2340
|
-
// null-guards via `this.gesture?.isDragging ?? false`.
|
|
2341
2131
|
__publicField(this, "gesture");
|
|
2342
2132
|
__publicField(this, "rootEl", null);
|
|
2343
2133
|
__publicField(this, "destroyed", false);
|
|
2344
|
-
// In-flight ViewTransition handle. A second snapTo while a VT is in flight
|
|
2345
|
-
// would otherwise let Chromium reject the second's promise and flicker —
|
|
2346
|
-
// newCycle() calls skipTransition() to abort cleanly.
|
|
2347
2134
|
__publicField(this, "currentViewTransition", null);
|
|
2348
|
-
// Each cycle captures the signal at entry; when a newer cycle aborts the
|
|
2349
|
-
// controller, the captured signal flips to `aborted=true` and post-await
|
|
2350
|
-
// guards short-circuit (prevents stale snap/open/close emits).
|
|
2351
2135
|
__publicField(this, "currentAbort", new AbortController());
|
|
2352
|
-
// Sub-pixel `--bs-size` deltas and <1% `--bs-progress` deltas are not
|
|
2353
|
-
// visually distinguishable; gating CSSOM writes drops 30-50% of writes
|
|
2354
|
-
// during the spring's settle tail.
|
|
2355
2136
|
__publicField(this, "sizeWriteSentinel", new WriteSentinel());
|
|
2356
2137
|
__publicField(this, "progressWriteSentinel", new WriteSentinel());
|
|
2357
2138
|
__publicField(this, "isTopSheet", true);
|
|
2358
|
-
// Pooled payload — identity documented in SheetEventMap.progress JSDoc;
|
|
2359
|
-
// consumers must not retain across frames.
|
|
2360
2139
|
__publicField(this, "progressPayload", {
|
|
2361
2140
|
value: 0,
|
|
2362
2141
|
size: 0
|
|
2363
2142
|
});
|
|
2364
|
-
// Pooled buffer for `getDragContext()` — onMove calls this 60-120×/s.
|
|
2365
|
-
// Inner `range` object identity is also stable (mutated in place).
|
|
2366
2143
|
__publicField(this, "dragContextBuf", {
|
|
2367
2144
|
size: 0,
|
|
2368
2145
|
maxAxisSize: 0,
|
|
@@ -2373,13 +2150,7 @@ var init_BottomSheetEngine = __esm({
|
|
|
2373
2150
|
__publicField(this, "persistKey");
|
|
2374
2151
|
__publicField(this, "linkedSheets", []);
|
|
2375
2152
|
__publicField(this, "scrollCache");
|
|
2376
|
-
// Single LIFO stack for ALL destroy-only teardowns. Plugins (added last)
|
|
2377
|
-
// tear down first before the infrastructure they depend on. Toggle-semantic
|
|
2378
|
-
// listeners (focus-trap / scroll-lock / scrim tap-to-close) stay as named
|
|
2379
|
-
// fields on their controllers.
|
|
2380
2153
|
__publicField(this, "teardowns", new TeardownStack());
|
|
2381
|
-
// Pre-computed transform template — built once per engine since `mode` is
|
|
2382
|
-
// fixed for its lifetime. Avoids the 4-arm switch at 60-120 Hz.
|
|
2383
2154
|
__publicField(this, "transformTemplate");
|
|
2384
2155
|
const resolved = resolveEngineOptions(opts, {
|
|
2385
2156
|
shouldApplyInertSiblings: () => {
|
|
@@ -2394,7 +2165,8 @@ var init_BottomSheetEngine = __esm({
|
|
|
2394
2165
|
this.handle = opts.handle ?? opts.element;
|
|
2395
2166
|
this.scrollContainer = opts.scrollContainer;
|
|
2396
2167
|
this.backdrop = opts.backdrop;
|
|
2397
|
-
this.screenComponent = opts.screenComponent;
|
|
2168
|
+
this.screenComponent = opts.scrim ?? opts.screenComponent;
|
|
2169
|
+
this.scrimParent = this.screenComponent?.parentElement ?? null;
|
|
2398
2170
|
this.mode = resolved.mode;
|
|
2399
2171
|
this.transformTemplate = buildTransformTemplate(this.mode);
|
|
2400
2172
|
this.aria = new AriaSliderWriter(this.handle, this.mode);
|
|
@@ -2422,8 +2194,6 @@ var init_BottomSheetEngine = __esm({
|
|
|
2422
2194
|
getRootEl: () => this.rootEl,
|
|
2423
2195
|
applySize: (size) => this.applySize(size),
|
|
2424
2196
|
getSize: () => this.size,
|
|
2425
|
-
// Optional chain protects synthetic test paths that drive animateTo
|
|
2426
|
-
// before attach() (gesture is constructed there).
|
|
2427
2197
|
isDragging: () => this.gesture?.isDragging ?? false
|
|
2428
2198
|
},
|
|
2429
2199
|
resolved.animation
|
|
@@ -2528,21 +2298,6 @@ var init_BottomSheetEngine = __esm({
|
|
|
2528
2298
|
on(event, fn) {
|
|
2529
2299
|
return this.bus.on(event, fn);
|
|
2530
2300
|
}
|
|
2531
|
-
/**
|
|
2532
|
-
* Register a plugin. `install` runs synchronously; if it returns a function,
|
|
2533
|
-
* it's captured for teardown during `destroy()`. No-op if already destroyed
|
|
2534
|
-
* — installing into a torn-down engine would leak listeners.
|
|
2535
|
-
*
|
|
2536
|
-
* Throws from `plugin.install` are caught and rethrown via `queueMicrotask`
|
|
2537
|
-
* so a buggy plugin can't take the engine down with it: the engine stays
|
|
2538
|
-
* usable, sibling plugins still install, and the error surfaces in dev tools
|
|
2539
|
-
* on the next tick instead of being swallowed. Mirrors the per-fn isolation
|
|
2540
|
-
* model used for teardowns.
|
|
2541
|
-
*
|
|
2542
|
-
* Plugins that accept the second `scope` argument get transactional cleanup:
|
|
2543
|
-
* push partial-install cleanups via `scope.add(fn)` and the engine drains
|
|
2544
|
-
* them on throw, OR merges them into destroy-time teardowns on success.
|
|
2545
|
-
*/
|
|
2546
2301
|
use(plugin) {
|
|
2547
2302
|
if (this.destroyed) {
|
|
2548
2303
|
console.warn(
|
|
@@ -2552,9 +2307,6 @@ var init_BottomSheetEngine = __esm({
|
|
|
2552
2307
|
}
|
|
2553
2308
|
const scoped = [];
|
|
2554
2309
|
const scope = {
|
|
2555
|
-
// typeof check — not just truthiness — so a JS-only plugin pushing a
|
|
2556
|
-
// bogus value is silently rejected instead of queueing a confusing
|
|
2557
|
-
// TypeError on destroy() drain.
|
|
2558
2310
|
add: (fn) => {
|
|
2559
2311
|
if (typeof fn === "function") scoped.push(fn);
|
|
2560
2312
|
}
|
|
@@ -2583,36 +2335,13 @@ var init_BottomSheetEngine = __esm({
|
|
|
2583
2335
|
}
|
|
2584
2336
|
return this;
|
|
2585
2337
|
}
|
|
2586
|
-
/**
|
|
2587
|
-
* Replace the linked-sheets list at runtime. Use when peer engines aren't
|
|
2588
|
-
* available at construction time (mounted later in the tree). The wiring
|
|
2589
|
-
* to the `open` event is independent of this list — it reads `linkedSheets`
|
|
2590
|
-
* lazily on emit, so this setter is a simple field swap.
|
|
2591
|
-
*/
|
|
2592
2338
|
setLinkedSheets(sheets) {
|
|
2593
2339
|
if (this.destroyed) return;
|
|
2594
2340
|
this.linkedSheets = sheets;
|
|
2595
2341
|
}
|
|
2596
|
-
/** Read-only view of the current allow-list, for cross-sheet target negotiation. */
|
|
2597
2342
|
getAllowedIds() {
|
|
2598
2343
|
return this.snaps.getAllowedIds().slice();
|
|
2599
2344
|
}
|
|
2600
|
-
/**
|
|
2601
|
-
* Animate to a snap point by id. Resolves when the animation completes.
|
|
2602
|
-
*
|
|
2603
|
-
* Two call shapes:
|
|
2604
|
-
* ```ts
|
|
2605
|
-
* engine.snapTo("full"); // default velocity
|
|
2606
|
-
* engine.snapTo("full", 0.5); // px/ms initial velocity
|
|
2607
|
-
* engine.snapTo("full", { velocity: 0.5, signal }); // abortable
|
|
2608
|
-
* ```
|
|
2609
|
-
*
|
|
2610
|
-
* When `opts.signal` is provided, calling `controller.abort()` cancels the
|
|
2611
|
-
* in-flight tween/spring and the returned promise resolves without firing
|
|
2612
|
-
* `snap`. The captured `AbortSignal` is checked after each await so external
|
|
2613
|
-
* aborts ride the same cycle invariant as internal ones (resize, destroy,
|
|
2614
|
-
* concurrent snapTo).
|
|
2615
|
-
*/
|
|
2616
2345
|
async snapTo(id, velocityOrOpts = 0, _skipBeforeSnap = false) {
|
|
2617
2346
|
if (this.destroyed) return;
|
|
2618
2347
|
const opts = typeof velocityOrOpts === "object" ? velocityOrOpts : { velocity: velocityOrOpts };
|
|
@@ -2671,16 +2400,6 @@ var init_BottomSheetEngine = __esm({
|
|
|
2671
2400
|
this.handleClose();
|
|
2672
2401
|
}
|
|
2673
2402
|
}
|
|
2674
|
-
/**
|
|
2675
|
-
* Drive the sheet to an arbitrary px size, bypassing snap matching.
|
|
2676
|
-
* Useful for preview scrubs, animation chaining, or programmatic gestures.
|
|
2677
|
-
* Animates with the configured spring/tween. Resolves when the animation
|
|
2678
|
-
* completes. Does NOT update `activeId` — call `snapTo(id)` after to commit.
|
|
2679
|
-
*
|
|
2680
|
-
* Unlike `snapTo`, this does not fire `before-snap` (it isn't a snap commit)
|
|
2681
|
-
* nor `snap` (the sheet isn't settling to a known snap). `progress` events
|
|
2682
|
-
* still fire via applySize. Target is clamped to `[0, maxAxisSize]`.
|
|
2683
|
-
*/
|
|
2684
2403
|
async dragTo(targetSize, velocityOrOpts = 0) {
|
|
2685
2404
|
if (this.destroyed) return;
|
|
2686
2405
|
const opts = typeof velocityOrOpts === "object" ? velocityOrOpts : { velocity: velocityOrOpts };
|
|
@@ -2718,20 +2437,10 @@ var init_BottomSheetEngine = __esm({
|
|
|
2718
2437
|
this.snaps.setAllowedIds(ids);
|
|
2719
2438
|
this.updateAriaSlider();
|
|
2720
2439
|
if (snap && ids.includes(snap)) {
|
|
2721
|
-
void this.snapTo(
|
|
2722
|
-
snap,
|
|
2723
|
-
0,
|
|
2724
|
-
/* internal */
|
|
2725
|
-
true
|
|
2726
|
-
);
|
|
2440
|
+
void this.snapTo(snap, 0, true);
|
|
2727
2441
|
} else if (!ids.includes(this.activeId)) {
|
|
2728
2442
|
const fallback = ids[0];
|
|
2729
|
-
if (fallback) void this.snapTo(
|
|
2730
|
-
fallback,
|
|
2731
|
-
0,
|
|
2732
|
-
/* internal */
|
|
2733
|
-
true
|
|
2734
|
-
);
|
|
2443
|
+
if (fallback) void this.snapTo(fallback, 0, true);
|
|
2735
2444
|
}
|
|
2736
2445
|
}
|
|
2737
2446
|
setBackdropRange(range) {
|
|
@@ -2749,21 +2458,6 @@ var init_BottomSheetEngine = __esm({
|
|
|
2749
2458
|
setScrimInteractive(interactive) {
|
|
2750
2459
|
this.scrim.setScrimInteractive(interactive);
|
|
2751
2460
|
}
|
|
2752
|
-
/**
|
|
2753
|
-
* Batch-update multiple scrim fields in one call. Apply order is:
|
|
2754
|
-
* 1. `preset` — fills baseline color/blur/range/interactive.
|
|
2755
|
-
* 2. `mode` — re-positions the scrim (fixed inset / clear / hide).
|
|
2756
|
-
* 3. `enabled` — flips the opacity contribution on/off.
|
|
2757
|
-
* 4. `tapToClose` — installs/tears the click listener.
|
|
2758
|
-
* 5. `color` / `blur` / `interactive` / `range` — explicit overrides.
|
|
2759
|
-
* 6. ONE `applySize` so the per-frame opacity stays consistent.
|
|
2760
|
-
*
|
|
2761
|
-
* Performance: collecting changes here (vs calling individual setters)
|
|
2762
|
-
* avoids repeated `applySize` calls during a multi-field swap. Setters
|
|
2763
|
-
* called here suppress their own internal `applySize` either by passing
|
|
2764
|
-
* through fast-paths (mode/enabled no-op when value unchanged) or by
|
|
2765
|
-
* being visual-only (color/blur/interactive don't influence opacity).
|
|
2766
|
-
*/
|
|
2767
2461
|
setScrim(opts) {
|
|
2768
2462
|
this.scrim.setScrim(opts, () => this.applySize(this.size));
|
|
2769
2463
|
}
|
|
@@ -2779,11 +2473,6 @@ var init_BottomSheetEngine = __esm({
|
|
|
2779
2473
|
setScrimOverlay(opts) {
|
|
2780
2474
|
return this.scrim.setScrimOverlay(opts);
|
|
2781
2475
|
}
|
|
2782
|
-
/**
|
|
2783
|
-
* Read-only snapshot of scrim state. Use the `setScrim*` setters to mutate.
|
|
2784
|
-
* Stable public API — internals (e.g. cached opacity sentinels) are NOT
|
|
2785
|
-
* exposed so consumers can't accidentally couple to ScrimController shape.
|
|
2786
|
-
*/
|
|
2787
2476
|
getScrimState() {
|
|
2788
2477
|
return { mode: this.scrim.scrimMode, enabled: this.scrim.scrimEnabled };
|
|
2789
2478
|
}
|
|
@@ -2829,24 +2518,11 @@ var init_BottomSheetEngine = __esm({
|
|
|
2829
2518
|
emit(event, payload) {
|
|
2830
2519
|
this.bus.emit(event, payload);
|
|
2831
2520
|
}
|
|
2832
|
-
/**
|
|
2833
|
-
* Abort the current cycle's signal and replace the controller. Returns the
|
|
2834
|
-
* fresh signal so the caller can capture it locally before any await — when
|
|
2835
|
-
* a future newCycle() / destroy aborts our controller, the captured signal
|
|
2836
|
-
* flips to aborted and post-await guards short-circuit.
|
|
2837
|
-
*/
|
|
2838
2521
|
newCycle() {
|
|
2839
2522
|
this.currentAbort.abort();
|
|
2840
2523
|
this.currentAbort = new AbortController();
|
|
2841
2524
|
return this.currentAbort.signal;
|
|
2842
2525
|
}
|
|
2843
|
-
/**
|
|
2844
|
-
* Fire `before-snap` and report whether a listener cancelled it. The
|
|
2845
|
-
* `cancel()` callback exposed to listeners is frozen after the synchronous
|
|
2846
|
-
* emit phase so async callers can't silently miss — they get a console
|
|
2847
|
-
* warning. Returns `true` when cancelled so callers can early-return /
|
|
2848
|
-
* spring-back without re-implementing the cancel/frozen pattern.
|
|
2849
|
-
*/
|
|
2850
2526
|
emitBeforeSnap(target, previousId) {
|
|
2851
2527
|
let cancelled = false;
|
|
2852
2528
|
let frozen = false;
|
|
@@ -2880,30 +2556,9 @@ var init_BottomSheetEngine = __esm({
|
|
|
2880
2556
|
this.snaps.setRaw(this.snapPointsRaw);
|
|
2881
2557
|
this.scrim.invalidateOpacityCache();
|
|
2882
2558
|
}
|
|
2883
|
-
/**
|
|
2884
|
-
* Memoised `allowedRange()` — delegates to SnapResolver which owns the cache.
|
|
2885
|
-
* Engine wrapper kept so existing call sites don't all need updating;
|
|
2886
|
-
* resolver-level memoization survives across method invocations.
|
|
2887
|
-
*/
|
|
2888
2559
|
getAllowedRange() {
|
|
2889
2560
|
return this.snaps.getAllowedRange();
|
|
2890
2561
|
}
|
|
2891
|
-
/**
|
|
2892
|
-
* Write ARIA slider value attributes onto the handle so the engine itself
|
|
2893
|
-
* is the source of truth for screen-reader announcements. Called from the
|
|
2894
|
-
* constructor and from every code path that mutates `activeId` /
|
|
2895
|
-
* `allowedIds`. WAI-ARIA 1.2 requires `aria-valuenow` for `role="slider"` —
|
|
2896
|
-
* without it screen readers can't announce drag/snap progress to keyboard
|
|
2897
|
-
* + AT users (WCAG 4.1.2 Name, Role, Value).
|
|
2898
|
-
*
|
|
2899
|
-
* Engine does NOT set `role="slider"` itself — that's the adapter's or
|
|
2900
|
-
* consumer markup's responsibility. We only decorate with dynamic values.
|
|
2901
|
-
*
|
|
2902
|
-
* Empty allowed-list is malformed input (settable via `setAllowed([])`);
|
|
2903
|
-
* short-circuit to remove ARIA value attributes so screen readers see a
|
|
2904
|
-
* no-value slider rather than a degenerate `min=max=now=0` (WAI-ARIA 1.2
|
|
2905
|
-
* requires `valuemax > valuemin` for `role="slider"`).
|
|
2906
|
-
*/
|
|
2907
2562
|
updateAriaSlider() {
|
|
2908
2563
|
this.aria.setValue(this.snaps.getAllowedIds(), this.activeId);
|
|
2909
2564
|
}
|
|
@@ -2928,11 +2583,6 @@ var init_BottomSheetEngine = __esm({
|
|
|
2928
2583
|
element: this.element,
|
|
2929
2584
|
mode: this.mode,
|
|
2930
2585
|
getRoot: () => this.rootEl,
|
|
2931
|
-
// Single coalesced reader — narrows the DI surface and removes 3 getter
|
|
2932
|
-
// dispatches per onMove frame at 60-120Hz. Returns a SHARED buffer
|
|
2933
|
-
// (this.dragContextBuf) — see field JSDoc for the retention contract.
|
|
2934
|
-
// Inner `range` object is mutated in place too so callers caching its
|
|
2935
|
-
// identity between frames stay valid.
|
|
2936
2586
|
getDragContext: () => {
|
|
2937
2587
|
const buf = this.dragContextBuf;
|
|
2938
2588
|
const r = this.getAllowedRange();
|
|
@@ -3098,7 +2748,6 @@ var init_BottomSheetEngine = __esm({
|
|
|
3098
2748
|
}
|
|
3099
2749
|
});
|
|
3100
2750
|
}
|
|
3101
|
-
/** Trigger a brief haptic tick (iOS Safari + Android Chrome support). */
|
|
3102
2751
|
haptic() {
|
|
3103
2752
|
if (typeof navigator !== "undefined" && "vibrate" in navigator) {
|
|
3104
2753
|
try {
|
|
@@ -3114,6 +2763,9 @@ var init_BottomSheetEngine = __esm({
|
|
|
3114
2763
|
style.transform = this.transformTemplate(offset);
|
|
3115
2764
|
if (this.sizeWriteSentinel.shouldWrite(size, SIZE_WRITE_EPSILON)) {
|
|
3116
2765
|
style.setProperty("--bs-size", `${size}px`);
|
|
2766
|
+
if (this.scrimParent) {
|
|
2767
|
+
this.scrimParent.style.setProperty("--bs-size", `${size}px`);
|
|
2768
|
+
}
|
|
3117
2769
|
}
|
|
3118
2770
|
const progress = this.computeProgress(size);
|
|
3119
2771
|
const progressChanged = this.progressWriteSentinel.shouldWrite(
|
|
@@ -3160,7 +2812,7 @@ var init_BottomSheetEngine = __esm({
|
|
|
3160
2812
|
var baseStyles;
|
|
3161
2813
|
var init_baseStyles = __esm({
|
|
3162
2814
|
"src/web-component/baseStyles.ts"() {
|
|
3163
|
-
baseStyles = `:where(.bs-root){--bs-surface:#ffffff;--bs-surface-border:rgba(225,227,237,1);--bs-shadow:0 -3px 12px rgba(0,0,0,0.12);--bs-radius:20px;--bs-handle-color:#b5b3a8;--bs-handle-width:40px;--bs-handle-height:5px;--bs-z-backdrop:90;--bs-z-sheet:100;--bs-header-min-height:80px;--bs-backdrop-color:rgba(0,0,0,0.5);--bs-scrim-color:rgba(0,0,0,0.4);--bs-scrim-blur:0px;--bs-z-scrim:calc(var(--bs-z-sheet) - 1);--bs-size:0px;--bs-progress:0}.bs-backdrop{position:fixed;inset:0;background:var(--bs-backdrop-color);opacity:0;pointer-events:none;z-index:var(--bs-z-backdrop);transition:opacity 0.15s linear;will-change:opacity}.bs-root[data-dragging="true"] .bs-backdrop,.bs-root[data-animating="true"] .bs-backdrop{transition:none}.bs-sheet{position:fixed;background:var(--bs-surface);box-shadow:var(--bs-shadow);z-index:var(--bs-z-sheet);overflow:hidden;display:flex;flex-direction:column;-webkit-tap-highlight-color:transparent;user-select:none;overscroll-behavior:contain}.bs-sheet[data-mode="bottom"]{left:0;right:0;bottom:0;width:100%;border-top-left-radius:var(--bs-radius);border-top-right-radius:var(--bs-radius);border-top:1px solid var(--bs-surface-border);padding-bottom:env(safe-area-inset-bottom);box-shadow:0 calc(var(--bs-progress,0) * -2px - 3px) calc(var(--bs-progress,0) * 18px + 12px) rgba(0,0,0,calc(var(--bs-progress,0) * 0.15 + 0.12))}.bs-sheet[data-mode="top"]{left:0;right:0;top:0;width:100%;border-bottom-left-radius:var(--bs-radius);border-bottom-right-radius:var(--bs-radius);border-bottom:1px solid var(--bs-surface-border);flex-direction:column-reverse;box-shadow:0 3px 12px rgba(0,0,0,0.12);padding-top:env(safe-area-inset-top)}.bs-sheet[data-mode="left"]{top:0;bottom:0;left:0;height:100%;border-top-right-radius:var(--bs-radius);border-bottom-right-radius:var(--bs-radius);border-right:1px solid var(--bs-surface-border);box-shadow:3px 0 12px rgba(0,0,0,0.12)}.bs-sheet[data-mode="right"]{top:0;bottom:0;right:0;height:100%;border-top-left-radius:var(--bs-radius);border-bottom-left-radius:var(--bs-radius);border-left:1px solid var(--bs-surface-border);box-shadow:-3px 0 12px rgba(0,0,0,0.12)}.bs-sheet[data-mode="left"] .bs-content{padding-right:36px}.bs-sheet[data-mode="right"] .bs-content{padding-left:36px}.bs-handle{flex-shrink:0;min-height:44px;display:flex;flex-direction:column;justify-content:center;padding:8px 16px 4px;cursor:grab;touch-action:none;user-select:none;background:var(--bs-surface);-webkit-tap-highlight-color:transparent;outline:none;position:relative}.bs-handle:active{cursor:grabbing}.bs-handle:focus-visible{outline:2px solid currentColor;outline-offset:-2px;border-radius:var(--bs-radius)}.bs-handle::before{content:"";display:block;width:var(--bs-handle-width);height:var(--bs-handle-height);background:var(--bs-handle-color);border-radius:calc(var(--bs-handle-height) / 2);margin:0 auto 8px;transition:width 0.15s ease,background 0.15s ease,transform 0.15s ease;pointer-events:none}.bs-sheet[data-mode="left"] .bs-handle,.bs-sheet[data-mode="right"] .bs-handle{position:absolute;top:0;bottom:0;width:28px;min-width:0;min-height:0;display:flex;flex-direction:column;align-items:center;justify-content:center;padding:0;background:var(--bs-surface);z-index:1;overflow:hidden}.bs-sheet[data-mode="left"] .bs-handle>*,.bs-sheet[data-mode="right"] .bs-handle>*{display:none}.bs-sheet[data-mode="left"] .bs-handle{right:0;border-left:1px solid var(--bs-surface-border)}.bs-sheet[data-mode="right"] .bs-handle{left:0;border-right:1px solid var(--bs-surface-border)}.bs-sheet[data-mode="left"] .bs-handle::before,.bs-sheet[data-mode="right"] .bs-handle::before{width:var(--bs-handle-height);height:var(--bs-handle-width);margin:0}.bs-sheet:hover .bs-handle::before{background:color-mix(in oklab,var(--bs-handle-color),#000 15%)}.bs-handle:active::before{background:color-mix(in oklab,var(--bs-handle-color),#000 35%);transform:scaleX(1.15)}.bs-handle.bs-handle--ticks::after{content:"";display:block;position:absolute;left:50%;bottom:6px;transform:translateX(-50%);width:calc(var(--bs-handle-width) * 2);height:3px;background-image:radial-gradient( circle,var(--bs-handle-color) 0 1.5px,transparent 1.6px );background-size:8px 3px;background-repeat:repeat-x;background-position:center;opacity:0;transition:opacity 0.18s ease-out;pointer-events:none}.bs-root[data-dragging="true"] .bs-handle.bs-handle--ticks::after{opacity:0.4}.bs-sheet[data-mode="top"] .bs-handle.bs-handle--ticks::after{bottom:auto;top:6px}.bs-sheet[data-mode="left"] .bs-handle.bs-handle--ticks::after,.bs-sheet[data-mode="right"] .bs-handle.bs-handle--ticks::after{left:50%;top:50%;bottom:auto;transform:translate(-50%,-50%);width:3px;height:calc(var(--bs-handle-width) * 2);background-size:3px 8px;background-repeat:repeat-y;margin-left:calc(var(--bs-handle-height) + 6px)}.bs-sheet[data-mode="right"] .bs-handle.bs-handle--ticks::after{margin-left:calc(-1 * (var(--bs-handle-height) + 6px))}.bs-content{flex:1;min-height:0;overflow-y:auto;-webkit-overflow-scrolling:touch;overscroll-behavior:contain;padding:0 16px 16px}.bs-screen{position:absolute;inset:0;pointer-events:none;
|
|
2815
|
+
baseStyles = `:where(.bs-root){--bs-surface:#ffffff;--bs-surface-border:rgba(225,227,237,1);--bs-shadow:0 -3px 12px rgba(0,0,0,0.12);--bs-radius:20px;--bs-handle-color:#b5b3a8;--bs-handle-width:40px;--bs-handle-height:5px;--bs-z-backdrop:90;--bs-z-sheet:100;--bs-header-min-height:80px;--bs-backdrop-color:rgba(0,0,0,0.5);--bs-scrim-color:rgba(0,0,0,0.4);--bs-scrim-blur:0px;--bs-z-scrim:calc(var(--bs-z-sheet) - 1);--bs-size:0px;--bs-progress:0}.bs-backdrop{position:fixed;inset:0;background:var(--bs-backdrop-color);opacity:0;pointer-events:none;z-index:var(--bs-z-backdrop);transition:opacity 0.15s linear;will-change:opacity}.bs-root[data-dragging="true"] .bs-backdrop,.bs-root[data-animating="true"] .bs-backdrop{transition:none}.bs-sheet{position:fixed;background:var(--bs-surface);box-shadow:var(--bs-shadow);z-index:var(--bs-z-sheet);overflow:hidden;display:flex;flex-direction:column;-webkit-tap-highlight-color:transparent;user-select:none;overscroll-behavior:contain}.bs-sheet[data-mode="bottom"]{left:0;right:0;bottom:0;width:100%;border-top-left-radius:var(--bs-radius);border-top-right-radius:var(--bs-radius);border-top:1px solid var(--bs-surface-border);padding-bottom:env(safe-area-inset-bottom);box-shadow:0 calc(var(--bs-progress,0) * -2px - 3px) calc(var(--bs-progress,0) * 18px + 12px) rgba(0,0,0,calc(var(--bs-progress,0) * 0.15 + 0.12))}.bs-sheet[data-mode="top"]{left:0;right:0;top:0;width:100%;border-bottom-left-radius:var(--bs-radius);border-bottom-right-radius:var(--bs-radius);border-bottom:1px solid var(--bs-surface-border);flex-direction:column-reverse;box-shadow:0 3px 12px rgba(0,0,0,0.12);padding-top:env(safe-area-inset-top)}.bs-sheet[data-mode="left"]{top:0;bottom:0;left:0;height:100%;border-top-right-radius:var(--bs-radius);border-bottom-right-radius:var(--bs-radius);border-right:1px solid var(--bs-surface-border);box-shadow:3px 0 12px rgba(0,0,0,0.12)}.bs-sheet[data-mode="right"]{top:0;bottom:0;right:0;height:100%;border-top-left-radius:var(--bs-radius);border-bottom-left-radius:var(--bs-radius);border-left:1px solid var(--bs-surface-border);box-shadow:-3px 0 12px rgba(0,0,0,0.12)}.bs-sheet[data-mode="left"] .bs-content{padding-right:36px}.bs-sheet[data-mode="right"] .bs-content{padding-left:36px}.bs-handle{flex-shrink:0;min-height:44px;display:flex;flex-direction:column;justify-content:center;padding:8px 16px 4px;cursor:grab;touch-action:none;user-select:none;background:var(--bs-surface);-webkit-tap-highlight-color:transparent;outline:none;position:relative}.bs-handle:active{cursor:grabbing}.bs-handle:focus-visible{outline:2px solid currentColor;outline-offset:-2px;border-radius:var(--bs-radius)}.bs-handle::before{content:"";display:block;width:var(--bs-handle-width);height:var(--bs-handle-height);background:var(--bs-handle-color);border-radius:calc(var(--bs-handle-height) / 2);margin:0 auto 8px;transition:width 0.15s ease,background 0.15s ease,transform 0.15s ease;pointer-events:none}.bs-sheet[data-mode="left"] .bs-handle,.bs-sheet[data-mode="right"] .bs-handle{position:absolute;top:0;bottom:0;width:28px;min-width:0;min-height:0;display:flex;flex-direction:column;align-items:center;justify-content:center;padding:0;background:var(--bs-surface);z-index:1;overflow:hidden}.bs-sheet[data-mode="left"] .bs-handle>*,.bs-sheet[data-mode="right"] .bs-handle>*{display:none}.bs-sheet[data-mode="left"] .bs-handle{right:0;border-left:1px solid var(--bs-surface-border)}.bs-sheet[data-mode="right"] .bs-handle{left:0;border-right:1px solid var(--bs-surface-border)}.bs-sheet[data-mode="left"] .bs-handle::before,.bs-sheet[data-mode="right"] .bs-handle::before{width:var(--bs-handle-height);height:var(--bs-handle-width);margin:0}.bs-sheet:hover .bs-handle::before{background:color-mix(in oklab,var(--bs-handle-color),#000 15%)}.bs-handle:active::before{background:color-mix(in oklab,var(--bs-handle-color),#000 35%);transform:scaleX(1.15)}.bs-handle.bs-handle--ticks::after{content:"";display:block;position:absolute;left:50%;bottom:6px;transform:translateX(-50%);width:calc(var(--bs-handle-width) * 2);height:3px;background-image:radial-gradient( circle,var(--bs-handle-color) 0 1.5px,transparent 1.6px );background-size:8px 3px;background-repeat:repeat-x;background-position:center;opacity:0;transition:opacity 0.18s ease-out;pointer-events:none}.bs-root[data-dragging="true"] .bs-handle.bs-handle--ticks::after{opacity:0.4}.bs-sheet[data-mode="top"] .bs-handle.bs-handle--ticks::after{bottom:auto;top:6px}.bs-sheet[data-mode="left"] .bs-handle.bs-handle--ticks::after,.bs-sheet[data-mode="right"] .bs-handle.bs-handle--ticks::after{left:50%;top:50%;bottom:auto;transform:translate(-50%,-50%);width:3px;height:calc(var(--bs-handle-width) * 2);background-size:3px 8px;background-repeat:repeat-y;margin-left:calc(var(--bs-handle-height) + 6px)}.bs-sheet[data-mode="right"] .bs-handle.bs-handle--ticks::after{margin-left:calc(-1 * (var(--bs-handle-height) + 6px))}.bs-content{flex:1;min-height:0;overflow-y:auto;-webkit-overflow-scrolling:touch;overscroll-behavior:contain;padding:0 16px 16px}.bs-screen{position:absolute;inset:0;pointer-events:none;z-index:var(--bs-z-scrim)}.bs-scrim-overlay{z-index:calc(var(--bs-z-sheet) + 1);pointer-events:none}.bs-scrim{background:var(--bs-scrim-color);transition:opacity 0.15s linear;will-change:opacity}.bs-root[data-dragging="true"] .bs-scrim,.bs-root[data-animating="true"] .bs-scrim{transition:none}.bs-scrim{backdrop-filter:blur(var(--bs-scrim-blur));-webkit-backdrop-filter:blur(var(--bs-scrim-blur))}.bs-button-slot{position:absolute;z-index:calc(var(--bs-z-sheet) + 1);pointer-events:auto}.bs-button-slot[data-side="left"]{left:16px;bottom:calc(var(--bs-size,0px) + 12px);transition:bottom 0.15s ease}.bs-button-slot[data-side="right"]{right:16px;bottom:calc(var(--bs-size,0px) + 12px);transition:bottom 0.15s ease}@media (prefers-reduced-motion:reduce){.bs-backdrop,.bs-handle::before,.bs-button-slot[data-side="left"],.bs-button-slot[data-side="right"]{transition:none !important}}@media (prefers-color-scheme:dark){:where(.bs-root){--bs-surface:#1a1a1d;--bs-surface-border:rgba(255,255,255,0.08);--bs-handle-color:rgba(255,255,255,0.45);--bs-shadow:0 -3px 16px rgba(0,0,0,0.5)}}.bs-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}:where(.ovl-root){--ovl-surface:var(--bs-surface,#ffffff);--ovl-surface-border:var(--bs-surface-border,rgba(0,0,0,0.08));--ovl-shadow:0 -8px 40px rgba(0,0,0,0.35);--ovl-radius:var(--bs-radius,20px);--ovl-backdrop-color:rgba(0,0,0,0.5);--ovl-z-backdrop:200;--ovl-z-panel:201}.ovl-backdrop{position:fixed;inset:0;background:var(--ovl-backdrop-color);opacity:0;pointer-events:none;z-index:var(--ovl-z-backdrop)}.ovl-panel{position:fixed;background:var(--ovl-surface);box-shadow:var(--ovl-shadow);z-index:var(--ovl-z-panel);-webkit-tap-highlight-color:transparent;outline:none;transition:transform 0.32s cubic-bezier(0.29,1.24,0.84,0.99),opacity 0.32s ease-out}.ovl-panel[data-state="open"]{transform:translate3d(0,0,0);opacity:1}@starting-style{.ovl-panel[data-edge="bottom"][data-state="open"]{transform:translate3d(0,100%,0);opacity:0}.ovl-panel[data-edge="top"][data-state="open"]{transform:translate3d(0,-100%,0);opacity:0}.ovl-panel[data-edge="left"][data-state="open"]{transform:translate3d(-100%,0,0);opacity:0}.ovl-panel[data-edge="right"][data-state="open"]{transform:translate3d(100%,0,0);opacity:0}}.ovl-panel[data-edge="bottom"]{left:0;right:0;bottom:0;width:100%;border-top-left-radius:var(--ovl-radius);border-top-right-radius:var(--ovl-radius);border-top:1px solid var(--ovl-surface-border);padding-bottom:env(safe-area-inset-bottom)}.ovl-panel[data-edge="top"]{left:0;right:0;top:0;width:100%;border-bottom-left-radius:var(--ovl-radius);border-bottom-right-radius:var(--ovl-radius);border-bottom:1px solid var(--ovl-surface-border);padding-top:env(safe-area-inset-top)}.ovl-panel[data-edge="left"]{top:0;bottom:0;left:0;height:100%;border-top-right-radius:var(--ovl-radius);border-bottom-right-radius:var(--ovl-radius);border-right:1px solid var(--ovl-surface-border)}.ovl-panel[data-edge="right"]{top:0;bottom:0;right:0;height:100%;border-top-left-radius:var(--ovl-radius);border-bottom-left-radius:var(--ovl-radius);border-left:1px solid var(--ovl-surface-border)}@media (prefers-reduced-motion:reduce){.ovl-panel,.ovl-backdrop{transition:none !important}}`;
|
|
3164
2816
|
}
|
|
3165
2817
|
});
|
|
3166
2818
|
|
|
@@ -3343,6 +2995,9 @@ var init_BottomSheetElement = __esm({
|
|
|
3343
2995
|
this.teardownEngine();
|
|
3344
2996
|
this.initEngine();
|
|
3345
2997
|
}
|
|
2998
|
+
getEngine() {
|
|
2999
|
+
return this.engine;
|
|
3000
|
+
}
|
|
3346
3001
|
teardownEngine() {
|
|
3347
3002
|
this.offHandlers.forEach((off) => off());
|
|
3348
3003
|
this.offHandlers = [];
|
|
@@ -3374,7 +3029,7 @@ var init_BottomSheetElement = __esm({
|
|
|
3374
3029
|
handle,
|
|
3375
3030
|
scrollContainer: content,
|
|
3376
3031
|
backdrop: showBackdrop ? backdrop : void 0,
|
|
3377
|
-
|
|
3032
|
+
scrim: this.refs.screen,
|
|
3378
3033
|
mode,
|
|
3379
3034
|
snapPoints: parseSnapPoints(this.getAttribute(ATTR_SNAP_POINTS)),
|
|
3380
3035
|
allowed: parseList(this.getAttribute(ATTR_ALLOWED)),
|