mirror of
https://github.com/material-components/material-web.git
synced 2024-08-16 17:10:22 +03:00
fix: rename and move internal/controller/events
Split `internal/controller/events` into `internal/events/redispatch-event` and `internal/events/form-label-activation` PiperOrigin-RevId: 592350371
This commit is contained in:
parent
57168f6a95
commit
eca1357f1a
@ -20,7 +20,7 @@ import {
|
||||
import {
|
||||
dispatchActivationClick,
|
||||
isActivationClick,
|
||||
} from '../../internal/events/events.js';
|
||||
} from '../../internal/events/form-label-activation.js';
|
||||
import {
|
||||
internals,
|
||||
mixinElementInternals,
|
||||
|
@ -16,8 +16,8 @@ import {requestUpdateOnAriaChange} from '../../internal/aria/delegate.js';
|
||||
import {
|
||||
dispatchActivationClick,
|
||||
isActivationClick,
|
||||
redispatchEvent,
|
||||
} from '../../internal/events/events.js';
|
||||
} from '../../internal/events/form-label-activation.js';
|
||||
import {redispatchEvent} from '../../internal/events/redispatch-event.js';
|
||||
import {
|
||||
createValidator,
|
||||
getValidityAnchor,
|
||||
|
@ -10,7 +10,7 @@ import {html, nothing} from 'lit';
|
||||
import {property, query} from 'lit/decorators.js';
|
||||
|
||||
import {ARIAMixinStrict} from '../../internal/aria/aria.js';
|
||||
import {redispatchEvent} from '../../internal/events/events.js';
|
||||
import {redispatchEvent} from '../../internal/events/redispatch-event.js';
|
||||
|
||||
import {MultiActionChip} from './multi-action-chip.js';
|
||||
import {renderRemoveButton} from './trailing-icons.js';
|
||||
|
@ -12,7 +12,7 @@ import {classMap} from 'lit/directives/class-map.js';
|
||||
|
||||
import {ARIAMixinStrict} from '../../internal/aria/aria.js';
|
||||
import {requestUpdateOnAriaChange} from '../../internal/aria/delegate.js';
|
||||
import {redispatchEvent} from '../../internal/events/events.js';
|
||||
import {redispatchEvent} from '../../internal/events/redispatch-event.js';
|
||||
|
||||
import {
|
||||
DIALOG_DEFAULT_CLOSE_ANIMATION,
|
||||
|
@ -4,43 +4,6 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Re-dispatches an event from the provided element.
|
||||
*
|
||||
* This function is useful for forwarding non-composed events, such as `change`
|
||||
* events.
|
||||
*
|
||||
* @example
|
||||
* class MyInput extends LitElement {
|
||||
* render() {
|
||||
* return html`<input @change=${this.redispatchEvent}>`;
|
||||
* }
|
||||
*
|
||||
* protected redispatchEvent(event: Event) {
|
||||
* redispatchEvent(this, event);
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* @param element The element to dispatch the event from.
|
||||
* @param event The event to re-dispatch.
|
||||
* @return Whether or not the event was dispatched (if cancelable).
|
||||
*/
|
||||
export function redispatchEvent(element: Element, event: Event) {
|
||||
// For bubbling events in SSR light DOM (or composed), stop their propagation
|
||||
// and dispatch the copy.
|
||||
if (event.bubbles && (!element.shadowRoot || event.composed)) {
|
||||
event.stopPropagation();
|
||||
}
|
||||
|
||||
const copy = Reflect.construct(event.constructor, [event.type, event]);
|
||||
const dispatched = element.dispatchEvent(copy);
|
||||
if (!dispatched) {
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
return dispatched;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches a click event to the given element that triggers a native action,
|
||||
* but is not composed and therefore is not seen outside the element.
|
92
internal/events/form-label-activation_test.ts
Normal file
92
internal/events/form-label-activation_test.ts
Normal file
@ -0,0 +1,92 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2021 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
// import 'jasmine'; (google3-only)
|
||||
|
||||
import {
|
||||
dispatchActivationClick,
|
||||
isActivationClick,
|
||||
} from './form-label-activation.js';
|
||||
|
||||
describe('label events', () => {
|
||||
let instance: HTMLDivElement;
|
||||
|
||||
beforeEach(() => {
|
||||
instance = document.createElement('div');
|
||||
instance
|
||||
.attachShadow({mode: 'open'})
|
||||
.append(document.createElement('slot'));
|
||||
// To have event.target set correctly, the EventTarget instance must be
|
||||
// attached to the DOM.
|
||||
document.body.appendChild(instance);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
document.body.removeChild(instance);
|
||||
});
|
||||
|
||||
describe('isActivationClick()', () => {
|
||||
it('returns true for click on listener', () => {
|
||||
const listener = jasmine.createSpy('listener', isActivationClick);
|
||||
listener.and.callThrough();
|
||||
instance.addEventListener('click', listener);
|
||||
instance.dispatchEvent(
|
||||
new MouseEvent('click', {bubbles: true, composed: true}),
|
||||
);
|
||||
expect(listener).toHaveBeenCalledTimes(1);
|
||||
expect(listener.calls.mostRecent().returnValue).toBe(true);
|
||||
});
|
||||
|
||||
it('returns false for click on element listener shadowRoot', () => {
|
||||
const listener = jasmine.createSpy('listener', isActivationClick);
|
||||
listener.and.callThrough();
|
||||
instance.addEventListener('click', listener);
|
||||
const innerEl = document.createElement('div');
|
||||
instance.shadowRoot!.append(innerEl);
|
||||
innerEl.dispatchEvent(
|
||||
new MouseEvent('click', {bubbles: true, composed: true}),
|
||||
);
|
||||
expect(listener).toHaveBeenCalledTimes(1);
|
||||
expect(listener.calls.mostRecent().returnValue).toBe(false);
|
||||
});
|
||||
|
||||
it('returns false for click on element listener child', () => {
|
||||
const listener = jasmine.createSpy('listener', isActivationClick);
|
||||
listener.and.callThrough();
|
||||
instance.addEventListener('click', listener);
|
||||
const slottedEl = document.createElement('div');
|
||||
instance.append(slottedEl);
|
||||
|
||||
slottedEl.dispatchEvent(
|
||||
new MouseEvent('click', {bubbles: true, composed: true}),
|
||||
);
|
||||
expect(listener).toHaveBeenCalledTimes(1);
|
||||
expect(listener.calls.mostRecent().returnValue).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('dispatchActivationClick()', () => {
|
||||
it('dispatches an event', () => {
|
||||
const innerEl = document.createElement('div');
|
||||
instance.shadowRoot!.append(innerEl);
|
||||
const listener = jasmine.createSpy('listener');
|
||||
innerEl.addEventListener('click', listener);
|
||||
dispatchActivationClick(innerEl);
|
||||
expect(listener).toHaveBeenCalledTimes(1);
|
||||
dispatchActivationClick(innerEl);
|
||||
expect(listener).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it('dispatches an event that cannot be heard outside dispatching scope', () => {
|
||||
const innerEl = document.createElement('div');
|
||||
instance.shadowRoot!.append(innerEl);
|
||||
const listener = jasmine.createSpy('listener');
|
||||
instance.addEventListener('click', listener);
|
||||
dispatchActivationClick(innerEl);
|
||||
expect(listener).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
});
|
||||
});
|
42
internal/events/redispatch-event.ts
Normal file
42
internal/events/redispatch-event.ts
Normal file
@ -0,0 +1,42 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2021 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Re-dispatches an event from the provided element.
|
||||
*
|
||||
* This function is useful for forwarding non-composed events, such as `change`
|
||||
* events.
|
||||
*
|
||||
* @example
|
||||
* class MyInput extends LitElement {
|
||||
* render() {
|
||||
* return html`<input @change=${this.redispatchEvent}>`;
|
||||
* }
|
||||
*
|
||||
* protected redispatchEvent(event: Event) {
|
||||
* redispatchEvent(this, event);
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* @param element The element to dispatch the event from.
|
||||
* @param event The event to re-dispatch.
|
||||
* @return Whether or not the event was dispatched (if cancelable).
|
||||
*/
|
||||
export function redispatchEvent(element: Element, event: Event) {
|
||||
// For bubbling events in SSR light DOM (or composed), stop their propagation
|
||||
// and dispatch the copy.
|
||||
if (event.bubbles && (!element.shadowRoot || event.composed)) {
|
||||
event.stopPropagation();
|
||||
}
|
||||
|
||||
const copy = Reflect.construct(event.constructor, [event.type, event]);
|
||||
const dispatched = element.dispatchEvent(copy);
|
||||
if (!dispatched) {
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
return dispatched;
|
||||
}
|
@ -6,11 +6,7 @@
|
||||
|
||||
// import 'jasmine'; (google3-only)
|
||||
|
||||
import {
|
||||
dispatchActivationClick,
|
||||
isActivationClick,
|
||||
redispatchEvent,
|
||||
} from './events.js';
|
||||
import {redispatchEvent} from './redispatch-event.js';
|
||||
|
||||
describe('events', () => {
|
||||
let instance: HTMLDivElement;
|
||||
@ -119,66 +115,4 @@ describe('events', () => {
|
||||
.toBe('bar');
|
||||
});
|
||||
});
|
||||
|
||||
describe('isActivationClick()', () => {
|
||||
it('returns true for click on listener', () => {
|
||||
const listener = jasmine.createSpy('listener', isActivationClick);
|
||||
listener.and.callThrough();
|
||||
instance.addEventListener('click', listener);
|
||||
instance.dispatchEvent(
|
||||
new MouseEvent('click', {bubbles: true, composed: true}),
|
||||
);
|
||||
expect(listener).toHaveBeenCalledTimes(1);
|
||||
expect(listener.calls.mostRecent().returnValue).toBe(true);
|
||||
});
|
||||
|
||||
it('returns false for click on element listener shadowRoot', () => {
|
||||
const listener = jasmine.createSpy('listener', isActivationClick);
|
||||
listener.and.callThrough();
|
||||
instance.addEventListener('click', listener);
|
||||
const innerEl = document.createElement('div');
|
||||
instance.shadowRoot!.append(innerEl);
|
||||
innerEl.dispatchEvent(
|
||||
new MouseEvent('click', {bubbles: true, composed: true}),
|
||||
);
|
||||
expect(listener).toHaveBeenCalledTimes(1);
|
||||
expect(listener.calls.mostRecent().returnValue).toBe(false);
|
||||
});
|
||||
|
||||
it('returns false for click on element listener child', () => {
|
||||
const listener = jasmine.createSpy('listener', isActivationClick);
|
||||
listener.and.callThrough();
|
||||
instance.addEventListener('click', listener);
|
||||
const slottedEl = document.createElement('div');
|
||||
instance.append(slottedEl);
|
||||
|
||||
slottedEl.dispatchEvent(
|
||||
new MouseEvent('click', {bubbles: true, composed: true}),
|
||||
);
|
||||
expect(listener).toHaveBeenCalledTimes(1);
|
||||
expect(listener.calls.mostRecent().returnValue).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('dispatchActivationClick()', () => {
|
||||
it('dispatches an event', () => {
|
||||
const innerEl = document.createElement('div');
|
||||
instance.shadowRoot!.append(innerEl);
|
||||
const listener = jasmine.createSpy('listener');
|
||||
innerEl.addEventListener('click', listener);
|
||||
dispatchActivationClick(innerEl);
|
||||
expect(listener).toHaveBeenCalledTimes(1);
|
||||
dispatchActivationClick(innerEl);
|
||||
expect(listener).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it('dispatches an event that cannot be heard outside dispatching scope', () => {
|
||||
const innerEl = document.createElement('div');
|
||||
instance.shadowRoot!.append(innerEl);
|
||||
const listener = jasmine.createSpy('listener');
|
||||
instance.addEventListener('click', listener);
|
||||
dispatchActivationClick(innerEl);
|
||||
expect(listener).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
});
|
||||
});
|
@ -11,7 +11,7 @@ import {html, isServer, LitElement} from 'lit';
|
||||
import {property, query} from 'lit/decorators.js';
|
||||
import {classMap} from 'lit/directives/class-map.js';
|
||||
|
||||
import {isActivationClick} from '../../internal/events/events.js';
|
||||
import {isActivationClick} from '../../internal/events/form-label-activation.js';
|
||||
import {
|
||||
createValidator,
|
||||
getValidityAnchor,
|
||||
|
@ -15,7 +15,7 @@ import {html as staticHtml, StaticValue} from 'lit/static-html.js';
|
||||
import {Field} from '../../field/internal/field.js';
|
||||
import {ARIAMixinStrict} from '../../internal/aria/aria.js';
|
||||
import {requestUpdateOnAriaChange} from '../../internal/aria/delegate.js';
|
||||
import {redispatchEvent} from '../../internal/events/events.js';
|
||||
import {redispatchEvent} from '../../internal/events/redispatch-event.js';
|
||||
import {
|
||||
createValidator,
|
||||
getValidityAnchor,
|
||||
|
@ -19,8 +19,8 @@ import {requestUpdateOnAriaChange} from '../../internal/aria/delegate.js';
|
||||
import {
|
||||
dispatchActivationClick,
|
||||
isActivationClick,
|
||||
redispatchEvent,
|
||||
} from '../../internal/events/events.js';
|
||||
} from '../../internal/events/form-label-activation.js';
|
||||
import {redispatchEvent} from '../../internal/events/redispatch-event.js';
|
||||
import {mixinElementInternals} from '../../labs/behaviors/element-internals.js';
|
||||
import {
|
||||
getFormValue,
|
||||
|
@ -15,8 +15,8 @@ import {requestUpdateOnAriaChange} from '../../internal/aria/delegate.js';
|
||||
import {
|
||||
dispatchActivationClick,
|
||||
isActivationClick,
|
||||
redispatchEvent,
|
||||
} from '../../internal/events/events.js';
|
||||
} from '../../internal/events/form-label-activation.js';
|
||||
import {redispatchEvent} from '../../internal/events/redispatch-event.js';
|
||||
import {
|
||||
createValidator,
|
||||
getValidityAnchor,
|
||||
|
@ -15,7 +15,7 @@ import {Field} from '../../field/internal/field.js';
|
||||
import {ARIAMixinStrict} from '../../internal/aria/aria.js';
|
||||
import {requestUpdateOnAriaChange} from '../../internal/aria/delegate.js';
|
||||
import {stringConverter} from '../../internal/controller/string-converter.js';
|
||||
import {redispatchEvent} from '../../internal/events/events.js';
|
||||
import {redispatchEvent} from '../../internal/events/redispatch-event.js';
|
||||
import {
|
||||
createValidator,
|
||||
getValidityAnchor,
|
||||
|
Loading…
Reference in New Issue
Block a user