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(accordion, accordion-item): getElementProp on child is factored out and parent gets a mutation observer to update children #6055

29 changes: 22 additions & 7 deletions src/components/accordion-item/accordion-item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
} from "../../utils/conditionalSlot";
import { CSS_UTILITY } from "../../utils/resources";
import { SLOTS, CSS } from "./resources";
import { Position } from "../interfaces";
import { Position, Scale } from "../interfaces";
import { ItemKeyEvent, RegistryEntry, RequestedItem } from "./interfaces";

/**
Expand All @@ -43,21 +43,24 @@ 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;

/** Specifies an icon to display at the start of the component. */
@Prop({ reflect: true }) iconStart: string;

/** Specifies an icon to display at the end of the component. */
@Prop({ reflect: true }) iconEnd: string;

/** Specifies the size of the component inherited from the `accordion`. */
@Prop({ reflect: true }) scale: Scale = "m";
Elijbet marked this conversation as resolved.
Show resolved Hide resolved

//--------------------------------------------------------------------------
//
// Events
Expand Down Expand Up @@ -135,13 +138,25 @@ export class AccordionItem implements ConditionalSlotComponent {
) : null;
}

iconScaleAdjustment: Scale = this.scale === "l" ? "m" : "s";
Elijbet marked this conversation as resolved.
Show resolved Hide resolved

render(): VNode {
const dir = getElementDir(this.el);
const iconStartEl = this.iconStart ? (
<calcite-icon class={CSS.iconStart} icon={this.iconStart} key="icon-start" scale="s" />
<calcite-icon
class={CSS.iconStart}
icon={this.iconStart}
key="icon-start"
scale={this.iconScaleAdjustment}
/>
) : null;
const iconEndEl = this.iconEnd ? (
<calcite-icon class={CSS.iconEnd} icon={this.iconEnd} key="icon-end" scale="s" />
<calcite-icon
class={CSS.iconEnd}
icon={this.iconEnd}
key="icon-end"
scale={this.iconScaleAdjustment}
/>
) : null;
const { description } = this;
return (
Expand Down Expand Up @@ -180,7 +195,7 @@ export class AccordionItem implements ConditionalSlotComponent {
? "minus"
: "plus"
}
scale="s"
scale={this.iconScaleAdjustment}
/>
</div>
{this.renderActionsEnd()}
Expand Down
42 changes: 39 additions & 3 deletions src/components/accordion/accordion.tsx
Original file line number Diff line number Diff line change
@@ -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 { AccordionAppearance, AccordionSelectionMode, RequestedItem } from "./interfaces";
import { Position, Scale } from "../interfaces";
import { createObserver } from "../../utils/observers";

/**
* @slot - A slot for adding `calcite-accordion-item`s. `calcite-accordion` cannot be nested, however `calcite-accordion-item`s can.
Expand Down Expand Up @@ -37,6 +48,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).
Expand All @@ -60,13 +76,22 @@ 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);
this.sorted = true;
}
}

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

render(): VNode {
const transparent = this.appearance === "transparent";
const minimal = this.appearance === "minimal";
Expand Down Expand Up @@ -155,11 +180,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());

//--------------------------------------------------------------------------
//
Expand Down Expand Up @@ -200,4 +227,13 @@ export class Accordion {

private sortItems = (items: any[]): any[] =>
items.sort((a, b) => a.position - b.position).map((a) => a.item);

private passPropsToAccordionItems = (): void => {
const accordionItems = this.el.querySelectorAll("calcite-accordion-item");
Elijbet marked this conversation as resolved.
Show resolved Hide resolved
if (accordionItems.length > 0) {
accordionItems.forEach((accordionItem) => {
accordionItem.scale = this.scale;
});
}
};
}