Skip to content

Commit

Permalink
fix(block): fix rendering tied to named-slot content (#10449)
Browse files Browse the repository at this point in the history
**Related Issue:** #6059

## Summary

- remove use of `getSlotted` utility
- replace with `slotchange` event and `@State` variables to update the
display of elements.
- existing tests should suffice
  • Loading branch information
driskull authored Oct 1, 2024
1 parent 3d56f0e commit a53540b
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 52 deletions.
19 changes: 8 additions & 11 deletions packages/calcite-components/src/components/block/block.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { html } from "../../../support/formatting";
import { openClose } from "../../tests/commonTests";
import { skipAnimations } from "../../tests/utils";
import { defaultEndMenuPlacement } from "../../utils/floating-ui";
import { CSS, SLOTS } from "./resources";
import { CSS, IDS, SLOTS } from "./resources";

describe("calcite-block", () => {
describe("renders", () => {
Expand Down Expand Up @@ -186,26 +186,23 @@ describe("calcite-block", () => {

it("can display/hide content", async () => {
const page = await newE2EPage();
await page.setContent("<calcite-block><div>some content</div></calcite-block>");
let element = await page.find("calcite-block");
let content = await page.find(`calcite-block >>> .${CSS.content}`);
await page.setContent(
html`<calcite-block heading="heading" description="description"><div>Hello world!</div></calcite-block>`,
);
await skipAnimations(page);

const element = await page.find("calcite-block");
const content = await page.find(`calcite-block >>> #${IDS.content}`);
expect(await element.getProperty("open")).toBe(false);
expect(await content.isVisible()).toBe(false);

element.setProperty("open", true);
await page.waitForChanges();
element = await page.find("calcite-block[open]");
content = await page.find(`calcite-block >>> .${CSS.content}`);

expect(element).toBeTruthy();
expect(await content.isVisible()).toBe(true);

element.setProperty("open", false);
await page.waitForChanges();
element = await page.find("calcite-block[open]");
content = await page.find(`calcite-block >>> .${CSS.content}`);

expect(element).toBeNull();
expect(await content.isVisible()).toBe(false);
});

Expand Down
78 changes: 37 additions & 41 deletions packages/calcite-components/src/components/block/block.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,7 @@ import {
VNode,
Watch,
} from "@stencil/core";
import {
ConditionalSlotComponent,
connectConditionalSlotComponent,
disconnectConditionalSlotComponent,
} from "../../utils/conditionalSlot";
import {
focusFirstTabbable,
getSlotted,
toAriaBoolean,
slotChangeHasAssignedElement,
} from "../../utils/dom";
import { focusFirstTabbable, toAriaBoolean, slotChangeHasAssignedElement } from "../../utils/dom";
import {
InteractiveComponent,
InteractiveContainer,
Expand Down Expand Up @@ -71,7 +61,6 @@ import { BlockMessages } from "./assets/block/t9n";
})
export class Block
implements
ConditionalSlotComponent,
InteractiveComponent,
LocalizedComponent,
T9nComponent,
Expand Down Expand Up @@ -233,6 +222,12 @@ export class Block
updateMessages(this, this.effectiveLocale);
}

@State() hasIcon = false;

@State() hasControl = false;

@State() hasMenuActions = false;

@State() hasContentStart = false;

@State() hasEndActions = false;
Expand All @@ -248,7 +243,6 @@ export class Block
// --------------------------------------------------------------------------

connectedCallback(): void {
connectConditionalSlotComponent(this);
connectLocalized(this);
connectMessages(this);

Expand All @@ -258,7 +252,6 @@ export class Block
disconnectedCallback(): void {
disconnectLocalized(this);
disconnectMessages(this);
disconnectConditionalSlotComponent(this);
}

async componentWillLoad(): Promise<void> {
Expand Down Expand Up @@ -314,6 +307,18 @@ export class Block
this.calciteBlockToggle.emit();
};

private controlSlotChangeHandler = (event: Event): void => {
this.hasControl = slotChangeHasAssignedElement(event);
};

private menuActionsSlotChangeHandler = (event: Event): void => {
this.hasMenuActions = slotChangeHasAssignedElement(event);
};

private iconSlotChangeHandler = (event: Event): void => {
this.hasIcon = slotChangeHasAssignedElement(event);
};

private actionsEndSlotChangeHandler = (event: Event): void => {
this.hasEndActions = slotChangeHasAssignedElement(event);
};
Expand All @@ -338,8 +343,6 @@ export class Block
private renderLoaderStatusIcon(): VNode[] {
const { loading, messages, status } = this;

const hasSlottedIcon = !!getSlotted(this.el, SLOTS.icon);

return loading ? (
<div class={CSS.icon} key="loader">
<calcite-loader inline label={messages.loading} />
Expand All @@ -356,25 +359,24 @@ export class Block
scale="s"
/>
</div>
) : hasSlottedIcon ? (
<div class={CSS.icon} key="icon-slot">
<slot key="icon-slot" name={SLOTS.icon} />
) : (
<div class={CSS.icon} hidden={!this.hasIcon} key="icon-slot">
<slot key="icon-slot" name={SLOTS.icon} onSlotchange={this.iconSlotChangeHandler} />
</div>
) : null;
);
}

private renderActionsEnd(): VNode {
return (
<div class={CSS.actionsEnd}>
<div class={CSS.actionsEnd} hidden={!this.hasEndActions}>
<slot name={SLOTS.actionsEnd} onSlotchange={this.actionsEndSlotChangeHandler} />
</div>
);
}

private renderContentStart(): VNode {
const { hasContentStart } = this;
return (
<div class={CSS.contentStart} hidden={!hasContentStart}>
<div class={CSS.contentStart} hidden={!this.hasContentStart}>
<slot name={SLOTS.contentStart} onSlotchange={this.handleContentStartSlotChange} />
</div>
);
Expand Down Expand Up @@ -422,7 +424,6 @@ export class Block
render(): VNode {
const {
collapsible,
el,
loading,
open,
heading,
Expand All @@ -446,8 +447,6 @@ export class Block
</header>
);

const hasControl = !!getSlotted(el, SLOTS.control);
const hasMenuActions = !!getSlotted(el, SLOTS.headerMenuActions);
const collapseIcon = open ? ICONS.opened : ICONS.closed;

const headerNode = (
Expand Down Expand Up @@ -477,21 +476,18 @@ export class Block
) : (
headerContent
)}
{hasControl ? (
<div aria-labelledby={IDS.header} class={CSS.controlContainer}>
<slot name={SLOTS.control} />
</div>
) : null}
{hasMenuActions ? (
<calcite-action-menu
flipPlacements={menuFlipPlacements ?? ["top", "bottom"]}
label={messages.options}
overlayPositioning={this.overlayPositioning}
placement={menuPlacement}
>
<slot name={SLOTS.headerMenuActions} />
</calcite-action-menu>
) : null}
<div aria-labelledby={IDS.header} class={CSS.controlContainer} hidden={!this.hasControl}>
<slot name={SLOTS.control} onSlotchange={this.controlSlotChangeHandler} />
</div>
<calcite-action-menu
flipPlacements={menuFlipPlacements ?? ["top", "bottom"]}
hidden={!this.hasMenuActions}
label={messages.options}
overlayPositioning={this.overlayPositioning}
placement={menuPlacement}
>
<slot name={SLOTS.headerMenuActions} onSlotchange={this.menuActionsSlotChangeHandler} />
</calcite-action-menu>
{this.renderActionsEnd()}
</div>
);
Expand Down

0 comments on commit a53540b

Please sign in to comment.