Skip to content
This repository has been archived by the owner on Jun 29, 2023. It is now read-only.

Commit

Permalink
feat: Add nesting support to picklist groups (#770)
Browse files Browse the repository at this point in the history
* Add nesting support to groups

* rename slot

* adding tests

* code review comment follow up

* feat: add styling and some updates for pick-list nesting (#783)

* initial tweaks

* Some clean up and demo updates (#767)

* Better check and radio UI. Interim solution until Icon Team delivers a `blank` icon. (#767)

* Only render secondary action node if slot is populated. (#767)

* Added `indented` modifier class. Spacing and demo updates. (#767)

* RTL for list group (#767)

* style update using template literal.

* reset demo page.

* reset demo pages.

* Nixed unnecessary classnames. (#767)

* Removed unnecessary `container` style. Added default class for container section node. Updated demos to also show non-nested pick-list-group.

* fix test

Co-authored-by: Alan Sangma <asangma@esri.com>
  • Loading branch information
pr3tori4n and asangma authored Jan 30, 2020
1 parent bc345ce commit 602264b
Show file tree
Hide file tree
Showing 15 changed files with 298 additions and 86 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,16 @@ describe("calcite-pick-list-group", () => {
expect(isVisible).toBe(true);
expect(heading.innerText).toBe(headingText);
});

it("should indent children if a parent slot is passed", async () => {
const page = await newE2EPage();
await page.setContent(`<calcite-pick-list filter-enabled>
<calcite-pick-list-group>
<calcite-pick-list-item slot="parent-item" value="nums" text-label="Numbers"></calcite-pick-list-item>
<calcite-pick-list-item value="1" text-label="One" text-description="uno"></calcite-pick-list-item>
</calcite-pick-list-group>
</calcite-pick-list>`);
const indentedContainer = await page.find(`calcite-pick-list-group >>> ${CSS.indented}`);
expect(indentedContainer).toBeDefined();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
@extend %component-host;
background-color: var(--calcite-app-background-clear);
display: block;
margin-bottom: var(--calcite-app-cap-spacing);
margin-bottom: var(--calcite-app-cap-spacing-quarter);
}

@import "../../scss/includes/_component";
Expand All @@ -14,12 +14,14 @@

h3.heading {
font-size: var(--calcite-app-font-size-0);
font-weight: var(--calcite-app-font-weight);
margin: var(--calcite-app-cap-spacing-half) var(--calcite-app-side-spacing-half);
margin: var(--calcite-app-cap-spacing-half) var(--calcite-app-side-spacing);
}

.container {
border-radius: var(--calcite-app-border-radius);
overflow: hidden;
@include borderShadow();
.container--indented {
margin-left: var(--calcite-app-side-spacing-plus-half);
}

.calcite--rtl.container--indented {
margin-left: 0;
margin-right: var(--calcite-app-side-spacing-plus-half);
}
28 changes: 24 additions & 4 deletions src/components/calcite-pick-list-group/calcite-pick-list-group.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { Component, Host, Prop, h } from "@stencil/core";
import { CSS } from "./resources";
import { Component, Element, Host, Prop, h } from "@stencil/core";
import classnames from "classnames";
import { CSS, SLOTS } from "./resources";
import { CSS_UTILITY } from "../utils/resources";
import { getElementDir } from "../utils/dom";

/**
* @slot - A slot for adding `calcite-pick-list-item` elements.
Expand All @@ -21,17 +24,34 @@ export class CalcitePickListGroup {
*/
@Prop({ reflect: true }) textGroupTitle: string;

// --------------------------------------------------------------------------
//
// Private Properties
//
// --------------------------------------------------------------------------

@Element() el: HTMLElement;

// --------------------------------------------------------------------------
//
// Render Methods
//
// --------------------------------------------------------------------------

render() {
const { el, textGroupTitle } = this;
const rtl = getElementDir(el) === "rtl";
const hasParentItem = el.querySelector(`[slot=${SLOTS.parentItem}]`) !== null;
const sectionClasses = {
[CSS.indented]: hasParentItem,
[CSS_UTILITY.rtl]: rtl
};

return (
<Host>
{this.textGroupTitle ? <h3 class={CSS.heading}>{this.textGroupTitle}</h3> : null}
<section class={CSS.container}>
{textGroupTitle ? <h3 class={CSS.heading}>{textGroupTitle}</h3> : null}
<slot name={SLOTS.parentItem} />
<section class={classnames(CSS.container, sectionClasses)}>
<slot />
</section>
</Host>
Expand Down
7 changes: 6 additions & 1 deletion src/components/calcite-pick-list-group/resources.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
export const CSS = {
heading: "heading",
container: "container"
container: "container",
indented: "container--indented"
};

export const SLOTS = {
parentItem: "parent-item"
};
20 changes: 11 additions & 9 deletions src/components/calcite-pick-list-item/calcite-pick-list-item.scss
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
:host {
@extend %component-host;
align-items: center;
background-color: var(--calcite-app-background-clear);
display: flex;
margin: 0 var(--calcite-app-side-spacing-half) var(--calcite-app-cap-spacing-minimum);
margin: 0;
color: var(--calcite-app-foreground);
transition: background-color var(--calcite-app-animation-time-fast) var(--calcite-app-easing-function);
animation: calcite-app-fade-in var(--calcite-app-animation-time) var(--calcite-app-easing-function);
Expand All @@ -15,23 +16,24 @@
background-color: var(--calcite-app-background-hover);
}

:host(:last-child) {
margin-bottom: 0;
@include borderShadow();
}

.icon {
color: var(--calcite-app-foreground-link);
flex: 0 0 0%;
line-height: 0;
width: var(--calcite-app-icon-size);
margin: 0 var(--calcite-app-side-spacing-half);
margin: 0 var(--calcite-app-side-spacing-quarter);
opacity: 0;
}

:host([selected]) .icon {
transition: opacity var(--calcite-app-animation-time-fast) var(--calcite-app-easing-function);
opacity: 1;
}

.label {
display: flex;
flex: 1 1 auto;
padding: var(--calcite-app-cap-spacing-three-quarters) var(--calcite-app-side-spacing-half);
padding: var(--calcite-app-cap-spacing-half) var(--calcite-app-side-spacing-half);
align-items: center;
cursor: pointer;

Expand All @@ -43,7 +45,7 @@
flex-flow: column nowrap;
overflow: hidden;
pointer-events: none;
padding: 0 var(--calcite-app-side-spacing-half);
padding: 0 var(--calcite-app-side-spacing-quarter);
}

.title {
Expand Down
15 changes: 11 additions & 4 deletions src/components/calcite-pick-list-item/calcite-pick-list-item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
Watch,
h
} from "@stencil/core";
import { CSS, ICONS } from "./resources";
import { CSS, ICONS, SLOTS } from "./resources";
import { ICON_TYPES } from "../calcite-pick-list/resources";

/**
Expand Down Expand Up @@ -207,6 +207,15 @@ export class CalcitePickListItem {
);
}

renderSecondaryAction() {
const hasSecondaryAction = this.el.querySelector(`[slot=${SLOTS.secondaryAction}]`);
return hasSecondaryAction ? (
<div class={CSS.action}>
<slot name={SLOTS.secondaryAction} />
</div>
) : null;
}

render() {
const description =
this.textDescription && !this.compact ? (
Expand All @@ -228,9 +237,7 @@ export class CalcitePickListItem {
{description}
</div>
</label>
<div class={CSS.action}>
<slot name="secondary-action" />
</div>
{this.renderSecondaryAction()}
</Host>
);
}
Expand Down
6 changes: 5 additions & 1 deletion src/components/calcite-pick-list-item/resources.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ export const CSS = {

export const ICONS = {
unchecked: "square",
checked: "check-square",
checked: "check",
selected: "circle-filled",
unselected: "circle"
};

export const SLOTS = {
secondaryAction: "secondary-action"
};
57 changes: 56 additions & 1 deletion src/components/calcite-pick-list/calcite-pick-list.e2e.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { newE2EPage } from "@stencil/core/testing";
import { E2EElement, E2EPage, newE2EPage } from "@stencil/core/testing";
import { ICON_TYPES } from "./resources";
import { accessible, hidden, renders } from "../../tests/commonTests";
import { tests } from "./shared-list-tests";
Expand Down Expand Up @@ -43,6 +43,61 @@ describe("calcite-pick-list", () => {

describe("filter behavior (hide/show items)", () => {
filterBehavior("pick");
describe("filtering with groups", () => {
let page: E2EPage = null;
let parentItem: E2EElement;
let item1: E2EElement;
let item2: E2EElement;
beforeEach(async () => {
page = await newE2EPage();
await page.setContent(`<calcite-pick-list filter-enabled>
<calcite-pick-list-group>
<calcite-pick-list-item slot="parent-item" value="nums" text-label="Numbers"></calcite-pick-list-item>
<calcite-pick-list-item value="1" text-label="One" text-description="uno"></calcite-pick-list-item>
<calcite-pick-list-item value="2" text-label="Two" text-description="dos"></calcite-pick-list-item>
</calcite-pick-list-group>
</calcite-pick-list>`);
parentItem = await page.find(`calcite-pick-list-item[slot="parent-item"]`);
item1 = await page.find(`calcite-pick-list-item[value="1"]`);
item2 = await page.find(`calcite-pick-list-item[value="2"]`);
item1.setProperty("metadata", { category: "first" });
item2.setProperty("metadata", { category: "second" });
await page.waitForChanges();
await page.evaluate(() => {
(window as any).filter = document
.querySelector(`calcite-pick-list`)
.shadowRoot.querySelector("calcite-filter");
const filter = (window as any).filter;
(window as any).filterInput = filter.shadowRoot.querySelector("input");
});
});
it("should show the group parent if a match is found in a child", async () => {
await page.evaluate(() => {
const filterInput = (window as any).filterInput;
filterInput.value = "one";
filterInput.dispatchEvent(new Event("input"));
});
await item2.waitForNotVisible();

const parentVisible = await parentItem.isVisible();

expect(parentVisible).toBe(true);
});
it("should show the children of a group if the parent matches", async () => {
await page.evaluate(() => {
const filterInput = (window as any).filterInput;
filterInput.value = "nums";
filterInput.dispatchEvent(new Event("input"));
});
await page.waitFor(500);

const item1Visible = await item1.isVisible();
const item2Visible = await item2.isVisible();

expect(item1Visible).toBe(true);
expect(item2Visible).toBe(true);
});
});
});

describe("disabled states", () => {
Expand Down
3 changes: 1 addition & 2 deletions src/components/calcite-pick-list/calcite-pick-list.scss
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
:host {
@extend %component-host;
align-items: stretch;
background-color: var(--calcite-app-background-clear);
display: flex;
flex: 1 0 auto;
flex-flow: column;
padding-bottom: var(--calcite-app-cap-spacing-half);
padding-bottom: var(--calcite-app-cap-spacing);
position: relative;
}

Expand Down
18 changes: 18 additions & 0 deletions src/components/calcite-pick-list/shared-list-logic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,25 @@ export const sharedListMethods = {
const filteredData = event.detail;
const values = filteredData.map((item) => item.value);
this.items.forEach((item) => {
const inGroup = item.parentElement.matches("calcite-pick-list-group");

item.hidden = values.indexOf(item.value) === -1;

// If item is in a group...
if (inGroup) {
const groupParent = item.parentElement.querySelector("[slot=parent-item]") as pickOrValueListItem;
// If there is a group parent
if (groupParent !== null) {
// If the group parent is a match, show me.
if (values.indexOf(groupParent.value) !== -1) {
item.hidden = false;
}
// If I am a match, show my parent.
if (values.indexOf(item.value) !== -1) {
groupParent.hidden = false;
}
}
}
});
},
getItemData(this: CalcitePickList | CalciteValueList): Record<string, string | object>[] {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
@extend %component-host;
@include borderShadow();
display: flex;
background-color: var(--calcite-app-background);
padding: var(--calcite-app-side-spacing-minimum);
transition: background-color var(--calcite-app-animation-time-fast) var(--calcite-app-easing-function),
box-shadow var(--calcite-app-animation-time-fast) var(--calcite-app-easing-function);
Expand Down
10 changes: 8 additions & 2 deletions src/demos/action-bar/add-action-after-init.html
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,16 @@ <h2>LTR</h2>
<h3>Bottom Actions</h3>
<calcite-action-bar id="slot-test">
<calcite-action text="Add">
<calcite-icon scale="s" icon="add"></calcite-icon>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
<path d="M9 7h5v2H9v5H7V9H2V7h5V2h2z" />
</svg>
</calcite-action>
<calcite-action text="Save">
<calcite-icon scale="s" icon="save"></calcite-icon>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
<path
d="M14 1H2a1 1 0 0 0-1 1v10a.99.99 0 0 0 .293.707l2 2A.995.995 0 0 0 4 15h10a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1zM6 14v-3h2v3zm6-.001V14h-1v-4H5v4H4v-4a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1zM12 6H4V2h8z"
/>
</svg>
</calcite-action>
</calcite-action-bar>

Expand Down
Loading

0 comments on commit 602264b

Please sign in to comment.