diff --git a/src/components/accordion-item/accordion-item.tsx b/src/components/accordion-item/accordion-item.tsx
index ccaaddbb2e9..e21ee0016d7 100644
--- a/src/components/accordion-item/accordion-item.tsx
+++ b/src/components/accordion-item/accordion-item.tsx
@@ -7,7 +7,8 @@ import {
Host,
Listen,
Prop,
- VNode
+ VNode,
+ Watch
} from "@stencil/core";
import { getElementDir, getElementProp, getSlotted, toAriaBoolean } from "../../utils/dom";
import {
@@ -17,7 +18,7 @@ import {
} from "../../utils/conditionalSlot";
import { CSS_UTILITY } from "../../utils/resources";
import { SLOTS, CSS } from "./resources";
-import { FlipContext, Position } from "../interfaces";
+import { FlipContext, Position, Scale } from "../interfaces";
import { RegistryEntry, RequestedItem } from "./interfaces";
/**
@@ -43,14 +44,17 @@ export class AccordionItem implements ConditionalSlotComponent {
//
//--------------------------------------------------------------------------
+ /** Specifies a description for the component. */
+ @Prop() description: string;
+
/** When `true`, the component is expanded. */
@Prop({ reflect: true, mutable: true }) expanded = false;
/** Specifies heading text for the component. */
@Prop() heading: string;
- /** Specifies a description for the component. */
- @Prop() description: string;
+ /** When `true`, the icon will be flipped when the element direction is right-to-left (`"rtl"`). */
+ @Prop({ reflect: true }) iconFlipRtl: FlipContext;
/** Specifies an icon to display at the start of the component. */
@Prop({ reflect: true }) iconStart: string;
@@ -58,8 +62,17 @@ export class AccordionItem implements ConditionalSlotComponent {
/** Specifies an icon to display at the end of the component. */
@Prop({ reflect: true }) iconEnd: string;
- /** When `true`, the icon will be flipped when the element direction is right-to-left (`"rtl"`). */
- @Prop({ reflect: true }) iconFlipRtl: FlipContext;
+ /**
+ * Specifies the size of the component inherited from the `accordion`.
+ *
+ * @internal
+ */
+ @Prop({ reflect: true }) scale: Scale = "m";
+
+ @Watch("scale")
+ onScaleChange(): void {
+ this.internalIconScale = this.scale === "l" ? "m" : "s";
+ }
//--------------------------------------------------------------------------
//
@@ -142,16 +155,15 @@ export class AccordionItem implements ConditionalSlotComponent {
flipRtl={iconFlipRtl === "both" || iconFlipRtl === "start"}
icon={this.iconStart}
key="icon-start"
- scale="s"
+ scale={this.internalIconScale}
/>
) : null;
const iconEndEl = this.iconEnd ? (
) : null;
const { description } = this;
@@ -191,7 +203,7 @@ export class AccordionItem implements ConditionalSlotComponent {
? "minus"
: "plus"
}
- scale="s"
+ scale={this.internalIconScale}
/>
{this.renderActionsEnd()}
@@ -258,6 +270,9 @@ export class AccordionItem implements ConditionalSlotComponent {
/** what icon type does the parent accordion specify */
private iconType: string;
+ /** size of the component to be inherited from the `accordion` */
+ private internalIconScale: Scale;
+
/** handle clicks on item header */
private itemHeaderClickHandler = (): void => this.emitRequestedItem();
//--------------------------------------------------------------------------
diff --git a/src/components/accordion-item/resources.ts b/src/components/accordion-item/resources.ts
index a5dff5f1bd2..7121fc15c83 100644
--- a/src/components/accordion-item/resources.ts
+++ b/src/components/accordion-item/resources.ts
@@ -4,17 +4,17 @@ export const SLOTS = {
};
export const CSS = {
- icon: "icon",
- header: "header",
- headerContent: "header-content",
actionsStart: "actions-start",
actionsEnd: "actions-end",
- headerText: "header-text",
- heading: "heading",
+ content: "content",
description: "description",
expandIcon: "expand-icon",
- content: "content",
+ header: "header",
+ headerContainer: "header-container",
+ headerContent: "header-content",
+ headerText: "header-text",
+ heading: "heading",
+ icon: "icon",
iconStart: "icon--start",
- iconEnd: "icon--end",
- headerContainer: "header-container"
+ iconEnd: "icon--end"
};
diff --git a/src/components/accordion/accordion.e2e.ts b/src/components/accordion/accordion.e2e.ts
index fa653a72533..c304af0ba46 100644
--- a/src/components/accordion/accordion.e2e.ts
+++ b/src/components/accordion/accordion.e2e.ts
@@ -1,4 +1,4 @@
-import { newE2EPage } from "@stencil/core/testing";
+import { E2EElement, E2EPage, newE2EPage } from "@stencil/core/testing";
import { accessible, renders, hidden } from "../../tests/commonTests";
import { html } from "../../../support/formatting";
import { CSS } from "../accordion-item/resources";
@@ -47,23 +47,58 @@ describe("calcite-accordion", () => {
expect(element).toEqualAttribute("icon-type", "caret");
});
- it("renders icon if requested", async () => {
- const page = await newE2EPage();
- await page.setContent(`
-
- Accordion Item Content
-
- Accordion Item Content
-
- Accordion Item Content
-
- `);
- const icon1 = await page.find(`calcite-accordion-item[id='1'] >>> .${CSS.iconStart}`);
- const icon2 = await page.find(`calcite-accordion-item[id='2'] >>> .${CSS.iconStart}`);
- const icon3 = await page.find(`calcite-accordion-item[id='3'] >>> .${CSS.iconStart}`);
- expect(icon1).not.toBe(null);
- expect(icon2).toBe(null);
- expect(icon3).not.toBe(null);
+ describe("icon behavior", () => {
+ let page: E2EPage;
+ const scale = { l: "l", m: "m", s: "s" };
+ const accordionItemContent = html`
+
+ `;
+
+ beforeEach(async () => {
+ page = await newE2EPage();
+ await page.setContent(html` ${accordionItemContent} `);
+ await page.waitForChanges();
+ });
+
+ it("renders icon if requested", async () => {
+ const icon1: E2EElement = await page.find(`calcite-accordion-item[id='1'] >>> .${CSS.iconStart}`);
+ const icon2: E2EElement = await page.find(`calcite-accordion-item[id='2'] >>> .${CSS.iconStart}`);
+ const icon3: E2EElement = await page.find(`calcite-accordion-item[id='3'] >>> .${CSS.iconStart}`);
+ expect(icon1).not.toBe(null);
+ expect(icon2).toBe(null);
+ expect(icon3).not.toBe(null);
+ });
+
+ it("renders m scale icon for l scale accordion-item", async () => {
+ const item1: E2EElement = await page.find(`calcite-accordion-item[id='1']`);
+ expect(await item1.getProperty("scale")).toBe(scale.l);
+ const icon1: E2EElement = await page.find(`calcite-accordion-item[id='1'] >>> .${CSS.iconStart}`);
+ expect(await icon1.getProperty("scale")).toBe(scale.m);
+ });
+
+ it("renders corresponding scale on accordion-item when parent scale changes, icon scale not affected", async () => {
+ const accordion: E2EElement = await page.find("calcite-accordion");
+ await accordion.setProperty("scale", scale.s);
+ await page.waitForChanges();
+
+ const item1: E2EElement = await page.find(`calcite-accordion-item[id='1']`);
+ expect(await item1.getProperty("scale")).toEqual(scale.s);
+
+ const icon1: E2EElement = await page.find(`calcite-accordion-item[id='1'] >>> .${CSS.iconStart}`);
+ expect(await icon1.getProperty("scale")).toEqual(scale.m);
+ });
+
+ it("renders expected scale icon on child when scale is set on child level (no parent override)", async () => {
+ const accordion: E2EElement = await page.find("calcite-accordion");
+ expect(await icon1.getProperty("scale")).toEqual(scale.l);
+
+ const item1: E2EElement = await page.find(`calcite-accordion-item[id='1']`);
+ await item1.setProperty("scale", scale.m);
+ await page.waitForChanges();
+
+ expect(await accordion.getProperty("scale")).toEqual(scale.l);
+ expect(await item1.getProperty("scale")).toEqual(scale.m);
+ });
});
it("renders expanded item based on attribute in dom", async () => {
diff --git a/src/components/accordion/accordion.tsx b/src/components/accordion/accordion.tsx
index 6e9bb00a59b..dffb72d3d37 100644
--- a/src/components/accordion/accordion.tsx
+++ b/src/components/accordion/accordion.tsx
@@ -1,6 +1,17 @@
-import { Component, Element, Event, EventEmitter, h, Listen, Prop, VNode } from "@stencil/core";
+import {
+ Component,
+ Element,
+ Event,
+ EventEmitter,
+ h,
+ Listen,
+ Prop,
+ VNode,
+ Watch
+} from "@stencil/core";
import { RequestedItem } from "./interfaces";
import { Appearance, Position, Scale } from "../interfaces";
+import { createObserver } from "../../utils/observers";
import { SelectionMode } from "../interfaces";
/**
* @slot - A slot for adding `calcite-accordion-item`s. `calcite-accordion` cannot be nested, however `calcite-accordion-item`s can.
@@ -40,6 +51,11 @@ export class Accordion {
/** Specifies the size of the component. */
@Prop({ reflect: true }) scale: Scale = "m";
+ @Watch("scale")
+ onScaleChange(): void {
+ this.passPropsToAccordionItems();
+ }
+
/**
* Specifies the selection mode - `"multiple"` (allow any number of open items), `"single"` (allow one open item),
* or `"single-persist"` (allow and require one open item).
@@ -66,6 +82,11 @@ export class Accordion {
//
//--------------------------------------------------------------------------
+ connectedCallback(): void {
+ this.passPropsToAccordionItems();
+ this.mutationObserver?.observe(this.el, { childList: true, subtree: true });
+ }
+
componentDidLoad(): void {
if (!this.sorted) {
this.items = this.sortItems(this.items);
@@ -73,6 +94,10 @@ export class Accordion {
}
}
+ disconnectedCallback(): void {
+ this.mutationObserver?.disconnect();
+ }
+
render(): VNode {
const transparent = this.appearance === "transparent";
const minimal = this.appearance === "minimal";
@@ -126,11 +151,13 @@ export class Accordion {
/** created list of Accordion items */
private items = [];
+ /** keep track of the requested item for multi mode */
+ private requestedAccordionItem: HTMLCalciteAccordionItemElement;
+
/** keep track of whether the items have been sorted so we don't re-sort */
private sorted = false;
- /** keep track of the requested item for multi mode */
- private requestedAccordionItem: HTMLCalciteAccordionItemElement;
+ mutationObserver = createObserver("mutation", () => this.passPropsToAccordionItems());
//--------------------------------------------------------------------------
//
@@ -140,4 +167,12 @@ export class Accordion {
private sortItems = (items: any[]): any[] =>
items.sort((a, b) => a.position - b.position).map((a) => a.item);
+
+ private passPropsToAccordionItems = (): void => {
+ (
+ Array.from(
+ this.el.querySelectorAll("calcite-accordion-item") as any
+ ) as HTMLCalciteAccordionItemElement[]
+ ).forEach((accordionItem) => (accordionItem.scale = this.scale));
+ };
}