@salesforcedevs/dx-components 0.20.1 → 0.22.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforcedevs/dx-components",
3
- "version": "0.20.1",
3
+ "version": "0.22.3",
4
4
  "description": "DX Lightning web components",
5
5
  "license": "MIT",
6
6
  "engines": {
@@ -29,5 +29,5 @@
29
29
  "@types/debounce": "^1.2.0",
30
30
  "@types/lodash.get": "^4.4.6"
31
31
  },
32
- "gitHead": "c7eab03d08445c1a6279f9480b7694d7e894e038"
32
+ "gitHead": "c45075053423bcb7a50d00953243aa0e93bf2a59"
33
33
  }
@@ -25,10 +25,6 @@ describe(TAG, () => {
25
25
  const oldNavigator = window.navigator;
26
26
  const oldError = console.error;
27
27
 
28
- afterEach(() => {
29
- jest.clearAllMocks();
30
- });
31
-
32
28
  afterAll(() => {
33
29
  Object.assign(window.navigator, oldNavigator);
34
30
  Object.assign(console.error, oldError);
@@ -41,7 +41,7 @@ export default class CodeBlock extends LightningElement {
41
41
  { label: "Visualforce", id: "visualforce" },
42
42
  { label: "Html", id: "html" },
43
43
  { label: "xml", id: "xml" },
44
- { label: "TypeScript", id: "TypeScript" },
44
+ { label: "TypeScript", id: "typescript" },
45
45
  { label: "PHP", id: "php" }
46
46
  ];
47
47
 
@@ -5,10 +5,6 @@ const TAG = "dx-grid";
5
5
  const render = createRenderComponent(TAG, Grid);
6
6
 
7
7
  describe(TAG, () => {
8
- afterEach(() => {
9
- jest.clearAllMocks();
10
- });
11
-
12
8
  [
13
9
  [4, "four", "dynamic"],
14
10
  [8, "four", "dynamic"],
@@ -21,9 +17,8 @@ describe(TAG, () => {
21
17
  ].forEach(([numElements, calculatedColumns, columns]) =>
22
18
  it(`choses ${calculatedColumns} columns when there are ${numElements} elements`, () => {
23
19
  const element = render({ columns });
24
- const slot: HTMLSlotElement = element.shadowRoot.querySelector(
25
- "slot"
26
- );
20
+ const slot: HTMLSlotElement =
21
+ element.shadowRoot.querySelector("slot");
27
22
  const div = document.createElement("div");
28
23
  slot.assignedElements = jest
29
24
  .fn()
@@ -89,7 +89,6 @@ describe(TAG, () => {
89
89
  });
90
90
 
91
91
  afterEach(() => {
92
- jest.clearAllMocks();
93
92
  subscribeCallback = null;
94
93
  });
95
94
 
@@ -0,0 +1,87 @@
1
+ import MinimalCard from "dx/minimalCard";
2
+ import TypeBadge from "dx/typeBadge";
3
+ import { createRenderComponent } from "utils/tests";
4
+ import { createMediaMock } from "utils/jest";
5
+ import { blogPostMock, podcastEpisodeMock } from "./mockProps";
6
+
7
+ const MOBILE_QUERY = "(max-width: 640px)";
8
+ const TAG = "dx-minimal-card";
9
+ const render = createRenderComponent(TAG, MinimalCard);
10
+
11
+ describe(TAG, () => {
12
+ describe("default render", () => {
13
+ beforeAll(() => {
14
+ window.matchMedia = createMediaMock();
15
+ });
16
+
17
+ it("renders a blog post", () => {
18
+ const component = render(blogPostMock);
19
+ const link: HTMLAnchorElement =
20
+ component.shadowRoot.querySelector("a");
21
+ expect(link).not.toBeNull();
22
+ expect(link.href).toMatch(blogPostMock.href);
23
+ expect(link.target).toBe("_self");
24
+
25
+ const heading = link.querySelector("h4");
26
+ expect(heading).not.toBeNull();
27
+ expect(heading?.textContent).toBe(blogPostMock.title);
28
+
29
+ const typeBadge: TypeBadge =
30
+ component.shadowRoot.querySelector("dx-type-badge");
31
+ expect(typeBadge).not.toBeNull();
32
+ expect(typeBadge.value).toBe("Blog");
33
+ expect(typeBadge.color).toBe("teal");
34
+ expect(typeBadge.size).toBe("default");
35
+
36
+ expect(window.matchMedia).toBeCalledTimes(1);
37
+ expect(window.matchMedia).toBeCalledWith(MOBILE_QUERY);
38
+
39
+ return expect(component).toBeAccessible();
40
+ });
41
+
42
+ it("renders a podcast episode with target blank", () => {
43
+ const target = "_blank";
44
+ const component = render({ ...podcastEpisodeMock, target });
45
+ const link: HTMLAnchorElement =
46
+ component.shadowRoot.querySelector("a");
47
+ expect(link).not.toBeNull();
48
+ expect(link.href).toMatch(podcastEpisodeMock.href);
49
+ expect(link.target).toBe(target);
50
+
51
+ const heading = link.querySelector("h4");
52
+ expect(heading).not.toBeNull();
53
+ expect(heading?.textContent).toBe(podcastEpisodeMock.title);
54
+
55
+ const typeBadge: TypeBadge =
56
+ component.shadowRoot.querySelector("dx-type-badge");
57
+ expect(typeBadge).not.toBeNull();
58
+ expect(typeBadge.value).toBe(podcastEpisodeMock.contentType);
59
+ expect(typeBadge.color).toBe("blue");
60
+ expect(typeBadge.size).toBe("default");
61
+
62
+ expect(window.matchMedia).toBeCalledTimes(1);
63
+ expect(window.matchMedia).toBeCalledWith(MOBILE_QUERY);
64
+
65
+ return expect(component).toBeAccessible();
66
+ });
67
+ });
68
+ describe("render mobile", () => {
69
+ beforeAll(() => {
70
+ window.matchMedia = createMediaMock(true);
71
+ });
72
+
73
+ it("renders dx-type-badge as small", () => {
74
+ const component = render(podcastEpisodeMock);
75
+ const typeBadge =
76
+ component.shadowRoot.querySelector("dx-type-badge");
77
+ expect(typeBadge).not.toBeNull();
78
+ expect(typeBadge.value).toBe(podcastEpisodeMock.contentType);
79
+ expect(typeBadge.color).toBe("blue");
80
+ expect(typeBadge.size).toBe("small");
81
+ expect(window.matchMedia).toBeCalledTimes(1);
82
+ expect(window.matchMedia).toBeCalledWith(MOBILE_QUERY);
83
+
84
+ return expect(component).toBeAccessible();
85
+ });
86
+ });
87
+ });
@@ -0,0 +1,10 @@
1
+ export const blogPostMock = {
2
+ title: "Lightning Web Components for Your Inbox",
3
+ href: "/awesome-post"
4
+ };
5
+
6
+ export const podcastEpisodeMock = {
7
+ title: "Episode 100: Trailhead Engineering with Jeff Douglas",
8
+ href: "/awesome-episode",
9
+ contentType: "Podcast"
10
+ };
@@ -0,0 +1,32 @@
1
+ @import "helpers/reset";
2
+
3
+ :host {
4
+ display: block;
5
+ }
6
+
7
+ a {
8
+ color: var(--dx-g-blue-vibrant-50);
9
+ display: -webkit-box;
10
+ flex-grow: 1;
11
+ font-family: var(--dx-g-font-sans);
12
+ font-size: var(--dx-g-text-sm);
13
+ font-weight: var(--dx-g-font-demi);
14
+ overflow: hidden;
15
+ -webkit-line-clamp: var(--dx-c-title-max-lines, 3);
16
+ -webkit-box-orient: vertical;
17
+ }
18
+
19
+ a:hover {
20
+ color: var(--dx-g-blue-vibrant-40);
21
+ }
22
+
23
+ a + * {
24
+ margin-left: var(--dx-g-spacing-sm);
25
+ }
26
+
27
+ .card-container {
28
+ align-items: center;
29
+ border-bottom: 1px solid var(--sds-g-gray-4);
30
+ display: flex;
31
+ padding: var(--dx-g-spacing-smd) 0;
32
+ }
@@ -0,0 +1,13 @@
1
+ <template>
2
+ <div class="card-container">
3
+ <a href={href} target={target}>
4
+ <h4>{title}</h4>
5
+ </a>
6
+ <dx-type-badge
7
+ color={badgeColor}
8
+ size={badgeSize}
9
+ type="content-type"
10
+ value={contentType}
11
+ ></dx-type-badge>
12
+ </div>
13
+ </template>
@@ -0,0 +1,32 @@
1
+ import { html } from "lit-html";
2
+ import { blogPostMock, podcastEpisodeMock } from "./__tests__/mockProps";
3
+
4
+ export default {
5
+ title: "dx/dx-minimal-card",
6
+ component: "dx-minimal-card"
7
+ };
8
+
9
+ export const BlogPost = (args: { title: string; href: string }) => html`
10
+ <dx-minimal-card
11
+ title="${args.title}"
12
+ href="${args.href}"
13
+ ></dx-minimal-card>
14
+ `;
15
+
16
+ BlogPost.args = {
17
+ title: blogPostMock.title,
18
+ href: blogPostMock.href
19
+ };
20
+
21
+ export const PodcastEpisode = (args: { title: string; href: string }) => html`
22
+ <dx-minimal-card
23
+ title="${args.title}"
24
+ href="${args.href}"
25
+ content-type="${podcastEpisodeMock.contentType}"
26
+ ></dx-minimal-card>
27
+ `;
28
+
29
+ PodcastEpisode.args = {
30
+ title: podcastEpisodeMock.title,
31
+ href: podcastEpisodeMock.href
32
+ };
@@ -0,0 +1,35 @@
1
+ import { LightningElement, api } from "lwc";
2
+ import { Color, LinkTarget } from "typings/custom";
3
+
4
+ const MOBILE_QUERY = "(max-width: 640px)";
5
+
6
+ export default class MinimalCard extends LightningElement {
7
+ @api contentType: "Blog" | "Podcast" = "Blog";
8
+ @api href!: string;
9
+ @api target: LinkTarget = "_self";
10
+ @api title!: string;
11
+
12
+ private matchMedia!: MediaQueryList;
13
+ private mobile = false;
14
+
15
+ get badgeColor(): Color {
16
+ return this.contentType === "Blog" ? "teal" : "blue";
17
+ }
18
+
19
+ get badgeSize(): string {
20
+ return (this.mobile && "small") || "default";
21
+ }
22
+
23
+ connectedCallback(): void {
24
+ this.matchMedia = window.matchMedia(MOBILE_QUERY);
25
+ this.onMediaChange(this.matchMedia);
26
+ this.matchMedia.addEventListener("change", this.onMediaChange);
27
+ }
28
+
29
+ disconnectedCallback(): void {
30
+ this.matchMedia.removeEventListener("change", this.onMediaChange);
31
+ }
32
+
33
+ private onMediaChange = (e: MediaQueryListEvent | MediaQueryList) =>
34
+ (this.mobile = e.matches);
35
+ }
@@ -16,10 +16,6 @@ describe(TAG, () => {
16
16
  global.console = { ...global.console, error: jest.fn() };
17
17
  });
18
18
 
19
- afterEach(() => {
20
- jest.clearAllMocks();
21
- });
22
-
23
19
  afterAll(() => {
24
20
  global.console = originalConsole;
25
21
  });
@@ -29,15 +25,13 @@ describe(TAG, () => {
29
25
 
30
26
  expect(console.error).not.toBeCalled();
31
27
 
32
- const menuEl: HTMLElement = component.shadowRoot.querySelector(
33
- ".popover-container"
34
- );
28
+ const menuEl: HTMLElement =
29
+ component.shadowRoot.querySelector(".popover-container");
35
30
  expect(menuEl).not.toBeNull();
36
31
  expect(menuEl.classList).toHaveLength(1);
37
32
 
38
- const popoverDiv: HTMLElement = menuEl.querySelector(
39
- "div.popover"
40
- )!;
33
+ const popoverDiv: HTMLElement =
34
+ menuEl.querySelector("div.popover")!;
41
35
  expect(popoverDiv).not.toBeNull();
42
36
  expect(popoverDiv.classList).toHaveLength(1);
43
37
 
@@ -47,15 +41,13 @@ describe(TAG, () => {
47
41
  it("renders with api properties", () => {
48
42
  const component = render(mockProps);
49
43
  expect(console.error).not.toBeCalled();
50
- const menuEl: HTMLElement = component.shadowRoot.querySelector(
51
- ".popover-container"
52
- );
44
+ const menuEl: HTMLElement =
45
+ component.shadowRoot.querySelector(".popover-container");
53
46
  expect(menuEl).not.toBeNull();
54
47
  expect(menuEl.classList).toHaveLength(1);
55
48
 
56
- const popoverDiv: HTMLElement = menuEl.querySelector(
57
- "div.popover"
58
- )!;
49
+ const popoverDiv: HTMLElement =
50
+ menuEl.querySelector("div.popover")!;
59
51
  expect(popoverDiv).not.toBeNull();
60
52
  expect(popoverDiv.classList).toHaveLength(4);
61
53
  expect(popoverDiv.classList).toContain(
@@ -74,9 +66,8 @@ describe(TAG, () => {
74
66
 
75
67
  expect(console.error).not.toBeCalled();
76
68
 
77
- const popoverDiv: HTMLElement = component.shadowRoot.querySelector(
78
- "div.popover"
79
- );
69
+ const popoverDiv: HTMLElement =
70
+ component.shadowRoot.querySelector("div.popover");
80
71
  expect(popoverDiv.classList).toHaveLength(2);
81
72
  expect(popoverDiv.classList).toContain("popover-fullwidth");
82
73
  });
@@ -89,9 +80,8 @@ describe(TAG, () => {
89
80
  'The "width" and "full-width" properties cannot be provided simultaneously.'
90
81
  );
91
82
 
92
- const popoverDiv: HTMLElement = component.shadowRoot.querySelector(
93
- "div.popover"
94
- );
83
+ const popoverDiv: HTMLElement =
84
+ component.shadowRoot.querySelector("div.popover");
95
85
  expect(popoverDiv.style).not.toBeNull();
96
86
  expect(popoverDiv.classList).toHaveLength(5);
97
87
  expect(popoverDiv.classList).toContain(
@@ -120,9 +110,8 @@ describe(TAG, () => {
120
110
 
121
111
  it("doesn't render menu content before interaction", async () => {
122
112
  const component = render();
123
- const content = component.shadowRoot.querySelector(
124
- ".popover-content"
125
- );
113
+ const content =
114
+ component.shadowRoot.querySelector(".popover-content");
126
115
 
127
116
  expect(content).toBeNull();
128
117
 
@@ -130,9 +119,8 @@ describe(TAG, () => {
130
119
 
131
120
  await Promise.resolve();
132
121
 
133
- const contentAfterOpen = component.shadowRoot.querySelector(
134
- ".popover-content"
135
- );
122
+ const contentAfterOpen =
123
+ component.shadowRoot.querySelector(".popover-content");
136
124
 
137
125
  expect(contentAfterOpen).not.toBeNull();
138
126
 
@@ -145,9 +133,8 @@ describe(TAG, () => {
145
133
 
146
134
  const renderComponent = createRenderComponent(TAG, Popover);
147
135
  const component = renderComponent();
148
- const content = component.shadowRoot.querySelector(
149
- ".popover-content"
150
- );
136
+ const content =
137
+ component.shadowRoot.querySelector(".popover-content");
151
138
 
152
139
  expect(content).not.toBeNull();
153
140
  });
@@ -183,9 +170,12 @@ describe(TAG, () => {
183
170
  it("doesn't fire open if passed control is disabled", () => {
184
171
  const element = render();
185
172
 
186
- const { slot: controlSlot, slottedElement } = mockSlottedElement<
187
- HTMLButtonElement
188
- >(element, "button", "control");
173
+ const { slot: controlSlot, slottedElement } =
174
+ mockSlottedElement<HTMLButtonElement>(
175
+ element,
176
+ "button",
177
+ "control"
178
+ );
189
179
  expect(controlSlot.assignedElements).toBeCalledTimes(1);
190
180
  expect(slottedElement.ariaHasPopup).toBe("true");
191
181
  expect(slottedElement.style.cursor).toBe("cursor");
@@ -237,9 +227,8 @@ describe(TAG, () => {
237
227
  const closeEvent = jest.fn();
238
228
  component.addEventListener("close", closeEvent);
239
229
 
240
- const popoverDiv: HTMLElement = component.shadowRoot.querySelector(
241
- ".popover"
242
- );
230
+ const popoverDiv: HTMLElement =
231
+ component.shadowRoot.querySelector(".popover");
243
232
  expect(popoverDiv).not.toBeNull();
244
233
 
245
234
  expect(component.open).toBe(true);
@@ -25,10 +25,6 @@ const GTM_EVENT_NAME = "custEv_leftNavLinkClick";
25
25
  const TOGGLE_BUTTON_LABEL = "Toggle Sidebar";
26
26
 
27
27
  describe(TAG, () => {
28
- afterEach(() => {
29
- jest.clearAllMocks();
30
- });
31
-
32
28
  describe("desktop", () => {
33
29
  beforeEach(() => {
34
30
  unmockQueryParameter();
@@ -19,10 +19,6 @@ const GTM_EVENT_NAME = "custEv_leftNavLinkClick";
19
19
  const TOGGLE_BUTTON_LABEL = "Toggle Sidebar";
20
20
 
21
21
  describe(TAG, () => {
22
- afterEach(() => {
23
- jest.clearAllMocks();
24
- });
25
-
26
22
  describe("desktop", () => {
27
23
  describe("component render", () => {
28
24
  it("should render as expanded with all the elements that sidebar includes", () => {