diff --git a/packages/calcite-components/src/components/modal/modal.e2e.ts b/packages/calcite-components/src/components/modal/modal.e2e.ts index dbb4c945c25..5bb96e17414 100644 --- a/packages/calcite-components/src/components/modal/modal.e2e.ts +++ b/packages/calcite-components/src/components/modal/modal.e2e.ts @@ -577,17 +577,16 @@ describe("calcite-modal", () => { it("renders correctly with no footer", async () => { const page = await newE2EPage(); - await page.setContent(` - + await page.setContent(html` + TEST `); - let footer = await page.$eval("calcite-modal", (el) => el.shadowRoot.querySelector(".footer")); - expect(footer).toBeDefined(); + const footer = await page.find("calcite-modal >>> .footer"); + expect(await footer.isVisible()).toBe(true); await page.$eval("calcite-button", (el) => el.parentElement.removeChild(el)); await page.waitForChanges(); - footer = await page.$eval("calcite-modal", (el) => el.shadowRoot.querySelector(".footer")); - expect(footer).toBeFalsy(); + expect(await footer.isVisible()).toBe(false); }); it("should render calcite-scrim with default background color", async () => { diff --git a/packages/calcite-components/src/components/modal/modal.tsx b/packages/calcite-components/src/components/modal/modal.tsx index cb3bd1d009c..6634cedd584 100644 --- a/packages/calcite-components/src/components/modal/modal.tsx +++ b/packages/calcite-components/src/components/modal/modal.tsx @@ -12,15 +12,10 @@ import { VNode, Watch, } from "@stencil/core"; -import { - ConditionalSlotComponent, - connectConditionalSlotComponent, - disconnectConditionalSlotComponent, -} from "../../utils/conditionalSlot"; import { ensureId, focusFirstTabbable, - getSlotted, + slotChangeGetAssignedElements, slotChangeHasAssignedElement, } from "../../utils/dom"; import { @@ -80,7 +75,6 @@ logger.deprecated("component", { }) export class Modal implements - ConditionalSlotComponent, OpenCloseComponent, FocusTrapComponent, LoadableComponent, @@ -194,8 +188,6 @@ export class Modal this.mutationObserver?.observe(this.el, { childList: true, subtree: true }); this.cssVarObserver?.observe(this.el, { attributeFilter: ["style"] }); this.updateSizeCssVars(); - this.updateFooterVisibility(); - connectConditionalSlotComponent(this); connectLocalized(this); connectMessages(this); connectFocusTrap(this); @@ -205,7 +197,6 @@ export class Modal this.removeOverflowHiddenClass(); this.mutationObserver?.disconnect(); this.cssVarObserver?.disconnect(); - disconnectConditionalSlotComponent(this); deactivateFocusTrap(this); disconnectLocalized(this); disconnectMessages(this); @@ -238,7 +229,7 @@ export class Modal
{this.renderCloseButton()}
- +
{this.renderContentTop()} @@ -249,7 +240,7 @@ export class Modal }} ref={(el) => (this.modalContent = el)} > - + {this.renderContentBottom()} {this.renderFooter()} @@ -260,19 +251,19 @@ export class Modal } renderFooter(): VNode { - return this.hasFooter ? ( -
+ return ( + - ) : null; + ); } renderContentTop(): VNode { @@ -357,7 +348,7 @@ export class Modal modalContent: HTMLDivElement; private mutationObserver: MutationObserver = createObserver("mutation", () => - this.handleMutationObserver(), + this.updateFocusTrapElements(), ); private cssVarObserver: MutationObserver = createObserver("mutation", () => { @@ -380,7 +371,24 @@ export class Modal @State() cssHeight: string | number; - @State() hasFooter = true; + @State() hasFooter = false; + + @Watch("hasBack") + @Watch("hasPrimary") + @Watch("hasSecondary") + handleHasFooterChange(): void { + this.hasFooter = this.hasBack || this.hasPrimary || this.hasSecondary; + } + + @State() titleEl: HTMLElement; + + @State() contentEl: HTMLElement; + + @State() hasBack = false; + + @State() hasPrimary = false; + + @State() hasSecondary = false; @State() hasContentTop = false; @@ -474,6 +482,26 @@ export class Modal // //-------------------------------------------------------------------------- + private handleHeaderSlotChange = (event: Event): void => { + this.titleEl = slotChangeGetAssignedElements(event)[0]; + }; + + private handleContentSlotChange = (event: Event): void => { + this.contentEl = slotChangeGetAssignedElements(event)[0]; + }; + + private handleBackSlotChange = (event: Event): void => { + this.hasBack = slotChangeHasAssignedElement(event); + }; + + private handlePrimarySlotChange = (event: Event): void => { + this.hasPrimary = slotChangeHasAssignedElement(event); + }; + + private handleSecondarySlotChange = (event: Event): void => { + this.hasSecondary = slotChangeHasAssignedElement(event); + }; + private setTransitionEl = (el: HTMLDivElement): void => { this.transitionEl = el; }; @@ -533,11 +561,9 @@ export class Modal await componentOnReady(this.el); this.el.addEventListener("calciteModalOpen", this.openEnd); this.opened = true; - const titleEl = getSlotted(this.el, SLOTS.header); - const contentEl = getSlotted(this.el, SLOTS.content); - this.titleId = ensureId(titleEl); - this.contentId = ensureId(contentEl); + this.titleId = ensureId(this.titleEl); + this.contentId = ensureId(this.contentEl); if (!this.embedded) { if (totalOpenModals === 0) { @@ -582,15 +608,6 @@ export class Modal document.documentElement.style.setProperty("overflow", initialDocumentOverflowStyle); } - private handleMutationObserver = (): void => { - this.updateFooterVisibility(); - this.updateFocusTrapElements(); - }; - - private updateFooterVisibility = (): void => { - this.hasFooter = !!getSlotted(this.el, [SLOTS.back, SLOTS.primary, SLOTS.secondary]); - }; - private updateSizeCssVars = (): void => { this.cssWidth = getComputedStyle(this.el).getPropertyValue("--calcite-modal-width"); this.cssHeight = getComputedStyle(this.el).getPropertyValue("--calcite-modal-height");