Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: use slotchange event instead of MutationObserver when possible #9316

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/calcite-components/src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5255,7 +5255,7 @@ export namespace Components {
}
interface CalciteTileGroup {
/**
* Specifies the alignment of each Tile's content.
* Specifies the alignment of each `calcite-tile`'s content.
*/
"alignment": Exclude<Alignment, "end">;
/**
Expand Down Expand Up @@ -13155,7 +13155,7 @@ declare namespace LocalJSX {
}
interface CalciteTileGroup {
/**
* Specifies the alignment of each Tile's content.
* Specifies the alignment of each `calcite-tile`'s content.
*/
"alignment"?: Exclude<Alignment, "end">;
/**
Expand Down
20 changes: 5 additions & 15 deletions packages/calcite-components/src/components/accordion/accordion.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import {
Watch,
} from "@stencil/core";
import { Appearance, Position, Scale, SelectionMode } from "../interfaces";
import { createObserver } from "../../utils/observers";
import { RequestedItem } from "./interfaces";
/**
* @slot - A slot for adding `calcite-accordion-item`s. `calcite-accordion` cannot be nested, however `calcite-accordion-item`s can.
Expand Down Expand Up @@ -58,7 +57,7 @@ export class Accordion {
@Watch("scale")
@Watch("selectionMode")
handlePropsChange(): void {
this.updateAccordionItems();
this.updateItems();
}

//--------------------------------------------------------------------------
Expand All @@ -78,15 +77,6 @@ export class Accordion {
//
//--------------------------------------------------------------------------

connectedCallback(): void {
this.mutationObserver?.observe(this.el, { childList: true });
this.updateAccordionItems();
}

disconnectedCallback(): void {
this.mutationObserver?.disconnect();
}

render(): VNode {
const transparent = this.appearance === "transparent";
return (
Expand All @@ -96,7 +86,7 @@ export class Accordion {
accordion: !transparent,
}}
>
<slot />
<slot onSlotchange={this.handleSlotChange} />
</div>
);
}
Expand All @@ -123,15 +113,13 @@ export class Accordion {

@Element() el: HTMLCalciteAccordionElement;

mutationObserver = createObserver("mutation", () => this.updateAccordionItems());

//--------------------------------------------------------------------------
//
// Private Methods
//
//--------------------------------------------------------------------------

private updateAccordionItems(): void {
private updateItems(): void {
this.el.querySelectorAll("calcite-accordion-item").forEach((item) => {
item.iconPosition = this.iconPosition;
item.iconType = this.iconType;
Expand All @@ -141,4 +129,6 @@ export class Accordion {
// sync props on items across shadow DOM
document.dispatchEvent(new CustomEvent("calciteInternalAccordionItemsSync"));
}

private handleSlotChange = (): void => this.updateItems();
}
15 changes: 6 additions & 9 deletions packages/calcite-components/src/components/action/action.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import {
setUpLoadableComponent,
} from "../../utils/loadable";
import { connectLocalized, disconnectLocalized, LocalizedComponent } from "../../utils/locale";
import { createObserver } from "../../utils/observers";
import { getIconScale } from "../../utils/component";
import {
connectMessages,
Expand Down Expand Up @@ -147,8 +146,6 @@ export class Action

buttonEl: HTMLButtonElement;

mutationObserver = createObserver("mutation", () => forceUpdate(this));

@State() effectiveLocale = "";

@Watch("effectiveLocale")
Expand All @@ -174,7 +171,6 @@ export class Action
connectInteractive(this);
connectLocalized(this);
connectMessages(this);
this.mutationObserver?.observe(this.el, { childList: true, subtree: true });
}

async componentWillLoad(): Promise<void> {
Expand All @@ -192,7 +188,6 @@ export class Action
disconnectInteractive(this);
disconnectLocalized(this);
disconnectMessages(this);
this.mutationObserver?.disconnect();
}

componentDidRender(): void {
Expand Down Expand Up @@ -272,16 +267,16 @@ export class Action
[CSS.slotContainerHidden]: loading,
}}
>
<slot />
<slot onSlotchange={this.handleSlotChange} />
</div>
);

return hasIconToDisplay ? (
<div aria-hidden="true" class={CSS.iconContainer} key="icon-container">
return (
<div class={CSS.iconContainer} hidden={!hasIconToDisplay} key="icon-container">
{iconNode}
{slotContainerNode}
</div>
) : null;
);
}

render(): VNode {
Expand Down Expand Up @@ -354,4 +349,6 @@ export class Action
tooltip.referenceElement = this.buttonEl;
}
};

private handleSlotChange = (): void => forceUpdate(this);
}
31 changes: 10 additions & 21 deletions packages/calcite-components/src/components/button/button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import {
updateMessages,
} from "../../utils/t9n";
import { Appearance, FlipContext, Kind, Scale, Width } from "../interfaces";
import { toAriaBoolean } from "../../utils/dom";
import { slotChangeHasContent, toAriaBoolean } from "../../utils/dom";
import { ButtonMessages } from "./assets/button/t9n";
import { ButtonAlignment } from "./interfaces";
import { CSS } from "./resources";
Expand Down Expand Up @@ -208,13 +208,11 @@ export class Button
connectLocalized(this);
connectMessages(this);
this.hasLoader = this.loading;
this.setupTextContentObserver();
connectLabel(this);
this.formEl = findAssociatedForm(this);
}

disconnectedCallback(): void {
this.mutationObserver?.disconnect();
disconnectInteractive(this);
disconnectLabel(this);
disconnectLocalized(this);
Expand All @@ -226,7 +224,6 @@ export class Button
async componentWillLoad(): Promise<void> {
setUpLoadableComponent(this);
if (Build.isBrowser) {
this.updateHasContent();
await setUpMessages(this);
}
}
Expand Down Expand Up @@ -274,8 +271,11 @@ export class Button
);

const contentEl = (
<span class={CSS.content} ref={(el) => (this.contentEl = el)}>
<slot />
<span
class={CSS.content}
ref={(el) => (this.contentEl = el)}
>
<slot onSlotchange={this.handleSlotChange} />
</span>
);

Expand Down Expand Up @@ -342,9 +342,6 @@ export class Button

labelEl: HTMLCalciteLabelElement;

/** watches for changing text content */
private mutationObserver = createObserver("mutation", () => this.updateHasContent());

/** the rendered child element */
private childEl?: HTMLElement;

Expand All @@ -363,18 +360,6 @@ export class Button

@State() defaultMessages: ButtonMessages;

private updateHasContent() {
const slottedContent = this.el.textContent.trim().length > 0 || this.el.childNodes.length > 0;
this.hasContent =
this.el.childNodes.length === 1 && this.el.childNodes[0]?.nodeName === "#text"
? this.el.textContent?.trim().length > 0
: slottedContent;
}

private setupTextContentObserver() {
this.mutationObserver?.observe(this.el, { childList: true, subtree: true });
}

/** keeps track of the tooltipText */
@State() tooltipText: string;

Expand Down Expand Up @@ -425,4 +410,8 @@ export class Button
this.resizeObserver?.observe(el);
}
};

