import * as i0 from '@angular/core'; import { OnInit, OnDestroy, EventEmitter } from '@angular/core'; /** * A viewport-anchored bottom sheet — the mobile presentation shared by the modal * shell and the multi-select dropdown. * * It owns only the sheet *chrome and gestures*: a bottom-anchored, full-width, * rounded-top surface with an optional dimming backdrop and drag grabber, a * slide-up entrance, swipe/flick-to-dismiss, and a promise-based slide-down exit. * It is deliberately presentational: the body is projected via ``, and * dismissal is reported through {@link dismiss} for the host to act on (run a close * guard, tear down its overlay, …) rather than being handled here. * * Positioning is `position: fixed` against the viewport, so the host relocates itself * to `document.body` on init and blocks scrolling behind it while open. Both are * unconditional: rendering viewport-fixed chrome in place made correctness depend on * where a consumer happened to write the tag. A `transform`/`filter`/`contain` * ancestor becomes the containing block and pushes the sheet to the middle of the * screen — which a *stacked* modal did to its own sheet — and, because `position: * fixed` moves where an element paints but not where it sits in the DOM, a gesture on * the backdrop still scrolled whichever ancestor was the scroll container. * * The multi-select and dropdown used to do the relocating themselves; that is why the * behaviour reads as new here but is not new to them. */ declare class MnBottomSheet implements OnInit, OnDestroy { /** Tailwind's `sm` breakpoint — at or below this the swipe gesture is armed. * Kept in step with the same constant in the modal shell and multi-select. */ private static readonly SHEET_MAX_WIDTH; /** Drag distance (px) past which a release dismisses regardless of speed. */ private static readonly SWIPE_DISMISS_THRESHOLD; /** Downward release speed (px/ms) above which a short drag still dismisses — a "flick". */ private static readonly FLICK_VELOCITY; /** Minimum drag distance (px) a flick must cover, so an incidental fast tap never dismisses. */ private static readonly FLICK_MIN_DISTANCE; /** Upper bound for the exit wait if no `transitionend` fires (e.g. animation suppressed). */ private static readonly CLOSE_FALLBACK_MS; /** Whether to render the dimming backdrop behind the sheet (default: true). * A host that already paints its own backdrop (the modal shell) sets this false. */ showBackdrop: boolean; /** Whether to render the drag grabber handle that arms swipe-to-dismiss (default: true). */ showGrabber: boolean; /** Whether the sheet can be dismissed by the user via swipe/flick or backdrop tap * (default: true). When false the gestures are inert and the backdrop is non-closing. */ dismissible: boolean; /** Optional `min-height` floor (px) for the container, so filtering its content * shorter cannot shrink the sheet mid-interaction. Null leaves it content-sized. */ minHeightPx: number | null; /** Cap on the sheet height as a fraction of the viewport, in vh (default: 80). */ maxHeightVh: number; /** Extra class(es) applied to the sheet container, so a host can attach the hooks * its own CSS depends on (e.g. the modal shell's `modal-container`). */ containerClass: string; /** Accessible name for the sheet dialog. */ ariaLabel?: string; /** Id of the element that labels this dialog (takes precedence over `ariaLabel`). */ ariaLabelledby?: string; /** * When true, the sheet grows to its `maxHeightVh` while the host app marks the soft * keyboard open (a `.mn-keyboard-open` class on a document ancestor), guaranteeing * scroll room to lift a focused field above an overlaying keyboard. Off by default so * a keyboard opened over an unrelated sheet (a multi-select search) does not resize it. */ growWithKeyboard: boolean; /** * Optional async gate consulted before a user-initiated dismissal (swipe/flick/backdrop * tap) is committed. Resolving false aborts the dismissal and springs the sheet back — * used by the modal to run its close guard (e.g. an unsaved-changes prompt). A * programmatic {@link startClosing} bypasses it. */ dismissGuard?: () => boolean | Promise; /** * Emitted once the user has dismissed the sheet — after the slide-down exit has * finished, so the host can remove the sheet from the DOM without cutting the * animation short. The host decides what dismissal means (close, run a guard, …). */ dismiss: EventEmitter; /** Current downward drag offset (px) applied to the sheet while swiping. */ sheetDragY: number; /** True while the user is actively dragging the grabber (disables the snap transition). */ isDraggingSheet: boolean; /** True once a dismissal has committed — the sheet glides off-screen via its transition. */ isDismissing: boolean; private readonly cdr; private readonly el; /** The sheet container element, used to measure its height and drive the exit. */ private readonly containerRef; private dragStartY; /** The two most recent (y, timestamp) pointer samples, for estimating flick velocity. * `t` uses the event timestamp (monotonic), so no wall-clock is read. */ private lastSample; private prevSample; /** In-flight exit animation, so a swipe-dismiss and a follow-up programmatic * {@link startClosing} share one glide instead of re-triggering it. */ private exitPromise; /** The host node once moved to `document.body`, so it is only detached if we moved it. */ private portalledHost; /** Blocks scroll gestures aimed at anything behind the sheet, while it is open. */ private scrollGuard; /** Moves the host out to `document.body` and stops the page behind scrolling. */ ngOnInit(): void; /** * Stops pointer scrolling behind the sheet for as long as it is open. * * Cancels the gesture rather than setting `overflow: hidden` on `document.body`: an * app whose scroll container is a layout element (a `
`, a drawer body) leaves * `body` unscrollable, so locking it there is a no-op and the page still slides about * under the sheet. Cancelling `wheel` and `touchmove` before anything acts on them * holds regardless of which element does the scrolling. * * Gestures that begin inside the sheet are let through so its own content still * scrolls; `overscroll-behavior: contain` keeps those from chaining out at the ends. * * Pointer input only. Page Down and the arrows still reach the page behind when focus * is left there — closing that needs either a key filter or moving focus into the * sheet, and neither belongs in this change. */ private lockScroll; /** Releases the scroll guard. Idempotent. */ private unlockScroll; /** * Detaches the relocated host. * * Angular tears a view down by removing the nodes it created from their parent; a * host we moved to `body` is no longer among the parent's children, so without * this the sheet would outlive the view that declared it. */ ngOnDestroy(): void; get hostClasses(): string; /** Whether the viewport is currently narrow enough for the sheet to accept a swipe. */ private get isNarrow(); onSheetPointerDown(event: PointerEvent): void; onSheetPointerMove(event: PointerEvent): void; onSheetPointerUp(): void; onBackdropClick(): void; /** * Plays the slide-down exit and resolves once it has finished. Exposed so a host that * dismisses the sheet programmatically (not via a gesture) can await the same exit * before tearing the sheet down. Idempotent: a swipe-dismiss already in flight and a * subsequent programmatic close share the one glide rather than restarting it. */ startClosing(): Promise; /** * Runs the optional {@link dismissGuard}, then either commits the dismissal (glide out * + emit) or springs the sheet back if the guard rejects. A non-dismissible sheet never * gets here from a gesture, but the guard is still short-circuited defensively. */ private attemptDismiss; /** Whether the release should dismiss: a long-enough drag OR a fast downward flick. */ private shouldDismiss; /** Downward release speed (px/ms) from the last two pointer samples; 0 when unusable. */ private releaseVelocity; /** Springs the sheet back to its resting position after a drag that didn't dismiss. */ private snapBack; /** * Commits a dismissal: glides the sheet the rest of the way off-screen, then emits * {@link dismiss} once the exit animation settles. Continuing the gesture (rather than * snapping back to 0 first) keeps a swipe feeling like one unbroken motion. */ private commitDismiss; /** Commits the exit animation exactly once and returns the shared in-flight promise. * Short-circuits under reduced motion and falls back to a timeout if no event fires. */ private playExit; /** Waits for the container's exit transition to end, with a reduced-motion short-circuit * and a fallback timeout so it always resolves. */ private awaitExit; private prefersReducedMotion; static ɵfac: i0.ɵɵFactoryDeclaration; static ɵcmp: i0.ɵɵComponentDeclaration; } export { MnBottomSheet };