sass-references/angular-material/material/core/ripple/ripple.ts

227 lines
7.3 KiB
TypeScript
Raw Normal View History

2024-12-06 10:42:08 +08:00
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.dev/license
*/
import {Platform} from '@angular/cdk/platform';
import {
Directive,
ElementRef,
InjectionToken,
Input,
NgZone,
OnDestroy,
OnInit,
ANIMATION_MODULE_TYPE,
Injector,
inject,
} from '@angular/core';
import {_CdkPrivateStyleLoader} from '@angular/cdk/private';
import {RippleAnimationConfig, RippleConfig, RippleRef} from './ripple-ref';
import {RippleRenderer, RippleTarget} from './ripple-renderer';
/** Configurable options for `matRipple`. */
export interface RippleGlobalOptions {
/**
* Whether ripples should be disabled. Ripples can be still launched manually by using
* the `launch()` method. Therefore focus indicators will still show up.
*/
disabled?: boolean;
/**
* Default configuration for the animation duration of the ripples. There are two phases with
* different durations for the ripples: `enter` and `leave`. The durations will be overwritten
* by the value of `matRippleAnimation` or if the `NoopAnimationsModule` is included.
*/
animation?: RippleAnimationConfig;
/**
* Whether ripples should start fading out immediately after the mouse or touch is released. By
* default, ripples will wait for the enter animation to complete and for mouse or touch release.
*/
terminateOnPointerUp?: boolean;
/**
* A namespace to use for ripple loader to allow multiple instances to exist on the same page.
*/
namespace?: string;
}
/** Injection token that can be used to specify the global ripple options. */
export const MAT_RIPPLE_GLOBAL_OPTIONS = new InjectionToken<RippleGlobalOptions>(
'mat-ripple-global-options',
);
@Directive({
selector: '[mat-ripple], [matRipple]',
exportAs: 'matRipple',
host: {
'class': 'mat-ripple',
'[class.mat-ripple-unbounded]': 'unbounded',
},
})
export class MatRipple implements OnInit, OnDestroy, RippleTarget {
private _elementRef = inject<ElementRef<HTMLElement>>(ElementRef);
private _animationMode = inject(ANIMATION_MODULE_TYPE, {optional: true});
/** Custom color for all ripples. */
@Input('matRippleColor') color: string;
/** Whether the ripples should be visible outside the component's bounds. */
@Input('matRippleUnbounded') unbounded: boolean;
/**
* Whether the ripple always originates from the center of the host element's bounds, rather
* than originating from the location of the click event.
*/
@Input('matRippleCentered') centered: boolean;
/**
* 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.
*/
@Input('matRippleRadius') radius: number = 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.
*/
@Input('matRippleAnimation') animation: RippleAnimationConfig;
/**
* Whether click events will not trigger the ripple. Ripples can be still launched manually
* by using the `launch()` method.
*/
@Input('matRippleDisabled')
get disabled() {
return this._disabled;
}
set disabled(value: boolean) {
if (value) {
this.fadeOutAllNonPersistent();
}
this._disabled = value;
this._setupTriggerEventsIfEnabled();
}
private _disabled: boolean = false;
/**
* The element that triggers the ripple when click events are received.
* Defaults to the directive's host element.
*/
@Input('matRippleTrigger')
get trigger() {
return this._trigger || this._elementRef.nativeElement;
}
set trigger(trigger: HTMLElement) {
this._trigger = trigger;
this._setupTriggerEventsIfEnabled();
}
private _trigger: HTMLElement;
/** Renderer for the ripple DOM manipulations. */
private _rippleRenderer: RippleRenderer;
/** Options that are set globally for all ripples. */
private _globalOptions: RippleGlobalOptions;
/** @docs-private Whether ripple directive is initialized and the input bindings are set. */
_isInitialized: boolean = false;
constructor(...args: unknown[]);
constructor() {
const ngZone = inject(NgZone);
const platform = inject(Platform);
const globalOptions = inject<RippleGlobalOptions>(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(): 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(): boolean {
return this.disabled || !!this._globalOptions.disabled;
}
/** Sets up the trigger event listeners if ripples are enabled. */
private _setupTriggerEventsIfEnabled() {
if (!this.disabled && this._isInitialized) {
this._rippleRenderer.setupTriggerEvents(this.trigger);
}
}
/**
* Launches a manual ripple using the specified ripple configuration.
* @param config Configuration for the manual ripple.
*/
launch(config: RippleConfig): RippleRef;
/**
* Launches a manual ripple at the specified coordinates relative to the viewport.
* @param x Coordinate along the X axis at which to fade-in the ripple. Coordinate
* should be relative to the viewport.
* @param y Coordinate along the Y axis at which to fade-in the ripple. Coordinate
* should be relative to the viewport.
* @param config Optional ripple configuration for the manual ripple.
*/
launch(x: number, y: number, config?: RippleConfig): RippleRef;
/** Launches a manual ripple at the specified coordinated or just by the ripple config. */
launch(configOrX: number | RippleConfig, y: number = 0, config?: RippleConfig): RippleRef {
if (typeof configOrX === 'number') {
return this._rippleRenderer.fadeInRipple(configOrX, y, {...this.rippleConfig, ...config});
} else {
return this._rippleRenderer.fadeInRipple(0, 0, {...this.rippleConfig, ...configOrX});
}
}
}