private handleSlotChange = (event: Event): void => {
this.hasContent = slotChangeHasContent(event);
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import {
Watch,
} from "@stencil/core";
import { Scale, SelectionMode } from "../interfaces";
import { createObserver } from "../../utils/observers";
import { CSS } from "../dropdown-item/resources";
import { RequestedItem } from "./interfaces";

Expand Down Expand Up @@ -76,19 +75,10 @@ export class DropdownGroup {
//
//--------------------------------------------------------------------------

connectedCallback(): void {
this.updateItems();
this.mutationObserver?.observe(this.el, { childList: true });
}

componentWillLoad(): void {
this.groupPosition = this.getGroupPosition();
}

disconnectedCallback(): void {
this.mutationObserver?.disconnect();
}

render(): VNode {
const groupTitle = this.groupTitle ? (
<span aria-hidden="true" class="dropdown-title">
Expand All @@ -109,7 +99,7 @@ export class DropdownGroup {
>
{dropdownSeparator}
{groupTitle}
<slot />
<slot onSlotchange={this.handleSlotChange} />
</div>
</Host>
);
Expand Down Expand Up @@ -148,24 +138,24 @@ export class DropdownGroup {
/** the requested item */
private requestedDropdownItem: HTMLCalciteDropdownItemElement;

private updateItems = (): void => {
Array.from(this.el.querySelectorAll("calcite-dropdown-item")).forEach(
(item) => (item.selectionMode = this.selectionMode),
);
};

mutationObserver = createObserver("mutation", () => this.updateItems());

//--------------------------------------------------------------------------
//
// Private Methods
//
//--------------------------------------------------------------------------

private updateItems = (): void => {
Array.from(this.el.querySelectorAll("calcite-dropdown-item")).forEach(
(item) => (item.selectionMode = this.selectionMode),
);
};

private getGroupPosition(): number {
return Array.prototype.indexOf.call(
this.el.parentElement.querySelectorAll("calcite-dropdown-group"),
this.el,
);
}

private handleSlotChange = (): void => this.updateItems();
}
16 changes: 3 additions & 13 deletions packages/calcite-components/src/components/flow/flow.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { Component, Element, h, Listen, Method, Prop, State, VNode } from "@stencil/core";
import { createObserver } from "../../utils/observers";
import {
componentFocusable,
LoadableComponent,
Expand Down Expand Up @@ -93,19 +92,12 @@ export class Flow implements LoadableComponent {

@State() items: FlowItemLikeElement[] = [];

itemMutationObserver = createObserver("mutation", () => this.updateFlowProps());

// --------------------------------------------------------------------------
//
// Lifecycle
//
// --------------------------------------------------------------------------

connectedCallback(): void {
this.itemMutationObserver?.observe(this.el, { childList: true, subtree: true });
this.updateFlowProps();
}

async componentWillLoad(): Promise<void> {
setUpLoadableComponent(this);
}
Expand All @@ -114,10 +106,6 @@ export class Flow implements LoadableComponent {
setComponentLoaded(this);
}

disconnectedCallback(): void {
this.itemMutationObserver?.disconnect();
}

// --------------------------------------------------------------------------
//
// Private Methods
Expand Down Expand Up @@ -179,6 +167,8 @@ export class Flow implements LoadableComponent {
}
};

private handleSlotChange = (): void => this.updateFlowProps();

// --------------------------------------------------------------------------
//
// Render Methods
Expand All @@ -196,7 +186,7 @@ export class Flow implements LoadableComponent {

return (
<div class={frameDirectionClasses}>
<slot />
<slot onSlotchange={this.handleSlotChange} />
</div>
);
}
Expand Down
Loading
Loading