@salesforcedevs/dx-components 0.20.0 → 0.22.0
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 +2 -2
- package/src/modules/dx/codeBlock/__tests__/codeBlock.test.ts +0 -4
- package/src/modules/dx/codeBlock/codeBlock.ts +1 -1
- package/src/modules/dx/grid/__tests__/grid.test.ts +2 -7
- package/src/modules/dx/headerSearch/__tests__/headerSearch.test.ts +0 -1
- package/src/modules/dx/input/input.css +1 -0
- package/src/modules/dx/minimalCard/__tests__/minimalCard.test.ts +87 -0
- package/src/modules/dx/minimalCard/__tests__/mockProps.ts +10 -0
- package/src/modules/dx/minimalCard/minimalCard.css +32 -0
- package/src/modules/dx/minimalCard/minimalCard.html +13 -0
- package/src/modules/dx/minimalCard/minimalCard.stories.ts +32 -0
- package/src/modules/dx/minimalCard/minimalCard.ts +35 -0
- package/src/modules/dx/popover/__tests__/popover.test.ts +26 -37
- package/src/modules/dx/sidebar/__tests__/sidebar.test.ts +0 -4
- package/src/modules/dx/sidebarOld/__tests__/sidebarOld.test.ts +0 -4
- package/src/modules/dx/sidebarSearch/__tests__/mockPreloadedState.ts +938 -930
- package/src/modules/dx/sidebarSearch/__tests__/sidebarSearch.test.ts +74 -15
- package/src/modules/dx/sidebarSearch/sidebarSearch.ts +4 -0
- package/src/modules/dx/socials/__tests__/socials.test.ts +12 -22
- package/src/modules/dx/tree/__tests__/tree.test.ts +17 -28
- package/src/modules/dx/treeItem/__tests__/treeItem.test.ts +36 -59
- package/src/modules/dx/typeBadge/typeBadge.css +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@salesforcedevs/dx-components",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.22.0",
|
|
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": "
|
|
32
|
+
"gitHead": "4a6bdaf5c490103e5620c3199b24528b4d3d26f0"
|
|
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: "
|
|
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 =
|
|
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()
|
|
@@ -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,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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 } =
|
|
187
|
-
HTMLButtonElement
|
|
188
|
-
|
|
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 =
|
|
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", () => {
|