scrollsheet
Advanced tools
| "use client"; | ||
| import { c as Slot, d as useSheetContext, i as Content$1, n as Description, r as Title, s as Trigger, t as Close, u as Root$1 } from "./misc-B6wh-cJ4.mjs"; | ||
| import { t as cn } from "./cn-DgpbGWy-.mjs"; | ||
| import * as React from "react"; | ||
| import { Fragment, jsx } from "react/jsx-runtime"; | ||
| import { createPortal } from "react-dom"; | ||
| //#region packages/scrollsheet/src/handle.tsx | ||
| function detentLabel(spec) { | ||
| if (spec === "full") return "Full"; | ||
| if (spec === "medium") return "Half"; | ||
| if (spec === "content") return "Fit content"; | ||
| if (typeof spec === "number") return `${Math.round(spec * 100)}%`; | ||
| return spec ?? ""; | ||
| } | ||
| const Handle$1 = React.forwardRef(function Handle({ asChild, onClick, onKeyDown, className, variant = "inside", ...props }, ref) { | ||
| const ctx = useSheetContext("Handle"); | ||
| const [mounted, setMounted] = React.useState(false); | ||
| React.useEffect(() => setMounted(true), []); | ||
| const outside = variant === "outside" && ctx.side === "bottom" && !(mounted && !ctx.canvasEl); | ||
| const variantAttr = outside ? "outside" : variant === "floating" ? "floating" : void 0; | ||
| const specs = ctx.detents; | ||
| const horizontal = ctx.side === "left" || ctx.side === "right"; | ||
| const multi = specs.length >= 2; | ||
| const activeIndex = specs.findIndex((s) => Object.is(s, ctx.activeDetent)); | ||
| const move = (delta) => { | ||
| if (!multi) return false; | ||
| const index = specs.findIndex((s) => Object.is(s, ctx.activeDetent)); | ||
| const next = specs[index + delta]; | ||
| if (next === void 0) return false; | ||
| ctx.setActiveDetent(next); | ||
| return true; | ||
| }; | ||
| const sliderAria = multi ? { | ||
| role: "slider", | ||
| "aria-orientation": horizontal ? "horizontal" : "vertical", | ||
| "aria-valuemin": 0, | ||
| "aria-valuemax": specs.length - 1, | ||
| ...activeIndex >= 0 ? { | ||
| "aria-valuenow": activeIndex, | ||
| "aria-valuetext": detentLabel(specs[activeIndex]) | ||
| } : {} | ||
| } : {}; | ||
| const button = jsx(asChild ? Slot : "button", { | ||
| ...asChild ? {} : { type: "button" }, | ||
| "aria-label": horizontal ? "Adjust sheet width" : "Adjust sheet height", | ||
| ...sliderAria, | ||
| ...props, | ||
| ref, | ||
| className: cn("scrollsheet-handle", className), | ||
| "data-scrollsheet-handle": true, | ||
| "data-scrollsheet-handle-variant": variantAttr, | ||
| onClick: (event) => { | ||
| onClick?.(event); | ||
| if (event.defaultPrevented) return; | ||
| if (!multi) return; | ||
| const index = specs.findIndex((s) => Object.is(s, ctx.activeDetent)); | ||
| const next = specs[(index + 1) % specs.length]; | ||
| if (next !== void 0) ctx.setActiveDetent(next); | ||
| }, | ||
| onKeyDown: (event) => { | ||
| onKeyDown?.(event); | ||
| if (event.defaultPrevented) return; | ||
| const expandKey = horizontal ? "ArrowRight" : "ArrowUp"; | ||
| const collapseKey = horizontal ? "ArrowLeft" : "ArrowDown"; | ||
| if (event.key === expandKey) { | ||
| event.preventDefault(); | ||
| move(1); | ||
| } else if (event.key === collapseKey) { | ||
| event.preventDefault(); | ||
| if (!move(-1) && ctx.dismissible) ctx.setOpen(false); | ||
| } else if (multi && event.key === "Home") { | ||
| event.preventDefault(); | ||
| const first = specs[0]; | ||
| if (first !== void 0) ctx.setActiveDetent(first); | ||
| } else if (multi && event.key === "End") { | ||
| event.preventDefault(); | ||
| const last = specs[specs.length - 1]; | ||
| if (last !== void 0) ctx.setActiveDetent(last); | ||
| } | ||
| } | ||
| }); | ||
| if (outside) return ctx.canvasEl ? createPortal(button, ctx.canvasEl) : null; | ||
| return button; | ||
| }); | ||
| //#endregion | ||
| //#region packages/scrollsheet/src/drawer/index.tsx | ||
| const wrapperClaims = new Map(); | ||
| const VAUL_CLOSE_THRESHOLD = .25; | ||
| function toDetentSpec(point) { | ||
| if (typeof point === "number") return point; | ||
| if (point === "fit-content" || point === "content") return "content"; | ||
| if (/^\d+(\.\d+)?px$/.test(point)) return `${Number.parseFloat(point)}px`; | ||
| const parsed = Number.parseFloat(point); | ||
| return Number.isFinite(parsed) ? parsed : "content"; | ||
| } | ||
| function resolveFadeFromIndex(snapPoints, fadeFromIndex) { | ||
| if (!snapPoints || snapPoints.length === 0) return void 0; | ||
| const point = snapPoints[fadeFromIndex ?? snapPoints.length - 1]; | ||
| return point !== void 0 ? toDetentSpec(point) : void 0; | ||
| } | ||
| function resolveCloseThreshold(snapPoints, closeThreshold) { | ||
| if (snapPoints !== void 0 && snapPoints.length > 0) return void 0; | ||
| return Math.min(1, Math.max(0, 1 - (closeThreshold ?? VAUL_CLOSE_THRESHOLD))); | ||
| } | ||
| function composeOpenChange(onOpenChange, onClose) { | ||
| if (!onOpenChange && !onClose) return void 0; | ||
| return (next) => { | ||
| if (!next) onClose?.(); | ||
| onOpenChange?.(next); | ||
| }; | ||
| } | ||
| function Root(props) { | ||
| const { children, open, defaultOpen, onOpenChange, onClose, dismissible, snapPoints, activeSnapPoint, setActiveSnapPoint, onAnimationEnd, autoFocus, nested, direction, modal, shouldScaleBackground, setBackgroundColorOnScale, noBodyStyles, disablePreventScroll, preventScrollRestoration, repositionInputs, scrollLockTimeout, closeThreshold, fadeFromIndex, snapToSequentialPoint, handleOnly, onDrag, onRelease, container, fixed, actionsRef, backdropDismissible, escapeDismissible, keyboardExpands, onTravel, scrollbar } = props; | ||
| const detents = snapPoints && snapPoints.length > 0 ? snapPoints.map(toDetentSpec) : void 0; | ||
| const activeDetent = activeSnapPoint != null ? toDetentSpec(activeSnapPoint) : void 0; | ||
| const largestUndimmedDetent = resolveFadeFromIndex(snapPoints, fadeFromIndex); | ||
| const resolvedCloseThreshold = resolveCloseThreshold(snapPoints, closeThreshold); | ||
| const handleRelease = onRelease ? (event, willRemainOpen) => onRelease(event, willRemainOpen) : void 0; | ||
| const handleOpenChange = composeOpenChange(onOpenChange, onClose); | ||
| const handleActiveDetentChange = (detent) => { | ||
| if (!setActiveSnapPoint) return; | ||
| const match = snapPoints?.find((point) => Object.is(toDetentSpec(point), detent)); | ||
| setActiveSnapPoint(match ?? detent); | ||
| }; | ||
| React.useEffect(() => { | ||
| if (!shouldScaleBackground) return; | ||
| const existing = document.querySelector("[data-scrollsheet-background]"); | ||
| if (existing && !wrapperClaims.has(existing)) return; | ||
| const wrapper = existing ?? document.querySelector("[data-vaul-drawer-wrapper]"); | ||
| if (!wrapper) return; | ||
| const count = wrapperClaims.get(wrapper) ?? 0; | ||
| wrapperClaims.set(wrapper, count + 1); | ||
| if (count === 0) wrapper.setAttribute("data-scrollsheet-background", ""); | ||
| return () => { | ||
| const remaining = (wrapperClaims.get(wrapper) ?? 1) - 1; | ||
| if (remaining <= 0) { | ||
| wrapperClaims.delete(wrapper); | ||
| wrapper.removeAttribute("data-scrollsheet-background"); | ||
| } else wrapperClaims.set(wrapper, remaining); | ||
| }; | ||
| }, [shouldScaleBackground]); | ||
| return jsx(DirectionContext.Provider, { | ||
| value: direction ?? "bottom", | ||
| children: jsx(Root$1, { | ||
| open, | ||
| defaultOpen, | ||
| onOpenChange: handleOpenChange, | ||
| onOpenChangeComplete: onAnimationEnd, | ||
| dismissible, | ||
| detents, | ||
| activeDetent, | ||
| onActiveDetentChange: setActiveSnapPoint ? handleActiveDetentChange : void 0, | ||
| side: direction, | ||
| modal, | ||
| backgroundEffect: shouldScaleBackground ? "scale" : "none", | ||
| largestUndimmedDetent, | ||
| handleOnly, | ||
| sequentialDetents: snapToSequentialPoint, | ||
| closeThreshold: resolvedCloseThreshold, | ||
| onRelease: handleRelease, | ||
| actionsRef, | ||
| backdropDismissible, | ||
| escapeDismissible, | ||
| keyboardExpands, | ||
| onTravel, | ||
| scrollbar, | ||
| children | ||
| }) | ||
| }); | ||
| } | ||
| const DirectionContext = React.createContext("bottom"); | ||
| const NestedRoot = Root; | ||
| function Portal({ children, container }) { | ||
| return jsx(Fragment, { children }); | ||
| } | ||
| function Overlay(_props) { | ||
| return null; | ||
| } | ||
| function hasMultipleSnapPoints(detents) { | ||
| return detents.length > 1; | ||
| } | ||
| const Content = React.forwardRef(function Content({ onPointerDownOutside, onOpenAutoFocus, onEscapeKeyDown, onCloseAutoFocus, onInteractOutside, onFocusOutside, forceMount, ...props }, ref) { | ||
| const ctx = useSheetContext("Content"); | ||
| const direction = React.useContext(DirectionContext); | ||
| const snapPointsActive = hasMultipleSnapPoints(ctx.detents); | ||
| return jsx(Content$1, { | ||
| ...props, | ||
| ref, | ||
| "data-vaul-drawer": "", | ||
| "data-vaul-drawer-direction": direction, | ||
| "data-vaul-snap-points": snapPointsActive ? "true" : "false" | ||
| }); | ||
| }); | ||
| function composeHandleClick(preventCycle, onClick) { | ||
| return (event) => { | ||
| onClick?.(event); | ||
| if (preventCycle) event.preventDefault(); | ||
| }; | ||
| } | ||
| const Handle = React.forwardRef(function Handle({ preventCycle, onClick, ...props }, ref) { | ||
| const ctx = useSheetContext("Handle"); | ||
| return jsx(Handle$1, { | ||
| ...props, | ||
| ref, | ||
| "data-vaul-handle": "", | ||
| "data-vaul-drawer-visible": ctx.open ? "true" : "false", | ||
| onClick: composeHandleClick(preventCycle, onClick) | ||
| }); | ||
| }); | ||
| const DrawerClose = React.forwardRef(function DrawerClose({ children, ...props }, ref) { | ||
| return jsx(Close, { | ||
| ...props, | ||
| ref, | ||
| children: children ?? null | ||
| }); | ||
| }); | ||
| const Drawer = { | ||
| Root, | ||
| NestedRoot, | ||
| Trigger, | ||
| Portal, | ||
| Overlay, | ||
| Content, | ||
| Close: DrawerClose, | ||
| Title, | ||
| Description, | ||
| Handle | ||
| }; | ||
| //#endregion | ||
| export { NestedRoot as a, Root as c, hasMultipleSnapPoints as d, resolveCloseThreshold as f, Handle as i, composeHandleClick as l, Handle$1 as m, Drawer as n, Overlay as o, resolveFadeFromIndex as p, DrawerClose as r, Portal as s, Content as t, composeOpenChange as u }; |
Sorry, the diff of this file is too big to display
| "use client"; | ||
| import { c as Slot, d as useSheetContext, i as Content$1, n as Description, r as Title, s as Trigger, t as Close, u as Root$1 } from "./misc-DiVXSPuI.mjs"; | ||
| import { h as warnOnce, t as cn } from "./cn-Cs7ZylHz.mjs"; | ||
| import * as React from "react"; | ||
| import { Fragment, jsx } from "react/jsx-runtime"; | ||
| import { createPortal } from "react-dom"; | ||
| //#region packages/scrollsheet/src/handle.tsx | ||
| function detentLabel(spec) { | ||
| if (spec === "full") return "Full"; | ||
| if (spec === "medium") return "Half"; | ||
| if (spec === "content") return "Fit content"; | ||
| if (typeof spec === "number") return `${Math.round(spec * 100)}%`; | ||
| return spec ?? ""; | ||
| } | ||
| const Handle$1 = React.forwardRef(function Handle({ asChild, onClick, onKeyDown, className, variant = "inside", ...props }, ref) { | ||
| const ctx = useSheetContext("Handle"); | ||
| const [mounted, setMounted] = React.useState(false); | ||
| React.useEffect(() => setMounted(true), []); | ||
| const outside = variant === "outside" && ctx.side === "bottom" && !(mounted && !ctx.canvasEl); | ||
| const variantAttr = outside ? "outside" : variant === "floating" ? "floating" : void 0; | ||
| const specs = ctx.detents; | ||
| const horizontal = ctx.side === "left" || ctx.side === "right"; | ||
| const multi = specs.length >= 2; | ||
| const activeIndex = specs.findIndex((s) => Object.is(s, ctx.activeDetent)); | ||
| const move = (delta) => { | ||
| if (!multi) return false; | ||
| const index = specs.findIndex((s) => Object.is(s, ctx.activeDetent)); | ||
| const next = specs[index + delta]; | ||
| if (next === void 0) return false; | ||
| ctx.setActiveDetent(next); | ||
| return true; | ||
| }; | ||
| const sliderAria = multi ? { | ||
| role: "slider", | ||
| "aria-orientation": horizontal ? "horizontal" : "vertical", | ||
| "aria-valuemin": 0, | ||
| "aria-valuemax": specs.length - 1, | ||
| ...activeIndex >= 0 ? { | ||
| "aria-valuenow": activeIndex, | ||
| "aria-valuetext": detentLabel(specs[activeIndex]) | ||
| } : {} | ||
| } : {}; | ||
| const button = jsx(asChild ? Slot : "button", { | ||
| ...asChild ? {} : { type: "button" }, | ||
| "aria-label": horizontal ? "Adjust sheet width" : "Adjust sheet height", | ||
| ...sliderAria, | ||
| ...props, | ||
| ref, | ||
| className: cn("scrollsheet-handle", className), | ||
| "data-scrollsheet-handle": true, | ||
| "data-scrollsheet-handle-variant": variantAttr, | ||
| onClick: (event) => { | ||
| onClick?.(event); | ||
| if (event.defaultPrevented) return; | ||
| if (!multi) return; | ||
| const index = specs.findIndex((s) => Object.is(s, ctx.activeDetent)); | ||
| const next = specs[(index + 1) % specs.length]; | ||
| if (next !== void 0) ctx.setActiveDetent(next); | ||
| }, | ||
| onKeyDown: (event) => { | ||
| onKeyDown?.(event); | ||
| if (event.defaultPrevented) return; | ||
| const expandKey = horizontal ? "ArrowRight" : "ArrowUp"; | ||
| const collapseKey = horizontal ? "ArrowLeft" : "ArrowDown"; | ||
| if (event.key === expandKey) { | ||
| event.preventDefault(); | ||
| move(1); | ||
| } else if (event.key === collapseKey) { | ||
| event.preventDefault(); | ||
| if (!move(-1) && ctx.dismissible) ctx.setOpen(false); | ||
| } else if (multi && event.key === "Home") { | ||
| event.preventDefault(); | ||
| const first = specs[0]; | ||
| if (first !== void 0) ctx.setActiveDetent(first); | ||
| } else if (multi && event.key === "End") { | ||
| event.preventDefault(); | ||
| const last = specs[specs.length - 1]; | ||
| if (last !== void 0) ctx.setActiveDetent(last); | ||
| } | ||
| } | ||
| }); | ||
| if (outside) return ctx.canvasEl ? createPortal(button, ctx.canvasEl) : null; | ||
| return button; | ||
| }); | ||
| //#endregion | ||
| //#region packages/scrollsheet/src/drawer/index.tsx | ||
| const wrapperClaims = new Map(); | ||
| const VAUL_CLOSE_THRESHOLD = .25; | ||
| const collectIgnored = (entries) => entries.filter(([, v]) => v !== void 0).map(([k]) => k); | ||
| function toDetentSpec(point) { | ||
| if (typeof point === "number") return point; | ||
| if (point === "fit-content" || point === "content") return "content"; | ||
| if (/^\d+(\.\d+)?px$/.test(point)) return `${Number.parseFloat(point)}px`; | ||
| const parsed = Number.parseFloat(point); | ||
| return Number.isFinite(parsed) ? parsed : "content"; | ||
| } | ||
| function resolveFadeFromIndex(snapPoints, fadeFromIndex) { | ||
| if (!snapPoints || snapPoints.length === 0) return void 0; | ||
| const point = snapPoints[fadeFromIndex ?? snapPoints.length - 1]; | ||
| return point !== void 0 ? toDetentSpec(point) : void 0; | ||
| } | ||
| function resolveCloseThreshold(snapPoints, closeThreshold) { | ||
| if (snapPoints !== void 0 && snapPoints.length > 0) return void 0; | ||
| return Math.min(1, Math.max(0, 1 - (closeThreshold ?? VAUL_CLOSE_THRESHOLD))); | ||
| } | ||
| function composeOpenChange(onOpenChange, onClose) { | ||
| if (!onOpenChange && !onClose) return void 0; | ||
| return (next) => { | ||
| if (!next) onClose?.(); | ||
| onOpenChange?.(next); | ||
| }; | ||
| } | ||
| function Root(props) { | ||
| const { children, open, defaultOpen, onOpenChange, onClose, dismissible, snapPoints, activeSnapPoint, setActiveSnapPoint, onAnimationEnd, autoFocus, nested, direction, modal, shouldScaleBackground, setBackgroundColorOnScale, noBodyStyles, disablePreventScroll, preventScrollRestoration, repositionInputs, scrollLockTimeout, closeThreshold, fadeFromIndex, snapToSequentialPoint, handleOnly, onDrag, onRelease, container, fixed, actionsRef, backdropDismissible, escapeDismissible, keyboardExpands, onTravel, scrollbar } = props; | ||
| { | ||
| const ignored = collectIgnored([ | ||
| ["setBackgroundColorOnScale", setBackgroundColorOnScale], | ||
| ["noBodyStyles", noBodyStyles], | ||
| ["disablePreventScroll", disablePreventScroll], | ||
| ["preventScrollRestoration", preventScrollRestoration], | ||
| ["repositionInputs", repositionInputs], | ||
| ["scrollLockTimeout", scrollLockTimeout], | ||
| ["onDrag", onDrag], | ||
| ["container", container], | ||
| ["fixed", fixed], | ||
| ["autoFocus", autoFocus], | ||
| ["nested", nested] | ||
| ]); | ||
| if (ignored.length > 0) warnOnce("root-ignored-props", `[scrollsheet Drawer] These <Drawer.Root> props from vaul have no effect in this compat layer and are ignored: ${ignored.join(", ")}. See the vaul migration notes in the README.${onDrag !== void 0 ? " onDrag: the native onTravel prop works on this same <Drawer.Root>." : ""}`); | ||
| } | ||
| const detents = snapPoints && snapPoints.length > 0 ? snapPoints.map(toDetentSpec) : void 0; | ||
| const activeDetent = activeSnapPoint != null ? toDetentSpec(activeSnapPoint) : void 0; | ||
| const largestUndimmedDetent = resolveFadeFromIndex(snapPoints, fadeFromIndex); | ||
| const resolvedCloseThreshold = resolveCloseThreshold(snapPoints, closeThreshold); | ||
| if (snapPoints !== void 0 && snapPoints.length > 0 && closeThreshold !== void 0) warnOnce("close-threshold-with-snap-points", "[scrollsheet Drawer] <Drawer.Root closeThreshold> has no effect when snapPoints is set — this matches real vaul, where closeThreshold is dead code once snapPoints exist (its onRelease returns through the snap-points branch before ever reading it). Use the native Sheet.Root `closeThreshold` (a live 0-1 fraction of the first detent, works alongside detents) if you want the upgrade."); | ||
| const handleRelease = onRelease ? (event, willRemainOpen) => onRelease(event, willRemainOpen) : void 0; | ||
| const handleOpenChange = composeOpenChange(onOpenChange, onClose); | ||
| const handleActiveDetentChange = (detent) => { | ||
| if (!setActiveSnapPoint) return; | ||
| const match = snapPoints?.find((point) => Object.is(toDetentSpec(point), detent)); | ||
| setActiveSnapPoint(match ?? detent); | ||
| }; | ||
| React.useEffect(() => { | ||
| if (!shouldScaleBackground) return; | ||
| const existing = document.querySelector("[data-scrollsheet-background]"); | ||
| if (existing && !wrapperClaims.has(existing)) return; | ||
| const wrapper = existing ?? document.querySelector("[data-vaul-drawer-wrapper]"); | ||
| if (!wrapper) return; | ||
| const count = wrapperClaims.get(wrapper) ?? 0; | ||
| wrapperClaims.set(wrapper, count + 1); | ||
| if (count === 0) wrapper.setAttribute("data-scrollsheet-background", ""); | ||
| return () => { | ||
| const remaining = (wrapperClaims.get(wrapper) ?? 1) - 1; | ||
| if (remaining <= 0) { | ||
| wrapperClaims.delete(wrapper); | ||
| wrapper.removeAttribute("data-scrollsheet-background"); | ||
| } else wrapperClaims.set(wrapper, remaining); | ||
| }; | ||
| }, [shouldScaleBackground]); | ||
| return jsx(DirectionContext.Provider, { | ||
| value: direction ?? "bottom", | ||
| children: jsx(Root$1, { | ||
| open, | ||
| defaultOpen, | ||
| onOpenChange: handleOpenChange, | ||
| onOpenChangeComplete: onAnimationEnd, | ||
| dismissible, | ||
| detents, | ||
| activeDetent, | ||
| onActiveDetentChange: setActiveSnapPoint ? handleActiveDetentChange : void 0, | ||
| side: direction, | ||
| modal, | ||
| backgroundEffect: shouldScaleBackground ? "scale" : "none", | ||
| largestUndimmedDetent, | ||
| handleOnly, | ||
| sequentialDetents: snapToSequentialPoint, | ||
| closeThreshold: resolvedCloseThreshold, | ||
| onRelease: handleRelease, | ||
| actionsRef, | ||
| backdropDismissible, | ||
| escapeDismissible, | ||
| keyboardExpands, | ||
| onTravel, | ||
| scrollbar, | ||
| children | ||
| }) | ||
| }); | ||
| } | ||
| const DirectionContext = React.createContext("bottom"); | ||
| const NestedRoot = Root; | ||
| function Portal({ children, container }) { | ||
| if (container !== void 0) warnOnce("portal-container", "[scrollsheet Drawer] <Drawer.Portal container> has no effect — scrollsheet's <dialog> always renders into the browser's top layer (effectively document.body), so there's no separate container to portal into."); | ||
| return jsx(Fragment, { children }); | ||
| } | ||
| function Overlay(_props) { | ||
| return null; | ||
| } | ||
| function hasMultipleSnapPoints(detents) { | ||
| return detents.length > 1; | ||
| } | ||
| const Content = React.forwardRef(function Content({ onPointerDownOutside, onOpenAutoFocus, onEscapeKeyDown, onCloseAutoFocus, onInteractOutside, onFocusOutside, forceMount, ...props }, ref) { | ||
| const ctx = useSheetContext("Content"); | ||
| const direction = React.useContext(DirectionContext); | ||
| const snapPointsActive = hasMultipleSnapPoints(ctx.detents); | ||
| { | ||
| const ignored = collectIgnored([ | ||
| ["onPointerDownOutside", onPointerDownOutside], | ||
| ["onOpenAutoFocus", onOpenAutoFocus], | ||
| ["onEscapeKeyDown", onEscapeKeyDown], | ||
| ["onCloseAutoFocus", onCloseAutoFocus], | ||
| ["onInteractOutside", onInteractOutside], | ||
| ["onFocusOutside", onFocusOutside], | ||
| ["forceMount", forceMount] | ||
| ]); | ||
| if (ignored.length > 0) warnOnce("content-ignored-props", `[scrollsheet Drawer] These <Drawer.Content> props from vaul have no effect in this compat layer and are stripped before reaching the DOM: ${ignored.join(", ")}. See the vaul migration notes in the README.${onPointerDownOutside !== void 0 || onInteractOutside !== void 0 || onEscapeKeyDown !== void 0 ? " To block backdrop-tap dismissal, set backdropDismissible={false} on <Drawer.Root>; to block Esc, escapeDismissible={false}." : ""}`); | ||
| } | ||
| return jsx(Content$1, { | ||
| ...props, | ||
| ref, | ||
| "data-vaul-drawer": "", | ||
| "data-vaul-drawer-direction": direction, | ||
| "data-vaul-snap-points": snapPointsActive ? "true" : "false" | ||
| }); | ||
| }); | ||
| function composeHandleClick(preventCycle, onClick) { | ||
| return (event) => { | ||
| onClick?.(event); | ||
| if (preventCycle) event.preventDefault(); | ||
| }; | ||
| } | ||
| const Handle = React.forwardRef(function Handle({ preventCycle, onClick, ...props }, ref) { | ||
| const ctx = useSheetContext("Handle"); | ||
| return jsx(Handle$1, { | ||
| ...props, | ||
| ref, | ||
| "data-vaul-handle": "", | ||
| "data-vaul-drawer-visible": ctx.open ? "true" : "false", | ||
| onClick: composeHandleClick(preventCycle, onClick) | ||
| }); | ||
| }); | ||
| const DrawerClose = React.forwardRef(function DrawerClose({ children, ...props }, ref) { | ||
| return jsx(Close, { | ||
| ...props, | ||
| ref, | ||
| children: children ?? null | ||
| }); | ||
| }); | ||
| const Drawer = { | ||
| Root, | ||
| NestedRoot, | ||
| Trigger, | ||
| Portal, | ||
| Overlay, | ||
| Content, | ||
| Close: DrawerClose, | ||
| Title, | ||
| Description, | ||
| Handle | ||
| }; | ||
| //#endregion | ||
| export { NestedRoot as a, Root as c, hasMultipleSnapPoints as d, resolveCloseThreshold as f, Handle as i, composeHandleClick as l, Handle$1 as m, Drawer as n, Overlay as o, resolveFadeFromIndex as p, DrawerClose as r, Portal as s, Content as t, composeOpenChange as u }; |
Sorry, the diff of this file is too big to display
| "use client"; | ||
| "use client"; | ||
| import { d as useSheetContext, i as Content$1, l as composeRefs, n as Description, r as Title, s as Trigger, t as Close, u as Root$1 } from "./misc-Bf6n3Ykh.mjs"; | ||
| import { d as useSheetContext, i as Content$1, l as composeRefs, n as Description, r as Title, s as Trigger, t as Close, u as Root$1 } from "./misc-B6wh-cJ4.mjs"; | ||
| import * as React from "react"; | ||
@@ -5,0 +5,0 @@ import { Fragment, jsx } from "react/jsx-runtime"; |
| "use client"; | ||
| "use client"; | ||
| import { n as Description, r as Title, s as Trigger } from "./misc-Bf6n3Ykh.mjs"; | ||
| import { a as NestedRoot, c as Root, d as hasMultipleSnapPoints, f as resolveCloseThreshold, i as Handle, l as composeHandleClick, n as Drawer, o as Overlay, p as resolveFadeFromIndex, r as DrawerClose, s as Portal, t as Content, u as composeOpenChange } from "./drawer-Daga_OBC.mjs"; | ||
| import { n as Description, r as Title, s as Trigger } from "./misc-B6wh-cJ4.mjs"; | ||
| import { a as NestedRoot, c as Root, d as hasMultipleSnapPoints, f as resolveCloseThreshold, i as Handle, l as composeHandleClick, n as Drawer, o as Overlay, p as resolveFadeFromIndex, r as DrawerClose, s as Portal, t as Content, u as composeOpenChange } from "./drawer-D2Y44hut.mjs"; | ||
| export { DrawerClose as Close, Content, Description, Drawer, Handle, NestedRoot, Overlay, Portal, Root, Title, Trigger, composeHandleClick, composeOpenChange, hasMultipleSnapPoints, resolveCloseThreshold, resolveFadeFromIndex }; |
| "use client"; | ||
| import { a as injectStylesInto, i as Content, n as Description, o as spring, r as Title, s as Trigger, t as Close, u as Root } from "./misc-Bf6n3Ykh.mjs"; | ||
| import { a as injectStylesInto, i as Content, n as Description, o as spring, r as Title, s as Trigger, t as Close, u as Root } from "./misc-B6wh-cJ4.mjs"; | ||
| import { o as hasDialogSupport } from "./cn-DgpbGWy-.mjs"; | ||
| import { m as Handle, n as Drawer } from "./drawer-Daga_OBC.mjs"; | ||
| import { m as Handle, n as Drawer } from "./drawer-D2Y44hut.mjs"; | ||
| import { Dialog } from "./dialog.mjs"; | ||
@@ -6,0 +6,0 @@ import { a as useSonner, i as toast, o as useToasts, r as injectToastStylesInto, t as ToasterShell } from "./toast-BEuD1_sZ.mjs"; |
| "use client"; | ||
| "use client"; | ||
| import { d as useSheetContext, i as Content$1, l as composeRefs, n as Description, r as Title, s as Trigger, t as Close, u as Root$1 } from "./misc-VkdphfSa.mjs"; | ||
| import { d as useSheetContext, i as Content$1, l as composeRefs, n as Description, r as Title, s as Trigger, t as Close, u as Root$1 } from "./misc-DiVXSPuI.mjs"; | ||
| import { h as warnOnce } from "./cn-Cs7ZylHz.mjs"; | ||
@@ -5,0 +5,0 @@ import * as React from "react"; |
| "use client"; | ||
| "use client"; | ||
| import { n as Description, r as Title, s as Trigger } from "./misc-VkdphfSa.mjs"; | ||
| import { a as NestedRoot, c as Root, d as hasMultipleSnapPoints, f as resolveCloseThreshold, i as Handle, l as composeHandleClick, n as Drawer, o as Overlay, p as resolveFadeFromIndex, r as DrawerClose, s as Portal, t as Content, u as composeOpenChange } from "./drawer-DqGJtMsN.mjs"; | ||
| import { n as Description, r as Title, s as Trigger } from "./misc-DiVXSPuI.mjs"; | ||
| import { a as NestedRoot, c as Root, d as hasMultipleSnapPoints, f as resolveCloseThreshold, i as Handle, l as composeHandleClick, n as Drawer, o as Overlay, p as resolveFadeFromIndex, r as DrawerClose, s as Portal, t as Content, u as composeOpenChange } from "./drawer-V3SkmxkW.mjs"; | ||
| export { DrawerClose as Close, Content, Description, Drawer, Handle, NestedRoot, Overlay, Portal, Root, Title, Trigger, composeHandleClick, composeOpenChange, hasMultipleSnapPoints, resolveCloseThreshold, resolveFadeFromIndex }; |
| "use client"; | ||
| import { a as injectStylesInto, i as Content, n as Description, o as spring, r as Title, s as Trigger, t as Close, u as Root } from "./misc-VkdphfSa.mjs"; | ||
| import { a as injectStylesInto, i as Content, n as Description, o as spring, r as Title, s as Trigger, t as Close, u as Root } from "./misc-DiVXSPuI.mjs"; | ||
| import { o as hasDialogSupport } from "./cn-Cs7ZylHz.mjs"; | ||
| import { m as Handle, n as Drawer } from "./drawer-DqGJtMsN.mjs"; | ||
| import { m as Handle, n as Drawer } from "./drawer-V3SkmxkW.mjs"; | ||
| import { Dialog } from "./dialog.mjs"; | ||
@@ -6,0 +6,0 @@ import { a as useSonner, i as toast, o as useToasts, r as injectToastStylesInto, t as ToasterShell } from "./toast-o4mAr-oF.mjs"; |
+1
-1
@@ -1,1 +0,1 @@ | ||
| .scrollsheet-dialog[data-scrollsheet-side=bottom]{--scrollsheet-keyboard-lift:var(--scrollsheet-keyboard,0px)}.scrollsheet-dialog{width:100%;height:calc(100% + var(--scrollsheet-keyboard-lift,0px));--scrollsheet-ease:linear(0, 0.042 3.4%, 0.136 6.9%, 0.37 13.8%, 0.481 17.2%, 0.58 20.7%, 0.664 24.1%, 0.735 27.6%, 0.793 31%, 0.839 34.5%, 0.876 37.9%, 0.906 41.4%, 0.928 44.8%, 0.946 48.3%, 0.96 51.7%, 0.978 58.6%, 0.988 65.5%, 0.994 72.4%, 0.998 82.8%, 1);--scrollsheet-dur:475ms;background:0 0;border:none;outline:none;max-width:none;max-height:none;margin:0;padding:0;position:fixed;inset:0;overflow:clip}.scrollsheet-dialog::backdrop{background:0 0}:where(.scrollsheet-backdrop){background:var(--scrollsheet-backdrop,#00000052);opacity:0;pointer-events:none;position:fixed;inset:0}.scrollsheet-dialog[data-scrollsheet-state=opening] .scrollsheet-backdrop{opacity:min(var(--scrollsheet-dim,0), 1);transition:opacity var(--scrollsheet-dur) var(--scrollsheet-ease)}.scrollsheet-dialog[data-scrollsheet-state=open] .scrollsheet-backdrop{opacity:min(var(--scrollsheet-dim,0), 1);transition:none}.scrollsheet-dialog[data-scrollsheet-state=closing] .scrollsheet-backdrop{opacity:0;transition:opacity var(--scrollsheet-dur) var(--scrollsheet-ease)}:where(.scrollsheet-top-chrome){height:calc(env(safe-area-inset-top,0px) + 8px);inset:0 0 auto}:where(.scrollsheet-bottom-chrome){height:calc(env(safe-area-inset-bottom,0px) + 32px);inset:auto 0 0}:where(.scrollsheet-top-chrome)~:where([data-scrollsheet-backdrop]){top:calc(env(safe-area-inset-top,0px) + 8px)}:where(.scrollsheet-bottom-chrome)~:where([data-scrollsheet-backdrop]){bottom:calc(env(safe-area-inset-bottom,0px) + 32px)}.scrollsheet-dialog:is([data-scrollsheet-state=pre],[data-scrollsheet-state=opening]) :is(.scrollsheet-top-chrome,.scrollsheet-bottom-chrome){opacity:min(var(--scrollsheet-dim,0), 1);transition:none}.scrollsheet-bottom-sentinel{height:min(calc(max(env(safe-area-inset-bottom,0px), 24px) + 45vh), var(--scrollsheet-reveal,24px));pointer-events:none;position:fixed;inset:auto 0 0}.scrollsheet-track{left:0;right:0;top:var(--scrollsheet-vv-top,0px);height:calc(var(--scrollsheet-vv-height,100%) + var(--scrollsheet-keyboard-lift,0px));overscroll-behavior:contain;scroll-snap-type:y mandatory;scrollbar-width:none;position:fixed;overflow-y:scroll}.scrollsheet-track::-webkit-scrollbar{display:none}.scrollsheet-dialog:is([data-scrollsheet-side=left],[data-scrollsheet-side=right]) .scrollsheet-track{scroll-snap-type:x mandatory;overscroll-behavior-x:none;overflow:scroll hidden}.scrollsheet-dialog[data-scrollsheet-modal=false]{pointer-events:none}.scrollsheet-dialog[data-scrollsheet-modal=false] .scrollsheet-panel{pointer-events:auto;touch-action:none}.scrollsheet-canvas{height:calc(100% + var(--scrollsheet-max-detent,0px));position:relative}.scrollsheet-dialog:is([data-scrollsheet-side=left],[data-scrollsheet-side=right]) .scrollsheet-canvas{width:calc(100% + var(--scrollsheet-max-detent,0px));height:100%}.scrollsheet-canvas:after{content:"";top:calc(100% - var(--scrollsheet-keyboard,0px));--scrollsheet-od:calc(120vh + var(--scrollsheet-keyboard,0px));height:0;box-shadow:0 calc(var(--scrollsheet-od) / 2) 0 calc(var(--scrollsheet-od) / 2) var(--scrollsheet-panel-bg,transparent);pointer-events:none;position:absolute;left:0;right:0}.scrollsheet-dialog[data-scrollsheet-side=top] .scrollsheet-canvas:after{box-shadow:0 -60vh 0 60vh var(--scrollsheet-panel-bg,transparent);top:auto;bottom:100%}.scrollsheet-dialog[data-scrollsheet-side=left] .scrollsheet-canvas:after{width:0;height:auto;box-shadow:-60vw 0 0 60vw var(--scrollsheet-panel-bg,transparent);inset:0 100% 0 auto}.scrollsheet-dialog[data-scrollsheet-side=right] .scrollsheet-canvas:after{width:0;height:auto;box-shadow:60vw 0 0 60vw var(--scrollsheet-panel-bg,transparent);inset:0 auto 0 100%}.scrollsheet-dialog[data-scrollsheet-detached] .scrollsheet-canvas:after{box-shadow:none}.scrollsheet-snap{pointer-events:none;scroll-snap-align:start;width:100%;height:1px;position:absolute;left:0}.scrollsheet-dialog:is([data-scrollsheet-side=left],[data-scrollsheet-side=right]) .scrollsheet-snap{width:1px;height:100%;top:0;left:auto}.scrollsheet-panel{--scrollsheet-eg:calc(var(--scrollsheet-inset-bottom,0px) + var(--scrollsheet-keyboard,0px));bottom:var(--scrollsheet-eg);left:var(--scrollsheet-inset-x,0px);right:var(--scrollsheet-inset-x,0px);height:var(--scrollsheet-max-detent,auto);max-height:var(--scrollsheet-vv-height,none);will-change:transform;padding-bottom:max(var(--scrollsheet-safe-area,env(safe-area-inset-bottom,0px)), 0px);position:absolute;overflow:hidden;transform:translateY(100%)}.scrollsheet-dialog[data-scrollsheet-side=top] .scrollsheet-panel{bottom:auto;top:var(--scrollsheet-inset-top,0px);left:var(--scrollsheet-inset-x,0px);right:var(--scrollsheet-inset-x,0px);height:var(--scrollsheet-max-detent,auto);padding-bottom:0;padding-top:max(var(--scrollsheet-safe-area-top,env(safe-area-inset-top,0px)), 0px);transform:translateY(-100%)}.scrollsheet-dialog:is([data-scrollsheet-side=left],[data-scrollsheet-side=right]) .scrollsheet-panel{top:var(--scrollsheet-inset-y,0px);bottom:var(--scrollsheet-inset-y,0px);width:var(--scrollsheet-max-detent,auto);height:auto;padding-top:max(var(--scrollsheet-safe-area-top,env(safe-area-inset-top,0px)), 0px)}.scrollsheet-dialog[data-scrollsheet-side=left] .scrollsheet-panel{right:auto;left:var(--scrollsheet-inset-left,0px);padding-left:max(var(--scrollsheet-safe-area-left,env(safe-area-inset-left,0px)), 0px);transform:translate(-100%)}.scrollsheet-dialog[data-scrollsheet-side=right] .scrollsheet-panel{left:auto;right:var(--scrollsheet-inset-right,0px);padding-right:max(var(--scrollsheet-safe-area-right,env(safe-area-inset-right,0px)), 0px);transform:translate(100%)}.scrollsheet-dialog:is([data-scrollsheet-side=top],[data-scrollsheet-side=left]) .scrollsheet-panel{justify-content:flex-end;display:flex}.scrollsheet-dialog[data-scrollsheet-side=top] .scrollsheet-panel{flex-direction:column}.scrollsheet-dialog[data-scrollsheet-side=left] .scrollsheet-panel{flex-direction:row}.scrollsheet-dialog[data-scrollsheet-side=left] .scrollsheet-panel>*{flex:0 0 100%;min-width:0}:where(.scrollsheet-panel){scrollbar-width:none}:where(.scrollsheet-panel)::-webkit-scrollbar{display:none}:where([data-scrollsheet-nested-scroll]){scrollbar-width:none}:where([data-scrollsheet-nested-scroll])::-webkit-scrollbar{display:none}:where(.scrollsheet-dialog[data-scrollsheet-scrollbar=overlay] [data-scrollsheet-nested-scroll]){position:relative}:where(.scrollsheet-panel){--scrollsheet-radius:20px;background:var(--scrollsheet-bg,#fff);color:var(--scrollsheet-fg,#1d1d1f);border-radius:var(--scrollsheet-radius) var(--scrollsheet-radius) 0 0;box-shadow:var(--scrollsheet-shadow,0 -8px 32px #00000029)}@media (prefers-color-scheme:dark){:where(.scrollsheet-panel){background:var(--scrollsheet-bg,#1c1c1e);color:var(--scrollsheet-fg,#f5f5f7)}}.scrollsheet-dialog[data-scrollsheet-side=top] :where(.scrollsheet-panel){border-radius:0 0 var(--scrollsheet-radius) var(--scrollsheet-radius);box-shadow:var(--scrollsheet-shadow,0 8px 32px #00000029)}.scrollsheet-dialog[data-scrollsheet-side=left] :where(.scrollsheet-panel){box-shadow:var(--scrollsheet-shadow,8px 0 32px #00000029);border-radius:0}.scrollsheet-dialog[data-scrollsheet-side=right] :where(.scrollsheet-panel){box-shadow:var(--scrollsheet-shadow,-8px 0 32px #00000029);border-radius:0}@media (min-width:768px){:where(.scrollsheet-dialog[data-scrollsheet-side=bottom]) :where(.scrollsheet-panel),:where(.scrollsheet-dialog[data-scrollsheet-side=bottom]) .scrollsheet-canvas:after{width:min(var(--scrollsheet-max-inline,640px), calc(100% - 2 * var(--scrollsheet-desktop-margin,24px)));margin-inline:auto var(--scrollsheet-desktop-margin,24px)}.scrollsheet-dialog[data-scrollsheet-side=bottom] .scrollsheet-panel{--scrollsheet-inset-bottom:var(--scrollsheet-desktop-margin,24px);--scrollsheet-dg:calc(var(--scrollsheet-desktop-margin,24px) + var(--scrollsheet-inset-x,0px) + 32px)}.scrollsheet-dialog[data-scrollsheet-side=bottom]:where([data-scrollsheet-detached]) .scrollsheet-panel,.scrollsheet-dialog[data-scrollsheet-side=bottom][data-scrollsheet-state=closing]:where([data-scrollsheet-detached]) .scrollsheet-panel{transform:translate3d(calc(100% + var(--scrollsheet-dg,32px)), 0, 0)}.scrollsheet-dialog[data-scrollsheet-side=bottom]:where([data-scrollsheet-detached][data-scrollsheet-rtl]) .scrollsheet-panel,.scrollsheet-dialog[data-scrollsheet-side=bottom][data-scrollsheet-state=closing]:where([data-scrollsheet-detached][data-scrollsheet-rtl]) .scrollsheet-panel{transform:translate3d(calc(-100% - var(--scrollsheet-dg,32px)), 0, 0)}.scrollsheet-dialog[data-scrollsheet-side=top] .scrollsheet-panel{top:var(--scrollsheet-desktop-margin,24px);border-radius:var(--scrollsheet-radius)}.scrollsheet-dialog[data-scrollsheet-side=bottom] :where(.scrollsheet-handle){opacity:0;pointer-events:none;width:5px;height:44px;margin:-22px 0 0;position:absolute;top:50%;left:10px}.scrollsheet-dialog[data-scrollsheet-side=bottom] :where(.scrollsheet-handle:focus-visible){opacity:1;pointer-events:auto}.scrollsheet-dialog[data-scrollsheet-side=bottom][data-scrollsheet-has-handle] :where(.scrollsheet-body){padding-top:18px}:where(.scrollsheet-dialog[data-scrollsheet-side=top]) :where(.scrollsheet-panel),:where(.scrollsheet-dialog[data-scrollsheet-side=top]) .scrollsheet-canvas:after{max-width:var(--scrollsheet-max-inline,640px);margin-inline:auto}}.scrollsheet-dialog[data-scrollsheet-detached] :where(.scrollsheet-panel){padding-bottom:max(var(--scrollsheet-safe-area,0px), 0px);border-radius:var(--scrollsheet-radius)}.scrollsheet-dialog[data-scrollsheet-detached][data-scrollsheet-side=bottom] :where(.scrollsheet-panel){--scrollsheet-eg:calc(max(var(--scrollsheet-inset-bottom,0px), env(safe-area-inset-bottom,0px)) + var(--scrollsheet-keyboard,0px));bottom:var(--scrollsheet-eg)}.scrollsheet-dialog[data-scrollsheet-scrollbar=native] .scrollsheet-panel{scrollbar-width:auto}.scrollsheet-dialog[data-scrollsheet-scrollbar=native] .scrollsheet-panel::-webkit-scrollbar{display:block}.scrollsheet-dialog[data-scrollsheet-scrollbar=native] [data-scrollsheet-nested-scroll]{scrollbar-width:auto}.scrollsheet-dialog[data-scrollsheet-scrollbar=native] [data-scrollsheet-nested-scroll]::-webkit-scrollbar{display:block}.scrollsheet-dialog[data-scrollsheet-state=opening] .scrollsheet-panel,.scrollsheet-dialog[data-scrollsheet-state=open] .scrollsheet-panel{transform:translate(0,0)}.scrollsheet-dialog[data-scrollsheet-state=closing] .scrollsheet-panel{transform:translate3d(0, calc(100% + var(--scrollsheet-eg,0px) + 32px), 0)}.scrollsheet-dialog[data-scrollsheet-side=top][data-scrollsheet-state=closing] .scrollsheet-panel{transform:translate3d(0, calc(-100% - var(--scrollsheet-inset-top,0px) - 32px), 0)}.scrollsheet-dialog[data-scrollsheet-side=left][data-scrollsheet-state=closing] .scrollsheet-panel{transform:translate3d(calc(-100% - var(--scrollsheet-inset-left,0px) - 32px), 0, 0)}.scrollsheet-dialog[data-scrollsheet-side=right][data-scrollsheet-state=closing] .scrollsheet-panel{transform:translate3d(calc(100% + var(--scrollsheet-inset-right,0px) + 32px), 0, 0)}.scrollsheet-dialog:is([data-scrollsheet-at-max],[data-scrollsheet-kb]) .scrollsheet-panel{overflow-y:auto}.scrollsheet-dialog[data-scrollsheet-kb][data-scrollsheet-side=bottom] .scrollsheet-panel{--scrollsheet-eg:calc(var(--scrollsheet-inset-bottom,0px) + var(--scrollsheet-keyboard,0px) + var(--scrollsheet-kb-hang,0px));box-shadow:none;border-bottom-right-radius:0;border-bottom-left-radius:0}.scrollsheet-kb-fade{display:none}.scrollsheet-dialog[data-scrollsheet-kb][data-scrollsheet-side=bottom] .scrollsheet-kb-fade{left:var(--scrollsheet-inset-x,0px);right:var(--scrollsheet-inset-x,0px);bottom:calc(var(--scrollsheet-keyboard,0px) + var(--scrollsheet-kb-hang,0px));background:linear-gradient(to bottom, transparent, var(--scrollsheet-panel-bg,#fff) 75%);pointer-events:none;z-index:1;height:18px;display:block;position:absolute}.scrollsheet-dialog:is([data-scrollsheet-handle-only],[data-scrollsheet-disable-drag]):not([data-scrollsheet-at-max],[data-scrollsheet-at-nested-boundary],[data-scrollsheet-kb]) :is(.scrollsheet-track,.scrollsheet-canvas){touch-action:none}.scrollsheet-dialog[data-scrollsheet-handle-only] .scrollsheet-panel,.scrollsheet-dialog[data-scrollsheet-disable-drag] .scrollsheet-panel{touch-action:pan-y}.scrollsheet-dialog[data-scrollsheet-handle-only]:not([data-scrollsheet-at-nested-boundary]) .scrollsheet-panel,.scrollsheet-dialog[data-scrollsheet-disable-drag]:not([data-scrollsheet-at-nested-boundary]) .scrollsheet-panel{overscroll-behavior:contain}.scrollsheet-dialog[data-scrollsheet-at-nested-boundary] .scrollsheet-track,.scrollsheet-dialog[data-scrollsheet-at-nested-boundary] .scrollsheet-canvas{touch-action:pan-y}.scrollsheet-dialog[data-scrollsheet-side=left][data-scrollsheet-at-nested-boundary] .scrollsheet-track,.scrollsheet-dialog[data-scrollsheet-side=left][data-scrollsheet-at-nested-boundary] .scrollsheet-canvas,.scrollsheet-dialog[data-scrollsheet-side=right][data-scrollsheet-at-nested-boundary] .scrollsheet-track,.scrollsheet-dialog[data-scrollsheet-side=right][data-scrollsheet-at-nested-boundary] .scrollsheet-canvas{touch-action:pan-x}:where(.scrollsheet-scrollbar){top:0;width:var(--scrollsheet-scrollbar-width,4px);box-sizing:border-box;background:var(--scrollsheet-scrollbar-color,#00000052);opacity:0;pointer-events:none;z-index:2;background-clip:padding-box;border:1px solid #ffffff38;border-radius:999px;transition:opacity .4s;position:absolute;inset-inline-end:3px}.scrollsheet-scrollbar[data-visible]{opacity:1;transition:opacity .12s}@media (prefers-reduced-motion:reduce){:where(.scrollsheet-scrollbar){transition:none}}.scrollsheet-panel:before{content:"";z-index:1;pointer-events:none;opacity:var(--scrollsheet-recede-dim,0);background:#000;position:absolute;inset:0}.scrollsheet-dialog[data-scrollsheet-behind] .scrollsheet-panel{--scrollsheet-recede-dim:.14;--scrollsheet-stack-progress:1;transform-origin:50% 0;transition:transform var(--scrollsheet-dur) var(--scrollsheet-ease);transform:translateY(8px)scale(.94)}.scrollsheet-dialog[data-scrollsheet-behind] .scrollsheet-panel:before{transition:opacity var(--scrollsheet-dur) var(--scrollsheet-ease)}.scrollsheet-dialog[data-scrollsheet-side=top][data-scrollsheet-behind] .scrollsheet-panel{transform-origin:50% 100%;transform:translateY(-8px)scale(.94)}.scrollsheet-dialog[data-scrollsheet-side=left][data-scrollsheet-behind] .scrollsheet-panel{transform-origin:100%;transform:translate(-8px)scale(.94)}.scrollsheet-dialog[data-scrollsheet-side=right][data-scrollsheet-behind] .scrollsheet-panel{transform-origin:0%;transform:translate(8px)scale(.94)}.scrollsheet-track,.scrollsheet-canvas,.scrollsheet-panel,.scrollsheet-dialog:focus-visible,.scrollsheet-track:focus-visible,.scrollsheet-canvas:focus-visible,.scrollsheet-panel:focus-visible{outline:none}[data-scrollsheet-dragging]{-webkit-user-select:none;user-select:none}[data-scrollsheet-dragging] .scrollsheet-panel{cursor:grabbing}.scrollsheet-dialog:is([data-scrollsheet-side=top],[data-scrollsheet-side=left],[data-scrollsheet-side=right]) .scrollsheet-panel{scroll-padding-bottom:var(--scrollsheet-keyboard,0px)}.scrollsheet-dialog:is([data-scrollsheet-side=top],[data-scrollsheet-side=left],[data-scrollsheet-side=right]) [data-scrollsheet-body]{padding-bottom:var(--scrollsheet-keyboard,0px)}:where([data-scrollsheet-body]){display:flow-root}.scrollsheet-panel[data-scrollsheet-fill]{flex-direction:column;display:flex}[data-scrollsheet-body][data-scrollsheet-fill]{flex-direction:column;flex:1;min-height:0;display:flex}@media (prefers-reduced-motion:reduce){.scrollsheet-dialog .scrollsheet-panel,.scrollsheet-dialog .scrollsheet-backdrop{transition:none!important}}@supports (animation-timeline:scroll()){@property --scrollsheet-progress{syntax:"<number>";inherits:true;initial-value:0}.scrollsheet-dialog[data-scrollsheet-sda]{timeline-scope:--scrollsheet-track}.scrollsheet-dialog[data-scrollsheet-sda] .scrollsheet-track{scroll-timeline:--scrollsheet-track y}.scrollsheet-dialog[data-scrollsheet-sda]:is([data-scrollsheet-side=left],[data-scrollsheet-side=right]) .scrollsheet-track{scroll-timeline:--scrollsheet-track x}.scrollsheet-dialog[data-scrollsheet-sda][data-scrollsheet-state=open] .scrollsheet-backdrop{animation:linear both scrollsheet-fade,linear both scrollsheet-progress-var;animation-timeline:--scrollsheet-track,--scrollsheet-track;animation-range:var(--scrollsheet-fade-start,0px) var(--scrollsheet-fade-end,100%), 0px var(--scrollsheet-first-detent,100%)}.scrollsheet-dialog[data-scrollsheet-sda][data-scrollsheet-state=open]:is([data-scrollsheet-side=top],[data-scrollsheet-side=left]) .scrollsheet-backdrop{animation-direction:reverse,reverse;animation-range:calc(var(--scrollsheet-max-detent,0px) - var(--scrollsheet-fade-end,0px)) calc(var(--scrollsheet-max-detent,0px) - var(--scrollsheet-fade-start,0px)), calc(var(--scrollsheet-max-detent,0px) - var(--scrollsheet-first-detent,0px)) var(--scrollsheet-max-detent,0px)}@keyframes scrollsheet-fade{0%{opacity:0}to{opacity:1}}@keyframes scrollsheet-progress-var{0%{--scrollsheet-progress:0}to{--scrollsheet-progress:1}}}.scrollsheet-fallback{z-index:2147483647;display:flex;position:fixed;inset:0}.scrollsheet-fallback[data-scrollsheet-modal=false]{pointer-events:none}.scrollsheet-fallback[data-scrollsheet-modal=false] .scrollsheet-fallback-panel{pointer-events:auto}.scrollsheet-fallback-backdrop{background:var(--scrollsheet-backdrop,#00000052);position:fixed;inset:0}:where(.scrollsheet-fallback-panel){--scrollsheet-radius:20px;background:var(--scrollsheet-bg,#fff);color:var(--scrollsheet-fg,#1d1d1f);box-shadow:var(--scrollsheet-shadow,0 -8px 32px #00000029);overscroll-behavior:contain;-webkit-overflow-scrolling:touch;outline:none;position:relative;overflow-y:auto}@media (prefers-color-scheme:dark){:where(.scrollsheet-fallback-panel){background:var(--scrollsheet-bg,#1c1c1e);color:var(--scrollsheet-fg,#f5f5f7)}}.scrollsheet-fallback[data-scrollsheet-side=bottom]{align-items:flex-end}.scrollsheet-fallback[data-scrollsheet-side=bottom] :where(.scrollsheet-fallback-panel){border-radius:var(--scrollsheet-radius) var(--scrollsheet-radius) 0 0;width:100%;max-height:85%;padding-bottom:max(var(--scrollsheet-safe-area,env(safe-area-inset-bottom,0px)), 0px)}.scrollsheet-fallback[data-scrollsheet-side=top]{align-items:flex-start}.scrollsheet-fallback[data-scrollsheet-side=top] :where(.scrollsheet-fallback-panel){border-radius:0 0 var(--scrollsheet-radius) var(--scrollsheet-radius);width:100%;max-height:85%;box-shadow:var(--scrollsheet-shadow,0 8px 32px #00000029);padding-top:max(var(--scrollsheet-safe-area-top,env(safe-area-inset-top,0px)), 0px)}.scrollsheet-fallback[data-scrollsheet-side=center]{justify-content:center;align-items:center}.scrollsheet-fallback[data-scrollsheet-side=center] :where(.scrollsheet-fallback-panel){max-inline-size:var(--scrollsheet-center-max-inline,min(560px, calc(100% - 40px)));border-radius:var(--scrollsheet-radius);max-height:85%;box-shadow:var(--scrollsheet-shadow,0 8px 32px #00000029)}.scrollsheet-fallback[data-scrollsheet-side=left]{justify-content:flex-start}.scrollsheet-fallback[data-scrollsheet-side=right]{justify-content:flex-end}.scrollsheet-fallback:is([data-scrollsheet-side=left],[data-scrollsheet-side=right]) :where(.scrollsheet-fallback-panel){max-width:85%;height:100%;padding-top:max(var(--scrollsheet-safe-area-top,env(safe-area-inset-top,0px)), 0px);padding-bottom:max(var(--scrollsheet-safe-area,env(safe-area-inset-bottom,0px)), 0px);border-radius:0}.scrollsheet-fallback[data-scrollsheet-side=left] :where(.scrollsheet-fallback-panel){box-shadow:var(--scrollsheet-shadow,8px 0 32px #00000029)}.scrollsheet-fallback[data-scrollsheet-side=right] :where(.scrollsheet-fallback-panel){box-shadow:var(--scrollsheet-shadow,-8px 0 32px #00000029)}@media (min-width:768px){.scrollsheet-fallback[data-scrollsheet-side=bottom] :where(.scrollsheet-fallback-panel),.scrollsheet-fallback[data-scrollsheet-side=top] :where(.scrollsheet-fallback-panel){max-width:var(--scrollsheet-max-inline,640px);margin-inline:auto}}.scrollsheet-fallback [data-scrollsheet-handle]{display:none}@media (forced-colors:active){:where(.scrollsheet-backdrop),:where(.scrollsheet-fallback-backdrop){forced-color-adjust:none}:where(.scrollsheet-panel),:where(.scrollsheet-fallback-panel){color:canvastext;box-shadow:none;background:canvas;border:1px solid buttonborder}.scrollsheet-dialog:is([data-scrollsheet-side=top],[data-scrollsheet-side=left],[data-scrollsheet-side=right]) :where(.scrollsheet-panel),.scrollsheet-fallback:is([data-scrollsheet-side=top],[data-scrollsheet-side=left],[data-scrollsheet-side=right]) :where(.scrollsheet-fallback-panel){box-shadow:none}:where(.scrollsheet-scrollbar){background:highlight}}.scrollsheet-dialog[data-scrollsheet-side=center] .scrollsheet-track{scroll-snap-type:none;box-sizing:border-box;padding:var(--scrollsheet-center-gutter,20px);padding-bottom:calc(var(--scrollsheet-center-gutter,20px) + var(--scrollsheet-keyboard,0px));place-items:center;display:grid;overflow:hidden}.scrollsheet-dialog[data-scrollsheet-side=center] .scrollsheet-canvas{display:contents}.scrollsheet-dialog[data-scrollsheet-side=center] .scrollsheet-canvas:after{content:none}.scrollsheet-dialog[data-scrollsheet-side=center] .scrollsheet-panel{width:auto;height:auto;max-inline-size:var(--scrollsheet-center-max-inline,min(560px, 100%));max-block-size:var(--scrollsheet-center-max-block,100%);border-radius:var(--scrollsheet-radius,16px);padding-bottom:0;position:static;inset:auto;overflow:auto}.scrollsheet-dialog[data-scrollsheet-side=center] .scrollsheet-handle{display:none}.scrollsheet-dialog[data-scrollsheet-side=center]:is([data-scrollsheet-state=pre],[data-scrollsheet-state=closing]) .scrollsheet-panel{opacity:0;transform:scale(.95)}.scrollsheet-handle:before{content:"";width:max(100%,44px);height:44px;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)}:where(.scrollsheet-handle){background:var(--scrollsheet-handle,#0003);cursor:grab;width:44px;height:5px;box-shadow:0 0 0 2px transparent, 0 0 0 calc(2px + var(--scrollsheet-focus-ring-width,2px)) transparent;transition:transform .18s var(--scrollsheet-ease), background .18s ease, box-shadow .15s ease;border:none;border-radius:999px;outline:none;margin:8px auto;padding:0;display:block;position:relative}:where(.scrollsheet-handle:hover){background:var(--scrollsheet-handle-hover,#00000052)}:where(.scrollsheet-handle:active){cursor:grabbing;transform:scaleX(1.3)}@media (prefers-color-scheme:dark){:where(.scrollsheet-handle){background:var(--scrollsheet-handle,#ffffff52)}:where(.scrollsheet-handle:hover){background:var(--scrollsheet-handle-hover,#ffffff75)}}:where(.scrollsheet-handle[data-scrollsheet-handle-variant=floating]){z-index:1;margin:0;position:absolute;top:8px;left:50%;translate:-50%}:where(.scrollsheet-canvas>.scrollsheet-handle[data-scrollsheet-handle-variant=outside]){left:50%;bottom:calc(var(--scrollsheet-ib,0px) + var(--scrollsheet-keyboard,0px) + var(--scrollsheet-kb-hang,0px) + var(--scrollsheet-max-detent,0px) + 10px);background:var(--scrollsheet-handle,#fffc);margin:0;position:absolute;translate:-50%}.scrollsheet-dialog:not([data-scrollsheet-state=open]) .scrollsheet-canvas>.scrollsheet-handle[data-scrollsheet-handle-variant=outside]{opacity:0;transition:opacity .12s}.scrollsheet-dialog[data-scrollsheet-modal=false] .scrollsheet-handle[data-scrollsheet-handle-variant=outside]{pointer-events:auto;touch-action:none}:where(.scrollsheet-close){top:12px;z-index:1;background:var(--scrollsheet-close-bg,#0000000f);width:28px;height:28px;color:var(--scrollsheet-close-color,#0000008c);cursor:pointer;box-shadow:0 0 0 2px transparent, 0 0 0 calc(2px + var(--scrollsheet-focus-ring-width,2px)) transparent;border:none;border-radius:999px;outline:none;place-items:center;padding:0;transition:background .15s,color .15s,box-shadow .15s;display:grid;position:absolute;inset-inline-end:12px}.scrollsheet-close:before{content:"";width:44px;height:44px;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)}:where(.scrollsheet-close:hover){background:var(--scrollsheet-close-bg-hover,#0000001a);color:var(--scrollsheet-close-color-hover,#000000bf)}@media (prefers-color-scheme:dark){:where(.scrollsheet-close){background:var(--scrollsheet-close-bg,#ffffff17);color:var(--scrollsheet-close-color,#ffffff9e)}:where(.scrollsheet-close:hover){background:var(--scrollsheet-close-bg-hover,#ffffff24);color:var(--scrollsheet-close-color-hover,#ffffffd9)}}:where(.scrollsheet-close:focus-visible),:where(.scrollsheet-handle:focus-visible){box-shadow:0 0 0 2px transparent, 0 0 0 calc(2px + var(--scrollsheet-focus-ring-width,2px)) var(--scrollsheet-focus-ring,#6366f199);outline:none}.scrollsheet-dialog[data-scrollsheet-side=left] .scrollsheet-handle:before,.scrollsheet-dialog[data-scrollsheet-side=right] .scrollsheet-handle:before{width:44px;height:max(100%,44px)}.scrollsheet-dialog[data-scrollsheet-side=left] :where(.scrollsheet-handle),.scrollsheet-dialog[data-scrollsheet-side=right] :where(.scrollsheet-handle){width:5px;height:44px;margin:auto 8px}.scrollsheet-dialog[data-scrollsheet-side=left] :where(.scrollsheet-handle:active),.scrollsheet-dialog[data-scrollsheet-side=right] :where(.scrollsheet-handle:active){transform:scaleY(1.3)}@media (forced-colors:active){:where(.scrollsheet-handle){box-shadow:none;background:buttonborder}:where(.scrollsheet-handle:focus-visible){box-shadow:none;outline:2px solid highlight}:where(.scrollsheet-close){color:buttontext;box-shadow:none;background:canvas;border:1px solid buttonborder}:where(.scrollsheet-close:focus-visible){box-shadow:none;outline:2px solid highlight}} | ||
| .scrollsheet-dialog[data-scrollsheet-side=bottom]{--scrollsheet-keyboard-lift:var(--scrollsheet-keyboard,0px)}.scrollsheet-dialog{width:100%;height:calc(100% + var(--scrollsheet-keyboard-lift,0px));--scrollsheet-ease:linear(0, 0.042 3.4%, 0.136 6.9%, 0.37 13.8%, 0.481 17.2%, 0.58 20.7%, 0.664 24.1%, 0.735 27.6%, 0.793 31%, 0.839 34.5%, 0.876 37.9%, 0.906 41.4%, 0.928 44.8%, 0.946 48.3%, 0.96 51.7%, 0.978 58.6%, 0.988 65.5%, 0.994 72.4%, 0.998 82.8%, 1);--scrollsheet-dur:475ms;background:0 0;border:none;outline:none;max-width:none;max-height:none;margin:0;padding:0;position:fixed;inset:0;overflow:clip}.scrollsheet-dialog::backdrop{background:0 0}:where(.scrollsheet-backdrop){background:var(--scrollsheet-backdrop,#00000052);opacity:0;pointer-events:none;position:fixed;inset:0}.scrollsheet-dialog[data-scrollsheet-state=opening] .scrollsheet-backdrop{opacity:min(var(--scrollsheet-dim,0), 1);transition:opacity var(--scrollsheet-dur) var(--scrollsheet-ease)}.scrollsheet-dialog[data-scrollsheet-state=open] .scrollsheet-backdrop{opacity:min(var(--scrollsheet-dim,0), 1);transition:none}.scrollsheet-dialog[data-scrollsheet-state=closing] .scrollsheet-backdrop{opacity:0;transition:opacity var(--scrollsheet-dur) var(--scrollsheet-ease)}:where(.scrollsheet-top-chrome){height:calc(env(safe-area-inset-top,0px) + 8px);inset:0 0 auto}:where(.scrollsheet-bottom-chrome){height:calc(env(safe-area-inset-bottom,0px) + 32px);inset:auto 0 0}:where(.scrollsheet-top-chrome)~:where([data-scrollsheet-backdrop]){top:calc(env(safe-area-inset-top,0px) + 8px)}:where(.scrollsheet-bottom-chrome)~:where([data-scrollsheet-backdrop]){bottom:calc(env(safe-area-inset-bottom,0px) + 32px)}.scrollsheet-dialog:is([data-scrollsheet-state=pre],[data-scrollsheet-state=opening]) :is(.scrollsheet-top-chrome,.scrollsheet-bottom-chrome){opacity:min(var(--scrollsheet-dim,0), 1);transition:none}.scrollsheet-bottom-sentinel{height:min(calc(max(env(safe-area-inset-bottom,0px), 24px) + 45vh), var(--scrollsheet-reveal,24px));pointer-events:none;position:fixed;inset:auto 0 0}.scrollsheet-track{left:0;right:0;top:var(--scrollsheet-vv-top,0px);height:calc(var(--scrollsheet-vv-height,100%) + var(--scrollsheet-keyboard-lift,0px));overscroll-behavior:contain;scroll-snap-type:y mandatory;scrollbar-width:none;position:fixed;overflow-y:scroll}.scrollsheet-track::-webkit-scrollbar{display:none}.scrollsheet-dialog:is([data-scrollsheet-side=left],[data-scrollsheet-side=right]) .scrollsheet-track{scroll-snap-type:x mandatory;overscroll-behavior-x:none;overflow:scroll hidden}.scrollsheet-dialog[data-scrollsheet-modal=false]{pointer-events:none}.scrollsheet-dialog[data-scrollsheet-modal=false] .scrollsheet-panel{pointer-events:auto;touch-action:none}.scrollsheet-canvas{height:calc(100% + var(--scrollsheet-max-detent,0px));position:relative}.scrollsheet-dialog:is([data-scrollsheet-side=left],[data-scrollsheet-side=right]) .scrollsheet-canvas{width:calc(100% + var(--scrollsheet-max-detent,0px));height:100%}.scrollsheet-canvas:after{content:"";top:calc(100% - var(--scrollsheet-keyboard,0px));--scrollsheet-od:calc(120vh + var(--scrollsheet-keyboard,0px));height:0;box-shadow:0 calc(var(--scrollsheet-od) / 2) 0 calc(var(--scrollsheet-od) / 2) var(--scrollsheet-panel-bg,transparent);pointer-events:none;position:absolute;left:0;right:0}.scrollsheet-dialog[data-scrollsheet-side=top] .scrollsheet-canvas:after{box-shadow:0 -60vh 0 60vh var(--scrollsheet-panel-bg,transparent);top:auto;bottom:100%}.scrollsheet-dialog[data-scrollsheet-side=left] .scrollsheet-canvas:after{width:0;height:auto;box-shadow:-60vw 0 0 60vw var(--scrollsheet-panel-bg,transparent);inset:0 100% 0 auto}.scrollsheet-dialog[data-scrollsheet-side=right] .scrollsheet-canvas:after{width:0;height:auto;box-shadow:60vw 0 0 60vw var(--scrollsheet-panel-bg,transparent);inset:0 auto 0 100%}.scrollsheet-dialog[data-scrollsheet-detached] .scrollsheet-canvas:after{box-shadow:none}.scrollsheet-snap{pointer-events:none;scroll-snap-align:start;width:100%;height:1px;position:absolute;left:0}.scrollsheet-dialog:is([data-scrollsheet-side=left],[data-scrollsheet-side=right]) .scrollsheet-snap{width:1px;height:100%;top:0;left:auto}.scrollsheet-panel{--scrollsheet-eg:calc(var(--scrollsheet-inset-bottom,0px) + var(--scrollsheet-keyboard,0px));bottom:var(--scrollsheet-eg);left:var(--scrollsheet-inset-x,0px);right:var(--scrollsheet-inset-x,0px);height:var(--scrollsheet-max-detent,auto);max-height:var(--scrollsheet-vv-height,none);will-change:transform;padding-bottom:max(var(--scrollsheet-safe-area,env(safe-area-inset-bottom,0px)), 0px);position:absolute;overflow:hidden;transform:translateY(100%)}.scrollsheet-dialog[data-scrollsheet-side=top] .scrollsheet-panel{bottom:auto;top:var(--scrollsheet-inset-top,0px);left:var(--scrollsheet-inset-x,0px);right:var(--scrollsheet-inset-x,0px);height:var(--scrollsheet-max-detent,auto);padding-bottom:0;padding-top:max(var(--scrollsheet-safe-area-top,env(safe-area-inset-top,0px)), 0px);transform:translateY(-100%)}.scrollsheet-dialog:is([data-scrollsheet-side=left],[data-scrollsheet-side=right]) .scrollsheet-panel{top:var(--scrollsheet-inset-y,0px);bottom:var(--scrollsheet-inset-y,0px);width:var(--scrollsheet-max-detent,auto);height:auto;padding-top:max(var(--scrollsheet-safe-area-top,env(safe-area-inset-top,0px)), 0px)}.scrollsheet-dialog[data-scrollsheet-side=left] .scrollsheet-panel{right:auto;left:var(--scrollsheet-inset-left,0px);padding-left:max(var(--scrollsheet-safe-area-left,env(safe-area-inset-left,0px)), 0px);transform:translate(-100%)}.scrollsheet-dialog[data-scrollsheet-side=right] .scrollsheet-panel{left:auto;right:var(--scrollsheet-inset-right,0px);padding-right:max(var(--scrollsheet-safe-area-right,env(safe-area-inset-right,0px)), 0px);transform:translate(100%)}.scrollsheet-dialog:is([data-scrollsheet-side=top],[data-scrollsheet-side=left]) .scrollsheet-panel{justify-content:flex-end;display:flex}.scrollsheet-dialog[data-scrollsheet-side=top] .scrollsheet-panel{flex-direction:column}.scrollsheet-dialog[data-scrollsheet-side=left] .scrollsheet-panel{flex-direction:row}.scrollsheet-dialog[data-scrollsheet-side=left] .scrollsheet-panel>*{flex:0 0 100%;min-width:0}:where(.scrollsheet-panel){scrollbar-width:none}:where(.scrollsheet-panel)::-webkit-scrollbar{display:none}:where([data-scrollsheet-nested-scroll]){scrollbar-width:none}:where([data-scrollsheet-nested-scroll])::-webkit-scrollbar{display:none}:where(.scrollsheet-dialog[data-scrollsheet-scrollbar=overlay] [data-scrollsheet-nested-scroll]){position:relative}:where(.scrollsheet-panel){--scrollsheet-radius:20px;background:var(--scrollsheet-bg,#fff);color:var(--scrollsheet-fg,#1d1d1f);border-radius:var(--scrollsheet-radius) var(--scrollsheet-radius) 0 0;box-shadow:var(--scrollsheet-shadow,0 -8px 32px #00000029)}:where([data-scrollsheet-theme=dark]) :where(.scrollsheet-panel){background:var(--scrollsheet-bg,#1c1c1e);color:var(--scrollsheet-fg,#f5f5f7)}@media (prefers-color-scheme:dark){:where([data-scrollsheet-theme=system]) :where(.scrollsheet-panel){background:var(--scrollsheet-bg,#1c1c1e);color:var(--scrollsheet-fg,#f5f5f7)}}.scrollsheet-dialog[data-scrollsheet-side=top] :where(.scrollsheet-panel){border-radius:0 0 var(--scrollsheet-radius) var(--scrollsheet-radius);box-shadow:var(--scrollsheet-shadow,0 8px 32px #00000029)}.scrollsheet-dialog[data-scrollsheet-side=left] :where(.scrollsheet-panel){box-shadow:var(--scrollsheet-shadow,8px 0 32px #00000029);border-radius:0}.scrollsheet-dialog[data-scrollsheet-side=right] :where(.scrollsheet-panel){box-shadow:var(--scrollsheet-shadow,-8px 0 32px #00000029);border-radius:0}@media (min-width:768px){:where(.scrollsheet-dialog[data-scrollsheet-side=bottom]) :where(.scrollsheet-panel),:where(.scrollsheet-dialog[data-scrollsheet-side=bottom]) .scrollsheet-canvas:after{width:min(var(--scrollsheet-max-inline,640px), calc(100% - 2 * var(--scrollsheet-desktop-margin,24px)));margin-inline:auto var(--scrollsheet-desktop-margin,24px)}.scrollsheet-dialog[data-scrollsheet-side=bottom] .scrollsheet-panel{--scrollsheet-inset-bottom:var(--scrollsheet-desktop-margin,24px);--scrollsheet-dg:calc(var(--scrollsheet-desktop-margin,24px) + var(--scrollsheet-inset-x,0px) + 32px)}.scrollsheet-dialog[data-scrollsheet-side=bottom]:where([data-scrollsheet-detached]) .scrollsheet-panel,.scrollsheet-dialog[data-scrollsheet-side=bottom][data-scrollsheet-state=closing]:where([data-scrollsheet-detached]) .scrollsheet-panel{transform:translate3d(calc(100% + var(--scrollsheet-dg,32px)), 0, 0)}.scrollsheet-dialog[data-scrollsheet-side=bottom]:where([data-scrollsheet-detached][data-scrollsheet-rtl]) .scrollsheet-panel,.scrollsheet-dialog[data-scrollsheet-side=bottom][data-scrollsheet-state=closing]:where([data-scrollsheet-detached][data-scrollsheet-rtl]) .scrollsheet-panel{transform:translate3d(calc(-100% - var(--scrollsheet-dg,32px)), 0, 0)}.scrollsheet-dialog[data-scrollsheet-side=top] .scrollsheet-panel{top:var(--scrollsheet-desktop-margin,24px);border-radius:var(--scrollsheet-radius)}.scrollsheet-dialog[data-scrollsheet-side=bottom] :where(.scrollsheet-handle){opacity:0;pointer-events:none;width:5px;height:44px;margin:-22px 0 0;position:absolute;top:50%;left:10px}.scrollsheet-dialog[data-scrollsheet-side=bottom] :where(.scrollsheet-handle:focus-visible){opacity:1;pointer-events:auto}.scrollsheet-dialog[data-scrollsheet-side=bottom][data-scrollsheet-has-handle] :where(.scrollsheet-body){padding-top:18px}:where(.scrollsheet-dialog[data-scrollsheet-side=top]) :where(.scrollsheet-panel),:where(.scrollsheet-dialog[data-scrollsheet-side=top]) .scrollsheet-canvas:after{max-width:var(--scrollsheet-max-inline,640px);margin-inline:auto}}.scrollsheet-dialog[data-scrollsheet-detached] :where(.scrollsheet-panel){padding-bottom:max(var(--scrollsheet-safe-area,0px), 0px);border-radius:var(--scrollsheet-radius)}.scrollsheet-dialog[data-scrollsheet-detached][data-scrollsheet-side=bottom] :where(.scrollsheet-panel){--scrollsheet-eg:calc(max(var(--scrollsheet-inset-bottom,0px), env(safe-area-inset-bottom,0px)) + var(--scrollsheet-keyboard,0px));bottom:var(--scrollsheet-eg)}.scrollsheet-dialog[data-scrollsheet-scrollbar=native] .scrollsheet-panel{scrollbar-width:auto}.scrollsheet-dialog[data-scrollsheet-scrollbar=native] .scrollsheet-panel::-webkit-scrollbar{display:block}.scrollsheet-dialog[data-scrollsheet-scrollbar=native] [data-scrollsheet-nested-scroll]{scrollbar-width:auto}.scrollsheet-dialog[data-scrollsheet-scrollbar=native] [data-scrollsheet-nested-scroll]::-webkit-scrollbar{display:block}.scrollsheet-dialog[data-scrollsheet-state=opening] .scrollsheet-panel,.scrollsheet-dialog[data-scrollsheet-state=open] .scrollsheet-panel{transform:translate(0,0)}.scrollsheet-dialog[data-scrollsheet-state=closing] .scrollsheet-panel{transform:translate3d(0, calc(100% + var(--scrollsheet-eg,0px) + 32px), 0)}.scrollsheet-dialog[data-scrollsheet-side=top][data-scrollsheet-state=closing] .scrollsheet-panel{transform:translate3d(0, calc(-100% - var(--scrollsheet-inset-top,0px) - 32px), 0)}.scrollsheet-dialog[data-scrollsheet-side=left][data-scrollsheet-state=closing] .scrollsheet-panel{transform:translate3d(calc(-100% - var(--scrollsheet-inset-left,0px) - 32px), 0, 0)}.scrollsheet-dialog[data-scrollsheet-side=right][data-scrollsheet-state=closing] .scrollsheet-panel{transform:translate3d(calc(100% + var(--scrollsheet-inset-right,0px) + 32px), 0, 0)}.scrollsheet-dialog:is([data-scrollsheet-at-max],[data-scrollsheet-kb]) .scrollsheet-panel{overflow-y:auto}.scrollsheet-dialog[data-scrollsheet-kb][data-scrollsheet-side=bottom] .scrollsheet-panel{--scrollsheet-eg:calc(var(--scrollsheet-inset-bottom,0px) + var(--scrollsheet-keyboard,0px) + var(--scrollsheet-kb-hang,0px));box-shadow:none;border-bottom-right-radius:0;border-bottom-left-radius:0}.scrollsheet-kb-fade{display:none}.scrollsheet-dialog[data-scrollsheet-kb][data-scrollsheet-side=bottom] .scrollsheet-kb-fade{left:var(--scrollsheet-inset-x,0px);right:var(--scrollsheet-inset-x,0px);bottom:calc(var(--scrollsheet-keyboard,0px) + var(--scrollsheet-kb-hang,0px));background:linear-gradient(to bottom, transparent, var(--scrollsheet-panel-bg,#fff) 75%);pointer-events:none;z-index:1;height:18px;display:block;position:absolute}.scrollsheet-dialog:is([data-scrollsheet-handle-only],[data-scrollsheet-disable-drag]):not([data-scrollsheet-at-max],[data-scrollsheet-at-nested-boundary],[data-scrollsheet-kb]) :is(.scrollsheet-track,.scrollsheet-canvas){touch-action:none}.scrollsheet-dialog[data-scrollsheet-handle-only] .scrollsheet-panel,.scrollsheet-dialog[data-scrollsheet-disable-drag] .scrollsheet-panel{touch-action:pan-y}.scrollsheet-dialog[data-scrollsheet-handle-only]:not([data-scrollsheet-at-nested-boundary]) .scrollsheet-panel,.scrollsheet-dialog[data-scrollsheet-disable-drag]:not([data-scrollsheet-at-nested-boundary]) .scrollsheet-panel{overscroll-behavior:contain}.scrollsheet-dialog[data-scrollsheet-at-nested-boundary] .scrollsheet-track,.scrollsheet-dialog[data-scrollsheet-at-nested-boundary] .scrollsheet-canvas{touch-action:pan-y}.scrollsheet-dialog[data-scrollsheet-side=left][data-scrollsheet-at-nested-boundary] .scrollsheet-track,.scrollsheet-dialog[data-scrollsheet-side=left][data-scrollsheet-at-nested-boundary] .scrollsheet-canvas,.scrollsheet-dialog[data-scrollsheet-side=right][data-scrollsheet-at-nested-boundary] .scrollsheet-track,.scrollsheet-dialog[data-scrollsheet-side=right][data-scrollsheet-at-nested-boundary] .scrollsheet-canvas{touch-action:pan-x}:where(.scrollsheet-scrollbar){top:0;width:var(--scrollsheet-scrollbar-width,4px);box-sizing:border-box;background:var(--scrollsheet-scrollbar-color,#00000052);opacity:0;pointer-events:none;z-index:2;background-clip:padding-box;border:1px solid #ffffff38;border-radius:999px;transition:opacity .4s;position:absolute;inset-inline-end:3px}.scrollsheet-scrollbar[data-visible]{opacity:1;transition:opacity .12s}@media (prefers-reduced-motion:reduce){:where(.scrollsheet-scrollbar){transition:none}}.scrollsheet-panel:before{content:"";z-index:1;pointer-events:none;opacity:var(--scrollsheet-recede-dim,0);background:#000;position:absolute;inset:0}.scrollsheet-dialog[data-scrollsheet-behind] .scrollsheet-panel{--scrollsheet-recede-dim:.14;--scrollsheet-stack-progress:1;transform-origin:50% 0;transition:transform var(--scrollsheet-dur) var(--scrollsheet-ease);transform:translateY(8px)scale(.94)}.scrollsheet-dialog[data-scrollsheet-behind] .scrollsheet-panel:before{transition:opacity var(--scrollsheet-dur) var(--scrollsheet-ease)}.scrollsheet-dialog[data-scrollsheet-side=top][data-scrollsheet-behind] .scrollsheet-panel{transform-origin:50% 100%;transform:translateY(-8px)scale(.94)}.scrollsheet-dialog[data-scrollsheet-side=left][data-scrollsheet-behind] .scrollsheet-panel{transform-origin:100%;transform:translate(-8px)scale(.94)}.scrollsheet-dialog[data-scrollsheet-side=right][data-scrollsheet-behind] .scrollsheet-panel{transform-origin:0%;transform:translate(8px)scale(.94)}.scrollsheet-track,.scrollsheet-canvas,.scrollsheet-panel,.scrollsheet-dialog:focus-visible,.scrollsheet-track:focus-visible,.scrollsheet-canvas:focus-visible,.scrollsheet-panel:focus-visible{outline:none}[data-scrollsheet-dragging]{-webkit-user-select:none;user-select:none}[data-scrollsheet-dragging] .scrollsheet-panel{cursor:grabbing}.scrollsheet-dialog:is([data-scrollsheet-side=top],[data-scrollsheet-side=left],[data-scrollsheet-side=right]) .scrollsheet-panel{scroll-padding-bottom:var(--scrollsheet-keyboard,0px)}.scrollsheet-dialog:is([data-scrollsheet-side=top],[data-scrollsheet-side=left],[data-scrollsheet-side=right]) [data-scrollsheet-body]{padding-bottom:var(--scrollsheet-keyboard,0px)}:where([data-scrollsheet-body]){display:flow-root}.scrollsheet-panel[data-scrollsheet-fill]{flex-direction:column;display:flex}[data-scrollsheet-body][data-scrollsheet-fill]{flex-direction:column;flex:1;min-height:0;display:flex}@media (prefers-reduced-motion:reduce){.scrollsheet-dialog .scrollsheet-panel,.scrollsheet-dialog .scrollsheet-backdrop{transition:none!important}}@supports (animation-timeline:scroll()){@property --scrollsheet-progress{syntax:"<number>";inherits:true;initial-value:0}.scrollsheet-dialog[data-scrollsheet-sda]{timeline-scope:--scrollsheet-track}.scrollsheet-dialog[data-scrollsheet-sda] .scrollsheet-track{scroll-timeline:--scrollsheet-track y}.scrollsheet-dialog[data-scrollsheet-sda]:is([data-scrollsheet-side=left],[data-scrollsheet-side=right]) .scrollsheet-track{scroll-timeline:--scrollsheet-track x}.scrollsheet-dialog[data-scrollsheet-sda][data-scrollsheet-state=open] .scrollsheet-backdrop{animation:linear both scrollsheet-fade,linear both scrollsheet-progress-var;animation-timeline:--scrollsheet-track,--scrollsheet-track;animation-range:var(--scrollsheet-fade-start,0px) var(--scrollsheet-fade-end,100%), 0px var(--scrollsheet-first-detent,100%)}.scrollsheet-dialog[data-scrollsheet-sda][data-scrollsheet-state=open]:is([data-scrollsheet-side=top],[data-scrollsheet-side=left]) .scrollsheet-backdrop{animation-direction:reverse,reverse;animation-range:calc(var(--scrollsheet-max-detent,0px) - var(--scrollsheet-fade-end,0px)) calc(var(--scrollsheet-max-detent,0px) - var(--scrollsheet-fade-start,0px)), calc(var(--scrollsheet-max-detent,0px) - var(--scrollsheet-first-detent,0px)) var(--scrollsheet-max-detent,0px)}@keyframes scrollsheet-fade{0%{opacity:0}to{opacity:1}}@keyframes scrollsheet-progress-var{0%{--scrollsheet-progress:0}to{--scrollsheet-progress:1}}}.scrollsheet-fallback{z-index:2147483647;display:flex;position:fixed;inset:0}.scrollsheet-fallback[data-scrollsheet-modal=false]{pointer-events:none}.scrollsheet-fallback[data-scrollsheet-modal=false] .scrollsheet-fallback-panel{pointer-events:auto}.scrollsheet-fallback-backdrop{background:var(--scrollsheet-backdrop,#00000052);position:fixed;inset:0}:where(.scrollsheet-fallback-panel){--scrollsheet-radius:20px;background:var(--scrollsheet-bg,#fff);color:var(--scrollsheet-fg,#1d1d1f);box-shadow:var(--scrollsheet-shadow,0 -8px 32px #00000029);overscroll-behavior:contain;-webkit-overflow-scrolling:touch;outline:none;position:relative;overflow-y:auto}:where([data-scrollsheet-theme=dark]) :where(.scrollsheet-fallback-panel){background:var(--scrollsheet-bg,#1c1c1e);color:var(--scrollsheet-fg,#f5f5f7)}@media (prefers-color-scheme:dark){:where([data-scrollsheet-theme=system]) :where(.scrollsheet-fallback-panel){background:var(--scrollsheet-bg,#1c1c1e);color:var(--scrollsheet-fg,#f5f5f7)}}.scrollsheet-fallback[data-scrollsheet-side=bottom]{align-items:flex-end}.scrollsheet-fallback[data-scrollsheet-side=bottom] :where(.scrollsheet-fallback-panel){border-radius:var(--scrollsheet-radius) var(--scrollsheet-radius) 0 0;width:100%;max-height:85%;padding-bottom:max(var(--scrollsheet-safe-area,env(safe-area-inset-bottom,0px)), 0px)}.scrollsheet-fallback[data-scrollsheet-side=top]{align-items:flex-start}.scrollsheet-fallback[data-scrollsheet-side=top] :where(.scrollsheet-fallback-panel){border-radius:0 0 var(--scrollsheet-radius) var(--scrollsheet-radius);width:100%;max-height:85%;box-shadow:var(--scrollsheet-shadow,0 8px 32px #00000029);padding-top:max(var(--scrollsheet-safe-area-top,env(safe-area-inset-top,0px)), 0px)}.scrollsheet-fallback[data-scrollsheet-side=center]{justify-content:center;align-items:center}.scrollsheet-fallback[data-scrollsheet-side=center] :where(.scrollsheet-fallback-panel){max-inline-size:var(--scrollsheet-center-max-inline,min(560px, calc(100% - 40px)));border-radius:var(--scrollsheet-radius);max-height:85%;box-shadow:var(--scrollsheet-shadow,0 8px 32px #00000029)}.scrollsheet-fallback[data-scrollsheet-side=left]{justify-content:flex-start}.scrollsheet-fallback[data-scrollsheet-side=right]{justify-content:flex-end}.scrollsheet-fallback:is([data-scrollsheet-side=left],[data-scrollsheet-side=right]) :where(.scrollsheet-fallback-panel){max-width:85%;height:100%;padding-top:max(var(--scrollsheet-safe-area-top,env(safe-area-inset-top,0px)), 0px);padding-bottom:max(var(--scrollsheet-safe-area,env(safe-area-inset-bottom,0px)), 0px);border-radius:0}.scrollsheet-fallback[data-scrollsheet-side=left] :where(.scrollsheet-fallback-panel){box-shadow:var(--scrollsheet-shadow,8px 0 32px #00000029)}.scrollsheet-fallback[data-scrollsheet-side=right] :where(.scrollsheet-fallback-panel){box-shadow:var(--scrollsheet-shadow,-8px 0 32px #00000029)}@media (min-width:768px){.scrollsheet-fallback[data-scrollsheet-side=bottom] :where(.scrollsheet-fallback-panel),.scrollsheet-fallback[data-scrollsheet-side=top] :where(.scrollsheet-fallback-panel){max-width:var(--scrollsheet-max-inline,640px);margin-inline:auto}}.scrollsheet-fallback [data-scrollsheet-handle]{display:none}@media (forced-colors:active){:where(.scrollsheet-backdrop),:where(.scrollsheet-fallback-backdrop){forced-color-adjust:none}:where(.scrollsheet-panel),:where(.scrollsheet-fallback-panel){color:canvastext;box-shadow:none;background:canvas;border:1px solid buttonborder}.scrollsheet-dialog:is([data-scrollsheet-side=top],[data-scrollsheet-side=left],[data-scrollsheet-side=right]) :where(.scrollsheet-panel),.scrollsheet-fallback:is([data-scrollsheet-side=top],[data-scrollsheet-side=left],[data-scrollsheet-side=right]) :where(.scrollsheet-fallback-panel){box-shadow:none}:where(.scrollsheet-scrollbar){background:highlight}}.scrollsheet-dialog[data-scrollsheet-side=center] .scrollsheet-track{scroll-snap-type:none;box-sizing:border-box;padding:var(--scrollsheet-center-gutter,20px);padding-bottom:calc(var(--scrollsheet-center-gutter,20px) + var(--scrollsheet-keyboard,0px));place-items:center;display:grid;overflow:hidden}.scrollsheet-dialog[data-scrollsheet-side=center] .scrollsheet-canvas{display:contents}.scrollsheet-dialog[data-scrollsheet-side=center] .scrollsheet-canvas:after{content:none}.scrollsheet-dialog[data-scrollsheet-side=center] .scrollsheet-panel{width:auto;height:auto;max-inline-size:var(--scrollsheet-center-max-inline,min(560px, 100%));max-block-size:var(--scrollsheet-center-max-block,100%);border-radius:var(--scrollsheet-radius,16px);padding-bottom:0;position:static;inset:auto;overflow:auto}.scrollsheet-dialog[data-scrollsheet-side=center] .scrollsheet-handle{display:none}.scrollsheet-dialog[data-scrollsheet-side=center]:is([data-scrollsheet-state=pre],[data-scrollsheet-state=closing]) .scrollsheet-panel{opacity:0;transform:scale(.95)}.scrollsheet-handle:before{content:"";width:max(100%,44px);height:44px;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)}:where(.scrollsheet-handle){background:var(--scrollsheet-handle,#0003);cursor:grab;width:44px;height:5px;box-shadow:0 0 0 2px transparent, 0 0 0 calc(2px + var(--scrollsheet-focus-ring-width,2px)) transparent;transition:transform .18s var(--scrollsheet-ease), background .18s ease, box-shadow .15s ease;border:none;border-radius:999px;outline:none;margin:8px auto;padding:0;display:block;position:relative}:where(.scrollsheet-handle:hover){background:var(--scrollsheet-handle-hover,#00000052)}:where(.scrollsheet-handle:active){cursor:grabbing;transform:scaleX(1.3)}:where([data-scrollsheet-theme=dark]) :where(.scrollsheet-handle){background:var(--scrollsheet-handle,#ffffff52)}:where([data-scrollsheet-theme=dark]) :where(.scrollsheet-handle:hover){background:var(--scrollsheet-handle-hover,#ffffff75)}@media (prefers-color-scheme:dark){:where([data-scrollsheet-theme=system]) :where(.scrollsheet-handle){background:var(--scrollsheet-handle,#ffffff52)}:where([data-scrollsheet-theme=system]) :where(.scrollsheet-handle:hover){background:var(--scrollsheet-handle-hover,#ffffff75)}}:where(.scrollsheet-handle[data-scrollsheet-handle-variant=floating]){z-index:1;margin:0;position:absolute;top:8px;left:50%;translate:-50%}:where(.scrollsheet-canvas>.scrollsheet-handle[data-scrollsheet-handle-variant=outside]){left:50%;bottom:calc(var(--scrollsheet-ib,0px) + var(--scrollsheet-keyboard,0px) + var(--scrollsheet-kb-hang,0px) + var(--scrollsheet-max-detent,0px) + 10px);background:var(--scrollsheet-handle,#fffc);margin:0;position:absolute;translate:-50%}.scrollsheet-dialog:not([data-scrollsheet-state=open]) .scrollsheet-canvas>.scrollsheet-handle[data-scrollsheet-handle-variant=outside]{opacity:0;transition:opacity .12s}.scrollsheet-dialog[data-scrollsheet-modal=false] .scrollsheet-handle[data-scrollsheet-handle-variant=outside]{pointer-events:auto;touch-action:none}:where(.scrollsheet-close){top:12px;z-index:1;background:var(--scrollsheet-close-bg,#0000000f);width:28px;height:28px;color:var(--scrollsheet-close-color,#0000008c);cursor:pointer;box-shadow:0 0 0 2px transparent, 0 0 0 calc(2px + var(--scrollsheet-focus-ring-width,2px)) transparent;border:none;border-radius:999px;outline:none;place-items:center;padding:0;transition:background .15s,color .15s,box-shadow .15s;display:grid;position:absolute;inset-inline-end:12px}.scrollsheet-close:before{content:"";width:44px;height:44px;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)}:where(.scrollsheet-close:hover){background:var(--scrollsheet-close-bg-hover,#0000001a);color:var(--scrollsheet-close-color-hover,#000000bf)}:where([data-scrollsheet-theme=dark]) :where(.scrollsheet-close){background:var(--scrollsheet-close-bg,#ffffff17);color:var(--scrollsheet-close-color,#ffffff9e)}:where([data-scrollsheet-theme=dark]) :where(.scrollsheet-close:hover){background:var(--scrollsheet-close-bg-hover,#ffffff24);color:var(--scrollsheet-close-color-hover,#ffffffd9)}@media (prefers-color-scheme:dark){:where([data-scrollsheet-theme=system]) :where(.scrollsheet-close){background:var(--scrollsheet-close-bg,#ffffff17);color:var(--scrollsheet-close-color,#ffffff9e)}:where([data-scrollsheet-theme=system]) :where(.scrollsheet-close:hover){background:var(--scrollsheet-close-bg-hover,#ffffff24);color:var(--scrollsheet-close-color-hover,#ffffffd9)}}:where(.scrollsheet-close:focus-visible),:where(.scrollsheet-handle:focus-visible){box-shadow:0 0 0 2px transparent, 0 0 0 calc(2px + var(--scrollsheet-focus-ring-width,2px)) var(--scrollsheet-focus-ring,#6366f199);outline:none}.scrollsheet-dialog[data-scrollsheet-side=left] .scrollsheet-handle:before,.scrollsheet-dialog[data-scrollsheet-side=right] .scrollsheet-handle:before{width:44px;height:max(100%,44px)}.scrollsheet-dialog[data-scrollsheet-side=left] :where(.scrollsheet-handle),.scrollsheet-dialog[data-scrollsheet-side=right] :where(.scrollsheet-handle){width:5px;height:44px;margin:auto 8px}.scrollsheet-dialog[data-scrollsheet-side=left] :where(.scrollsheet-handle:active),.scrollsheet-dialog[data-scrollsheet-side=right] :where(.scrollsheet-handle:active){transform:scaleY(1.3)}@media (forced-colors:active){:where(.scrollsheet-handle){box-shadow:none;background:buttonborder}:where(.scrollsheet-handle:focus-visible){box-shadow:none;outline:2px solid highlight}:where(.scrollsheet-close){color:buttontext;box-shadow:none;background:canvas;border:1px solid buttonborder}:where(.scrollsheet-close:focus-visible){box-shadow:none;outline:2px solid highlight}} |
+1
-4
| { | ||
| "name": "scrollsheet", | ||
| "version": "1.0.0-beta.5", | ||
| "publishConfig": { | ||
| "tag": "beta" | ||
| }, | ||
| "version": "1.0.0", | ||
| "description": "The bottom sheet that scrolls. Native-feeling React drawer built on <dialog> and CSS scroll-snap. Zero dependencies.", | ||
@@ -8,0 +5,0 @@ "license": "MIT", |
+21
-10
@@ -5,7 +5,9 @@ # scrollsheet | ||
| One primitive for bottom sheets, drawers, modal dialogs, side panels, and toasts. A real `<dialog>` in the top layer. The browser's own scroll engine for gestures. Spring physics compiled to CSS `linear()`. <!--size:index.gzip:1-->17.6<!--/size--> kB gzipped, <!--size:index.brotli:1-->15.7<!--/size--> kB brotli, plus a mandatory 3.8 kB stylesheet: 22.3 kB combined. React 18+. | ||
| <img src="docs/public/hero.gif" width="290" align="right" alt="A bottom sheet dragged between detents 1:1 and flick-dismissed, rendered in a native dialog"> | ||
| One primitive for bottom sheets, drawers, modal dialogs, side panels, and toasts. A real `<dialog>` in the top layer. The browser's own scroll engine for gestures. Spring physics compiled to CSS `linear()`. <!--size:index.gzip:1-->17.6<!--/size--> kB gzipped, <!--size:index.brotli:1-->15.7<!--/size--> kB brotli, plus a 3.9 kB stylesheet. React 18+. | ||
| ## Why another drawer | ||
| [vaul](https://github.com/emilkowalski/vaul) carried the ecosystem for two years and last shipped in December 2024. Its bug tracker tells one story over and over: pointer tracking fights the browser. scrollsheet takes the opposite bet: **don't simulate the gesture, be the scroll.** | ||
| [vaul](https://github.com/emilkowalski/vaul) is the React drawer nearly everyone ships: 37 million downloads a week. Its bug tracker tells one story over and over: pointer tracking fights the browser. scrollsheet takes the opposite bet: **don't simulate the gesture, be the scroll.** | ||
@@ -22,3 +24,3 @@ 1. **The sheet is a native `<dialog>`.** Top layer, so no z-index wars. Focus containment, Esc, and background inerting come from the platform. | ||
| ```sh | ||
| bun add scrollsheet@beta # or npm/pnpm/yarn | ||
| bun add scrollsheet # or npm/pnpm/yarn | ||
| ``` | ||
@@ -57,2 +59,11 @@ | ||
| ### Centered dialogs | ||
| ```tsx | ||
| <Sheet.Root side="center"> // a content-sized modal, zoom+fade, your CSS owns the width | ||
| <Sheet.Root desktopSide="center"> // bottom sheet on phones, that modal at 768px and up | ||
| ``` | ||
| Same component, same props, same focus behavior. [Guide](https://scrollsheet.dev/docs/presentation/centered-dialog), [responsive profiles](https://scrollsheet.dev/docs/presentation/responsive-profiles). | ||
| ### API | ||
@@ -62,3 +73,3 @@ | ||
| | --- | --- | | ||
| | `Sheet.Root` | State owner. `open`, `onOpenChange`, `onOpenChangeComplete`, `actionsRef` (`open()` / `close()` / `snapTo(detent)`), `detents`, `activeDetent`, `onActiveDetentChange`, `dismissible`, `escapeDismissible`, `backdropDismissible`, `onTravel`, `nonce`, `side`, `modal`, `backgroundEffect`, `scrollbar`, `largestUndimmedDetent`, `handleOnly`, `disableDrag`, `sequentialDetents`, `closeThreshold`, `keyboardExpands`, `onRelease` | | ||
| | `Sheet.Root` | State owner. `open` / `onOpenChange`, `detents` / `activeDetent`, `side` (any edge or `'center'`), `desktopSide` / `desktopBreakpoint`, `modal`, the `dismissible` family, `actionsRef` (`open()` / `close()` / `snapTo(detent)`), plus travel, keyboard, and gesture tuning props | | ||
| | `Sheet.Trigger` | Button wired with `aria-haspopup` / `aria-expanded` | | ||
@@ -78,8 +89,9 @@ | `Sheet.Content` | The `<dialog>`, backdrop, scroll track, and panel | | ||
| - **Keyboard engine.** `visualViewport`-tracked insets so the keyboard never reveals the page through a gap (the classic vaul bug). Works on every side; `keyboardExpands` promotes a peek-detent sheet to its tallest detent while the keyboard is up. | ||
| - **Desktop mouse drag**, `fill` prop, Shadow DOM injection, `themeColorDimming`, hidden scrollbars with an overlay thumb. | ||
| - **Radix Dialog drop-in.** `import { Dialog } from 'scrollsheet'` keeps @radix-ui/react-dialog JSX working against the centered presentation, `data-state` animation CSS included; radix-only props warn once in dev with the replacement recipe. [Migration guide](https://scrollsheet.dev/docs/migrating/from-radix-dialog). | ||
| - **vaul drop-in.** `import { Drawer } from 'scrollsheet'` keeps vaul's API and `data-vaul-*` attributes; props that existed to fight the page warn once in dev. [Migration guide](https://scrollsheet.dev/docs/migrating/from-vaul). | ||
| - **Toasts, no Sonner knowledge required.** `import { toast, Toaster, useToasts } from 'scrollsheet'` styles with `.scrollsheet-toast` classes and `--scrollsheet-toast-*` custom properties: `.promise()`, update-by-id, all six positions with per-toast overrides, swipe-to-dismiss with a velocity flick. Already on Sonner? Your `.sonner-toast` CSS still matches, unchanged, and `useSonner`/`toasterId` keep working. [Migration guide](https://scrollsheet.dev/docs/migrating/from-sonner). | ||
| - **Agent skills.** [`skills/`](skills/) ships `migrate-from-vaul`, `migrate-from-sonner`, and `build-with-scrollsheet` for coding agents. | ||
| - **Toasts, no Sonner knowledge required.** `import { toast, Toaster, useToasts } from 'scrollsheet'` styles with `.scrollsheet-toast` classes and `--scrollsheet-toast-*` custom properties: `.promise()`, update-by-id, all six positions with per-toast overrides, swipe-to-dismiss with a velocity flick. Already on Sonner? Your `.sonner-toast` CSS still matches, unchanged, and `useSonner`/`toasterId` keep working; fresh integrations can drop the mirrors with `sonnerCompat={false}`. [Migration guide](https://scrollsheet.dev/docs/migrating/from-sonner). | ||
| - **Smaller things.** Desktop mouse drag, the `fill` prop, Shadow DOM injection, `themeColorDimming`, hidden scrollbars with an overlay thumb. | ||
| - **Agent skills.** [`skills/`](skills/) ships `migrate-from-vaul`, `migrate-from-sonner`, `migrate-from-radix-dialog`, and `build-with-scrollsheet` for coding agents. | ||
| - **Motion core (experimental).** `scrollsheet/motion` is the React-free layer the sheet runs on: closed-form spring solver, interruptible WAAPI wrapper, scroll tween. 1.6 kB gzipped standalone. | ||
| - **Zero-config entry.** `scrollsheet/auto` embeds the stylesheet and injects it on first open: no CSS import needed, <!--size:auto.gzip:1-->21.8<!--/size--> kB gzip for `Sheet` against the default entry's <!--size:index.gzip:1-->17.6<!--/size-->. | ||
| - **Zero-config entry.** `scrollsheet/auto` embeds the stylesheet and injects it on first open: no CSS import needed, <!--size:auto.gzip:1-->21.9<!--/size--> kB gzip for `Sheet` against the default entry's <!--size:index.gzip:1-->17.6<!--/size-->. | ||
@@ -92,3 +104,2 @@ Focus containment comes from the platform's `showModal()`, not a JS focus trap. On open, focus lands on the panel so mobile keyboards don't pop unasked; use native `autofocus` to override. | ||
| | --- | --- | --- | --- | --- | | ||
| | Maintained | yes | **no** | yes | yes | | ||
| | Runtime deps | **0** | Radix Dialog (+24 transitive) | 0 | Motion (peer) | | ||
@@ -129,3 +140,3 @@ | Native `<dialog>` / top layer | **yes** | no | no | no | | ||
| Items: `drawer`, `sheet`, `confirm`, `share-sheet`, `sidebar`, `toast`. Each writes one file into `components/ui/` with shadcn's default styling applied, wrapping the primitives above. Swap `drawer.json` in the URL for any of them. These URLs only resolve once the repo is public. | ||
| Items: `drawer`, `sheet`, `dialog`, `confirm`, `share-sheet`, `sidebar`, `toast`. Each writes one file into `components/ui/` with shadcn's default styling applied, wrapping the primitives above. Swap `drawer.json` in the URL for any of them. | ||
@@ -132,0 +143,0 @@ ## Roadmap |
| "use client"; | ||
| import { c as Slot, d as useSheetContext, i as Content$1, n as Description, r as Title, s as Trigger, t as Close, u as Root$1 } from "./misc-Bf6n3Ykh.mjs"; | ||
| import { t as cn } from "./cn-DgpbGWy-.mjs"; | ||
| import * as React from "react"; | ||
| import { Fragment, jsx } from "react/jsx-runtime"; | ||
| import { createPortal } from "react-dom"; | ||
| //#region packages/scrollsheet/src/handle.tsx | ||
| function detentLabel(spec) { | ||
| if (spec === "full") return "Full"; | ||
| if (spec === "medium") return "Half"; | ||
| if (spec === "content") return "Fit content"; | ||
| if (typeof spec === "number") return `${Math.round(spec * 100)}%`; | ||
| return spec ?? ""; | ||
| } | ||
| const Handle$1 = React.forwardRef(function Handle({ asChild, onClick, onKeyDown, className, variant = "inside", ...props }, ref) { | ||
| const ctx = useSheetContext("Handle"); | ||
| const [mounted, setMounted] = React.useState(false); | ||
| React.useEffect(() => setMounted(true), []); | ||
| const outside = variant === "outside" && ctx.side === "bottom" && !(mounted && !ctx.canvasEl); | ||
| const variantAttr = outside ? "outside" : variant === "floating" ? "floating" : void 0; | ||
| const specs = ctx.detents; | ||
| const horizontal = ctx.side === "left" || ctx.side === "right"; | ||
| const multi = specs.length >= 2; | ||
| const activeIndex = specs.findIndex((s) => Object.is(s, ctx.activeDetent)); | ||
| const move = (delta) => { | ||
| if (!multi) return false; | ||
| const index = specs.findIndex((s) => Object.is(s, ctx.activeDetent)); | ||
| const next = specs[index + delta]; | ||
| if (next === void 0) return false; | ||
| ctx.setActiveDetent(next); | ||
| return true; | ||
| }; | ||
| const sliderAria = multi ? { | ||
| role: "slider", | ||
| "aria-orientation": horizontal ? "horizontal" : "vertical", | ||
| "aria-valuemin": 0, | ||
| "aria-valuemax": specs.length - 1, | ||
| ...activeIndex >= 0 ? { | ||
| "aria-valuenow": activeIndex, | ||
| "aria-valuetext": detentLabel(specs[activeIndex]) | ||
| } : {} | ||
| } : {}; | ||
| const button = jsx(asChild ? Slot : "button", { | ||
| ...asChild ? {} : { type: "button" }, | ||
| "aria-label": horizontal ? "Adjust sheet width" : "Adjust sheet height", | ||
| ...sliderAria, | ||
| ...props, | ||
| ref, | ||
| className: cn("scrollsheet-handle", className), | ||
| "data-scrollsheet-handle": true, | ||
| "data-scrollsheet-handle-variant": variantAttr, | ||
| onClick: (event) => { | ||
| onClick?.(event); | ||
| if (event.defaultPrevented) return; | ||
| if (!multi) return; | ||
| const index = specs.findIndex((s) => Object.is(s, ctx.activeDetent)); | ||
| const next = specs[(index + 1) % specs.length]; | ||
| if (next !== void 0) ctx.setActiveDetent(next); | ||
| }, | ||
| onKeyDown: (event) => { | ||
| onKeyDown?.(event); | ||
| if (event.defaultPrevented) return; | ||
| const expandKey = horizontal ? "ArrowRight" : "ArrowUp"; | ||
| const collapseKey = horizontal ? "ArrowLeft" : "ArrowDown"; | ||
| if (event.key === expandKey) { | ||
| event.preventDefault(); | ||
| move(1); | ||
| } else if (event.key === collapseKey) { | ||
| event.preventDefault(); | ||
| if (!move(-1) && ctx.dismissible) ctx.setOpen(false); | ||
| } else if (multi && event.key === "Home") { | ||
| event.preventDefault(); | ||
| const first = specs[0]; | ||
| if (first !== void 0) ctx.setActiveDetent(first); | ||
| } else if (multi && event.key === "End") { | ||
| event.preventDefault(); | ||
| const last = specs[specs.length - 1]; | ||
| if (last !== void 0) ctx.setActiveDetent(last); | ||
| } | ||
| } | ||
| }); | ||
| if (outside) return ctx.canvasEl ? createPortal(button, ctx.canvasEl) : null; | ||
| return button; | ||
| }); | ||
| //#endregion | ||
| //#region packages/scrollsheet/src/drawer/index.tsx | ||
| const wrapperClaims = new Map(); | ||
| const VAUL_CLOSE_THRESHOLD = .25; | ||
| function toDetentSpec(point) { | ||
| if (typeof point === "number") return point; | ||
| if (point === "fit-content" || point === "content") return "content"; | ||
| if (/^\d+(\.\d+)?px$/.test(point)) return `${Number.parseFloat(point)}px`; | ||
| const parsed = Number.parseFloat(point); | ||
| return Number.isFinite(parsed) ? parsed : "content"; | ||
| } | ||
| function resolveFadeFromIndex(snapPoints, fadeFromIndex) { | ||
| if (!snapPoints || snapPoints.length === 0) return void 0; | ||
| const point = snapPoints[fadeFromIndex ?? snapPoints.length - 1]; | ||
| return point !== void 0 ? toDetentSpec(point) : void 0; | ||
| } | ||
| function resolveCloseThreshold(snapPoints, closeThreshold) { | ||
| if (snapPoints !== void 0 && snapPoints.length > 0) return void 0; | ||
| return Math.min(1, Math.max(0, 1 - (closeThreshold ?? VAUL_CLOSE_THRESHOLD))); | ||
| } | ||
| function composeOpenChange(onOpenChange, onClose) { | ||
| if (!onOpenChange && !onClose) return void 0; | ||
| return (next) => { | ||
| if (!next) onClose?.(); | ||
| onOpenChange?.(next); | ||
| }; | ||
| } | ||
| function Root(props) { | ||
| const { children, open, defaultOpen, onOpenChange, onClose, dismissible, snapPoints, activeSnapPoint, setActiveSnapPoint, onAnimationEnd, autoFocus, nested, direction, modal, shouldScaleBackground, setBackgroundColorOnScale, noBodyStyles, disablePreventScroll, preventScrollRestoration, repositionInputs, scrollLockTimeout, closeThreshold, fadeFromIndex, snapToSequentialPoint, handleOnly, onDrag, onRelease, container, fixed, actionsRef, backdropDismissible, escapeDismissible, keyboardExpands, onTravel, scrollbar } = props; | ||
| const detents = snapPoints && snapPoints.length > 0 ? snapPoints.map(toDetentSpec) : void 0; | ||
| const activeDetent = activeSnapPoint != null ? toDetentSpec(activeSnapPoint) : void 0; | ||
| const largestUndimmedDetent = resolveFadeFromIndex(snapPoints, fadeFromIndex); | ||
| const resolvedCloseThreshold = resolveCloseThreshold(snapPoints, closeThreshold); | ||
| const handleRelease = onRelease ? (event, willRemainOpen) => onRelease(event, willRemainOpen) : void 0; | ||
| const handleOpenChange = composeOpenChange(onOpenChange, onClose); | ||
| const handleActiveDetentChange = (detent) => { | ||
| if (!setActiveSnapPoint) return; | ||
| const match = snapPoints?.find((point) => Object.is(toDetentSpec(point), detent)); | ||
| setActiveSnapPoint(match ?? detent); | ||
| }; | ||
| React.useEffect(() => { | ||
| if (!shouldScaleBackground) return; | ||
| const existing = document.querySelector("[data-scrollsheet-background]"); | ||
| if (existing && !wrapperClaims.has(existing)) return; | ||
| const wrapper = existing ?? document.querySelector("[data-vaul-drawer-wrapper]"); | ||
| if (!wrapper) return; | ||
| const count = wrapperClaims.get(wrapper) ?? 0; | ||
| wrapperClaims.set(wrapper, count + 1); | ||
| if (count === 0) wrapper.setAttribute("data-scrollsheet-background", ""); | ||
| return () => { | ||
| const remaining = (wrapperClaims.get(wrapper) ?? 1) - 1; | ||
| if (remaining <= 0) { | ||
| wrapperClaims.delete(wrapper); | ||
| wrapper.removeAttribute("data-scrollsheet-background"); | ||
| } else wrapperClaims.set(wrapper, remaining); | ||
| }; | ||
| }, [shouldScaleBackground]); | ||
| return jsx(DirectionContext.Provider, { | ||
| value: direction ?? "bottom", | ||
| children: jsx(Root$1, { | ||
| open, | ||
| defaultOpen, | ||
| onOpenChange: handleOpenChange, | ||
| onOpenChangeComplete: onAnimationEnd, | ||
| dismissible, | ||
| detents, | ||
| activeDetent, | ||
| onActiveDetentChange: setActiveSnapPoint ? handleActiveDetentChange : void 0, | ||
| side: direction, | ||
| modal, | ||
| backgroundEffect: shouldScaleBackground ? "scale" : "none", | ||
| largestUndimmedDetent, | ||
| handleOnly, | ||
| sequentialDetents: snapToSequentialPoint, | ||
| closeThreshold: resolvedCloseThreshold, | ||
| onRelease: handleRelease, | ||
| actionsRef, | ||
| backdropDismissible, | ||
| escapeDismissible, | ||
| keyboardExpands, | ||
| onTravel, | ||
| scrollbar, | ||
| children | ||
| }) | ||
| }); | ||
| } | ||
| const DirectionContext = React.createContext("bottom"); | ||
| const NestedRoot = Root; | ||
| function Portal({ children, container }) { | ||
| return jsx(Fragment, { children }); | ||
| } | ||
| function Overlay(_props) { | ||
| return null; | ||
| } | ||
| function hasMultipleSnapPoints(detents) { | ||
| return detents.length > 1; | ||
| } | ||
| const Content = React.forwardRef(function Content({ onPointerDownOutside, onOpenAutoFocus, onEscapeKeyDown, onCloseAutoFocus, onInteractOutside, onFocusOutside, forceMount, ...props }, ref) { | ||
| const ctx = useSheetContext("Content"); | ||
| const direction = React.useContext(DirectionContext); | ||
| const snapPointsActive = hasMultipleSnapPoints(ctx.detents); | ||
| return jsx(Content$1, { | ||
| ...props, | ||
| ref, | ||
| "data-vaul-drawer": "", | ||
| "data-vaul-drawer-direction": direction, | ||
| "data-vaul-snap-points": snapPointsActive ? "true" : "false" | ||
| }); | ||
| }); | ||
| function composeHandleClick(preventCycle, onClick) { | ||
| return (event) => { | ||
| onClick?.(event); | ||
| if (preventCycle) event.preventDefault(); | ||
| }; | ||
| } | ||
| const Handle = React.forwardRef(function Handle({ preventCycle, onClick, ...props }, ref) { | ||
| const ctx = useSheetContext("Handle"); | ||
| return jsx(Handle$1, { | ||
| ...props, | ||
| ref, | ||
| "data-vaul-handle": "", | ||
| "data-vaul-drawer-visible": ctx.open ? "true" : "false", | ||
| onClick: composeHandleClick(preventCycle, onClick) | ||
| }); | ||
| }); | ||
| const DrawerClose = React.forwardRef(function DrawerClose({ children, ...props }, ref) { | ||
| return jsx(Close, { | ||
| ...props, | ||
| ref, | ||
| children: children ?? null | ||
| }); | ||
| }); | ||
| const Drawer = { | ||
| Root, | ||
| NestedRoot, | ||
| Trigger, | ||
| Portal, | ||
| Overlay, | ||
| Content, | ||
| Close: DrawerClose, | ||
| Title, | ||
| Description, | ||
| Handle | ||
| }; | ||
| //#endregion | ||
| export { NestedRoot as a, Root as c, hasMultipleSnapPoints as d, resolveCloseThreshold as f, Handle as i, composeHandleClick as l, Handle$1 as m, Drawer as n, Overlay as o, resolveFadeFromIndex as p, DrawerClose as r, Portal as s, Content as t, composeOpenChange as u }; |
Sorry, the diff of this file is too big to display
| "use client"; | ||
| import { c as Slot, d as useSheetContext, i as Content$1, n as Description, r as Title, s as Trigger, t as Close, u as Root$1 } from "./misc-VkdphfSa.mjs"; | ||
| import { h as warnOnce, t as cn } from "./cn-Cs7ZylHz.mjs"; | ||
| import * as React from "react"; | ||
| import { Fragment, jsx } from "react/jsx-runtime"; | ||
| import { createPortal } from "react-dom"; | ||
| //#region packages/scrollsheet/src/handle.tsx | ||
| function detentLabel(spec) { | ||
| if (spec === "full") return "Full"; | ||
| if (spec === "medium") return "Half"; | ||
| if (spec === "content") return "Fit content"; | ||
| if (typeof spec === "number") return `${Math.round(spec * 100)}%`; | ||
| return spec ?? ""; | ||
| } | ||
| const Handle$1 = React.forwardRef(function Handle({ asChild, onClick, onKeyDown, className, variant = "inside", ...props }, ref) { | ||
| const ctx = useSheetContext("Handle"); | ||
| const [mounted, setMounted] = React.useState(false); | ||
| React.useEffect(() => setMounted(true), []); | ||
| const outside = variant === "outside" && ctx.side === "bottom" && !(mounted && !ctx.canvasEl); | ||
| const variantAttr = outside ? "outside" : variant === "floating" ? "floating" : void 0; | ||
| const specs = ctx.detents; | ||
| const horizontal = ctx.side === "left" || ctx.side === "right"; | ||
| const multi = specs.length >= 2; | ||
| const activeIndex = specs.findIndex((s) => Object.is(s, ctx.activeDetent)); | ||
| const move = (delta) => { | ||
| if (!multi) return false; | ||
| const index = specs.findIndex((s) => Object.is(s, ctx.activeDetent)); | ||
| const next = specs[index + delta]; | ||
| if (next === void 0) return false; | ||
| ctx.setActiveDetent(next); | ||
| return true; | ||
| }; | ||
| const sliderAria = multi ? { | ||
| role: "slider", | ||
| "aria-orientation": horizontal ? "horizontal" : "vertical", | ||
| "aria-valuemin": 0, | ||
| "aria-valuemax": specs.length - 1, | ||
| ...activeIndex >= 0 ? { | ||
| "aria-valuenow": activeIndex, | ||
| "aria-valuetext": detentLabel(specs[activeIndex]) | ||
| } : {} | ||
| } : {}; | ||
| const button = jsx(asChild ? Slot : "button", { | ||
| ...asChild ? {} : { type: "button" }, | ||
| "aria-label": horizontal ? "Adjust sheet width" : "Adjust sheet height", | ||
| ...sliderAria, | ||
| ...props, | ||
| ref, | ||
| className: cn("scrollsheet-handle", className), | ||
| "data-scrollsheet-handle": true, | ||
| "data-scrollsheet-handle-variant": variantAttr, | ||
| onClick: (event) => { | ||
| onClick?.(event); | ||
| if (event.defaultPrevented) return; | ||
| if (!multi) return; | ||
| const index = specs.findIndex((s) => Object.is(s, ctx.activeDetent)); | ||
| const next = specs[(index + 1) % specs.length]; | ||
| if (next !== void 0) ctx.setActiveDetent(next); | ||
| }, | ||
| onKeyDown: (event) => { | ||
| onKeyDown?.(event); | ||
| if (event.defaultPrevented) return; | ||
| const expandKey = horizontal ? "ArrowRight" : "ArrowUp"; | ||
| const collapseKey = horizontal ? "ArrowLeft" : "ArrowDown"; | ||
| if (event.key === expandKey) { | ||
| event.preventDefault(); | ||
| move(1); | ||
| } else if (event.key === collapseKey) { | ||
| event.preventDefault(); | ||
| if (!move(-1) && ctx.dismissible) ctx.setOpen(false); | ||
| } else if (multi && event.key === "Home") { | ||
| event.preventDefault(); | ||
| const first = specs[0]; | ||
| if (first !== void 0) ctx.setActiveDetent(first); | ||
| } else if (multi && event.key === "End") { | ||
| event.preventDefault(); | ||
| const last = specs[specs.length - 1]; | ||
| if (last !== void 0) ctx.setActiveDetent(last); | ||
| } | ||
| } | ||
| }); | ||
| if (outside) return ctx.canvasEl ? createPortal(button, ctx.canvasEl) : null; | ||
| return button; | ||
| }); | ||
| //#endregion | ||
| //#region packages/scrollsheet/src/drawer/index.tsx | ||
| const wrapperClaims = new Map(); | ||
| const VAUL_CLOSE_THRESHOLD = .25; | ||
| const collectIgnored = (entries) => entries.filter(([, v]) => v !== void 0).map(([k]) => k); | ||
| function toDetentSpec(point) { | ||
| if (typeof point === "number") return point; | ||
| if (point === "fit-content" || point === "content") return "content"; | ||
| if (/^\d+(\.\d+)?px$/.test(point)) return `${Number.parseFloat(point)}px`; | ||
| const parsed = Number.parseFloat(point); | ||
| return Number.isFinite(parsed) ? parsed : "content"; | ||
| } | ||
| function resolveFadeFromIndex(snapPoints, fadeFromIndex) { | ||
| if (!snapPoints || snapPoints.length === 0) return void 0; | ||
| const point = snapPoints[fadeFromIndex ?? snapPoints.length - 1]; | ||
| return point !== void 0 ? toDetentSpec(point) : void 0; | ||
| } | ||
| function resolveCloseThreshold(snapPoints, closeThreshold) { | ||
| if (snapPoints !== void 0 && snapPoints.length > 0) return void 0; | ||
| return Math.min(1, Math.max(0, 1 - (closeThreshold ?? VAUL_CLOSE_THRESHOLD))); | ||
| } | ||
| function composeOpenChange(onOpenChange, onClose) { | ||
| if (!onOpenChange && !onClose) return void 0; | ||
| return (next) => { | ||
| if (!next) onClose?.(); | ||
| onOpenChange?.(next); | ||
| }; | ||
| } | ||
| function Root(props) { | ||
| const { children, open, defaultOpen, onOpenChange, onClose, dismissible, snapPoints, activeSnapPoint, setActiveSnapPoint, onAnimationEnd, autoFocus, nested, direction, modal, shouldScaleBackground, setBackgroundColorOnScale, noBodyStyles, disablePreventScroll, preventScrollRestoration, repositionInputs, scrollLockTimeout, closeThreshold, fadeFromIndex, snapToSequentialPoint, handleOnly, onDrag, onRelease, container, fixed, actionsRef, backdropDismissible, escapeDismissible, keyboardExpands, onTravel, scrollbar } = props; | ||
| { | ||
| const ignored = collectIgnored([ | ||
| ["setBackgroundColorOnScale", setBackgroundColorOnScale], | ||
| ["noBodyStyles", noBodyStyles], | ||
| ["disablePreventScroll", disablePreventScroll], | ||
| ["preventScrollRestoration", preventScrollRestoration], | ||
| ["repositionInputs", repositionInputs], | ||
| ["scrollLockTimeout", scrollLockTimeout], | ||
| ["onDrag", onDrag], | ||
| ["container", container], | ||
| ["fixed", fixed], | ||
| ["autoFocus", autoFocus], | ||
| ["nested", nested] | ||
| ]); | ||
| if (ignored.length > 0) warnOnce("root-ignored-props", `[scrollsheet Drawer] These <Drawer.Root> props from vaul have no effect in this compat layer and are ignored: ${ignored.join(", ")}. See the vaul migration notes in the README.${onDrag !== void 0 ? " onDrag: the native onTravel prop works on this same <Drawer.Root>." : ""}`); | ||
| } | ||
| const detents = snapPoints && snapPoints.length > 0 ? snapPoints.map(toDetentSpec) : void 0; | ||
| const activeDetent = activeSnapPoint != null ? toDetentSpec(activeSnapPoint) : void 0; | ||
| const largestUndimmedDetent = resolveFadeFromIndex(snapPoints, fadeFromIndex); | ||
| const resolvedCloseThreshold = resolveCloseThreshold(snapPoints, closeThreshold); | ||
| if (snapPoints !== void 0 && snapPoints.length > 0 && closeThreshold !== void 0) warnOnce("close-threshold-with-snap-points", "[scrollsheet Drawer] <Drawer.Root closeThreshold> has no effect when snapPoints is set — this matches real vaul, where closeThreshold is dead code once snapPoints exist (its onRelease returns through the snap-points branch before ever reading it). Use the native Sheet.Root `closeThreshold` (a live 0-1 fraction of the first detent, works alongside detents) if you want the upgrade."); | ||
| const handleRelease = onRelease ? (event, willRemainOpen) => onRelease(event, willRemainOpen) : void 0; | ||
| const handleOpenChange = composeOpenChange(onOpenChange, onClose); | ||
| const handleActiveDetentChange = (detent) => { | ||
| if (!setActiveSnapPoint) return; | ||
| const match = snapPoints?.find((point) => Object.is(toDetentSpec(point), detent)); | ||
| setActiveSnapPoint(match ?? detent); | ||
| }; | ||
| React.useEffect(() => { | ||
| if (!shouldScaleBackground) return; | ||
| const existing = document.querySelector("[data-scrollsheet-background]"); | ||
| if (existing && !wrapperClaims.has(existing)) return; | ||
| const wrapper = existing ?? document.querySelector("[data-vaul-drawer-wrapper]"); | ||
| if (!wrapper) return; | ||
| const count = wrapperClaims.get(wrapper) ?? 0; | ||
| wrapperClaims.set(wrapper, count + 1); | ||
| if (count === 0) wrapper.setAttribute("data-scrollsheet-background", ""); | ||
| return () => { | ||
| const remaining = (wrapperClaims.get(wrapper) ?? 1) - 1; | ||
| if (remaining <= 0) { | ||
| wrapperClaims.delete(wrapper); | ||
| wrapper.removeAttribute("data-scrollsheet-background"); | ||
| } else wrapperClaims.set(wrapper, remaining); | ||
| }; | ||
| }, [shouldScaleBackground]); | ||
| return jsx(DirectionContext.Provider, { | ||
| value: direction ?? "bottom", | ||
| children: jsx(Root$1, { | ||
| open, | ||
| defaultOpen, | ||
| onOpenChange: handleOpenChange, | ||
| onOpenChangeComplete: onAnimationEnd, | ||
| dismissible, | ||
| detents, | ||
| activeDetent, | ||
| onActiveDetentChange: setActiveSnapPoint ? handleActiveDetentChange : void 0, | ||
| side: direction, | ||
| modal, | ||
| backgroundEffect: shouldScaleBackground ? "scale" : "none", | ||
| largestUndimmedDetent, | ||
| handleOnly, | ||
| sequentialDetents: snapToSequentialPoint, | ||
| closeThreshold: resolvedCloseThreshold, | ||
| onRelease: handleRelease, | ||
| actionsRef, | ||
| backdropDismissible, | ||
| escapeDismissible, | ||
| keyboardExpands, | ||
| onTravel, | ||
| scrollbar, | ||
| children | ||
| }) | ||
| }); | ||
| } | ||
| const DirectionContext = React.createContext("bottom"); | ||
| const NestedRoot = Root; | ||
| function Portal({ children, container }) { | ||
| if (container !== void 0) warnOnce("portal-container", "[scrollsheet Drawer] <Drawer.Portal container> has no effect — scrollsheet's <dialog> always renders into the browser's top layer (effectively document.body), so there's no separate container to portal into."); | ||
| return jsx(Fragment, { children }); | ||
| } | ||
| function Overlay(_props) { | ||
| return null; | ||
| } | ||
| function hasMultipleSnapPoints(detents) { | ||
| return detents.length > 1; | ||
| } | ||
| const Content = React.forwardRef(function Content({ onPointerDownOutside, onOpenAutoFocus, onEscapeKeyDown, onCloseAutoFocus, onInteractOutside, onFocusOutside, forceMount, ...props }, ref) { | ||
| const ctx = useSheetContext("Content"); | ||
| const direction = React.useContext(DirectionContext); | ||
| const snapPointsActive = hasMultipleSnapPoints(ctx.detents); | ||
| { | ||
| const ignored = collectIgnored([ | ||
| ["onPointerDownOutside", onPointerDownOutside], | ||
| ["onOpenAutoFocus", onOpenAutoFocus], | ||
| ["onEscapeKeyDown", onEscapeKeyDown], | ||
| ["onCloseAutoFocus", onCloseAutoFocus], | ||
| ["onInteractOutside", onInteractOutside], | ||
| ["onFocusOutside", onFocusOutside], | ||
| ["forceMount", forceMount] | ||
| ]); | ||
| if (ignored.length > 0) warnOnce("content-ignored-props", `[scrollsheet Drawer] These <Drawer.Content> props from vaul have no effect in this compat layer and are stripped before reaching the DOM: ${ignored.join(", ")}. See the vaul migration notes in the README.${onPointerDownOutside !== void 0 || onInteractOutside !== void 0 || onEscapeKeyDown !== void 0 ? " To block backdrop-tap dismissal, set backdropDismissible={false} on <Drawer.Root>; to block Esc, escapeDismissible={false}." : ""}`); | ||
| } | ||
| return jsx(Content$1, { | ||
| ...props, | ||
| ref, | ||
| "data-vaul-drawer": "", | ||
| "data-vaul-drawer-direction": direction, | ||
| "data-vaul-snap-points": snapPointsActive ? "true" : "false" | ||
| }); | ||
| }); | ||
| function composeHandleClick(preventCycle, onClick) { | ||
| return (event) => { | ||
| onClick?.(event); | ||
| if (preventCycle) event.preventDefault(); | ||
| }; | ||
| } | ||
| const Handle = React.forwardRef(function Handle({ preventCycle, onClick, ...props }, ref) { | ||
| const ctx = useSheetContext("Handle"); | ||
| return jsx(Handle$1, { | ||
| ...props, | ||
| ref, | ||
| "data-vaul-handle": "", | ||
| "data-vaul-drawer-visible": ctx.open ? "true" : "false", | ||
| onClick: composeHandleClick(preventCycle, onClick) | ||
| }); | ||
| }); | ||
| const DrawerClose = React.forwardRef(function DrawerClose({ children, ...props }, ref) { | ||
| return jsx(Close, { | ||
| ...props, | ||
| ref, | ||
| children: children ?? null | ||
| }); | ||
| }); | ||
| const Drawer = { | ||
| Root, | ||
| NestedRoot, | ||
| Trigger, | ||
| Portal, | ||
| Overlay, | ||
| Content, | ||
| Close: DrawerClose, | ||
| Title, | ||
| Description, | ||
| Handle | ||
| }; | ||
| //#endregion | ||
| export { NestedRoot as a, Root as c, hasMultipleSnapPoints as d, resolveCloseThreshold as f, Handle as i, composeHandleClick as l, Handle$1 as m, Drawer as n, Overlay as o, resolveFadeFromIndex as p, DrawerClose as r, Portal as s, Content as t, composeOpenChange as u }; |
Sorry, the diff of this file is too big to display
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
874422
0.46%18118
0.04%1
-50%152
7.8%0
-100%