From 69ff4f0bbcf62369d7590921d2920be9d2bb1900 Mon Sep 17 00:00:00 2001 From: Cory LaViska Date: Fri, 16 Sep 2022 16:21:40 -0400 Subject: [PATCH] refactor emit into ShoelaceElement --- docs/resources/changelog.md | 1 + .../plop/templates/component/component.hbs | 3 +-- src/components/alert/alert.ts | 10 +++++----- .../animated-image/animated-image.ts | 5 ++--- src/components/animation/animation.ts | 9 ++++----- src/components/button/button.ts | 5 ++--- src/components/checkbox/checkbox.ts | 7 +++---- src/components/color-picker/color-picker.ts | 3 +-- src/components/details/details.ts | 10 +++++----- src/components/dialog/dialog.ts | 14 +++++++------- src/components/drawer/drawer.ts | 14 +++++++------- src/components/dropdown/dropdown.ts | 10 +++++----- src/components/icon-button/icon-button.ts | 5 ++--- src/components/icon/icon.ts | 9 ++++----- .../image-comparer/image-comparer.ts | 3 +-- src/components/include/include.ts | 7 +++---- src/components/input/input.ts | 19 +++++++++---------- src/components/menu-item/menu-item.ts | 3 +-- src/components/menu/menu.ts | 3 +-- .../mutation-observer/mutation-observer.ts | 3 +-- src/components/popup/popup.ts | 3 +-- src/components/radio-button/radio-button.ts | 5 ++--- src/components/radio-group/radio-group.ts | 3 +-- src/components/radio/radio.ts | 5 ++--- src/components/range/range.ts | 7 +++---- src/components/rating/rating.ts | 3 +-- .../resize-observer/resize-observer.ts | 3 +-- src/components/select/select.ts | 9 ++++----- src/components/split-panel/split-panel.ts | 3 +-- src/components/switch/switch.ts | 11 +++++------ src/components/tab-group/tab-group.ts | 5 ++--- src/components/tab/tab.ts | 3 +-- src/components/tag/tag.ts | 3 +-- src/components/textarea/textarea.ts | 15 +++++++-------- src/components/tooltip/tooltip.ts | 10 +++++----- src/components/tree-item/tree-item.ts | 13 ++++++------- src/components/tree/tree.ts | 3 +-- src/internal/event.ts | 19 +------------------ src/internal/shoelace-element.ts | 15 +++++++++++++++ 39 files changed, 125 insertions(+), 156 deletions(-) diff --git a/docs/resources/changelog.md b/docs/resources/changelog.md index bf9d72f9..c46e8a00 100644 --- a/docs/resources/changelog.md +++ b/docs/resources/changelog.md @@ -28,6 +28,7 @@ This release removes the `` component. When this component - Fixed a bug in `` that prevented the textarea from resizing automatically when setting the value programmatically [#912](https://github.com/shoelace-style/shoelace/discussions/912) - Fixed a handful of paths to prevent TypeScript from getting upset [#886](https://github.com/shoelace-style/shoelace/issues/886) - Fixed a bug in `` where the `button-group__base` part was documented but not exposed [#909](https://github.com/shoelace-style/shoelace/discussions/909) +- Refactored the internal event emitter to be part of `ShoelaceElement` to reduce imports and improve DX - Upgraded the status of ``, ``, and `` from experimental to stable ## 2.0.0-beta.82 diff --git a/scripts/plop/templates/component/component.hbs b/scripts/plop/templates/component/component.hbs index 401bfc2b..4232ee88 100644 --- a/scripts/plop/templates/component/component.hbs +++ b/scripts/plop/templates/component/component.hbs @@ -1,6 +1,5 @@ import { html } from 'lit'; import { customElement, property } from 'lit/decorators.js'; -import { emit } from '../../internal/event'; import ShoelaceElement from '../../internal/shoelace-element'; import { watch } from '../../internal/watch'; import { LocalizeController } from '../../utilities/localize'; @@ -34,7 +33,7 @@ export default class {{ properCase tag }} extends ShoelaceElement { @watch('someProp') doSomething() { // Example event - emit(this, 'sl-event-name'); + this.emit('sl-event-name'); } render() { diff --git a/src/components/alert/alert.ts b/src/components/alert/alert.ts index 19ffd414..707e970c 100644 --- a/src/components/alert/alert.ts +++ b/src/components/alert/alert.ts @@ -2,7 +2,7 @@ import { html } from 'lit'; import { customElement, property, query } from 'lit/decorators.js'; import { classMap } from 'lit/directives/class-map.js'; import { animateTo, stopAnimations } from '../../internal/animate'; -import { emit, waitForEvent } from '../../internal/event'; +import { waitForEvent } from '../../internal/event'; import ShoelaceElement from '../../internal/shoelace-element'; import { HasSlotController } from '../../internal/slot'; import { watch } from '../../internal/watch'; @@ -144,7 +144,7 @@ export default class SlAlert extends ShoelaceElement { async handleOpenChange() { if (this.open) { // Show - emit(this, 'sl-show'); + this.emit('sl-show'); if (this.duration < Infinity) { this.restartAutoHide(); @@ -155,10 +155,10 @@ export default class SlAlert extends ShoelaceElement { const { keyframes, options } = getAnimation(this, 'alert.show', { dir: this.localize.dir() }); await animateTo(this.base, keyframes, options); - emit(this, 'sl-after-show'); + this.emit('sl-after-show'); } else { // Hide - emit(this, 'sl-hide'); + this.emit('sl-hide'); clearTimeout(this.autoHideTimeout); @@ -167,7 +167,7 @@ export default class SlAlert extends ShoelaceElement { await animateTo(this.base, keyframes, options); this.base.hidden = true; - emit(this, 'sl-after-hide'); + this.emit('sl-after-hide'); } } diff --git a/src/components/animated-image/animated-image.ts b/src/components/animated-image/animated-image.ts index 154e67b4..4ef1a47a 100644 --- a/src/components/animated-image/animated-image.ts +++ b/src/components/animated-image/animated-image.ts @@ -1,6 +1,5 @@ import { html } from 'lit'; import { customElement, property, query, state } from 'lit/decorators.js'; -import { emit } from '../../internal/event'; import ShoelaceElement from '../../internal/shoelace-element'; import { watch } from '../../internal/watch'; import '../icon/icon'; @@ -54,13 +53,13 @@ export default class SlAnimatedImage extends ShoelaceElement { this.frozenFrame = canvas.toDataURL('image/gif'); if (!this.isLoaded) { - emit(this, 'sl-load'); + this.emit('sl-load'); this.isLoaded = true; } } handleError() { - emit(this, 'sl-error'); + this.emit('sl-error'); } @watch('play', { waitUntilFirstUpdate: true }) diff --git a/src/components/animation/animation.ts b/src/components/animation/animation.ts index 49788993..3f4f677f 100644 --- a/src/components/animation/animation.ts +++ b/src/components/animation/animation.ts @@ -1,6 +1,5 @@ import { html } from 'lit'; import { customElement, property, queryAsync } from 'lit/decorators.js'; -import { emit } from '../../internal/event'; import ShoelaceElement from '../../internal/shoelace-element'; import { watch } from '../../internal/watch'; import styles from './animation.styles'; @@ -117,13 +116,13 @@ export default class SlAnimation extends ShoelaceElement { handleAnimationFinish() { this.play = false; this.hasStarted = false; - emit(this, 'sl-finish'); + this.emit('sl-finish'); } handleAnimationCancel() { this.play = false; this.hasStarted = false; - emit(this, 'sl-cancel'); + this.emit('sl-cancel'); } @watch('play') @@ -131,7 +130,7 @@ export default class SlAnimation extends ShoelaceElement { if (this.animation) { if (this.play && !this.hasStarted) { this.hasStarted = true; - emit(this, 'sl-start'); + this.emit('sl-start'); } if (this.play) { @@ -184,7 +183,7 @@ export default class SlAnimation extends ShoelaceElement { if (this.play) { this.hasStarted = true; - emit(this, 'sl-start'); + this.emit('sl-start'); } else { this.animation.pause(); } diff --git a/src/components/button/button.ts b/src/components/button/button.ts index 3c3baf37..f35bf53c 100644 --- a/src/components/button/button.ts +++ b/src/components/button/button.ts @@ -2,7 +2,6 @@ import { customElement, property, query, state } from 'lit/decorators.js'; import { classMap } from 'lit/directives/class-map.js'; import { ifDefined } from 'lit/directives/if-defined.js'; import { html, literal } from 'lit/static-html.js'; -import { emit } from '../../internal/event'; import { FormSubmitController } from '../../internal/form'; import ShoelaceElement from '../../internal/shoelace-element'; import { HasSlotController } from '../../internal/slot'; @@ -136,12 +135,12 @@ export default class SlButton extends ShoelaceElement { handleBlur() { this.hasFocus = false; - emit(this, 'sl-blur'); + this.emit('sl-blur'); } handleFocus() { this.hasFocus = true; - emit(this, 'sl-focus'); + this.emit('sl-focus'); } handleClick(event: MouseEvent) { diff --git a/src/components/checkbox/checkbox.ts b/src/components/checkbox/checkbox.ts index 2effae66..a4b850ec 100644 --- a/src/components/checkbox/checkbox.ts +++ b/src/components/checkbox/checkbox.ts @@ -4,7 +4,6 @@ import { classMap } from 'lit/directives/class-map.js'; import { ifDefined } from 'lit/directives/if-defined.js'; import { live } from 'lit/directives/live.js'; import { defaultValue } from '../../internal/default-value'; -import { emit } from '../../internal/event'; import { FormSubmitController } from '../../internal/form'; import ShoelaceElement from '../../internal/shoelace-element'; import { watch } from '../../internal/watch'; @@ -100,12 +99,12 @@ export default class SlCheckbox extends ShoelaceElement { handleClick() { this.checked = !this.checked; this.indeterminate = false; - emit(this, 'sl-change'); + this.emit('sl-change'); } handleBlur() { this.hasFocus = false; - emit(this, 'sl-blur'); + this.emit('sl-blur'); } @watch('disabled', { waitUntilFirstUpdate: true }) @@ -117,7 +116,7 @@ export default class SlCheckbox extends ShoelaceElement { handleFocus() { this.hasFocus = true; - emit(this, 'sl-focus'); + this.emit('sl-focus'); } @watch('checked', { waitUntilFirstUpdate: true }) diff --git a/src/components/color-picker/color-picker.ts b/src/components/color-picker/color-picker.ts index f57e9d52..5c61d964 100644 --- a/src/components/color-picker/color-picker.ts +++ b/src/components/color-picker/color-picker.ts @@ -7,7 +7,6 @@ import { live } from 'lit/directives/live.js'; import { styleMap } from 'lit/directives/style-map.js'; import { defaultValue } from '../../internal/default-value'; import { drag } from '../../internal/drag'; -import { emit } from '../../internal/event'; import { FormSubmitController } from '../../internal/form'; import { clamp } from '../../internal/math'; import ShoelaceElement from '../../internal/shoelace-element'; @@ -674,7 +673,7 @@ export default class SlColorPicker extends ShoelaceElement { } if (this.value !== this.lastValueEmitted) { - emit(this, 'sl-change'); + this.emit('sl-change'); this.lastValueEmitted = this.value; } } diff --git a/src/components/details/details.ts b/src/components/details/details.ts index b9cb6155..22d6fc2a 100644 --- a/src/components/details/details.ts +++ b/src/components/details/details.ts @@ -2,7 +2,7 @@ import { html } from 'lit'; import { customElement, property, query } from 'lit/decorators.js'; import { classMap } from 'lit/directives/class-map.js'; import { animateTo, shimKeyframesHeightAuto, stopAnimations } from '../../internal/animate'; -import { emit, waitForEvent } from '../../internal/event'; +import { waitForEvent } from '../../internal/event'; import ShoelaceElement from '../../internal/shoelace-element'; import { watch } from '../../internal/watch'; import { getAnimation, setDefaultAnimation } from '../../utilities/animation-registry'; @@ -116,7 +116,7 @@ export default class SlDetails extends ShoelaceElement { async handleOpenChange() { if (this.open) { // Show - emit(this, 'sl-show'); + this.emit('sl-show'); await stopAnimations(this.body); this.body.hidden = false; @@ -125,10 +125,10 @@ export default class SlDetails extends ShoelaceElement { await animateTo(this.body, shimKeyframesHeightAuto(keyframes, this.body.scrollHeight), options); this.body.style.height = 'auto'; - emit(this, 'sl-after-show'); + this.emit('sl-after-show'); } else { // Hide - emit(this, 'sl-hide'); + this.emit('sl-hide'); await stopAnimations(this.body); @@ -137,7 +137,7 @@ export default class SlDetails extends ShoelaceElement { this.body.hidden = true; this.body.style.height = 'auto'; - emit(this, 'sl-after-hide'); + this.emit('sl-after-hide'); } } diff --git a/src/components/dialog/dialog.ts b/src/components/dialog/dialog.ts index f297e73a..a0c45bb4 100644 --- a/src/components/dialog/dialog.ts +++ b/src/components/dialog/dialog.ts @@ -3,7 +3,7 @@ import { customElement, property, query } from 'lit/decorators.js'; import { classMap } from 'lit/directives/class-map.js'; import { ifDefined } from 'lit/directives/if-defined.js'; import { animateTo, stopAnimations } from '../../internal/animate'; -import { emit, waitForEvent } from '../../internal/event'; +import { waitForEvent } from '../../internal/event'; import Modal from '../../internal/modal'; import { lockBodyScrolling, unlockBodyScrolling } from '../../internal/scroll'; import ShoelaceElement from '../../internal/shoelace-element'; @@ -126,7 +126,7 @@ export default class SlDialog extends ShoelaceElement { } private requestClose(source: 'close-button' | 'keyboard' | 'overlay') { - const slRequestClose = emit(this, 'sl-request-close', { + const slRequestClose = this.emit('sl-request-close', { cancelable: true, detail: { source } }); @@ -151,7 +151,7 @@ export default class SlDialog extends ShoelaceElement { async handleOpenChange() { if (this.open) { // Show - emit(this, 'sl-show'); + this.emit('sl-show'); this.originalTrigger = document.activeElement as HTMLElement; this.modal.activate(); @@ -173,7 +173,7 @@ export default class SlDialog extends ShoelaceElement { // Set initial focus requestAnimationFrame(() => { - const slInitialFocus = emit(this, 'sl-initial-focus', { cancelable: true }); + const slInitialFocus = this.emit('sl-initial-focus', { cancelable: true }); if (!slInitialFocus.defaultPrevented) { // Set focus to the autofocus target and restore the attribute @@ -197,10 +197,10 @@ export default class SlDialog extends ShoelaceElement { animateTo(this.overlay, overlayAnimation.keyframes, overlayAnimation.options) ]); - emit(this, 'sl-after-show'); + this.emit('sl-after-show'); } else { // Hide - emit(this, 'sl-hide'); + this.emit('sl-hide'); this.modal.deactivate(); await Promise.all([stopAnimations(this.dialog), stopAnimations(this.overlay)]); @@ -233,7 +233,7 @@ export default class SlDialog extends ShoelaceElement { setTimeout(() => trigger.focus()); } - emit(this, 'sl-after-hide'); + this.emit('sl-after-hide'); } } diff --git a/src/components/drawer/drawer.ts b/src/components/drawer/drawer.ts index ab8166b7..c7e0efe2 100644 --- a/src/components/drawer/drawer.ts +++ b/src/components/drawer/drawer.ts @@ -3,7 +3,7 @@ import { customElement, property, query } from 'lit/decorators.js'; import { classMap } from 'lit/directives/class-map.js'; import { ifDefined } from 'lit/directives/if-defined.js'; import { animateTo, stopAnimations } from '../../internal/animate'; -import { emit, waitForEvent } from '../../internal/event'; +import { waitForEvent } from '../../internal/event'; import Modal from '../../internal/modal'; import { lockBodyScrolling, unlockBodyScrolling } from '../../internal/scroll'; import ShoelaceElement from '../../internal/shoelace-element'; @@ -143,7 +143,7 @@ export default class SlDrawer extends ShoelaceElement { } private requestClose(source: 'close-button' | 'keyboard' | 'overlay') { - const slRequestClose = emit(this, 'sl-request-close', { + const slRequestClose = this.emit('sl-request-close', { cancelable: true, detail: { source } }); @@ -168,7 +168,7 @@ export default class SlDrawer extends ShoelaceElement { async handleOpenChange() { if (this.open) { // Show - emit(this, 'sl-show'); + this.emit('sl-show'); this.originalTrigger = document.activeElement as HTMLElement; // Lock body scrolling only if the drawer isn't contained @@ -193,7 +193,7 @@ export default class SlDrawer extends ShoelaceElement { // Set initial focus requestAnimationFrame(() => { - const slInitialFocus = emit(this, 'sl-initial-focus', { cancelable: true }); + const slInitialFocus = this.emit('sl-initial-focus', { cancelable: true }); if (!slInitialFocus.defaultPrevented) { // Set focus to the autofocus target and restore the attribute @@ -219,10 +219,10 @@ export default class SlDrawer extends ShoelaceElement { animateTo(this.overlay, overlayAnimation.keyframes, overlayAnimation.options) ]); - emit(this, 'sl-after-show'); + this.emit('sl-after-show'); } else { // Hide - emit(this, 'sl-hide'); + this.emit('sl-hide'); this.modal.deactivate(); unlockBodyScrolling(this); @@ -256,7 +256,7 @@ export default class SlDrawer extends ShoelaceElement { setTimeout(() => trigger.focus()); } - emit(this, 'sl-after-hide'); + this.emit('sl-after-hide'); } } diff --git a/src/components/dropdown/dropdown.ts b/src/components/dropdown/dropdown.ts index fa65b6df..94c62b23 100644 --- a/src/components/dropdown/dropdown.ts +++ b/src/components/dropdown/dropdown.ts @@ -2,7 +2,7 @@ import { html } from 'lit'; import { customElement, property, query } from 'lit/decorators.js'; import { classMap } from 'lit/directives/class-map.js'; import { animateTo, stopAnimations } from '../../internal/animate'; -import { emit, waitForEvent } from '../../internal/event'; +import { waitForEvent } from '../../internal/event'; import { scrollIntoView } from '../../internal/scroll'; import ShoelaceElement from '../../internal/shoelace-element'; import { getTabbableBoundary } from '../../internal/tabbable'; @@ -361,7 +361,7 @@ export default class SlDropdown extends ShoelaceElement { if (this.open) { // Show - emit(this, 'sl-show'); + this.emit('sl-show'); this.addOpenListeners(); await stopAnimations(this); @@ -370,10 +370,10 @@ export default class SlDropdown extends ShoelaceElement { const { keyframes, options } = getAnimation(this, 'dropdown.show', { dir: this.localize.dir() }); await animateTo(this.popup.popup, keyframes, options); - emit(this, 'sl-after-show'); + this.emit('sl-after-show'); } else { // Hide - emit(this, 'sl-hide'); + this.emit('sl-hide'); this.removeOpenListeners(); await stopAnimations(this); @@ -382,7 +382,7 @@ export default class SlDropdown extends ShoelaceElement { this.panel.hidden = true; this.popup.active = false; - emit(this, 'sl-after-hide'); + this.emit('sl-after-hide'); } } diff --git a/src/components/icon-button/icon-button.ts b/src/components/icon-button/icon-button.ts index 1160733e..b9dea30d 100644 --- a/src/components/icon-button/icon-button.ts +++ b/src/components/icon-button/icon-button.ts @@ -2,7 +2,6 @@ import { customElement, property, query, state } from 'lit/decorators.js'; import { classMap } from 'lit/directives/class-map.js'; import { ifDefined } from 'lit/directives/if-defined.js'; import { html, literal } from 'lit/static-html.js'; -import { emit } from '../../internal/event'; import ShoelaceElement from '../../internal/shoelace-element'; import '../icon/icon'; import styles from './icon-button.styles'; @@ -71,12 +70,12 @@ export default class SlIconButton extends ShoelaceElement { handleBlur() { this.hasFocus = false; - emit(this, 'sl-blur'); + this.emit('sl-blur'); } handleFocus() { this.hasFocus = true; - emit(this, 'sl-focus'); + this.emit('sl-focus'); } handleClick(event: MouseEvent) { diff --git a/src/components/icon/icon.ts b/src/components/icon/icon.ts index 334175aa..faca5925 100644 --- a/src/components/icon/icon.ts +++ b/src/components/icon/icon.ts @@ -2,7 +2,6 @@ import { html } from 'lit'; import { customElement, property, state } from 'lit/decorators.js'; import { ifDefined } from 'lit/directives/if-defined.js'; import { unsafeSVG } from 'lit/directives/unsafe-svg.js'; -import { emit } from '../../internal/event'; import ShoelaceElement from '../../internal/shoelace-element'; import { watch } from '../../internal/watch'; import styles from './icon.styles'; @@ -96,17 +95,17 @@ export default class SlIcon extends ShoelaceElement { if (svgEl !== null) { library?.mutator?.(svgEl); this.svg = svgEl.outerHTML; - emit(this, 'sl-load'); + this.emit('sl-load'); } else { this.svg = ''; - emit(this, 'sl-error'); + this.emit('sl-error'); } } else { this.svg = ''; - emit(this, 'sl-error'); + this.emit('sl-error'); } } catch { - emit(this, 'sl-error'); + this.emit('sl-error'); } } else if (this.svg.length > 0) { // If we can't resolve a URL and an icon was previously set, remove it diff --git a/src/components/image-comparer/image-comparer.ts b/src/components/image-comparer/image-comparer.ts index 4323ecf8..9a4c3e46 100644 --- a/src/components/image-comparer/image-comparer.ts +++ b/src/components/image-comparer/image-comparer.ts @@ -3,7 +3,6 @@ import { customElement, property, query } from 'lit/decorators.js'; import { classMap } from 'lit/directives/class-map.js'; import { styleMap } from 'lit/directives/style-map.js'; import { drag } from '../../internal/drag'; -import { emit } from '../../internal/event'; import { clamp } from '../../internal/math'; import ShoelaceElement from '../../internal/shoelace-element'; import { watch } from '../../internal/watch'; @@ -90,7 +89,7 @@ export default class SlImageComparer extends ShoelaceElement { @watch('position', { waitUntilFirstUpdate: true }) handlePositionChange() { - emit(this, 'sl-change'); + this.emit('sl-change'); } render() { diff --git a/src/components/include/include.ts b/src/components/include/include.ts index 643f2a68..ec3a030a 100644 --- a/src/components/include/include.ts +++ b/src/components/include/include.ts @@ -1,6 +1,5 @@ import { html } from 'lit'; import { customElement, property } from 'lit/decorators.js'; -import { emit } from '../../internal/event'; import ShoelaceElement from '../../internal/shoelace-element'; import { watch } from '../../internal/watch'; import styles from './include.styles'; @@ -54,7 +53,7 @@ export default class SlInclude extends ShoelaceElement { } if (!file.ok) { - emit(this, 'sl-error', { detail: { status: file.status } }); + this.emit('sl-error', { detail: { status: file.status } }); return; } @@ -64,9 +63,9 @@ export default class SlInclude extends ShoelaceElement { [...this.querySelectorAll('script')].forEach(script => this.executeScript(script)); } - emit(this, 'sl-load'); + this.emit('sl-load'); } catch { - emit(this, 'sl-error', { detail: { status: -1 } }); + this.emit('sl-error', { detail: { status: -1 } }); } } diff --git a/src/components/input/input.ts b/src/components/input/input.ts index 34f6b479..3d2941a2 100644 --- a/src/components/input/input.ts +++ b/src/components/input/input.ts @@ -4,7 +4,6 @@ import { classMap } from 'lit/directives/class-map.js'; import { ifDefined } from 'lit/directives/if-defined.js'; import { live } from 'lit/directives/live.js'; import { defaultValue } from '../../internal/default-value'; -import { emit } from '../../internal/event'; import { FormSubmitController } from '../../internal/form'; import ShoelaceElement from '../../internal/shoelace-element'; import { HasSlotController } from '../../internal/slot'; @@ -246,8 +245,8 @@ export default class SlInput extends ShoelaceElement { if (this.value !== this.input.value) { this.value = this.input.value; - emit(this, 'sl-input'); - emit(this, 'sl-change'); + this.emit('sl-input'); + this.emit('sl-change'); } } @@ -264,19 +263,19 @@ export default class SlInput extends ShoelaceElement { handleBlur() { this.hasFocus = false; - emit(this, 'sl-blur'); + this.emit('sl-blur'); } handleChange() { this.value = this.input.value; - emit(this, 'sl-change'); + this.emit('sl-change'); } handleClearClick(event: MouseEvent) { this.value = ''; - emit(this, 'sl-clear'); - emit(this, 'sl-input'); - emit(this, 'sl-change'); + this.emit('sl-clear'); + this.emit('sl-input'); + this.emit('sl-change'); this.input.focus(); event.stopPropagation(); @@ -299,12 +298,12 @@ export default class SlInput extends ShoelaceElement { handleFocus() { this.hasFocus = true; - emit(this, 'sl-focus'); + this.emit('sl-focus'); } handleInput() { this.value = this.input.value; - emit(this, 'sl-input'); + this.emit('sl-input'); } handleInvalid() { diff --git a/src/components/menu-item/menu-item.ts b/src/components/menu-item/menu-item.ts index 63c35b0e..198bb268 100644 --- a/src/components/menu-item/menu-item.ts +++ b/src/components/menu-item/menu-item.ts @@ -1,7 +1,6 @@ import { html } from 'lit'; import { customElement, property, query } from 'lit/decorators.js'; import { classMap } from 'lit/directives/class-map.js'; -import { emit } from '../../internal/event'; import ShoelaceElement from '../../internal/shoelace-element'; import { getTextContent } from '../../internal/slot'; import { watch } from '../../internal/watch'; @@ -76,7 +75,7 @@ export default class SlMenuItem extends ShoelaceElement { if (textLabel !== this.cachedTextLabel) { this.cachedTextLabel = textLabel; - emit(this, 'sl-label-change'); + this.emit('sl-label-change'); } } diff --git a/src/components/menu/menu.ts b/src/components/menu/menu.ts index 62301b8b..e39b4802 100644 --- a/src/components/menu/menu.ts +++ b/src/components/menu/menu.ts @@ -1,6 +1,5 @@ import { html } from 'lit'; import { customElement, query } from 'lit/decorators.js'; -import { emit } from '../../internal/event'; import ShoelaceElement from '../../internal/shoelace-element'; import { getTextContent } from '../../internal/slot'; import styles from './menu.styles'; @@ -107,7 +106,7 @@ export default class SlMenu extends ShoelaceElement { const item = target.closest('sl-menu-item'); if (item?.disabled === false) { - emit(this, 'sl-select', { detail: { item } }); + this.emit('sl-select', { detail: { item } }); } } diff --git a/src/components/mutation-observer/mutation-observer.ts b/src/components/mutation-observer/mutation-observer.ts index 537a508c..ca167ce9 100644 --- a/src/components/mutation-observer/mutation-observer.ts +++ b/src/components/mutation-observer/mutation-observer.ts @@ -1,6 +1,5 @@ import { html } from 'lit'; import { customElement, property } from 'lit/decorators.js'; -import { emit } from '../../internal/event'; import ShoelaceElement from '../../internal/shoelace-element'; import { watch } from '../../internal/watch'; import styles from './mutation-observer.styles'; @@ -76,7 +75,7 @@ export default class SlMutationObserver extends ShoelaceElement { } handleMutation(mutationList: MutationRecord[]) { - emit(this, 'sl-mutation', { + this.emit('sl-mutation', { detail: { mutationList } }); } diff --git a/src/components/popup/popup.ts b/src/components/popup/popup.ts index 3aa9381a..f39416a5 100644 --- a/src/components/popup/popup.ts +++ b/src/components/popup/popup.ts @@ -2,7 +2,6 @@ import { arrow, autoUpdate, computePosition, flip, offset, shift, size } from '@ import { html } from 'lit'; import { customElement, property, query } from 'lit/decorators.js'; import { classMap } from 'lit/directives/class-map.js'; -import { emit } from '../../internal/event'; import ShoelaceElement from '../../internal/shoelace-element'; import styles from './popup.styles'; import type { CSSResultGroup } from 'lit'; @@ -425,7 +424,7 @@ export default class SlPopup extends ShoelaceElement { } }); - emit(this, 'sl-reposition'); + this.emit('sl-reposition'); } render() { diff --git a/src/components/radio-button/radio-button.ts b/src/components/radio-button/radio-button.ts index d30af6c2..9ef6ecc2 100644 --- a/src/components/radio-button/radio-button.ts +++ b/src/components/radio-button/radio-button.ts @@ -2,7 +2,6 @@ import { customElement, property, query, state } from 'lit/decorators.js'; import { classMap } from 'lit/directives/class-map.js'; import { ifDefined } from 'lit/directives/if-defined.js'; import { html } from 'lit/static-html.js'; -import { emit } from '../../internal/event'; import ShoelaceElement from '../../internal/shoelace-element'; import { HasSlotController } from '../../internal/slot'; import { watch } from '../../internal/watch'; @@ -62,7 +61,7 @@ export default class SlRadioButton extends ShoelaceElement { handleBlur() { this.hasFocus = false; - emit(this, 'sl-blur'); + this.emit('sl-blur'); } handleClick(e: MouseEvent) { @@ -77,7 +76,7 @@ export default class SlRadioButton extends ShoelaceElement { handleFocus() { this.hasFocus = true; - emit(this, 'sl-focus'); + this.emit('sl-focus'); } render() { diff --git a/src/components/radio-group/radio-group.ts b/src/components/radio-group/radio-group.ts index 2da2d259..ac15c67e 100644 --- a/src/components/radio-group/radio-group.ts +++ b/src/components/radio-group/radio-group.ts @@ -1,7 +1,6 @@ import { html } from 'lit'; import { customElement, property, query, state } from 'lit/decorators.js'; import { classMap } from 'lit/directives/class-map.js'; -import { emit } from '../../internal/event'; import { FormSubmitController } from '../../internal/form'; import ShoelaceElement from '../../internal/shoelace-element'; import { watch } from '../../internal/watch'; @@ -70,7 +69,7 @@ export default class SlRadioGroup extends ShoelaceElement { @watch('value') handleValueChange() { if (this.hasUpdated) { - emit(this, 'sl-change'); + this.emit('sl-change'); this.updateCheckedRadio(); } } diff --git a/src/components/radio/radio.ts b/src/components/radio/radio.ts index 33b14910..504af332 100644 --- a/src/components/radio/radio.ts +++ b/src/components/radio/radio.ts @@ -1,7 +1,6 @@ import { html } from 'lit'; import { customElement, property, state } from 'lit/decorators.js'; import { classMap } from 'lit/directives/class-map.js'; -import { emit } from '../../internal/event'; import ShoelaceElement from '../../internal/shoelace-element'; import { watch } from '../../internal/watch'; import styles from './radio.styles'; @@ -53,7 +52,7 @@ export default class SlRadio extends ShoelaceElement { private handleBlur() { this.hasFocus = false; - emit(this, 'sl-blur'); + this.emit('sl-blur'); } private handleClick() { @@ -64,7 +63,7 @@ export default class SlRadio extends ShoelaceElement { private handleFocus() { this.hasFocus = true; - emit(this, 'sl-focus'); + this.emit('sl-focus'); } private addEventListeners() { diff --git a/src/components/range/range.ts b/src/components/range/range.ts index b10c01e1..bd98d9fe 100644 --- a/src/components/range/range.ts +++ b/src/components/range/range.ts @@ -4,7 +4,6 @@ import { classMap } from 'lit/directives/class-map.js'; import { ifDefined } from 'lit/directives/if-defined.js'; import { live } from 'lit/directives/live.js'; import { defaultValue } from '../../internal/default-value'; -import { emit } from '../../internal/event'; import { FormSubmitController } from '../../internal/form'; import ShoelaceElement from '../../internal/shoelace-element'; import { HasSlotController } from '../../internal/slot'; @@ -135,7 +134,7 @@ export default class SlRange extends ShoelaceElement { handleInput() { this.value = parseFloat(this.input.value); - emit(this, 'sl-change'); + this.emit('sl-change'); this.syncRange(); } @@ -143,7 +142,7 @@ export default class SlRange extends ShoelaceElement { handleBlur() { this.hasFocus = false; this.hasTooltip = false; - emit(this, 'sl-blur'); + this.emit('sl-blur'); } @watch('value', { waitUntilFirstUpdate: true }) @@ -168,7 +167,7 @@ export default class SlRange extends ShoelaceElement { handleFocus() { this.hasFocus = true; this.hasTooltip = true; - emit(this, 'sl-focus'); + this.emit('sl-focus'); } handleThumbDragStart() { diff --git a/src/components/rating/rating.ts b/src/components/rating/rating.ts index a89765ff..647b42c7 100644 --- a/src/components/rating/rating.ts +++ b/src/components/rating/rating.ts @@ -3,7 +3,6 @@ import { customElement, property, query, state } from 'lit/decorators.js'; import { classMap } from 'lit/directives/class-map.js'; import { styleMap } from 'lit/directives/style-map.js'; import { unsafeHTML } from 'lit/directives/unsafe-html.js'; -import { emit } from '../../internal/event'; import { clamp } from '../../internal/math'; import ShoelaceElement from '../../internal/shoelace-element'; import { watch } from '../../internal/watch'; @@ -165,7 +164,7 @@ export default class SlRating extends ShoelaceElement { @watch('value', { waitUntilFirstUpdate: true }) handleValueChange() { - emit(this, 'sl-change'); + this.emit('sl-change'); } roundToPrecision(numberToRound: number, precision = 0.5) { diff --git a/src/components/resize-observer/resize-observer.ts b/src/components/resize-observer/resize-observer.ts index c8c83919..bda9f508 100644 --- a/src/components/resize-observer/resize-observer.ts +++ b/src/components/resize-observer/resize-observer.ts @@ -1,6 +1,5 @@ import { html } from 'lit'; import { customElement, property } from 'lit/decorators.js'; -import { emit } from '../../internal/event'; import ShoelaceElement from '../../internal/shoelace-element'; import { watch } from '../../internal/watch'; import styles from './resize-observer.styles'; @@ -27,7 +26,7 @@ export default class SlResizeObserver extends ShoelaceElement { connectedCallback() { super.connectedCallback(); this.resizeObserver = new ResizeObserver((entries: ResizeObserverEntry[]) => { - emit(this, 'sl-resize', { detail: { entries } }); + this.emit('sl-resize', { detail: { entries } }); }); if (!this.disabled) { diff --git a/src/components/select/select.ts b/src/components/select/select.ts index b7209f03..1278a90d 100644 --- a/src/components/select/select.ts +++ b/src/components/select/select.ts @@ -2,7 +2,6 @@ import { html } from 'lit'; import { customElement, property, query, state } from 'lit/decorators.js'; import { classMap } from 'lit/directives/class-map.js'; import { defaultValue } from '../../internal/default-value'; -import { emit } from '../../internal/event'; import { FormSubmitController } from '../../internal/form'; import ShoelaceElement from '../../internal/shoelace-element'; import { HasSlotController } from '../../internal/slot'; @@ -196,14 +195,14 @@ export default class SlSelect extends ShoelaceElement { // Don't blur if the control is open. We'll move focus back once it closes. if (!this.isOpen) { this.hasFocus = false; - emit(this, 'sl-blur'); + this.emit('sl-blur'); } } handleClearClick(event: MouseEvent) { event.stopPropagation(); this.value = this.multiple ? [] : ''; - emit(this, 'sl-clear'); + this.emit('sl-clear'); this.syncItemsFromValue(); } @@ -221,7 +220,7 @@ export default class SlSelect extends ShoelaceElement { handleFocus() { if (!this.hasFocus) { this.hasFocus = true; - emit(this, 'sl-focus'); + this.emit('sl-focus'); } } @@ -365,7 +364,7 @@ export default class SlSelect extends ShoelaceElement { this.syncItemsFromValue(); await this.updateComplete; this.invalid = !this.input.checkValidity(); - emit(this, 'sl-change'); + this.emit('sl-change'); } resizeMenu() { diff --git a/src/components/split-panel/split-panel.ts b/src/components/split-panel/split-panel.ts index 1fb497eb..184d9626 100644 --- a/src/components/split-panel/split-panel.ts +++ b/src/components/split-panel/split-panel.ts @@ -2,7 +2,6 @@ import { html } from 'lit'; import { customElement, property, query } from 'lit/decorators.js'; import { ifDefined } from 'lit/directives/if-defined.js'; import { drag } from '../../internal/drag'; -import { emit } from '../../internal/event'; import { clamp } from '../../internal/math'; import ShoelaceElement from '../../internal/shoelace-element'; import { watch } from '../../internal/watch'; @@ -190,7 +189,7 @@ export default class SlSplitPanel extends ShoelaceElement { handlePositionChange() { this.cachedPositionInPixels = this.percentageToPixels(this.position); this.positionInPixels = this.percentageToPixels(this.position); - emit(this, 'sl-reposition'); + this.emit('sl-reposition'); } @watch('positionInPixels') diff --git a/src/components/switch/switch.ts b/src/components/switch/switch.ts index a5a812d9..70bd8513 100644 --- a/src/components/switch/switch.ts +++ b/src/components/switch/switch.ts @@ -4,7 +4,6 @@ import { classMap } from 'lit/directives/class-map.js'; import { ifDefined } from 'lit/directives/if-defined.js'; import { live } from 'lit/directives/live.js'; import { defaultValue } from '../../internal/default-value'; -import { emit } from '../../internal/event'; import { FormSubmitController } from '../../internal/form'; import ShoelaceElement from '../../internal/shoelace-element'; import { watch } from '../../internal/watch'; @@ -99,7 +98,7 @@ export default class SlSwitch extends ShoelaceElement { handleBlur() { this.hasFocus = false; - emit(this, 'sl-blur'); + this.emit('sl-blur'); } @watch('checked', { waitUntilFirstUpdate: true }) @@ -110,7 +109,7 @@ export default class SlSwitch extends ShoelaceElement { handleClick() { this.checked = !this.checked; - emit(this, 'sl-change'); + this.emit('sl-change'); } @watch('disabled', { waitUntilFirstUpdate: true }) @@ -122,20 +121,20 @@ export default class SlSwitch extends ShoelaceElement { handleFocus() { this.hasFocus = true; - emit(this, 'sl-focus'); + this.emit('sl-focus'); } handleKeyDown(event: KeyboardEvent) { if (event.key === 'ArrowLeft') { event.preventDefault(); this.checked = false; - emit(this, 'sl-change'); + this.emit('sl-change'); } if (event.key === 'ArrowRight') { event.preventDefault(); this.checked = true; - emit(this, 'sl-change'); + this.emit('sl-change'); } } diff --git a/src/components/tab-group/tab-group.ts b/src/components/tab-group/tab-group.ts index 03d43df5..4edb6364 100644 --- a/src/components/tab-group/tab-group.ts +++ b/src/components/tab-group/tab-group.ts @@ -1,7 +1,6 @@ import { html } from 'lit'; import { customElement, property, query, state } from 'lit/decorators.js'; import { classMap } from 'lit/directives/class-map.js'; -import { emit } from '../../internal/event'; import { scrollIntoView } from '../../internal/scroll'; import ShoelaceElement from '../../internal/shoelace-element'; import { watch } from '../../internal/watch'; @@ -272,10 +271,10 @@ export default class SlTabGroup extends ShoelaceElement { // Emit events if (options.emitEvents) { if (previousTab) { - emit(this, 'sl-tab-hide', { detail: { name: previousTab.panel } }); + this.emit('sl-tab-hide', { detail: { name: previousTab.panel } }); } - emit(this, 'sl-tab-show', { detail: { name: this.activeTab.panel } }); + this.emit('sl-tab-show', { detail: { name: this.activeTab.panel } }); } } } diff --git a/src/components/tab/tab.ts b/src/components/tab/tab.ts index 089f3882..e637e9e1 100644 --- a/src/components/tab/tab.ts +++ b/src/components/tab/tab.ts @@ -2,7 +2,6 @@ import { html } from 'lit'; import { customElement, property, query } from 'lit/decorators.js'; import { classMap } from 'lit/directives/class-map.js'; import { autoIncrement } from '../../internal/auto-increment'; -import { emit } from '../../internal/event'; import ShoelaceElement from '../../internal/shoelace-element'; import { watch } from '../../internal/watch'; import { LocalizeController } from '../../utilities/localize'; @@ -62,7 +61,7 @@ export default class SlTab extends ShoelaceElement { } handleCloseClick() { - emit(this, 'sl-close'); + this.emit('sl-close'); } @watch('active') diff --git a/src/components/tag/tag.ts b/src/components/tag/tag.ts index 03ca7a23..39cb033a 100644 --- a/src/components/tag/tag.ts +++ b/src/components/tag/tag.ts @@ -1,7 +1,6 @@ import { html } from 'lit'; import { customElement, property } from 'lit/decorators.js'; import { classMap } from 'lit/directives/class-map.js'; -import { emit } from '../../internal/event'; import ShoelaceElement from '../../internal/shoelace-element'; import { LocalizeController } from '../../utilities/localize'; import '../icon-button/icon-button'; @@ -41,7 +40,7 @@ export default class SlTag extends ShoelaceElement { @property({ type: Boolean }) removable = false; handleRemoveClick() { - emit(this, 'sl-remove'); + this.emit('sl-remove'); } render() { diff --git a/src/components/textarea/textarea.ts b/src/components/textarea/textarea.ts index 8b160b8a..e22a02ac 100644 --- a/src/components/textarea/textarea.ts +++ b/src/components/textarea/textarea.ts @@ -4,7 +4,6 @@ import { classMap } from 'lit/directives/class-map.js'; import { ifDefined } from 'lit/directives/if-defined.js'; import { live } from 'lit/directives/live.js'; import { defaultValue } from '../../internal/default-value'; -import { emit } from '../../internal/event'; import { FormSubmitController } from '../../internal/form'; import ShoelaceElement from '../../internal/shoelace-element'; import { HasSlotController } from '../../internal/slot'; @@ -188,14 +187,14 @@ export default class SlTextarea extends ShoelaceElement { if (this.value !== this.input.value) { this.value = this.input.value; - emit(this, 'sl-input'); + this.emit('sl-input'); } if (this.value !== this.input.value) { this.value = this.input.value; this.setTextareaHeight(); - emit(this, 'sl-input'); - emit(this, 'sl-change'); + this.emit('sl-input'); + this.emit('sl-change'); } } @@ -212,13 +211,13 @@ export default class SlTextarea extends ShoelaceElement { handleBlur() { this.hasFocus = false; - emit(this, 'sl-blur'); + this.emit('sl-blur'); } handleChange() { this.value = this.input.value; this.setTextareaHeight(); - emit(this, 'sl-change'); + this.emit('sl-change'); } @watch('disabled', { waitUntilFirstUpdate: true }) @@ -230,12 +229,12 @@ export default class SlTextarea extends ShoelaceElement { handleFocus() { this.hasFocus = true; - emit(this, 'sl-focus'); + this.emit('sl-focus'); } handleInput() { this.value = this.input.value; - emit(this, 'sl-input'); + this.emit('sl-input'); } @watch('rows', { waitUntilFirstUpdate: true }) diff --git a/src/components/tooltip/tooltip.ts b/src/components/tooltip/tooltip.ts index a20a51df..3aef4ae0 100644 --- a/src/components/tooltip/tooltip.ts +++ b/src/components/tooltip/tooltip.ts @@ -2,7 +2,7 @@ import { html } from 'lit'; import { customElement, property, query } from 'lit/decorators.js'; import { classMap } from 'lit/directives/class-map.js'; import { animateTo, parseDuration, stopAnimations } from '../../internal/animate'; -import { emit, waitForEvent } from '../../internal/event'; +import { waitForEvent } from '../../internal/event'; import ShoelaceElement from '../../internal/shoelace-element'; import { watch } from '../../internal/watch'; import { getAnimation, setDefaultAnimation } from '../../utilities/animation-registry'; @@ -221,7 +221,7 @@ export default class SlTooltip extends ShoelaceElement { } // Show - emit(this, 'sl-show'); + this.emit('sl-show'); await stopAnimations(this.body); this.body.hidden = false; @@ -229,10 +229,10 @@ export default class SlTooltip extends ShoelaceElement { const { keyframes, options } = getAnimation(this, 'tooltip.show', { dir: this.localize.dir() }); await animateTo(this.popup.popup, keyframes, options); - emit(this, 'sl-after-show'); + this.emit('sl-after-show'); } else { // Hide - emit(this, 'sl-hide'); + this.emit('sl-hide'); await stopAnimations(this.body); const { keyframes, options } = getAnimation(this, 'tooltip.hide', { dir: this.localize.dir() }); @@ -240,7 +240,7 @@ export default class SlTooltip extends ShoelaceElement { this.popup.active = false; this.body.hidden = true; - emit(this, 'sl-after-hide'); + this.emit('sl-after-hide'); } } diff --git a/src/components/tree-item/tree-item.ts b/src/components/tree-item/tree-item.ts index 1fcd7dde..8d9f04a3 100644 --- a/src/components/tree-item/tree-item.ts +++ b/src/components/tree-item/tree-item.ts @@ -4,7 +4,6 @@ import { classMap } from 'lit/directives/class-map.js'; import { live } from 'lit/directives/live.js'; import { when } from 'lit/directives/when.js'; import { animateTo, shimKeyframesHeightAuto, stopAnimations } from '../../internal/animate'; -import { emit } from '../../internal/event'; import ShoelaceElement from '../../internal/shoelace-element'; import { watch } from '../../internal/watch'; import { getAnimation, setDefaultAnimation } from '../../utilities/animation-registry'; @@ -137,7 +136,7 @@ export default class SlTreeItem extends ShoelaceElement { if (this.lazy) { this.loading = true; - emit(this, 'sl-lazy-load'); + this.emit('sl-lazy-load'); } else { this.animateExpand(); } @@ -148,11 +147,11 @@ export default class SlTreeItem extends ShoelaceElement { @watch('lazy', { waitUntilFirstUpdate: true }) handleLazyChange() { - emit(this, 'sl-lazy-change'); + this.emit('sl-lazy-change'); } private async animateExpand() { - emit(this, 'sl-expand'); + this.emit('sl-expand'); await stopAnimations(this.childrenContainer); this.childrenContainer.hidden = false; @@ -165,11 +164,11 @@ export default class SlTreeItem extends ShoelaceElement { ); this.childrenContainer.style.height = 'auto'; - emit(this, 'sl-after-expand'); + this.emit('sl-after-expand'); } private async animateCollapse() { - emit(this, 'sl-collapse'); + this.emit('sl-collapse'); await stopAnimations(this.childrenContainer); @@ -181,7 +180,7 @@ export default class SlTreeItem extends ShoelaceElement { ); this.childrenContainer.hidden = true; - emit(this, 'sl-after-collapse'); + this.emit('sl-after-collapse'); } // Gets all the nested tree items diff --git a/src/components/tree/tree.ts b/src/components/tree/tree.ts index bbb2747d..95751d29 100644 --- a/src/components/tree/tree.ts +++ b/src/components/tree/tree.ts @@ -1,6 +1,5 @@ import { html } from 'lit'; import { customElement, property, query } from 'lit/decorators.js'; -import { emit } from '../../internal/event'; import { clamp } from '../../internal/math'; import ShoelaceElement from '../../internal/shoelace-element'; import { watch } from '../../internal/watch'; @@ -188,7 +187,7 @@ export default class SlTree extends ShoelaceElement { selectedItem.expanded = !selectedItem.expanded; } - emit(this, 'sl-selection-change', { detail: { selection: this.selectedItems } }); + this.emit('sl-selection-change', { detail: { selection: this.selectedItems } }); } // Returns the list of tree items that are selected in the tree. diff --git a/src/internal/event.ts b/src/internal/event.ts index 38b64512..37c0ff55 100644 --- a/src/internal/event.ts +++ b/src/internal/event.ts @@ -1,21 +1,4 @@ -// -// Emits a custom event with more convenient defaults. -// -export function emit(el: HTMLElement, name: string, options?: CustomEventInit) { - const event = new CustomEvent(name, { - bubbles: true, - cancelable: false, - composed: true, - detail: {}, - ...options - }); - el.dispatchEvent(event); - return event; -} - -// -// Waits for a specific event to be emitted from an element. Ignores events that bubble up from child elements. -// +/** Waits for a specific event to be emitted from an element. Ignores events that bubble up from child elements. */ export function waitForEvent(el: HTMLElement, eventName: string) { return new Promise(resolve => { function done(event: Event) { diff --git a/src/internal/shoelace-element.ts b/src/internal/shoelace-element.ts index ed089388..93786d19 100644 --- a/src/internal/shoelace-element.ts +++ b/src/internal/shoelace-element.ts @@ -5,4 +5,19 @@ export default class ShoelaceElement extends LitElement { // Make localization attributes reactive @property() dir: string; @property() lang: string; + + /** Emits a custom event with more convenient defaults. */ + emit(name: string, options?: CustomEventInit) { + const event = new CustomEvent(name, { + bubbles: true, + cancelable: false, + composed: true, + detail: {}, + ...options + }); + + this.dispatchEvent(event); + + return event; + } }