Skip to content

Commit

Permalink
refactor(web-components): move checking slot existence from updated
Browse files Browse the repository at this point in the history
… to `willUpdate` life cycle (#329)

* refactor(web-components): move checking slot existence from updated to willUpdate life cycle

* feat: add slotchange event to all components

* fix: import updates
  • Loading branch information
amir78729 authored Jan 6, 2025
1 parent 4283577 commit 9083a55
Show file tree
Hide file tree
Showing 11 changed files with 266 additions and 176 deletions.
2 changes: 1 addition & 1 deletion packages/web-components/src/avatar/avatar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export class Avatar extends LitElement {
@property()
public size: "xs" | "sm" | "md" | "lg" | "xlg" | "xxlg" = "md";

protected override updated(changed: PropertyValues) {
protected override updated(changed: PropertyValues<this>) {
if (changed.has("image")) {
this._hasError = false;
}
Expand Down
31 changes: 18 additions & 13 deletions packages/web-components/src/badge/badge.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { html, LitElement, type PropertyValues } from "lit";
import type { DirectiveResult } from "lit/async-directive";
import { property, state } from "lit/decorators.js";
import { property, queryAssignedNodes, state } from "lit/decorators.js";
import { classMap, type ClassMapDirective } from "lit/directives/class-map.js";
import { getRenderRootSlot, runAfterRepaint } from "../utils";
import { isSSR } from "../utils";
import { Slots } from "./constants";

type ClassMap = DirectiveResult<typeof ClassMapDirective>;
Expand Down Expand Up @@ -40,18 +40,20 @@ export class Badge extends LitElement {
public size: "md" | "sm" = "md";

@state()
private _hasIcon = false;
private _hasIconSlot = false;

protected override updated(changed: PropertyValues<this>): void {
super.updated(changed);
@queryAssignedNodes({ slot: Slots.ICON })
private _iconSlotNodes!: Node[];

runAfterRepaint(() => {
const iconSlot = getRenderRootSlot(this.renderRoot, Slots.ICON);

if (!iconSlot) return;
protected override willUpdate(changed: PropertyValues<this>): void {
super.willUpdate(changed);
this._handleIconSlotChange();
}

this._hasIcon = iconSlot.assignedNodes().length > 0;
});
private _handleIconSlotChange() {
if (!isSSR()) {
this._hasIconSlot = this._iconSlotNodes.length > 0;
}
}

private _renderDotBadge(rootClasses: ClassMap) {
Expand Down Expand Up @@ -79,9 +81,12 @@ export class Badge extends LitElement {
<div
class=${Slots.ICON}
part=${Slots.ICON}
?hidden=${!this._hasIcon}
?hidden=${!this._hasIconSlot}
>
<slot name=${Slots.ICON}></slot>
<slot
@slotchange=${this._handleIconSlotChange}
name=${Slots.ICON}
></slot>
</div>
${this.value ?? ""}
</div>
Expand Down
31 changes: 20 additions & 11 deletions packages/web-components/src/banner/banner.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { LitElement, type PropertyValues, html } from "lit";
import { property, state } from "lit/decorators.js";
import { property, queryAssignedNodes, state } from "lit/decorators.js";
import { classMap } from "lit/directives/class-map.js";
import { getRenderRootSlot, runAfterRepaint } from "../utils";
import { isSSR } from "../utils";
import {
DEFAULT_BACKGROUND_COLOR,
DEFAULT_TEXT_COLOR,
Expand Down Expand Up @@ -46,7 +46,10 @@ export class Banner extends LitElement {
public textColor?: string = DEFAULT_TEXT_COLOR;

@state()
private _hasAction = false;
private _hasActionSlot = false;

@queryAssignedNodes({ slot: Slots.ACTION })
private _actionSlotNodes!: Node[];

protected override updated(changed: PropertyValues<this>): void {
super.updated(changed);
Expand Down Expand Up @@ -78,14 +81,17 @@ export class Banner extends LitElement {
this.style.removeProperty(token);
}
}
}

runAfterRepaint(() => {
const actionSlot = getRenderRootSlot(this.renderRoot, Slots.ACTION);

if (!actionSlot) return;
protected override willUpdate(changed: PropertyValues<this>) {
super.willUpdate(changed);
this._handleActionSlotChange();
}

this._hasAction = actionSlot.assignedNodes().length > 0;
});
private _handleActionSlotChange() {
if (!isSSR()) {
this._hasActionSlot = this._actionSlotNodes.length > 0;
}
}

private _renderHeading() {
Expand Down Expand Up @@ -131,9 +137,12 @@ export class Banner extends LitElement {
<div
class=${Slots.ACTION}
part=${Slots.ACTION}
?hidden=${!this._hasAction}
?hidden=${!this._hasActionSlot}
>
<slot name=${Slots.ACTION}></slot>
<slot
@slotchange=${this._handleActionSlotChange}
name=${Slots.ACTION}
></slot>
</div>
</div>
</div>
Expand Down
46 changes: 31 additions & 15 deletions packages/web-components/src/base-text-input/base-text-input.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import { html, nothing, type PropertyValues, type TemplateResult } from "lit";
import { property, state } from "lit/decorators.js";
import { property, queryAssignedNodes, state } from "lit/decorators.js";
import { type ClassInfo, classMap } from "lit/directives/class-map.js";
import BaseInput from "../base-input";
import {
getFormValue,
getRenderRootSlot,
getValidityAnchor,
isSSR,
onReportValidity,
redispatchEvent,
runAfterRepaint,
} from "../utils";
import { Slots } from "./constants";
import { stringConverter } from "./utils";
Expand Down Expand Up @@ -139,6 +138,12 @@ export abstract class BaseTextInput extends BaseInput {
@state()
private _refreshErrorAlert = false;

@queryAssignedNodes({ slot: Slots.LEADING_ICON })
private _leadingIconSlotNodes!: Node[];

@queryAssignedNodes({ slot: Slots.TRAILING })
private _trailingSlotNodes!: Node[];

/**
* Selects all the text in the text field.
*
Expand Down Expand Up @@ -207,20 +212,25 @@ export abstract class BaseTextInput extends BaseInput {
this._refreshErrorAlert = false;
});
}
}

runAfterRepaint(() => {
const leadingSlot = getRenderRootSlot(
this.renderRoot,
Slots.LEADING_ICON,
);
protected override willUpdate(changed: PropertyValues<this>) {
super.willUpdate(changed);

const trailingSlot = getRenderRootSlot(this.renderRoot, Slots.TRAILING);
this._handleLeadingIconSlotChange();
this._handleTrailingSlotChange();
}

if (!leadingSlot || !trailingSlot) return;
private _handleLeadingIconSlotChange() {
if (!isSSR()) {
this.hasLeadingIconSlot = this._leadingIconSlotNodes.length > 0;
}
}

this.hasLeadingIconSlot = leadingSlot.assignedNodes().length > 0;
this.hasTrailingSlot = trailingSlot.assignedNodes().length > 0;
});
private _handleTrailingSlotChange() {
if (!isSSR()) {
this.hasTrailingSlot = this._trailingSlotNodes.length > 0;
}
}

protected override getInputElement() {
Expand Down Expand Up @@ -348,15 +358,21 @@ export abstract class BaseTextInput extends BaseInput {
part=${Slots.LEADING_ICON}
?hidden=${!this.hasLeadingIconSlot}
>
<slot name=${Slots.LEADING_ICON}></slot>
<slot
@slotchange=${this._handleLeadingIconSlotChange}
name=${Slots.LEADING_ICON}
></slot>
</div>
${this.renderInput()}
<div
class=${Slots.TRAILING}
part=${Slots.TRAILING}
?hidden=${!this.hasTrailingSlot}
>
<slot name=${Slots.TRAILING}></slot>
<slot
@slotchange=${this._handleTrailingSlotChange}
name=${Slots.TRAILING}
></slot>
</div>
</div>
`;
Expand Down
35 changes: 20 additions & 15 deletions packages/web-components/src/bottom-navigation/item/item.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,8 @@
import { html, LitElement, type PropertyValues } from "lit";
import { property, state } from "lit/decorators.js";
import { property, queryAssignedNodes, state } from "lit/decorators.js";
import { classMap } from "lit/directives/class-map.js";
import { KeyboardKeys } from "../../internals";
import {
getRenderRootSlot,
runAfterRepaint,
SystemError,
waitAMicrotask,
} from "../../utils";
import { isSSR, SystemError, waitAMicrotask } from "../../utils";
import { Slots } from "./constants";
import { ActivateEvent } from "./events";

Expand All @@ -26,7 +21,10 @@ export class BottomNavigationItem extends LitElement {
public value: string = "";

@state()
private _hasIcon = false;
private _hasIconSlot = false;

@queryAssignedNodes({ slot: Slots.ICON })
private _iconSlotNodes!: Node[];

protected override updated(changed: PropertyValues<this>): void {
super.updated(changed);
Expand All @@ -37,14 +35,18 @@ export class BottomNavigationItem extends LitElement {
"bottom-navigation-item",
);
}
}

runAfterRepaint(() => {
const iconSlot = getRenderRootSlot(this.renderRoot, Slots.ICON);
protected override willUpdate(changed: PropertyValues<this>) {
super.willUpdate(changed);

if (!iconSlot) return;
this._handleIconSlotChange();
}

this._hasIcon = iconSlot.assignedNodes().length > 0;
});
private _handleIconSlotChange() {
if (!isSSR()) {
this._hasIconSlot = this._iconSlotNodes.length > 0;
}
}

public override focus(options?: FocusOptions): void {
Expand Down Expand Up @@ -102,9 +104,12 @@ export class BottomNavigationItem extends LitElement {
aria-hidden
class=${Slots.ICON}
part=${Slots.ICON}
?hidden=${!this._hasIcon}
?hidden=${!this._hasIconSlot}
>
<slot name=${Slots.ICON}></slot>
<slot
@slotchange=${this._handleIconSlotChange}
name=${Slots.ICON}
></slot>
</div>
<div
class="content"
Expand Down
56 changes: 33 additions & 23 deletions packages/web-components/src/button/standard/button.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,39 @@
import { html, type PropertyValues, type TemplateResult } from "lit";
import { state } from "lit/decorators.js";
import { getRenderRootSlot, runAfterRepaint } from "../../utils";
import { queryAssignedNodes, state } from "lit/decorators.js";
import { isSSR } from "../../utils";
import { BaseButton } from "../base";
import { Slots } from "./constants";

export class Button extends BaseButton {
@state()
private _hasLeadingIcon = false;
private _hasLeadingIconSlot = false;

@state()
private _hasTrailingIcon = false;
private _hasTrailingIconSlot = false;

protected override updated(changed: PropertyValues<this>): void {
super.updated(changed);
@queryAssignedNodes({ slot: Slots.LEADING_ICON })
private _leadingIconSlotNodes!: Node[];

runAfterRepaint(() => {
const leadingIconSlot = getRenderRootSlot(
this.renderRoot,
Slots.LEADING_ICON,
);
@queryAssignedNodes({ slot: Slots.TRAILING_ICON })
private _trailingIconSlotNodes!: Node[];

const trailingIconSlot = getRenderRootSlot(
this.renderRoot,
Slots.TRAILING_ICON,
);
protected override willUpdate(changed: PropertyValues<this>): void {
super.willUpdate(changed);

if (!leadingIconSlot || !trailingIconSlot) return;
this._handleLeadingIconSlotChange();
this._handleTrailingIconSlotChange();
}

private _handleLeadingIconSlotChange() {
if (!isSSR()) {
this._hasLeadingIconSlot = this._leadingIconSlotNodes.length > 0;
}
}

this._hasLeadingIcon = leadingIconSlot.assignedNodes().length > 0;
this._hasTrailingIcon = trailingIconSlot.assignedNodes().length > 0;
});
private _handleTrailingIconSlotChange() {
if (!isSSR()) {
this._hasTrailingIconSlot = this._trailingIconSlotNodes.length > 0;
}
}

protected override renderLoading(): TemplateResult {
Expand All @@ -45,9 +49,12 @@ export class Button extends BaseButton {
<div
class="icon"
part=${Slots.LEADING_ICON}
?hidden=${!this._hasLeadingIcon}
?hidden=${!this._hasLeadingIconSlot}
>
<slot name=${Slots.LEADING_ICON}></slot>
<slot
@slotchange=${this._handleLeadingIconSlotChange}
name=${Slots.LEADING_ICON}
></slot>
</div>
<div
class="content"
Expand All @@ -58,9 +65,12 @@ export class Button extends BaseButton {
<div
class="icon"
part=${Slots.TRAILING_ICON}
?hidden=${!this._hasTrailingIcon}
?hidden=${!this._hasTrailingIconSlot}
>
<slot name=${Slots.TRAILING_ICON}></slot>
<slot
@slotchange=${this._handleTrailingIconSlotChange}
name=${Slots.TRAILING_ICON}
></slot>
</div>
</div>
`;
Expand Down
Loading

0 comments on commit 9083a55

Please sign in to comment.