Merge pull request #1372 from justinfagnani/no-bind

Code size optimizations: Replace .bind() with arrow functions, add listeners in constructors.
pull/1377/head
Konnor Rogers 2023-06-15 11:58:08 -04:00 zatwierdzone przez GitHub
commit c167bdd80f
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
15 zmienionych plików z 106 dodań i 188 usunięć

Wyświetl plik

@ -91,8 +91,6 @@ export default class SlAnimation extends ShoelaceElement {
connectedCallback() { connectedCallback() {
super.connectedCallback(); super.connectedCallback();
this.createAnimation(); this.createAnimation();
this.handleAnimationCancel = this.handleAnimationCancel.bind(this);
this.handleAnimationFinish = this.handleAnimationFinish.bind(this);
} }
disconnectedCallback() { disconnectedCallback() {
@ -100,17 +98,17 @@ export default class SlAnimation extends ShoelaceElement {
this.destroyAnimation(); this.destroyAnimation();
} }
private handleAnimationFinish() { private handleAnimationFinish = () => {
this.play = false; this.play = false;
this.hasStarted = false; this.hasStarted = false;
this.emit('sl-finish'); this.emit('sl-finish');
} };
private handleAnimationCancel() { private handleAnimationCancel = () => {
this.play = false; this.play = false;
this.hasStarted = false; this.hasStarted = false;
this.emit('sl-cancel'); this.emit('sl-cancel');
} };
private handleSlotChange() { private handleSlotChange() {
this.destroyAnimation(); this.destroyAnimation();

Wyświetl plik

@ -167,17 +167,11 @@ export default class SlButton extends ShoelaceElement implements ShoelaceFormCon
return ''; return '';
} }
connectedCallback() { constructor() {
super.connectedCallback(); super();
this.handleHostClick = this.handleHostClick.bind(this);
this.addEventListener('click', this.handleHostClick); this.addEventListener('click', this.handleHostClick);
} }
disconnectedCallback() {
super.disconnectedCallback();
this.removeEventListener('click', this.handleHostClick);
}
firstUpdated() { firstUpdated() {
if (this.isButton()) { if (this.isButton()) {
this.formControlController.updateValidity(); this.formControlController.updateValidity();
@ -204,13 +198,13 @@ export default class SlButton extends ShoelaceElement implements ShoelaceFormCon
} }
} }
private handleHostClick(event: MouseEvent) { private handleHostClick = (event: MouseEvent) => {
// Prevent the click event from being emitted when the button is disabled or loading // Prevent the click event from being emitted when the button is disabled or loading
if (this.disabled || this.loading) { if (this.disabled || this.loading) {
event.preventDefault(); event.preventDefault();
event.stopImmediatePropagation(); event.stopImmediatePropagation();
} }
} };
private handleInvalid(event: Event) { private handleInvalid(event: Event) {
this.formControlController.setValidity(false); this.formControlController.setValidity(false);

Wyświetl plik

@ -132,7 +132,7 @@ export default class SlCarousel extends ShoelaceElement {
protected firstUpdated(): void { protected firstUpdated(): void {
this.initializeSlides(); this.initializeSlides();
this.mutationObserver = new MutationObserver(this.handleSlotChange.bind(this)); this.mutationObserver = new MutationObserver(this.handleSlotChange);
this.mutationObserver.observe(this, { childList: true, subtree: false }); this.mutationObserver.observe(this, { childList: true, subtree: false });
} }
@ -211,7 +211,7 @@ export default class SlCarousel extends ShoelaceElement {
} }
} }
private handleSlotChange(mutations: MutationRecord[]) { private handleSlotChange = (mutations: MutationRecord[]) => {
const needsInitialization = mutations.some(mutation => const needsInitialization = mutations.some(mutation =>
[...mutation.addedNodes, ...mutation.removedNodes].some( [...mutation.addedNodes, ...mutation.removedNodes].some(
node => SlCarouselItem.isCarouselItem(node) && !(node as HTMLElement).hasAttribute('data-clone') node => SlCarouselItem.isCarouselItem(node) && !(node as HTMLElement).hasAttribute('data-clone')
@ -223,7 +223,7 @@ export default class SlCarousel extends ShoelaceElement {
this.initializeSlides(); this.initializeSlides();
} }
this.requestUpdate(); this.requestUpdate();
} };
@watch('loop', { waitUntilFirstUpdate: true }) @watch('loop', { waitUntilFirstUpdate: true })
@watch('slidesPerPage', { waitUntilFirstUpdate: true }) @watch('slidesPerPage', { waitUntilFirstUpdate: true })

Wyświetl plik

@ -20,16 +20,7 @@ export class ScrollController<T extends ScrollHost> implements ReactiveControlle
constructor(host: T) { constructor(host: T) {
this.host = host; this.host = host;
host.addController(this); host.addController(this);
this.handleScroll = this.handleScroll.bind(this);
this.handlePointerDown = this.handlePointerDown.bind(this);
this.handlePointerMove = this.handlePointerMove.bind(this);
this.handlePointerUp = this.handlePointerUp.bind(this);
this.handlePointerUp = this.handlePointerUp.bind(this);
this.handleTouchStart = this.handleTouchStart.bind(this);
this.handleTouchEnd = this.handleTouchEnd.bind(this);
} }
async hostConnected() { async hostConnected() {
@ -58,13 +49,13 @@ export class ScrollController<T extends ScrollHost> implements ReactiveControlle
scrollContainer.removeEventListener('touchend', this.handleTouchEnd); scrollContainer.removeEventListener('touchend', this.handleTouchEnd);
} }
handleScroll() { handleScroll = () => {
if (!this.scrolling) { if (!this.scrolling) {
this.scrolling = true; this.scrolling = true;
this.host.requestUpdate(); this.host.requestUpdate();
} }
this.handleScrollEnd(); this.handleScrollEnd();
} };
@debounce(100) @debounce(100)
handleScrollEnd() { handleScrollEnd() {
@ -84,7 +75,7 @@ export class ScrollController<T extends ScrollHost> implements ReactiveControlle
} }
} }
handlePointerDown(event: PointerEvent) { handlePointerDown = (event: PointerEvent) => {
if (event.pointerType === 'touch') { if (event.pointerType === 'touch') {
return; return;
} }
@ -97,9 +88,9 @@ export class ScrollController<T extends ScrollHost> implements ReactiveControlle
this.host.scrollContainer.addEventListener('pointermove', this.handlePointerMove); this.host.scrollContainer.addEventListener('pointermove', this.handlePointerMove);
} }
} };
handlePointerMove(event: PointerEvent) { handlePointerMove = (event: PointerEvent) => {
const scrollContainer = this.host.scrollContainer; const scrollContainer = this.host.scrollContainer;
const hasMoved = !!event.movementX || !!event.movementY; const hasMoved = !!event.movementX || !!event.movementY;
@ -111,28 +102,28 @@ export class ScrollController<T extends ScrollHost> implements ReactiveControlle
// Ignore pointers that we are not tracking // Ignore pointers that we are not tracking
this.handleDrag(event); this.handleDrag(event);
} }
} };
handlePointerUp(event: PointerEvent) { handlePointerUp = (event: PointerEvent) => {
this.pointers.delete(event.pointerId); this.pointers.delete(event.pointerId);
this.host.scrollContainer.releasePointerCapture(event.pointerId); this.host.scrollContainer.releasePointerCapture(event.pointerId);
if (this.pointers.size === 0) { if (this.pointers.size === 0) {
this.handleDragEnd(); this.handleDragEnd();
} }
} };
handleTouchEnd(event: TouchEvent) { handleTouchEnd = (event: TouchEvent) => {
for (const touch of event.changedTouches) { for (const touch of event.changedTouches) {
this.pointers.delete(touch.identifier); this.pointers.delete(touch.identifier);
} }
} };
handleTouchStart(event: TouchEvent) { handleTouchStart = (event: TouchEvent) => {
for (const touch of event.touches) { for (const touch of event.touches) {
this.pointers.add(touch.identifier); this.pointers.add(touch.identifier);
} }
} };
handleDragStart() { handleDragStart() {
const host = this.host; const host = this.host;

Wyświetl plik

@ -190,20 +190,12 @@ export default class SlColorPicker extends ShoelaceElement implements ShoelaceFo
return this.input.validationMessage; return this.input.validationMessage;
} }
connectedCallback() { constructor() {
super.connectedCallback(); super();
this.handleFocusIn = this.handleFocusIn.bind(this);
this.handleFocusOut = this.handleFocusOut.bind(this);
this.addEventListener('focusin', this.handleFocusIn); this.addEventListener('focusin', this.handleFocusIn);
this.addEventListener('focusout', this.handleFocusOut); this.addEventListener('focusout', this.handleFocusOut);
} }
disconnectedCallback() {
super.disconnectedCallback();
this.removeEventListener('focusin', this.handleFocusIn);
this.removeEventListener('focusout', this.handleFocusOut);
}
firstUpdated() { firstUpdated() {
this.input.updateComplete.then(() => { this.input.updateComplete.then(() => {
this.formControlController.updateValidity(); this.formControlController.updateValidity();
@ -222,15 +214,15 @@ export default class SlColorPicker extends ShoelaceElement implements ShoelaceFo
}); });
} }
private handleFocusIn() { private handleFocusIn = () => {
this.hasFocus = true; this.hasFocus = true;
this.emit('sl-focus'); this.emit('sl-focus');
} };
private handleFocusOut() { private handleFocusOut = () => {
this.hasFocus = false; this.hasFocus = false;
this.emit('sl-blur'); this.emit('sl-blur');
} };
private handleFormatToggle() { private handleFormatToggle() {
const formats = ['hex', 'rgb', 'hsl', 'hsv']; const formats = ['hex', 'rgb', 'hsl', 'hsv'];

Wyświetl plik

@ -67,7 +67,7 @@ export default class SlDialog extends ShoelaceElement {
private readonly hasSlotController = new HasSlotController(this, 'footer'); private readonly hasSlotController = new HasSlotController(this, 'footer');
private readonly localize = new LocalizeController(this); private readonly localize = new LocalizeController(this);
private modal: Modal; private modal = new Modal(this);
private originalTrigger: HTMLElement | null; private originalTrigger: HTMLElement | null;
@query('.dialog') dialog: HTMLElement; @query('.dialog') dialog: HTMLElement;
@ -92,12 +92,6 @@ export default class SlDialog extends ShoelaceElement {
*/ */
@property({ attribute: 'no-header', type: Boolean, reflect: true }) noHeader = false; @property({ attribute: 'no-header', type: Boolean, reflect: true }) noHeader = false;
connectedCallback() {
super.connectedCallback();
this.handleDocumentKeyDown = this.handleDocumentKeyDown.bind(this);
this.modal = new Modal(this);
}
firstUpdated() { firstUpdated() {
this.dialog.hidden = !this.open; this.dialog.hidden = !this.open;
@ -136,12 +130,12 @@ export default class SlDialog extends ShoelaceElement {
document.removeEventListener('keydown', this.handleDocumentKeyDown); document.removeEventListener('keydown', this.handleDocumentKeyDown);
} }
private handleDocumentKeyDown(event: KeyboardEvent) { private handleDocumentKeyDown = (event: KeyboardEvent) => {
if (this.open && event.key === 'Escape') { if (this.open && event.key === 'Escape') {
event.stopPropagation(); event.stopPropagation();
this.requestClose('keyboard'); this.requestClose('keyboard');
} }
} };
@watch('open', { waitUntilFirstUpdate: true }) @watch('open', { waitUntilFirstUpdate: true })
async handleOpenChange() { async handleOpenChange() {

Wyświetl plik

@ -75,7 +75,7 @@ export default class SlDrawer extends ShoelaceElement {
private readonly hasSlotController = new HasSlotController(this, 'footer'); private readonly hasSlotController = new HasSlotController(this, 'footer');
private readonly localize = new LocalizeController(this); private readonly localize = new LocalizeController(this);
private modal: Modal; private modal = new Modal(this);
private originalTrigger: HTMLElement | null; private originalTrigger: HTMLElement | null;
@query('.drawer') drawer: HTMLElement; @query('.drawer') drawer: HTMLElement;
@ -109,12 +109,6 @@ export default class SlDrawer extends ShoelaceElement {
*/ */
@property({ attribute: 'no-header', type: Boolean, reflect: true }) noHeader = false; @property({ attribute: 'no-header', type: Boolean, reflect: true }) noHeader = false;
connectedCallback() {
super.connectedCallback();
this.handleDocumentKeyDown = this.handleDocumentKeyDown.bind(this);
this.modal = new Modal(this);
}
firstUpdated() { firstUpdated() {
this.drawer.hidden = !this.open; this.drawer.hidden = !this.open;
@ -156,12 +150,12 @@ export default class SlDrawer extends ShoelaceElement {
document.removeEventListener('keydown', this.handleDocumentKeyDown); document.removeEventListener('keydown', this.handleDocumentKeyDown);
} }
private handleDocumentKeyDown(event: KeyboardEvent) { private handleDocumentKeyDown = (event: KeyboardEvent) => {
if (this.open && !this.contained && event.key === 'Escape') { if (this.open && !this.contained && event.key === 'Escape') {
event.stopPropagation(); event.stopPropagation();
this.requestClose('keyboard'); this.requestClose('keyboard');
} }
} };
@watch('open', { waitUntilFirstUpdate: true }) @watch('open', { waitUntilFirstUpdate: true })
async handleOpenChange() { async handleOpenChange() {

Wyświetl plik

@ -103,10 +103,6 @@ export default class SlDropdown extends ShoelaceElement {
connectedCallback() { connectedCallback() {
super.connectedCallback(); super.connectedCallback();
this.handlePanelSelect = this.handlePanelSelect.bind(this);
this.handleKeyDown = this.handleKeyDown.bind(this);
this.handleDocumentKeyDown = this.handleDocumentKeyDown.bind(this);
this.handleDocumentMouseDown = this.handleDocumentMouseDown.bind(this);
if (!this.containingElement) { if (!this.containingElement) {
this.containingElement = this; this.containingElement = this;
@ -142,7 +138,7 @@ export default class SlDropdown extends ShoelaceElement {
| undefined; | undefined;
} }
handleKeyDown(event: KeyboardEvent) { private handleKeyDown = (event: KeyboardEvent) => {
// Close when escape is pressed inside an open dropdown. We need to listen on the panel itself and stop propagation // Close when escape is pressed inside an open dropdown. We need to listen on the panel itself and stop propagation
// in case any ancestors are also listening for this key. // in case any ancestors are also listening for this key.
if (this.open && event.key === 'Escape') { if (this.open && event.key === 'Escape') {
@ -150,9 +146,9 @@ export default class SlDropdown extends ShoelaceElement {
this.hide(); this.hide();
this.focusOnTrigger(); this.focusOnTrigger();
} }
} };
handleDocumentKeyDown(event: KeyboardEvent) { private handleDocumentKeyDown = (event: KeyboardEvent) => {
// Close when escape or tab is pressed // Close when escape or tab is pressed
if (event.key === 'Escape' && this.open) { if (event.key === 'Escape' && this.open) {
event.stopPropagation(); event.stopPropagation();
@ -189,17 +185,17 @@ export default class SlDropdown extends ShoelaceElement {
} }
}); });
} }
} };
handleDocumentMouseDown(event: MouseEvent) { private handleDocumentMouseDown = (event: MouseEvent) => {
// Close when clicking outside of the containing element // Close when clicking outside of the containing element
const path = event.composedPath(); const path = event.composedPath();
if (this.containingElement && !path.includes(this.containingElement)) { if (this.containingElement && !path.includes(this.containingElement)) {
this.hide(); this.hide();
} }
} };
handlePanelSelect(event: SlSelectEvent) { private handlePanelSelect = (event: SlSelectEvent) => {
const target = event.target as HTMLElement; const target = event.target as HTMLElement;
// Hide the dropdown when a menu item is selected // Hide the dropdown when a menu item is selected
@ -207,7 +203,7 @@ export default class SlDropdown extends ShoelaceElement {
this.hide(); this.hide();
this.focusOnTrigger(); this.focusOnTrigger();
} }
} };
handleTriggerClick() { handleTriggerClick() {
if (this.open) { if (this.open) {

Wyświetl plik

@ -48,17 +48,11 @@ export default class SlMenuItem extends ShoelaceElement {
/** Draws the menu item in a disabled state, preventing selection. */ /** Draws the menu item in a disabled state, preventing selection. */
@property({ type: Boolean, reflect: true }) disabled = false; @property({ type: Boolean, reflect: true }) disabled = false;
connectedCallback() { constructor() {
super.connectedCallback(); super();
this.handleHostClick = this.handleHostClick.bind(this);
this.addEventListener('click', this.handleHostClick); this.addEventListener('click', this.handleHostClick);
} }
disconnectedCallback() {
super.disconnectedCallback();
this.removeEventListener('click', this.handleHostClick);
}
private handleDefaultSlotChange() { private handleDefaultSlotChange() {
const textLabel = this.getTextLabel(); const textLabel = this.getTextLabel();
@ -75,13 +69,13 @@ export default class SlMenuItem extends ShoelaceElement {
} }
} }
private handleHostClick(event: MouseEvent) { private handleHostClick = (event: MouseEvent) => {
// Prevent the click event from being emitted when the button is disabled or loading // Prevent the click event from being emitted when the button is disabled or loading
if (this.disabled) { if (this.disabled) {
event.preventDefault(); event.preventDefault();
event.stopImmediatePropagation(); event.stopImmediatePropagation();
} }
} };
@watch('checked') @watch('checked')
handleCheckedChange() { handleCheckedChange() {

Wyświetl plik

@ -44,7 +44,6 @@ export default class SlMutationObserver extends ShoelaceElement {
connectedCallback() { connectedCallback() {
super.connectedCallback(); super.connectedCallback();
this.handleMutation = this.handleMutation.bind(this);
this.mutationObserver = new MutationObserver(this.handleMutation); this.mutationObserver = new MutationObserver(this.handleMutation);
@ -57,11 +56,11 @@ export default class SlMutationObserver extends ShoelaceElement {
this.stopObserver(); this.stopObserver();
} }
private handleMutation(mutationList: MutationRecord[]) { private handleMutation = (mutationList: MutationRecord[]) => {
this.emit('sl-mutation', { this.emit('sl-mutation', {
detail: { mutationList } detail: { mutationList }
}); });
} };
private startObserver() { private startObserver() {
const observeAttributes = typeof this.attr === 'string' && this.attr.length > 0; const observeAttributes = typeof this.attr === 'string' && this.attr.length > 0;

Wyświetl plik

@ -45,47 +45,33 @@ export default class SlRadio extends ShoelaceElement {
/** Disables the radio. */ /** Disables the radio. */
@property({ type: Boolean, reflect: true }) disabled = false; @property({ type: Boolean, reflect: true }) disabled = false;
connectedCallback() { constructor() {
super.connectedCallback(); super();
this.handleBlur = this.handleBlur.bind(this);
this.handleClick = this.handleClick.bind(this);
this.handleFocus = this.handleFocus.bind(this);
this.setInitialAttributes();
this.addEventListeners();
}
disconnectedCallback() {
this.removeEventListeners();
}
private addEventListeners() {
this.addEventListener('blur', this.handleBlur); this.addEventListener('blur', this.handleBlur);
this.addEventListener('click', this.handleClick); this.addEventListener('click', this.handleClick);
this.addEventListener('focus', this.handleFocus); this.addEventListener('focus', this.handleFocus);
} }
private removeEventListeners() { connectedCallback() {
this.removeEventListener('blur', this.handleBlur); super.connectedCallback();
this.removeEventListener('click', this.handleClick); this.setInitialAttributes();
this.removeEventListener('focus', this.handleFocus);
} }
private handleBlur() { private handleBlur = () => {
this.hasFocus = false; this.hasFocus = false;
this.emit('sl-blur'); this.emit('sl-blur');
} };
private handleClick() { private handleClick = () => {
if (!this.disabled) { if (!this.disabled) {
this.checked = true; this.checked = true;
} }
} };
private handleFocus() { private handleFocus = () => {
this.hasFocus = true; this.hasFocus = true;
this.emit('sl-focus'); this.emit('sl-focus');
} };
private setInitialAttributes() { private setInitialAttributes() {
this.setAttribute('role', 'radio'); this.setAttribute('role', 'radio');

Wyświetl plik

@ -180,9 +180,6 @@ export default class SlSelect extends ShoelaceElement implements ShoelaceFormCon
connectedCallback() { connectedCallback() {
super.connectedCallback(); super.connectedCallback();
this.handleDocumentFocusIn = this.handleDocumentFocusIn.bind(this);
this.handleDocumentKeyDown = this.handleDocumentKeyDown.bind(this);
this.handleDocumentMouseDown = this.handleDocumentMouseDown.bind(this);
// Because this is a form control, it shouldn't be opened initially // Because this is a form control, it shouldn't be opened initially
this.open = false; this.open = false;
@ -211,15 +208,15 @@ export default class SlSelect extends ShoelaceElement implements ShoelaceFormCon
this.emit('sl-blur'); this.emit('sl-blur');
} }
private handleDocumentFocusIn(event: KeyboardEvent) { private handleDocumentFocusIn = (event: KeyboardEvent) => {
// Close when focusing out of the select // Close when focusing out of the select
const path = event.composedPath(); const path = event.composedPath();
if (this && !path.includes(this)) { if (this && !path.includes(this)) {
this.hide(); this.hide();
} }
} };
private handleDocumentKeyDown(event: KeyboardEvent) { private handleDocumentKeyDown = (event: KeyboardEvent) => {
const target = event.target as HTMLElement; const target = event.target as HTMLElement;
const isClearButton = target.closest('.select__clear') !== null; const isClearButton = target.closest('.select__clear') !== null;
const isIconButton = target.closest('sl-icon-button') !== null; const isIconButton = target.closest('sl-icon-button') !== null;
@ -346,15 +343,15 @@ export default class SlSelect extends ShoelaceElement implements ShoelaceFormCon
} }
} }
} }
} };
private handleDocumentMouseDown(event: MouseEvent) { private handleDocumentMouseDown = (event: MouseEvent) => {
// Close when clicking outside of the select // Close when clicking outside of the select
const path = event.composedPath(); const path = event.composedPath();
if (this && !path.includes(this)) { if (this && !path.includes(this)) {
this.hide(); this.hide();
} }
} };
private handleLabelClick() { private handleLabelClick() {
this.displayInput.focus(); this.displayInput.focus();

Wyświetl plik

@ -70,7 +70,7 @@ export default class SlTabGroup extends ShoelaceElement {
@property({ attribute: 'no-scroll-controls', type: Boolean }) noScrollControls = false; @property({ attribute: 'no-scroll-controls', type: Boolean }) noScrollControls = false;
connectedCallback() { connectedCallback() {
const whenAllDefined = Promise.allSettled([ const whenAllDefined = Promise.all([
customElements.whenDefined('sl-tab'), customElements.whenDefined('sl-tab'),
customElements.whenDefined('sl-tab-panel') customElements.whenDefined('sl-tab-panel')
]); ]);

Wyświetl plik

@ -98,23 +98,20 @@ export default class SlTooltip extends ShoelaceElement {
*/ */
@property({ type: Boolean }) hoist = false; @property({ type: Boolean }) hoist = false;
constructor() {
super();
// TODO (justinfagnani): does this need to be done in firstUpdated for some
// reason? If so, document why in a comment.
this.addEventListener('blur', this.handleBlur, true);
this.addEventListener('focus', this.handleFocus, true);
this.addEventListener('click', this.handleClick);
this.addEventListener('keydown', this.handleKeyDown);
this.addEventListener('mouseover', this.handleMouseOver);
this.addEventListener('mouseout', this.handleMouseOut);
}
connectedCallback() { connectedCallback() {
super.connectedCallback(); super.connectedCallback();
this.handleBlur = this.handleBlur.bind(this);
this.handleClick = this.handleClick.bind(this);
this.handleFocus = this.handleFocus.bind(this);
this.handleKeyDown = this.handleKeyDown.bind(this);
this.handleMouseOver = this.handleMouseOver.bind(this);
this.handleMouseOut = this.handleMouseOut.bind(this);
this.updateComplete.then(() => {
this.addEventListener('blur', this.handleBlur, true);
this.addEventListener('focus', this.handleFocus, true);
this.addEventListener('click', this.handleClick);
this.addEventListener('keydown', this.handleKeyDown);
this.addEventListener('mouseover', this.handleMouseOver);
this.addEventListener('mouseout', this.handleMouseOut);
});
} }
firstUpdated() { firstUpdated() {
@ -127,23 +124,13 @@ export default class SlTooltip extends ShoelaceElement {
} }
} }
disconnectedCallback() { private handleBlur = () => {
super.disconnectedCallback();
this.removeEventListener('blur', this.handleBlur, true);
this.removeEventListener('focus', this.handleFocus, true);
this.removeEventListener('click', this.handleClick);
this.removeEventListener('keydown', this.handleKeyDown);
this.removeEventListener('mouseover', this.handleMouseOver);
this.removeEventListener('mouseout', this.handleMouseOut);
}
private handleBlur() {
if (this.hasTrigger('focus')) { if (this.hasTrigger('focus')) {
this.hide(); this.hide();
} }
} };
private handleClick() { private handleClick = () => {
if (this.hasTrigger('click')) { if (this.hasTrigger('click')) {
if (this.open) { if (this.open) {
this.hide(); this.hide();
@ -151,37 +138,37 @@ export default class SlTooltip extends ShoelaceElement {
this.show(); this.show();
} }
} }
} };
private handleFocus() { private handleFocus = () => {
if (this.hasTrigger('focus')) { if (this.hasTrigger('focus')) {
this.show(); this.show();
} }
} };
private handleKeyDown(event: KeyboardEvent) { private handleKeyDown = (event: KeyboardEvent) => {
// Pressing escape when the target element has focus should dismiss the tooltip // Pressing escape when the target element has focus should dismiss the tooltip
if (this.open && event.key === 'Escape') { if (this.open && event.key === 'Escape') {
event.stopPropagation(); event.stopPropagation();
this.hide(); this.hide();
} }
} };
private handleMouseOver() { private handleMouseOver = () => {
if (this.hasTrigger('hover')) { if (this.hasTrigger('hover')) {
const delay = parseDuration(getComputedStyle(this).getPropertyValue('--show-delay')); const delay = parseDuration(getComputedStyle(this).getPropertyValue('--show-delay'));
clearTimeout(this.hoverTimeout); clearTimeout(this.hoverTimeout);
this.hoverTimeout = window.setTimeout(() => this.show(), delay); this.hoverTimeout = window.setTimeout(() => this.show(), delay);
} }
} };
private handleMouseOut() { private handleMouseOut = () => {
if (this.hasTrigger('hover')) { if (this.hasTrigger('hover')) {
const delay = parseDuration(getComputedStyle(this).getPropertyValue('--hide-delay')); const delay = parseDuration(getComputedStyle(this).getPropertyValue('--hide-delay'));
clearTimeout(this.hoverTimeout); clearTimeout(this.hoverTimeout);
this.hoverTimeout = window.setTimeout(() => this.hide(), delay); this.hoverTimeout = window.setTimeout(() => this.hide(), delay);
} }
} };
private hasTrigger(triggerType: string) { private hasTrigger(triggerType: string) {
const triggers = this.trigger.split(' '); const triggers = this.trigger.split(' ');

Wyświetl plik

@ -92,18 +92,18 @@ export default class SlTree extends ShoelaceElement {
private mutationObserver: MutationObserver; private mutationObserver: MutationObserver;
private clickTarget: SlTreeItem | null = null; private clickTarget: SlTreeItem | null = null;
async connectedCallback() { constructor() {
super.connectedCallback(); super();
this.handleTreeChanged = this.handleTreeChanged.bind(this);
this.handleFocusIn = this.handleFocusIn.bind(this);
this.handleFocusOut = this.handleFocusOut.bind(this);
this.setAttribute('role', 'tree');
this.setAttribute('tabindex', '0');
this.addEventListener('focusin', this.handleFocusIn); this.addEventListener('focusin', this.handleFocusIn);
this.addEventListener('focusout', this.handleFocusOut); this.addEventListener('focusout', this.handleFocusOut);
this.addEventListener('sl-lazy-change', this.handleSlotChange); this.addEventListener('sl-lazy-change', this.handleSlotChange);
}
async connectedCallback() {
super.connectedCallback();
this.setAttribute('role', 'tree');
this.setAttribute('tabindex', '0');
await this.updateComplete; await this.updateComplete;
@ -115,10 +115,6 @@ export default class SlTree extends ShoelaceElement {
super.disconnectedCallback(); super.disconnectedCallback();
this.mutationObserver.disconnect(); this.mutationObserver.disconnect();
this.removeEventListener('focusin', this.handleFocusIn);
this.removeEventListener('focusout', this.handleFocusOut);
this.removeEventListener('sl-lazy-change', this.handleSlotChange);
} }
// Generates a clone of the expand icon element to use for each tree item // Generates a clone of the expand icon element to use for each tree item
@ -160,7 +156,7 @@ export default class SlTree extends ShoelaceElement {
}); });
}; };
private handleTreeChanged(mutations: MutationRecord[]) { private handleTreeChanged = (mutations: MutationRecord[]) => {
for (const mutation of mutations) { for (const mutation of mutations) {
const addedNodes: SlTreeItem[] = [...mutation.addedNodes].filter(SlTreeItem.isTreeItem) as SlTreeItem[]; const addedNodes: SlTreeItem[] = [...mutation.addedNodes].filter(SlTreeItem.isTreeItem) as SlTreeItem[];
const removedNodes = [...mutation.removedNodes].filter(SlTreeItem.isTreeItem) as SlTreeItem[]; const removedNodes = [...mutation.removedNodes].filter(SlTreeItem.isTreeItem) as SlTreeItem[];
@ -172,7 +168,7 @@ export default class SlTree extends ShoelaceElement {
this.focusItem(this.getFocusableItems()[0]); this.focusItem(this.getFocusableItems()[0]);
} }
} }
} };
private syncTreeItems(selectedItem: SlTreeItem) { private syncTreeItems(selectedItem: SlTreeItem) {
const items = this.getAllTreeItems(); const items = this.getAllTreeItems();
@ -322,16 +318,16 @@ export default class SlTree extends ShoelaceElement {
this.clickTarget = event.target as SlTreeItem; this.clickTarget = event.target as SlTreeItem;
} }
private handleFocusOut(event: FocusEvent) { private handleFocusOut = (event: FocusEvent) => {
const relatedTarget = event.relatedTarget as HTMLElement; const relatedTarget = event.relatedTarget as HTMLElement;
// If the element that got the focus is not in the tree // If the element that got the focus is not in the tree
if (!relatedTarget || !this.contains(relatedTarget)) { if (!relatedTarget || !this.contains(relatedTarget)) {
this.tabIndex = 0; this.tabIndex = 0;
} }
} };
private handleFocusIn(event: FocusEvent) { private handleFocusIn = (event: FocusEvent) => {
const target = event.target as SlTreeItem; const target = event.target as SlTreeItem;
// If the tree has been focused, move the focus to the last focused item // If the tree has been focused, move the focus to the last focused item
@ -349,7 +345,7 @@ export default class SlTree extends ShoelaceElement {
target.tabIndex = 0; target.tabIndex = 0;
} }
} };
private handleSlotChange() { private handleSlotChange() {
const items = this.getAllTreeItems(); const items = this.getAllTreeItems();