mirror of
https://github.com/material-components/material-web.git
synced 2024-09-20 18:17:15 +03:00
0cc7d2959a
PiperOrigin-RevId: 511251253
96 lines
2.9 KiB
TypeScript
96 lines
2.9 KiB
TypeScript
/**
|
|
* @license
|
|
* Copyright 2022 Google LLC
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
import {noChange} from 'lit';
|
|
import {Directive, directive, DirectiveParameters, ElementPart, PartInfo, PartType} from 'lit/directive.js';
|
|
|
|
import {Ripple} from './lib/ripple.js';
|
|
|
|
/**
|
|
* Normalized ripple accessor type.
|
|
*
|
|
* Use with `await rippleFunction()`
|
|
*/
|
|
type RippleFunction = () => Ripple|null|Promise<Ripple|null>;
|
|
|
|
class RippleDirective extends Directive {
|
|
private rippleGetter: RippleFunction = async () => null;
|
|
private element?: HTMLElement;
|
|
|
|
constructor(partInfo: PartInfo) {
|
|
super(partInfo);
|
|
if (partInfo.type !== PartType.ELEMENT) {
|
|
throw new Error('The `ripple` directive must be used on an element');
|
|
}
|
|
}
|
|
|
|
render(ripple: RippleFunction|Promise<Ripple|null>) {
|
|
return noChange;
|
|
}
|
|
|
|
// Use EventListenerObject::handleEvent interface to handle events without
|
|
// generating bound event handlers
|
|
async handleEvent(event: Event) {
|
|
const ripple = await this.rippleGetter();
|
|
if (!ripple) {
|
|
return;
|
|
}
|
|
switch (event.type) {
|
|
case 'click':
|
|
ripple.handleClick();
|
|
break;
|
|
case 'contextmenu':
|
|
ripple.handleContextmenu();
|
|
break;
|
|
case 'pointercancel':
|
|
ripple.handlePointercancel(event as PointerEvent);
|
|
break;
|
|
case 'pointerdown':
|
|
await ripple.handlePointerdown(event as PointerEvent);
|
|
break;
|
|
case 'pointerenter':
|
|
ripple.handlePointerenter(event as PointerEvent);
|
|
break;
|
|
case 'pointerleave':
|
|
ripple.handlePointerleave(event as PointerEvent);
|
|
break;
|
|
case 'pointerup':
|
|
ripple.handlePointerup(event as PointerEvent);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
override update(part: ElementPart, [ripple]: DirectiveParameters<this>) {
|
|
if (!this.element) {
|
|
// NOTE: addEventListener typing needs to be used with HTMLElements or a
|
|
// subclass
|
|
this.element = part.element as HTMLElement;
|
|
this.element.addEventListener('click', this);
|
|
this.element.addEventListener('contextmenu', this);
|
|
this.element.addEventListener('pointercancel', this);
|
|
this.element.addEventListener('pointerdown', this);
|
|
this.element.addEventListener('pointerenter', this);
|
|
this.element.addEventListener('pointerleave', this);
|
|
this.element.addEventListener('pointerup', this);
|
|
}
|
|
// Normalize given ripple accessor
|
|
this.rippleGetter = typeof ripple === 'function' ? ripple : () => ripple;
|
|
return noChange;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Connects a Ripple element to a node that drives the interaction
|
|
*
|
|
* @param rippleGetter A function that returns an `md-ripple` element
|
|
* @param simulateKeyboardClick For elements that do not issue a click on
|
|
* keyboard interaction, pass `true` to enable press animations on Enter or
|
|
* Spacebar
|
|
*/
|
|
export const ripple = directive(RippleDirective);
|