-
Notifications
You must be signed in to change notification settings - Fork 904
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'material-components:main' into cg-fix-validator-custom-…
…error
- Loading branch information
Showing
28 changed files
with
797 additions
and
219 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -37,7 +37,6 @@ jobs: | |
committer: lit-robot <[email protected]> | ||
title: 'chore: update sizes' | ||
body: This PR was auto generated by the update-size-on-main GitHub action. | ||
reviewers: e111077,asyncliz | ||
branch: auto-update-size | ||
# Don't automatically add Ready for Google label until we're ready | ||
branch: auto-update-sizes | ||
# Don't automatically add reviewers or Ready for Google label until we're ready | ||
# since this will be noisy. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
# Contributing | ||
|
||
Thank you for your interest in contributing! The following sections describe | ||
ways to get involved. | ||
|
||
## Code of conduct | ||
|
||
Please review and follow our [code of conduct](CODE_OF_CONDUCT.md). | ||
|
||
## Feedback | ||
|
||
User feedback is the most valuable to us. It's a great way to start | ||
contributing! | ||
|
||
- [File new issues](https://github.com/material-components/material-web/issues/new/choose) | ||
for bugs you run into or feature requests you have. | ||
|
||
- [Create a discussion](https://github.com/material-components/material-web/discussions/new/choose) | ||
for help, feedback on changes, or feature proposals. | ||
|
||
## Discord | ||
|
||
Join the `#material` channel on [Lit's Discord](https://lit.dev/discord) to chat | ||
directly with the team and other users. | ||
|
||
## Pull requests | ||
|
||
Pull requests are welcome! Keep a few things in mind: | ||
|
||
- Create an | ||
[issue](https://github.com/material-components/material-web/issues/new/choose) | ||
or | ||
[discussion](https://github.com/material-components/material-web/discussions/new/choose) | ||
before opening a pull request. | ||
- Trivial changes, such as documentation, don't need an issue. | ||
- Create draft PRs in the `@material/web/labs` folder for new features. | ||
- Please be patient! It may take a while for the team to review. Keep changes | ||
small and scoped to speed things up. | ||
|
||
### New components | ||
|
||
Please understand that new component implementations are difficult for us to | ||
directly accept. They need to complete several engineer, design, and | ||
accessibility reviews that are not easy with our externally available workflows. | ||
|
||
If you want to help build a new component, create a | ||
[new discussion](https://github.com/material-components/material-web/discussions/new/choose). | ||
Add any design docs, code samples, reference implementations in draft PRs, and | ||
get community feedback. | ||
|
||
### Contributor License Agreement | ||
|
||
Code contributions must | ||
[sign Google's CLA](https://cla.developers.google.com/clas). When you open a | ||
pull request, our friendly bot will check and provide help if you haven't | ||
signed. | ||
|
||
[Set your email in git](https://help.github.com/articles/setting-your-email-in-git/) | ||
to the same email used to sign the CLA. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,176 @@ | ||
/** | ||
* @license | ||
* Copyright 2023 Google LLC | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
/** | ||
* A symbol used to access dispatch hooks on an event. | ||
*/ | ||
const dispatchHooks = Symbol('dispatchHooks'); | ||
|
||
/** | ||
* An `Event` with additional symbols for dispatch hooks. | ||
*/ | ||
interface EventWithDispatchHooks extends Event { | ||
[dispatchHooks]: EventTarget; | ||
} | ||
|
||
/** | ||
* Add a hook for an event that is called after the event is dispatched and | ||
* propagates to other event listeners. | ||
* | ||
* This is useful for behaviors that need to check if an event is canceled. | ||
* | ||
* The callback is invoked synchronously, which allows for better integration | ||
* with synchronous platform APIs (like `<form>` or `<label>` clicking). | ||
* | ||
* Note: `setupDispatchHooks()` must be called on the element before adding any | ||
* other event listeners. Call it in the constructor of an element or | ||
* controller. | ||
* | ||
* @example | ||
* ```ts | ||
* class MyControl extends LitElement { | ||
* constructor() { | ||
* super(); | ||
* setupDispatchHooks(this, 'click'); | ||
* this.addEventListener('click', event => { | ||
* afterDispatch(event, () => { | ||
* if (event.defaultPrevented) { | ||
* return | ||
* } | ||
* | ||
* // ... perform logic | ||
* }); | ||
* }); | ||
* } | ||
* } | ||
* ``` | ||
* | ||
* @example | ||
* ```ts | ||
* class MyController implements ReactiveController { | ||
* constructor(host: ReactiveElement) { | ||
* // setupDispatchHooks() may be called multiple times for the same | ||
* // element and events, making it safe for multiple controllers to use it. | ||
* setupDispatchHooks(host, 'click'); | ||
* host.addEventListener('click', event => { | ||
* afterDispatch(event, () => { | ||
* if (event.defaultPrevented) { | ||
* return; | ||
* } | ||
* | ||
* // ... perform logic | ||
* }); | ||
* }); | ||
* } | ||
* } | ||
* ``` | ||
* | ||
* @param event The event to add a hook to. | ||
* @param callback A hook that is called after the event finishes dispatching. | ||
*/ | ||
export function afterDispatch(event: Event, callback: () => void) { | ||
const hooks = (event as EventWithDispatchHooks)[dispatchHooks]; | ||
if (!hooks) { | ||
throw new Error(`'${event.type}' event needs setupDispatchHooks().`); | ||
} | ||
|
||
hooks.addEventListener('after', callback); | ||
} | ||
|
||
/** | ||
* A lookup map of elements and event types that have a dispatch hook listener | ||
* set up. Used to ensure we don't set up multiple hook listeners on the same | ||
* element for the same event. | ||
*/ | ||
const ELEMENT_DISPATCH_HOOK_TYPES = new WeakMap<Element, Set<string>>(); | ||
|
||
/** | ||
* Sets up an element to add dispatch hooks to given event types. This must be | ||
* called before adding any event listeners that need to use dispatch hooks | ||
* like `afterDispatch()`. | ||
* | ||
* This function is safe to call multiple times with the same element or event | ||
* types. Call it in the constructor of elements, mixins, and controllers to | ||
* ensure it is set up before external listeners. | ||
* | ||
* @example | ||
* ```ts | ||
* class MyControl extends LitElement { | ||
* constructor() { | ||
* super(); | ||
* setupDispatchHooks(this, 'click'); | ||
* this.addEventListener('click', this.listenerUsingAfterDispatch); | ||
* } | ||
* } | ||
* ``` | ||
* | ||
* @param element The element to set up event dispatch hooks for. | ||
* @param eventTypes The event types to add dispatch hooks to. | ||
*/ | ||
export function setupDispatchHooks( | ||
element: Element, | ||
...eventTypes: [string, ...string[]] | ||
) { | ||
let typesAlreadySetUp = ELEMENT_DISPATCH_HOOK_TYPES.get(element); | ||
if (!typesAlreadySetUp) { | ||
typesAlreadySetUp = new Set(); | ||
ELEMENT_DISPATCH_HOOK_TYPES.set(element, typesAlreadySetUp); | ||
} | ||
|
||
for (const eventType of eventTypes) { | ||
// Don't register multiple dispatch hook listeners. A second registration | ||
// would lead to the second listener re-dispatching a re-dispatched event, | ||
// which can cause an infinite loop inside the other one. | ||
if (typesAlreadySetUp.has(eventType)) { | ||
continue; | ||
} | ||
|
||
// When we re-dispatch the event, it's going to immediately trigger this | ||
// listener again. Use a flag to ignore it. | ||
let isRedispatching = false; | ||
element.addEventListener( | ||
eventType, | ||
(event: Event) => { | ||
if (isRedispatching) { | ||
return; | ||
} | ||
|
||
// Do not let the event propagate to any other listener (not just | ||
// bubbling listeners with `stopPropagation()`). | ||
event.stopImmediatePropagation(); | ||
// Make a copy. | ||
const eventCopy = Reflect.construct(event.constructor, [ | ||
event.type, | ||
event, | ||
]); | ||
|
||
// Add hooks onto the event. | ||
const hooks = new EventTarget(); | ||
(eventCopy as EventWithDispatchHooks)[dispatchHooks] = hooks; | ||
|
||
// Re-dispatch the event. We can't reuse `redispatchEvent()` since we | ||
// need to add the hooks to the copy before it's dispatched. | ||
isRedispatching = true; | ||
const dispatched = element.dispatchEvent(eventCopy); | ||
isRedispatching = false; | ||
if (!dispatched) { | ||
event.preventDefault(); | ||
} | ||
|
||
// Synchronously call afterDispatch() hooks. | ||
hooks.dispatchEvent(new Event('after')); | ||
}, | ||
{ | ||
// Ensure this listener runs before other listeners. | ||
// `setupDispatchHooks()` should be called in constructors to also | ||
// ensure they run before any other externally-added capture listeners. | ||
capture: true, | ||
}, | ||
); | ||
|
||
typesAlreadySetUp.add(eventType); | ||
} | ||
} |
Oops, something went wrong.