123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639 |
- import { normalizePassiveListenerOptions, _getEventTarget, Platform } from '@angular/cdk/platform';
- import * as i0 from '@angular/core';
- import { Component, ChangeDetectionStrategy, ViewEncapsulation, InjectionToken, inject, ElementRef, ANIMATION_MODULE_TYPE, NgZone, Injector, Directive, Input } from '@angular/core';
- import { isFakeMousedownFromScreenReader, isFakeTouchstartFromScreenReader } from '@angular/cdk/a11y';
- import { coerceElement } from '@angular/cdk/coercion';
- import { _CdkPrivateStyleLoader } from '@angular/cdk/private';
- /** Possible states for a ripple element. */
- var RippleState;
- (function (RippleState) {
- RippleState[RippleState["FADING_IN"] = 0] = "FADING_IN";
- RippleState[RippleState["VISIBLE"] = 1] = "VISIBLE";
- RippleState[RippleState["FADING_OUT"] = 2] = "FADING_OUT";
- RippleState[RippleState["HIDDEN"] = 3] = "HIDDEN";
- })(RippleState || (RippleState = {}));
- /**
- * Reference to a previously launched ripple element.
- */
- class RippleRef {
- _renderer;
- element;
- config;
- _animationForciblyDisabledThroughCss;
- /** Current state of the ripple. */
- state = RippleState.HIDDEN;
- constructor(_renderer,
- /** Reference to the ripple HTML element. */
- element,
- /** Ripple configuration used for the ripple. */
- config,
- /* Whether animations are forcibly disabled for ripples through CSS. */
- _animationForciblyDisabledThroughCss = false) {
- this._renderer = _renderer;
- this.element = element;
- this.config = config;
- this._animationForciblyDisabledThroughCss = _animationForciblyDisabledThroughCss;
- }
- /** Fades out the ripple element. */
- fadeOut() {
- this._renderer.fadeOutRipple(this);
- }
- }
- /** Options used to bind a passive capturing event. */
- const passiveCapturingEventOptions$1 = normalizePassiveListenerOptions({
- passive: true,
- capture: true,
- });
- /** Manages events through delegation so that as few event handlers as possible are bound. */
- class RippleEventManager {
- _events = new Map();
- /** Adds an event handler. */
- addHandler(ngZone, name, element, handler) {
- const handlersForEvent = this._events.get(name);
- if (handlersForEvent) {
- const handlersForElement = handlersForEvent.get(element);
- if (handlersForElement) {
- handlersForElement.add(handler);
- }
- else {
- handlersForEvent.set(element, new Set([handler]));
- }
- }
- else {
- this._events.set(name, new Map([[element, new Set([handler])]]));
- ngZone.runOutsideAngular(() => {
- document.addEventListener(name, this._delegateEventHandler, passiveCapturingEventOptions$1);
- });
- }
- }
- /** Removes an event handler. */
- removeHandler(name, element, handler) {
- const handlersForEvent = this._events.get(name);
- if (!handlersForEvent) {
- return;
- }
- const handlersForElement = handlersForEvent.get(element);
- if (!handlersForElement) {
- return;
- }
- handlersForElement.delete(handler);
- if (handlersForElement.size === 0) {
- handlersForEvent.delete(element);
- }
- if (handlersForEvent.size === 0) {
- this._events.delete(name);
- document.removeEventListener(name, this._delegateEventHandler, passiveCapturingEventOptions$1);
- }
- }
- /** Event handler that is bound and which dispatches the events to the different targets. */
- _delegateEventHandler = (event) => {
- const target = _getEventTarget(event);
- if (target) {
- this._events.get(event.type)?.forEach((handlers, element) => {
- if (element === target || element.contains(target)) {
- handlers.forEach(handler => handler.handleEvent(event));
- }
- });
- }
- };
- }
- /**
- * Default ripple animation configuration for ripples without an explicit
- * animation config specified.
- */
- const defaultRippleAnimationConfig = {
- enterDuration: 225,
- exitDuration: 150,
- };
- /**
- * Timeout for ignoring mouse events. Mouse events will be temporary ignored after touch
- * events to avoid synthetic mouse events.
- */
- const ignoreMouseEventsTimeout = 800;
- /** Options used to bind a passive capturing event. */
- const passiveCapturingEventOptions = normalizePassiveListenerOptions({
- passive: true,
- capture: true,
- });
- /** Events that signal that the pointer is down. */
- const pointerDownEvents = ['mousedown', 'touchstart'];
- /** Events that signal that the pointer is up. */
- const pointerUpEvents = ['mouseup', 'mouseleave', 'touchend', 'touchcancel'];
- class _MatRippleStylesLoader {
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: _MatRippleStylesLoader, deps: [], target: i0.ɵɵFactoryTarget.Component });
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.6", type: _MatRippleStylesLoader, isStandalone: true, selector: "ng-component", host: { attributes: { "mat-ripple-style-loader": "" } }, ngImport: i0, template: '', isInline: true, styles: [".mat-ripple{overflow:hidden;position:relative}.mat-ripple:not(:empty){transform:translateZ(0)}.mat-ripple.mat-ripple-unbounded{overflow:visible}.mat-ripple-element{position:absolute;border-radius:50%;pointer-events:none;transition:opacity,transform 0ms cubic-bezier(0, 0, 0.2, 1);transform:scale3d(0, 0, 0);background-color:var(--mat-ripple-color, color-mix(in srgb, var(--mat-sys-on-surface) 10%, transparent))}@media(forced-colors: active){.mat-ripple-element{display:none}}.cdk-drag-preview .mat-ripple-element,.cdk-drag-placeholder .mat-ripple-element{display:none}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
- }
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: _MatRippleStylesLoader, decorators: [{
- type: Component,
- args: [{ template: '', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: { 'mat-ripple-style-loader': '' }, styles: [".mat-ripple{overflow:hidden;position:relative}.mat-ripple:not(:empty){transform:translateZ(0)}.mat-ripple.mat-ripple-unbounded{overflow:visible}.mat-ripple-element{position:absolute;border-radius:50%;pointer-events:none;transition:opacity,transform 0ms cubic-bezier(0, 0, 0.2, 1);transform:scale3d(0, 0, 0);background-color:var(--mat-ripple-color, color-mix(in srgb, var(--mat-sys-on-surface) 10%, transparent))}@media(forced-colors: active){.mat-ripple-element{display:none}}.cdk-drag-preview .mat-ripple-element,.cdk-drag-placeholder .mat-ripple-element{display:none}\n"] }]
- }] });
- /**
- * Helper service that performs DOM manipulations. Not intended to be used outside this module.
- * The constructor takes a reference to the ripple directive's host element and a map of DOM
- * event handlers to be installed on the element that triggers ripple animations.
- * This will eventually become a custom renderer once Angular support exists.
- * @docs-private
- */
- class RippleRenderer {
- _target;
- _ngZone;
- _platform;
- /** Element where the ripples are being added to. */
- _containerElement;
- /** Element which triggers the ripple elements on mouse events. */
- _triggerElement;
- /** Whether the pointer is currently down or not. */
- _isPointerDown = false;
- /**
- * Map of currently active ripple references.
- * The ripple reference is mapped to its element event listeners.
- * The reason why `| null` is used is that event listeners are added only
- * when the condition is truthy (see the `_startFadeOutTransition` method).
- */
- _activeRipples = new Map();
- /** Latest non-persistent ripple that was triggered. */
- _mostRecentTransientRipple;
- /** Time in milliseconds when the last touchstart event happened. */
- _lastTouchStartEvent;
- /** Whether pointer-up event listeners have been registered. */
- _pointerUpEventsRegistered = false;
- /**
- * Cached dimensions of the ripple container. Set when the first
- * ripple is shown and cleared once no more ripples are visible.
- */
- _containerRect;
- static _eventManager = new RippleEventManager();
- constructor(_target, _ngZone, elementOrElementRef, _platform, injector) {
- this._target = _target;
- this._ngZone = _ngZone;
- this._platform = _platform;
- // Only do anything if we're on the browser.
- if (_platform.isBrowser) {
- this._containerElement = coerceElement(elementOrElementRef);
- }
- if (injector) {
- injector.get(_CdkPrivateStyleLoader).load(_MatRippleStylesLoader);
- }
- }
- /**
- * Fades in a ripple at the given coordinates.
- * @param x Coordinate within the element, along the X axis at which to start the ripple.
- * @param y Coordinate within the element, along the Y axis at which to start the ripple.
- * @param config Extra ripple options.
- */
- fadeInRipple(x, y, config = {}) {
- const containerRect = (this._containerRect =
- this._containerRect || this._containerElement.getBoundingClientRect());
- const animationConfig = { ...defaultRippleAnimationConfig, ...config.animation };
- if (config.centered) {
- x = containerRect.left + containerRect.width / 2;
- y = containerRect.top + containerRect.height / 2;
- }
- const radius = config.radius || distanceToFurthestCorner(x, y, containerRect);
- const offsetX = x - containerRect.left;
- const offsetY = y - containerRect.top;
- const enterDuration = animationConfig.enterDuration;
- const ripple = document.createElement('div');
- ripple.classList.add('mat-ripple-element');
- ripple.style.left = `${offsetX - radius}px`;
- ripple.style.top = `${offsetY - radius}px`;
- ripple.style.height = `${radius * 2}px`;
- ripple.style.width = `${radius * 2}px`;
- // If a custom color has been specified, set it as inline style. If no color is
- // set, the default color will be applied through the ripple theme styles.
- if (config.color != null) {
- ripple.style.backgroundColor = config.color;
- }
- ripple.style.transitionDuration = `${enterDuration}ms`;
- this._containerElement.appendChild(ripple);
- // By default the browser does not recalculate the styles of dynamically created
- // ripple elements. This is critical to ensure that the `scale` animates properly.
- // We enforce a style recalculation by calling `getComputedStyle` and *accessing* a property.
- // See: https://gist.github.com/paulirish/5d52fb081b3570c81e3a
- const computedStyles = window.getComputedStyle(ripple);
- const userTransitionProperty = computedStyles.transitionProperty;
- const userTransitionDuration = computedStyles.transitionDuration;
- // Note: We detect whether animation is forcibly disabled through CSS (e.g. through
- // `transition: none` or `display: none`). This is technically unexpected since animations are
- // controlled through the animation config, but this exists for backwards compatibility. This
- // logic does not need to be super accurate since it covers some edge cases which can be easily
- // avoided by users.
- const animationForciblyDisabledThroughCss = userTransitionProperty === 'none' ||
- // Note: The canonical unit for serialized CSS `<time>` properties is seconds. Additionally
- // some browsers expand the duration for every property (in our case `opacity` and `transform`).
- userTransitionDuration === '0s' ||
- userTransitionDuration === '0s, 0s' ||
- // If the container is 0x0, it's likely `display: none`.
- (containerRect.width === 0 && containerRect.height === 0);
- // Exposed reference to the ripple that will be returned.
- const rippleRef = new RippleRef(this, ripple, config, animationForciblyDisabledThroughCss);
- // Start the enter animation by setting the transform/scale to 100%. The animation will
- // execute as part of this statement because we forced a style recalculation before.
- // Note: We use a 3d transform here in order to avoid an issue in Safari where
- // the ripples aren't clipped when inside the shadow DOM (see #24028).
- ripple.style.transform = 'scale3d(1, 1, 1)';
- rippleRef.state = RippleState.FADING_IN;
- if (!config.persistent) {
- this._mostRecentTransientRipple = rippleRef;
- }
- let eventListeners = null;
- // Do not register the `transition` event listener if fade-in and fade-out duration
- // are set to zero. The events won't fire anyway and we can save resources here.
- if (!animationForciblyDisabledThroughCss && (enterDuration || animationConfig.exitDuration)) {
- this._ngZone.runOutsideAngular(() => {
- const onTransitionEnd = () => {
- // Clear the fallback timer since the transition fired correctly.
- if (eventListeners) {
- eventListeners.fallbackTimer = null;
- }
- clearTimeout(fallbackTimer);
- this._finishRippleTransition(rippleRef);
- };
- const onTransitionCancel = () => this._destroyRipple(rippleRef);
- // In some cases where there's a higher load on the browser, it can choose not to dispatch
- // neither `transitionend` nor `transitioncancel` (see b/227356674). This timer serves as a
- // fallback for such cases so that the ripple doesn't become stuck. We add a 100ms buffer
- // because timers aren't precise. Note that another approach can be to transition the ripple
- // to the `VISIBLE` state immediately above and to `FADING_IN` afterwards inside
- // `transitionstart`. We go with the timer because it's one less event listener and
- // it's less likely to break existing tests.
- const fallbackTimer = setTimeout(onTransitionCancel, enterDuration + 100);
- ripple.addEventListener('transitionend', onTransitionEnd);
- // If the transition is cancelled (e.g. due to DOM removal), we destroy the ripple
- // directly as otherwise we would keep it part of the ripple container forever.
- // https://www.w3.org/TR/css-transitions-1/#:~:text=no%20longer%20in%20the%20document.
- ripple.addEventListener('transitioncancel', onTransitionCancel);
- eventListeners = { onTransitionEnd, onTransitionCancel, fallbackTimer };
- });
- }
- // Add the ripple reference to the list of all active ripples.
- this._activeRipples.set(rippleRef, eventListeners);
- // In case there is no fade-in transition duration, we need to manually call the transition
- // end listener because `transitionend` doesn't fire if there is no transition.
- if (animationForciblyDisabledThroughCss || !enterDuration) {
- this._finishRippleTransition(rippleRef);
- }
- return rippleRef;
- }
- /** Fades out a ripple reference. */
- fadeOutRipple(rippleRef) {
- // For ripples already fading out or hidden, this should be a noop.
- if (rippleRef.state === RippleState.FADING_OUT || rippleRef.state === RippleState.HIDDEN) {
- return;
- }
- const rippleEl = rippleRef.element;
- const animationConfig = { ...defaultRippleAnimationConfig, ...rippleRef.config.animation };
- // This starts the fade-out transition and will fire the transition end listener that
- // removes the ripple element from the DOM.
- rippleEl.style.transitionDuration = `${animationConfig.exitDuration}ms`;
- rippleEl.style.opacity = '0';
- rippleRef.state = RippleState.FADING_OUT;
- // In case there is no fade-out transition duration, we need to manually call the
- // transition end listener because `transitionend` doesn't fire if there is no transition.
- if (rippleRef._animationForciblyDisabledThroughCss || !animationConfig.exitDuration) {
- this._finishRippleTransition(rippleRef);
- }
- }
- /** Fades out all currently active ripples. */
- fadeOutAll() {
- this._getActiveRipples().forEach(ripple => ripple.fadeOut());
- }
- /** Fades out all currently active non-persistent ripples. */
- fadeOutAllNonPersistent() {
- this._getActiveRipples().forEach(ripple => {
- if (!ripple.config.persistent) {
- ripple.fadeOut();
- }
- });
- }
- /** Sets up the trigger event listeners */
- setupTriggerEvents(elementOrElementRef) {
- const element = coerceElement(elementOrElementRef);
- if (!this._platform.isBrowser || !element || element === this._triggerElement) {
- return;
- }
- // Remove all previously registered event listeners from the trigger element.
- this._removeTriggerEvents();
- this._triggerElement = element;
- // Use event delegation for the trigger events since they're
- // set up during creation and are performance-sensitive.
- pointerDownEvents.forEach(type => {
- RippleRenderer._eventManager.addHandler(this._ngZone, type, element, this);
- });
- }
- /**
- * Handles all registered events.
- * @docs-private
- */
- handleEvent(event) {
- if (event.type === 'mousedown') {
- this._onMousedown(event);
- }
- else if (event.type === 'touchstart') {
- this._onTouchStart(event);
- }
- else {
- this._onPointerUp();
- }
- // If pointer-up events haven't been registered yet, do so now.
- // We do this on-demand in order to reduce the total number of event listeners
- // registered by the ripples, which speeds up the rendering time for large UIs.
- if (!this._pointerUpEventsRegistered) {
- // The events for hiding the ripple are bound directly on the trigger, because:
- // 1. Some of them occur frequently (e.g. `mouseleave`) and any advantage we get from
- // delegation will be diminished by having to look through all the data structures often.
- // 2. They aren't as performance-sensitive, because they're bound only after the user
- // has interacted with an element.
- this._ngZone.runOutsideAngular(() => {
- pointerUpEvents.forEach(type => {
- this._triggerElement.addEventListener(type, this, passiveCapturingEventOptions);
- });
- });
- this._pointerUpEventsRegistered = true;
- }
- }
- /** Method that will be called if the fade-in or fade-in transition completed. */
- _finishRippleTransition(rippleRef) {
- if (rippleRef.state === RippleState.FADING_IN) {
- this._startFadeOutTransition(rippleRef);
- }
- else if (rippleRef.state === RippleState.FADING_OUT) {
- this._destroyRipple(rippleRef);
- }
- }
- /**
- * Starts the fade-out transition of the given ripple if it's not persistent and the pointer
- * is not held down anymore.
- */
- _startFadeOutTransition(rippleRef) {
- const isMostRecentTransientRipple = rippleRef === this._mostRecentTransientRipple;
- const { persistent } = rippleRef.config;
- rippleRef.state = RippleState.VISIBLE;
- // When the timer runs out while the user has kept their pointer down, we want to
- // keep only the persistent ripples and the latest transient ripple. We do this,
- // because we don't want stacked transient ripples to appear after their enter
- // animation has finished.
- if (!persistent && (!isMostRecentTransientRipple || !this._isPointerDown)) {
- rippleRef.fadeOut();
- }
- }
- /** Destroys the given ripple by removing it from the DOM and updating its state. */
- _destroyRipple(rippleRef) {
- const eventListeners = this._activeRipples.get(rippleRef) ?? null;
- this._activeRipples.delete(rippleRef);
- // Clear out the cached bounding rect if we have no more ripples.
- if (!this._activeRipples.size) {
- this._containerRect = null;
- }
- // If the current ref is the most recent transient ripple, unset it
- // avoid memory leaks.
- if (rippleRef === this._mostRecentTransientRipple) {
- this._mostRecentTransientRipple = null;
- }
- rippleRef.state = RippleState.HIDDEN;
- if (eventListeners !== null) {
- rippleRef.element.removeEventListener('transitionend', eventListeners.onTransitionEnd);
- rippleRef.element.removeEventListener('transitioncancel', eventListeners.onTransitionCancel);
- if (eventListeners.fallbackTimer !== null) {
- clearTimeout(eventListeners.fallbackTimer);
- }
- }
- rippleRef.element.remove();
- }
- /** Function being called whenever the trigger is being pressed using mouse. */
- _onMousedown(event) {
- // Screen readers will fire fake mouse events for space/enter. Skip launching a
- // ripple in this case for consistency with the non-screen-reader experience.
- const isFakeMousedown = isFakeMousedownFromScreenReader(event);
- const isSyntheticEvent = this._lastTouchStartEvent &&
- Date.now() < this._lastTouchStartEvent + ignoreMouseEventsTimeout;
- if (!this._target.rippleDisabled && !isFakeMousedown && !isSyntheticEvent) {
- this._isPointerDown = true;
- this.fadeInRipple(event.clientX, event.clientY, this._target.rippleConfig);
- }
- }
- /** Function being called whenever the trigger is being pressed using touch. */
- _onTouchStart(event) {
- if (!this._target.rippleDisabled && !isFakeTouchstartFromScreenReader(event)) {
- // Some browsers fire mouse events after a `touchstart` event. Those synthetic mouse
- // events will launch a second ripple if we don't ignore mouse events for a specific
- // time after a touchstart event.
- this._lastTouchStartEvent = Date.now();
- this._isPointerDown = true;
- // Use `changedTouches` so we skip any touches where the user put
- // their finger down, but used another finger to tap the element again.
- const touches = event.changedTouches;
- // According to the typings the touches should always be defined, but in some cases
- // the browser appears to not assign them in tests which leads to flakes.
- if (touches) {
- for (let i = 0; i < touches.length; i++) {
- this.fadeInRipple(touches[i].clientX, touches[i].clientY, this._target.rippleConfig);
- }
- }
- }
- }
- /** Function being called whenever the trigger is being released. */
- _onPointerUp() {
- if (!this._isPointerDown) {
- return;
- }
- this._isPointerDown = false;
- // Fade-out all ripples that are visible and not persistent.
- this._getActiveRipples().forEach(ripple => {
- // By default, only ripples that are completely visible will fade out on pointer release.
- // If the `terminateOnPointerUp` option is set, ripples that still fade in will also fade out.
- const isVisible = ripple.state === RippleState.VISIBLE ||
- (ripple.config.terminateOnPointerUp && ripple.state === RippleState.FADING_IN);
- if (!ripple.config.persistent && isVisible) {
- ripple.fadeOut();
- }
- });
- }
- _getActiveRipples() {
- return Array.from(this._activeRipples.keys());
- }
- /** Removes previously registered event listeners from the trigger element. */
- _removeTriggerEvents() {
- const trigger = this._triggerElement;
- if (trigger) {
- pointerDownEvents.forEach(type => RippleRenderer._eventManager.removeHandler(type, trigger, this));
- if (this._pointerUpEventsRegistered) {
- pointerUpEvents.forEach(type => trigger.removeEventListener(type, this, passiveCapturingEventOptions));
- this._pointerUpEventsRegistered = false;
- }
- }
- }
- }
- /**
- * Returns the distance from the point (x, y) to the furthest corner of a rectangle.
- */
- function distanceToFurthestCorner(x, y, rect) {
- const distX = Math.max(Math.abs(x - rect.left), Math.abs(x - rect.right));
- const distY = Math.max(Math.abs(y - rect.top), Math.abs(y - rect.bottom));
- return Math.sqrt(distX * distX + distY * distY);
- }
- /** Injection token that can be used to specify the global ripple options. */
- const MAT_RIPPLE_GLOBAL_OPTIONS = new InjectionToken('mat-ripple-global-options');
- class MatRipple {
- _elementRef = inject(ElementRef);
- _animationMode = inject(ANIMATION_MODULE_TYPE, { optional: true });
- /** Custom color for all ripples. */
- color;
- /** Whether the ripples should be visible outside the component's bounds. */
- unbounded;
- /**
- * Whether the ripple always originates from the center of the host element's bounds, rather
- * than originating from the location of the click event.
- */
- centered;
- /**
- * If set, the radius in pixels of foreground ripples when fully expanded. If unset, the radius
- * will be the distance from the center of the ripple to the furthest corner of the host element's
- * bounding rectangle.
- */
- radius = 0;
- /**
- * Configuration for the ripple animation. Allows modifying the enter and exit animation
- * duration of the ripples. The animation durations will be overwritten if the
- * `NoopAnimationsModule` is being used.
- */
- animation;
- /**
- * Whether click events will not trigger the ripple. Ripples can be still launched manually
- * by using the `launch()` method.
- */
- get disabled() {
- return this._disabled;
- }
- set disabled(value) {
- if (value) {
- this.fadeOutAllNonPersistent();
- }
- this._disabled = value;
- this._setupTriggerEventsIfEnabled();
- }
- _disabled = false;
- /**
- * The element that triggers the ripple when click events are received.
- * Defaults to the directive's host element.
- */
- get trigger() {
- return this._trigger || this._elementRef.nativeElement;
- }
- set trigger(trigger) {
- this._trigger = trigger;
- this._setupTriggerEventsIfEnabled();
- }
- _trigger;
- /** Renderer for the ripple DOM manipulations. */
- _rippleRenderer;
- /** Options that are set globally for all ripples. */
- _globalOptions;
- /** @docs-private Whether ripple directive is initialized and the input bindings are set. */
- _isInitialized = false;
- constructor() {
- const ngZone = inject(NgZone);
- const platform = inject(Platform);
- const globalOptions = inject(MAT_RIPPLE_GLOBAL_OPTIONS, { optional: true });
- const injector = inject(Injector);
- // Note: cannot use `inject()` here, because this class
- // gets instantiated manually in the ripple loader.
- this._globalOptions = globalOptions || {};
- this._rippleRenderer = new RippleRenderer(this, ngZone, this._elementRef, platform, injector);
- }
- ngOnInit() {
- this._isInitialized = true;
- this._setupTriggerEventsIfEnabled();
- }
- ngOnDestroy() {
- this._rippleRenderer._removeTriggerEvents();
- }
- /** Fades out all currently showing ripple elements. */
- fadeOutAll() {
- this._rippleRenderer.fadeOutAll();
- }
- /** Fades out all currently showing non-persistent ripple elements. */
- fadeOutAllNonPersistent() {
- this._rippleRenderer.fadeOutAllNonPersistent();
- }
- /**
- * Ripple configuration from the directive's input values.
- * @docs-private Implemented as part of RippleTarget
- */
- get rippleConfig() {
- return {
- centered: this.centered,
- radius: this.radius,
- color: this.color,
- animation: {
- ...this._globalOptions.animation,
- ...(this._animationMode === 'NoopAnimations' ? { enterDuration: 0, exitDuration: 0 } : {}),
- ...this.animation,
- },
- terminateOnPointerUp: this._globalOptions.terminateOnPointerUp,
- };
- }
- /**
- * Whether ripples on pointer-down are disabled or not.
- * @docs-private Implemented as part of RippleTarget
- */
- get rippleDisabled() {
- return this.disabled || !!this._globalOptions.disabled;
- }
- /** Sets up the trigger event listeners if ripples are enabled. */
- _setupTriggerEventsIfEnabled() {
- if (!this.disabled && this._isInitialized) {
- this._rippleRenderer.setupTriggerEvents(this.trigger);
- }
- }
- /** Launches a manual ripple at the specified coordinated or just by the ripple config. */
- launch(configOrX, y = 0, config) {
- if (typeof configOrX === 'number') {
- return this._rippleRenderer.fadeInRipple(configOrX, y, { ...this.rippleConfig, ...config });
- }
- else {
- return this._rippleRenderer.fadeInRipple(0, 0, { ...this.rippleConfig, ...configOrX });
- }
- }
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: MatRipple, deps: [], target: i0.ɵɵFactoryTarget.Directive });
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.6", type: MatRipple, isStandalone: true, selector: "[mat-ripple], [matRipple]", inputs: { color: ["matRippleColor", "color"], unbounded: ["matRippleUnbounded", "unbounded"], centered: ["matRippleCentered", "centered"], radius: ["matRippleRadius", "radius"], animation: ["matRippleAnimation", "animation"], disabled: ["matRippleDisabled", "disabled"], trigger: ["matRippleTrigger", "trigger"] }, host: { properties: { "class.mat-ripple-unbounded": "unbounded" }, classAttribute: "mat-ripple" }, exportAs: ["matRipple"], ngImport: i0 });
- }
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: MatRipple, decorators: [{
- type: Directive,
- args: [{
- selector: '[mat-ripple], [matRipple]',
- exportAs: 'matRipple',
- host: {
- 'class': 'mat-ripple',
- '[class.mat-ripple-unbounded]': 'unbounded',
- },
- }]
- }], ctorParameters: () => [], propDecorators: { color: [{
- type: Input,
- args: ['matRippleColor']
- }], unbounded: [{
- type: Input,
- args: ['matRippleUnbounded']
- }], centered: [{
- type: Input,
- args: ['matRippleCentered']
- }], radius: [{
- type: Input,
- args: ['matRippleRadius']
- }], animation: [{
- type: Input,
- args: ['matRippleAnimation']
- }], disabled: [{
- type: Input,
- args: ['matRippleDisabled']
- }], trigger: [{
- type: Input,
- args: ['matRippleTrigger']
- }] } });
- export { MatRipple as M, RippleRenderer as R, MAT_RIPPLE_GLOBAL_OPTIONS as a, RippleState as b, RippleRef as c, defaultRippleAnimationConfig as d };
- //# sourceMappingURL=ripple-BT3tzh6F.mjs.map
|