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(stepper, stepper-item): getElementProp is refactored out in favor of inheritable props set directly on parent #7593

Merged
merged 27 commits into from
Aug 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
aaacd74
refactor(segmented-control, segmented-control-item: getElementProp is…
Elijbet Aug 24, 2023
d42ec3e
refactor(stepper, stepper-item): getElementProp is refactored out acr…
Elijbet Aug 24, 2023
cffa286
merge conflicts resolved
Elijbet Aug 25, 2023
38364c5
test(list): Use the dragAndDrop utility for mouse tests (#7604)
driskull Aug 25, 2023
7bb86e4
pass in stepperParent as well
Elijbet Aug 25, 2023
fde5914
fix(flow): catch error when beforeBack promise is rejected (#7601)
driskull Aug 25, 2023
982dfa8
fix(modal): catch error when beforeClose promise is rejected (#7600)
driskull Aug 25, 2023
c567006
chore: release next
github-actions[bot] Aug 25, 2023
f8ce915
feat(combobox): add single-persist selection mode (#7583)
jcfranco Aug 25, 2023
265dddf
chore: release next
github-actions[bot] Aug 25, 2023
1f6ad79
fix(tree-item): updates state when selection changes programmatically…
anveshmekala Aug 25, 2023
951708f
chore: release next
github-actions[bot] Aug 25, 2023
6ce661f
fix(rating): adds focus outline on click (#7341)
anveshmekala Aug 26, 2023
c32f5c4
chore: release next
github-actions[bot] Aug 26, 2023
68c642d
merge conflicts resolved
Elijbet Aug 29, 2023
501693b
Merge branch 'main' into elijbet/6038-refactor-getElementProp-stepper…
Elijbet Aug 30, 2023
165df30
revert unrelated changes
Elijbet Aug 30, 2023
ddd6cf1
Merge branch 'main' into elijbet/6038-refactor-getElementProp-stepper…
Elijbet Aug 30, 2023
0eebfcf
Merge branch 'main' into elijbet/6038-refactor-getElementProp-stepper…
Elijbet Aug 30, 2023
868ee5c
remove unnecessary parent prop and query items
Elijbet Aug 30, 2023
1ce1986
revert package-lock
Elijbet Aug 30, 2023
adfb0b0
Merge branch 'main' into elijbet/6038-refactor-getElementProp-stepper…
Elijbet Aug 30, 2023
d158c6d
Merge branch 'main' into elijbet/6038-refactor-getElementProp-stepper…
Elijbet Aug 31, 2023
e35c1f5
cleanup
Elijbet Aug 31, 2023
59931e1
revert unrelated automatic formatting
Elijbet Aug 31, 2023
2fb803a
reflect internal props for item styling to apply
jcfranco Aug 31, 2023
ee8bdaf
keep existing behavior by dropping default internal layout value
jcfranco Aug 31, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
VNode,
Watch,
} from "@stencil/core";
import { getElementProp, toAriaBoolean } from "../../utils/dom";
import { toAriaBoolean } from "../../utils/dom";
import { Layout, Scale } from "../interfaces";
import {
connectInteractive,
Expand Down Expand Up @@ -81,27 +81,9 @@ export class StepperItem implements InteractiveComponent, LocalizedComponent, Lo
/** A description for the component. Displays below the header text. */
@Prop() description: string;

// internal props inherited from wrapping calcite-stepper
/** Defines the layout of the component. */
/** @internal */
@Prop({ reflect: true, mutable: true }) layout: Extract<"horizontal" | "vertical", Layout> =
"horizontal";

/** When `true`, displays a status icon in the component's heading. */
/** @internal */
@Prop({ mutable: true }) icon = false;

/** When `true`, the icon will be flipped when the element direction is right-to-left (`"rtl"`). */
@Prop({ reflect: true }) iconFlipRtl = false;

/** When `true`, displays the step number in the component's heading. */
/** @internal */
@Prop({ mutable: true }) numbered = false;

/** Specifies the size of the component. */
/** @internal */
@Prop({ reflect: true, mutable: true }) scale: Scale = "m";

/**
* @internal
*/
Expand All @@ -113,6 +95,34 @@ export class StepperItem implements InteractiveComponent, LocalizedComponent, Lo
this.registerStepperItem();
}

/**
* When `true`, displays a status icon in the `calcite-stepper-item` heading inherited from parent `calcite-stepper`.
*
* @internal
*/
@Prop() icon = false;

/**
* Specifies the layout of the `calcite-stepper-item` inherited from parent `calcite-stepper`, defaults to `horizontal`.
*
* @internal
*/
@Prop({ reflect: true }) layout: Extract<"horizontal" | "vertical", Layout>;

/**
* When `true`, displays the step number in the `calcite-stepper-item` heading inherited from parent `calcite-stepper`.
*
* @internal
*/
@Prop() numbered = false;

/**
* Specifies the size of the component inherited from the `calcite-stepper`, defaults to `m`.
*
* @internal
*/
@Prop({ reflect: true }) scale: Scale = "m";

//--------------------------------------------------------------------------
//
// Internal State/Props
Expand Down Expand Up @@ -175,10 +185,6 @@ export class StepperItem implements InteractiveComponent, LocalizedComponent, Lo

componentWillLoad(): void {
setUpLoadableComponent(this);
this.icon = getElementProp(this.el, "icon", false);
this.numbered = getElementProp(this.el, "numbered", false);
this.layout = getElementProp(this.el, "layout", false);
this.scale = getElementProp(this.el, "scale", "m");
this.parentStepperEl = this.el.parentElement as HTMLCalciteStepperElement;
this.itemPosition = this.getItemPosition();
this.registerStepperItem();
Expand Down
112 changes: 68 additions & 44 deletions packages/calcite-components/src/components/stepper/stepper.e2e.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,52 @@
import { E2EPage, newE2EPage } from "@stencil/core/testing";
import { renders, hidden } from "../../tests/commonTests";
import { defaults, hidden, reflects, renders } from "../../tests/commonTests";
import { html } from "../../../support/formatting";
import { NumberStringFormatOptions } from "../../utils/locale";

// todo test the automatic setting of first item to selected
describe("calcite-stepper", () => {
describe("defaults", () => {
defaults("calcite-stepper", [
{
propertyName: "icon",
defaultValue: false,
},
{
propertyName: "layout",
defaultValue: "horizontal",
},
{
propertyName: "numbered",
defaultValue: false,
},
{
propertyName: "scale",
defaultValue: "m",
},
]);
});

describe("reflects", () => {
reflects("calcite-stepper", [
{
propertyName: "icon",
value: true,
},
{
propertyName: "layout",
value: "horizontal",
},
{
propertyName: "numbered",
value: true,
},
{
propertyName: "scale",
value: "m",
},
]);
});

describe("renders", () => {
renders(
html`<calcite-stepper>
Expand All @@ -25,50 +67,32 @@ describe("calcite-stepper", () => {
);
});

it("renders default props when none are provided", async () => {
const page = await newE2EPage();
await page.setContent(html`<calcite-stepper>
<calcite-stepper-item heading="Step 1" id="step-1">
<div>Step 1 content</div>
</calcite-stepper-item>
<calcite-stepper-item heading="Step 2" id="step-2">
<div>Step 2 content</div>
</calcite-stepper-item>
<calcite-stepper-item heading="Step 3" id="step-3">
<div>Step 3 content</div>
</calcite-stepper-item>
<calcite-stepper-item heading="Step 4" id="step-4">
<div>Step 4 content</div>
</calcite-stepper-item>
</calcite-stepper>`);
const element = await page.find("calcite-stepper");
expect(element).toEqualAttribute("layout", "horizontal");
expect(element).toEqualAttribute("scale", "m");
expect(element).not.toHaveAttribute("numbered");
expect(element).not.toHaveAttribute("icon");
});

it("renders requested props when valid props are provided", async () => {
it("inheritable props: `icon`, `layout`, `numbered`, and `scale` get passed to items from parents", async () => {
const page = await newE2EPage();
await page.setContent(html`<calcite-stepper layout="vertical" scale="l" numbered icon>
<calcite-stepper-item heading="Step 1" id="step-1">
<div>Step 1 content</div>
</calcite-stepper-item>
<calcite-stepper-item heading="Step 2" id="step-2">
<div>Step 2 content</div>
</calcite-stepper-item>
<calcite-stepper-item heading="Step 3" id="step-3">
<div>Step 3 content</div>
</calcite-stepper-item>
<calcite-stepper-item heading="Step 4" id="step-4">
<div>Step 4 content</div>
</calcite-stepper-item>
</calcite-stepper>`);
const element = await page.find("calcite-stepper");
expect(element).toEqualAttribute("layout", "vertical");
expect(element).toEqualAttribute("scale", "l");
expect(element).toHaveAttribute("numbered");
expect(element).toHaveAttribute("icon");
await page.setContent(html`
<calcite-stepper layout="vertical" scale="l" numbered icon>
<calcite-stepper-item heading="Step 1" id="step-1">
<div>Step 1 content</div>
</calcite-stepper-item>
<calcite-stepper-item heading="Step 2" id="step-2">
<div>Step 2 content</div>
</calcite-stepper-item>
<calcite-stepper-item heading="Step 3" id="step-3">
<div>Step 3 content</div>
</calcite-stepper-item>
<calcite-stepper-item heading="Step 4" id="step-4">
<div>Step 4 content</div>
</calcite-stepper-item>
</calcite-stepper>
`);
const stepperItems = await page.findAll("calcite-stepper-items");

stepperItems.forEach(async (item) => {
expect(await item.getProperty("icon")).toBe(true);
expect(await item.getProperty("layout")).toBe("vertical");
expect(await item.getProperty("scale")).toBe("l");
expect(await item.getProperty("numbered")).toBe(true);
});
});

// eslint-disable-next-line jest/no-disabled-tests
Expand Down
32 changes: 29 additions & 3 deletions packages/calcite-components/src/components/stepper/stepper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { focusElementInGroup } from "../../utils/dom";
import { NumberingSystem } from "../../utils/locale";
import { Layout, Scale } from "../interfaces";
import { StepperItemChangeEventDetail, StepperItemKeyEventDetail } from "./interfaces";
import { createObserver } from "../../utils/observers";

/**
* @slot - A slot for adding `calcite-stepper-item` elements.
Expand All @@ -40,6 +41,17 @@ export class Stepper {
/** When `true`, displays the step number in the `calcite-stepper-item` heading. */
@Prop({ reflect: true }) numbered = false;

/** Specifies the size of the component. */
@Prop({ reflect: true }) scale: Scale = "m";

@Watch("icon")
@Watch("layout")
@Watch("numbered")
@Watch("scale")
handleItemPropChange(): void {
this.updateItems();
}

/**
* Specifies the Unicode numeral system used by the component for localization.
*/
Expand All @@ -57,9 +69,6 @@ export class Stepper {
*/
@Prop({ mutable: true }) selectedItem: HTMLCalciteStepperItemElement = null;

/** Specifies the size of the component. */
@Prop({ reflect: true }) scale: Scale = "m";

//--------------------------------------------------------------------------
//
// Events
Expand All @@ -86,6 +95,12 @@ export class Stepper {
// Lifecycle
//
//--------------------------------------------------------------------------

connectedCallback(): void {
this.mutationObserver?.observe(this.el, { childList: true });
this.updateItems();
}

componentDidLoad(): void {
// if no stepper items are set as active, default to the first one
if (typeof this.currentPosition !== "number") {
Expand Down Expand Up @@ -258,6 +273,17 @@ export class Stepper {
/** keep track of the currently active item position */
private currentPosition: number;

private mutationObserver = createObserver("mutation", () => this.updateItems());

private updateItems(): void {
this.el.querySelectorAll("calcite-stepper-item").forEach((item) => {
item.icon = this.icon;
item.numbered = this.numbered;
item.layout = this.layout;
item.scale = this.scale;
});
}

//--------------------------------------------------------------------------
//
// Private Methods
Expand Down
Loading