@@ -15,30 +15,32 @@ import {
15
15
OnDestroy ,
16
16
inject ,
17
17
} from '@angular/core' ;
18
- import {
19
- MAT_RIPPLE_GLOBAL_OPTIONS ,
20
- MatRipple ,
21
- RippleConfig ,
22
- RippleGlobalOptions ,
23
- RippleRenderer ,
24
- RippleTarget ,
25
- } from '@angular/material/core' ;
26
18
import { Platform } from '@angular/cdk/platform' ;
19
+ import { MAT_RIPPLE_GLOBAL_OPTIONS , MatRipple } from '@angular/material/core' ;
27
20
28
21
/** The options for the MatButtonRippleLoader's event listeners. */
29
22
const eventListenerOptions = { capture : true } ;
30
23
31
24
/** The events that should trigger the initialization of the ripple. */
32
25
const rippleInteractionEvents = [ 'focus' , 'click' , 'mouseenter' , 'touchstart' ] ;
33
26
34
- /** The attribute attached to a mat-button whose ripple has not yet been initialized. */
35
- export const MAT_BUTTON_RIPPLE_UNINITIALIZED = 'mat-button-ripple-uninitialized' ;
27
+ /** The attribute attached to a component whose ripple has not yet been initialized. */
28
+ const matRippleUninitialized = 'mat-ripple-loader-uninitialized' ;
29
+
30
+ /** Additional classes that should be added to the ripple when it is rendered. */
31
+ const matRippleClassName = 'mat-ripple-loader-class-name' ;
32
+
33
+ /** Whether the ripple should be centered. */
34
+ const matRippleCentered = 'mat-ripple-loader-centered' ;
35
+
36
+ /** Whether the ripple should be disabled. */
37
+ const matRippleDisabled = 'mat-ripple-loader-disabled' ;
36
38
37
39
/**
38
- * Handles attaching the MatButton's ripple on demand.
40
+ * Handles attaching ripples on demand.
39
41
*
40
- * This service allows us to avoid eagerly creating & attaching the MatButton's ripple .
41
- * It works by creating & attaching the ripple only when a MatButton is first interacted with.
42
+ * This service allows us to avoid eagerly creating & attaching MatRipples .
43
+ * It works by creating & attaching a ripple only when a component is first interacted with.
42
44
*/
43
45
@Injectable ( { providedIn : 'root' } )
44
46
export class MatButtonLazyLoader implements OnDestroy {
@@ -62,50 +64,93 @@ export class MatButtonLazyLoader implements OnDestroy {
62
64
}
63
65
}
64
66
65
- /** Handles creating and attaching button internals when a button is initially interacted with. */
66
- private _onInteraction = ( event : Event ) => {
67
- if ( event . target === this . _document ) {
68
- return ;
67
+ /**
68
+ * Configures the ripple that will be rendered by the ripple loader.
69
+ *
70
+ * Stores the given information about how the ripple should be configured on the host
71
+ * element so that it can later be retrived & used when the ripple is actually created.
72
+ */
73
+ configureRipple (
74
+ host : HTMLElement ,
75
+ config : {
76
+ className ?: string ;
77
+ centered ?: boolean ;
78
+ disabled ?: boolean ;
79
+ } ,
80
+ ) : void {
81
+ // Indicates that the ripple has not yet been rendered for this component.
82
+ host . setAttribute ( matRippleUninitialized , '' ) ;
83
+
84
+ // Store the additional class name(s) that should be added to the ripple element.
85
+ if ( config . className || ! host . hasAttribute ( matRippleClassName ) ) {
86
+ host . setAttribute ( matRippleClassName , config . className || '' ) ;
69
87
}
70
- const eventTarget = event . target as Element ;
71
88
72
- // TODO(wagnermaciel): Consider batching these events to improve runtime performance.
89
+ // Store whether the ripple should be centered.
90
+ if ( config . centered ) {
91
+ host . setAttribute ( matRippleCentered , '' ) ;
92
+ }
73
93
74
- const button = eventTarget . closest ( `[${ MAT_BUTTON_RIPPLE_UNINITIALIZED } ]` ) ;
75
- if ( button ) {
76
- button . removeAttribute ( MAT_BUTTON_RIPPLE_UNINITIALIZED ) ;
77
- this . _appendRipple ( button as HTMLElement ) ;
94
+ if ( config . disabled ) {
95
+ host . setAttribute ( matRippleDisabled , '' ) ;
78
96
}
79
- } ;
97
+ }
80
98
81
- /** Creates a MatButtonRipple and appends it to the given button element. */
82
- private _appendRipple ( button : HTMLElement ) : void {
83
- if ( ! this . _document ) {
84
- return ;
99
+ /** Returns the ripple instance for the given host element. */
100
+ getRipple ( host : HTMLElement ) : MatRipple | undefined {
101
+ if ( ( host as any ) . matRipple ) {
102
+ return ( host as any ) . matRipple ;
85
103
}
86
- const ripple = this . _document . createElement ( 'span' ) ;
87
- ripple . classList . add ( 'mat-mdc-button-ripple' ) ;
104
+ return this . createRipple ( host ) ;
105
+ }
88
106
89
- const target = new MatButtonRippleTarget (
90
- button ,
91
- this . _globalRippleOptions ? this . _globalRippleOptions : undefined ,
92
- this . _animationMode ? this . _animationMode : undefined ,
93
- ) ;
94
- target . rippleConfig . centered = button . hasAttribute ( 'mat-icon-button' ) ;
107
+ /** Sets the disabled state on the ripple instance corresponding to the given host element. */
108
+ setDisabled ( host : HTMLElement , disabled : boolean ) : void {
109
+ const ripple = ( host as any ) . matRipple as MatRipple | undefined ;
95
110
96
- const rippleRenderer = new RippleRenderer ( target , this . _ngZone , ripple , this . _platform ) ;
97
- rippleRenderer . setupTriggerEvents ( button ) ;
98
- button . append ( ripple ) ;
111
+ // If the ripple has already been instantiated, just disable it.
112
+ if ( ripple ) {
113
+ ripple . disabled = disabled ;
114
+ return ;
115
+ }
116
+
117
+ // Otherwise, set an attribute so we know what the
118
+ // disabled state should be when the ripple is initialized.
119
+ if ( disabled ) {
120
+ host . setAttribute ( matRippleDisabled , '' ) ;
121
+ } else {
122
+ host . removeAttribute ( matRippleDisabled ) ;
123
+ }
99
124
}
100
125
101
- _createMatRipple ( button : HTMLElement ) : MatRipple | undefined {
126
+ /** Handles creating and attaching component internals when a component it is initially interacted with. */
127
+ private _onInteraction = ( event : Event ) => {
128
+ if ( ! ( event . target instanceof HTMLElement ) ) {
129
+ return ;
130
+ }
131
+ const eventTarget = event . target as HTMLElement ;
132
+
133
+ // TODO(wagnermaciel): Consider batching these events to improve runtime performance.
134
+
135
+ const element = eventTarget . closest ( `[${ matRippleUninitialized } ]` ) ;
136
+ if ( element ) {
137
+ this . createRipple ( element as HTMLElement ) ;
138
+ }
139
+ } ;
140
+
141
+ /** Creates a MatRipple and appends it to the given element. */
142
+ createRipple ( host : HTMLElement ) : MatRipple | undefined {
102
143
if ( ! this . _document ) {
103
144
return ;
104
145
}
105
- button . querySelector ( '.mat-mdc-button-ripple' ) ?. remove ( ) ;
106
- button . removeAttribute ( MAT_BUTTON_RIPPLE_UNINITIALIZED ) ;
146
+
147
+ // Create the ripple element.
148
+ host . querySelector ( '.mat-ripple' ) ?. remove ( ) ;
107
149
const rippleEl = this . _document ! . createElement ( 'span' ) ;
108
- rippleEl . classList . add ( 'mat-mdc-button-ripple' ) ;
150
+ rippleEl . classList . add ( 'mat-ripple' , host . getAttribute ( matRippleClassName ) ! ) ;
151
+ host . append ( rippleEl ) ;
152
+
153
+ // Create the MatRipple.
109
154
const ripple = new MatRipple (
110
155
new ElementRef ( rippleEl ) ,
111
156
this . _ngZone ,
@@ -114,38 +159,15 @@ export class MatButtonLazyLoader implements OnDestroy {
114
159
this . _animationMode ? this . _animationMode : undefined ,
115
160
) ;
116
161
ripple . _isInitialized = true ;
117
- ripple . trigger = button ;
118
- button . append ( rippleEl ) ;
162
+ ripple . trigger = host ;
163
+ ripple . centered = host . hasAttribute ( matRippleCentered ) ;
164
+ ripple . disabled = host . hasAttribute ( matRippleDisabled ) ;
165
+ this . attachRipple ( host , ripple ) ;
119
166
return ripple ;
120
167
}
121
- }
122
-
123
- /**
124
- * The RippleTarget for the lazily rendered MatButton ripple.
125
- * It handles ripple configuration and disabled state for ripples interactions.
126
- *
127
- * Note that this configuration is usually handled by the MatRipple, but the MatButtonLazyLoader does not use the
128
- * MatRipple Directive. In order to create & attach a ripple on demand, it uses the "lower level" RippleRenderer.
129
- */
130
- class MatButtonRippleTarget implements RippleTarget {
131
- rippleConfig : RippleConfig & RippleGlobalOptions ;
132
-
133
- constructor (
134
- private _button : HTMLElement ,
135
- private _globalRippleOptions ?: RippleGlobalOptions ,
136
- animationMode ?: string ,
137
- ) {
138
- this . _setRippleConfig ( _globalRippleOptions , animationMode ) ;
139
- }
140
-
141
- private _setRippleConfig ( globalRippleOptions ?: RippleGlobalOptions , animationMode ?: string ) {
142
- this . rippleConfig = globalRippleOptions || { } ;
143
- if ( animationMode === 'NoopAnimations' ) {
144
- this . rippleConfig . animation = { enterDuration : 0 , exitDuration : 0 } ;
145
- }
146
- }
147
168
148
- get rippleDisabled ( ) : boolean {
149
- return this . _button . hasAttribute ( 'disabled' ) || ! ! this . _globalRippleOptions ?. disabled ;
169
+ attachRipple ( host : Element , ripple : MatRipple ) : void {
170
+ host . removeAttribute ( matRippleUninitialized ) ;
171
+ ( host as any ) . matRipple = ripple ;
150
172
}
151
173
}
0 commit comments