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