@salesforcedevs/dx-components 0.5.5 → 0.8.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 +3 -3
- package/src/modules/dx/codeBlock/codeBlock.html +6 -3
- package/src/modules/dx/dropdown/__tests__/dropdown.test.ts +53 -12
- package/src/modules/dx/dropdown/dropdown.html +0 -1
- package/src/modules/dx/dropdown/dropdown.ts +19 -30
- package/src/modules/dx/header/__tests__/header.test.ts +21 -0
- package/src/modules/dx/header/header.html +1 -0
- package/src/modules/dx/headerSearch/__tests__/headerSearch.test.ts +1 -1
- package/src/modules/dx/headerSearch/headerSearch.ts +1 -1
- package/src/modules/dx/popover/__tests__/mockProps.ts +0 -1
- package/src/modules/dx/popover/popover.ts +19 -14
- package/src/modules/dx/sidebar/__tests__/sidebar.test.ts +41 -1
- package/src/modules/dx/sidebar/sidebar.ts +12 -3
- package/src/modules/dx/tooltip/__tests__/tooltip.test.ts +6 -49
- package/src/modules/dx/tooltip/microtip.css +269 -0
- package/src/modules/dx/tooltip/tooltip.css +22 -10
- package/src/modules/dx/tooltip/tooltip.html +1 -1
- package/src/modules/dx/tooltip/tooltip.stories.ts +7 -26
- package/src/modules/dx/tooltip/tooltip.ts +3 -39
- package/src/modules/dx/treeItem/__tests__/treeItem.test.ts +43 -1
- package/src/modules/dx/treeItem/treeItem.html +1 -1
- package/src/modules/dx/treeItem/treeItem.ts +17 -2
- package/src/modules/utils/headerBase/headerBase.ts +8 -0
- package/src/modules/dx/tooltip/tippy.css +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@salesforcedevs/dx-components",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.3",
|
|
4
4
|
"description": "DX Lightning web components",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"engines": {
|
|
@@ -22,12 +22,12 @@
|
|
|
22
22
|
"debounce": "^1.2.0",
|
|
23
23
|
"lightning-base-components": "1.12.3-alpha",
|
|
24
24
|
"lodash.get": "^4.4.2",
|
|
25
|
-
"
|
|
25
|
+
"microtip": "0.2.2"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
28
|
"@types/classnames": "^2.2.10",
|
|
29
29
|
"@types/debounce": "^1.2.0",
|
|
30
30
|
"@types/lodash.get": "^4.4.6"
|
|
31
31
|
},
|
|
32
|
-
"gitHead": "
|
|
32
|
+
"gitHead": "6eea544cc7d58dc43abb71a74816c23dff1191ea"
|
|
33
33
|
}
|
|
@@ -28,7 +28,10 @@
|
|
|
28
28
|
</template>
|
|
29
29
|
<template if:true={showCodeSourceBtn}>
|
|
30
30
|
<div class="toolbar-item">
|
|
31
|
-
<dx-tooltip
|
|
31
|
+
<dx-tooltip
|
|
32
|
+
label="View Code Source"
|
|
33
|
+
placement="top-left"
|
|
34
|
+
>
|
|
32
35
|
<dx-button
|
|
33
36
|
href={sourceLink}
|
|
34
37
|
type="button"
|
|
@@ -44,7 +47,7 @@
|
|
|
44
47
|
<div class="divider"></div>
|
|
45
48
|
</template>
|
|
46
49
|
<div class="toolbar-item">
|
|
47
|
-
<dx-tooltip label={updateThemeBtnText}>
|
|
50
|
+
<dx-tooltip label={updateThemeBtnText} placement="top-left">
|
|
48
51
|
<dx-button
|
|
49
52
|
onclick={updateTheme}
|
|
50
53
|
type="button"
|
|
@@ -57,7 +60,7 @@
|
|
|
57
60
|
</div>
|
|
58
61
|
<div class="divider"></div>
|
|
59
62
|
<div class="toolbar-item">
|
|
60
|
-
<dx-tooltip
|
|
63
|
+
<dx-tooltip label={copyBtnText} placement="top-left">
|
|
61
64
|
<dx-button
|
|
62
65
|
onclick={copySource}
|
|
63
66
|
type="button"
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import Dropdown from "dx/dropdown";
|
|
2
2
|
import DropdownOption from "dx/dropdownOption";
|
|
3
|
+
import Popover from "dx/popover";
|
|
3
4
|
import { getOptionsCount } from "utils/options";
|
|
4
5
|
import { createRenderComponent } from "utils/tests";
|
|
5
6
|
import mockNestedOptions from "./mockNestedOptions";
|
|
@@ -12,6 +13,13 @@ describe(TAG, () => {
|
|
|
12
13
|
describe("render", () => {
|
|
13
14
|
it("renders all options when open", () => {
|
|
14
15
|
const component = render({ ...mockProps, open: true });
|
|
16
|
+
|
|
17
|
+
const menuDiv: HTMLElement = component.shadowRoot.querySelector(
|
|
18
|
+
".menu_list"
|
|
19
|
+
);
|
|
20
|
+
expect(menuDiv).not.toBeNull();
|
|
21
|
+
expect(menuDiv.getAttribute("role")).toBe("menu");
|
|
22
|
+
|
|
15
23
|
const options = component.shadowRoot.querySelectorAll(
|
|
16
24
|
"dx-dropdown-option"
|
|
17
25
|
);
|
|
@@ -55,6 +63,24 @@ describe(TAG, () => {
|
|
|
55
63
|
expect(id).toEqual(mockProps.value);
|
|
56
64
|
return expect(component).toBeAccessible();
|
|
57
65
|
});
|
|
66
|
+
|
|
67
|
+
it("renders with menu-offset-small and menu-hidden", () => {
|
|
68
|
+
const component = render({ offset: "small", options: [] });
|
|
69
|
+
const popover: Popover = component.shadowRoot.querySelector(
|
|
70
|
+
"dx-popover"
|
|
71
|
+
);
|
|
72
|
+
expect(popover).not.toBeNull();
|
|
73
|
+
|
|
74
|
+
expect(popover.classList).toContain("menu-offset-small");
|
|
75
|
+
expect(popover.classList).toContain("menu-hidden");
|
|
76
|
+
|
|
77
|
+
const options = component.shadowRoot.querySelectorAll(
|
|
78
|
+
"dx-dropdown-option"
|
|
79
|
+
);
|
|
80
|
+
expect(options).toHaveLength(0);
|
|
81
|
+
|
|
82
|
+
return expect(component).toBeAccessible();
|
|
83
|
+
});
|
|
58
84
|
});
|
|
59
85
|
|
|
60
86
|
describe("interactions", () => {
|
|
@@ -98,34 +124,49 @@ describe(TAG, () => {
|
|
|
98
124
|
option.dispatchEvent(new CustomEvent("select", { detail: id }));
|
|
99
125
|
|
|
100
126
|
expect(mockClose).toHaveBeenCalledTimes(1);
|
|
101
|
-
expect(component.open).toEqual(false);
|
|
102
127
|
return expect(component).toBeAccessible();
|
|
103
128
|
});
|
|
104
129
|
|
|
105
|
-
it("handles
|
|
106
|
-
const
|
|
107
|
-
|
|
130
|
+
it("handles keydown event with ArrowDown key", () => {
|
|
131
|
+
const [firstOption] = mockProps.options;
|
|
132
|
+
const component = render({ ...mockProps, value: null, open: true });
|
|
133
|
+
expect(component.focusedValue).toBeNull();
|
|
108
134
|
|
|
109
|
-
|
|
110
|
-
"
|
|
135
|
+
component.dispatchEvent(
|
|
136
|
+
new KeyboardEvent("keydown", { key: "ArrowDown" })
|
|
111
137
|
);
|
|
112
|
-
expect(
|
|
113
|
-
|
|
138
|
+
expect(component.focusedValue).toBe(firstOption.id);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it("ignores other click keys", () => {
|
|
142
|
+
const component = render({ ...mockProps, open: true });
|
|
114
143
|
|
|
115
|
-
|
|
144
|
+
component.dispatchEvent(
|
|
145
|
+
new KeyboardEvent("keydown", { key: "ArrowDown" })
|
|
146
|
+
);
|
|
147
|
+
expect(component.focusedValue).toBe(mockProps.value);
|
|
148
|
+
|
|
149
|
+
component.dispatchEvent(
|
|
150
|
+
new KeyboardEvent("keydown", { key: "ArrowLeft" })
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
expect(component.focusedValue).toBe(mockProps.value);
|
|
116
154
|
});
|
|
117
155
|
|
|
118
156
|
it("handles close event from popover", () => {
|
|
119
157
|
const component = render({ ...mockProps, open: true });
|
|
120
|
-
|
|
158
|
+
|
|
159
|
+
component.dispatchEvent(
|
|
160
|
+
new KeyboardEvent("keydown", { key: "ArrowDown" })
|
|
161
|
+
);
|
|
162
|
+
expect(component.focusedValue).toBe(mockProps.value);
|
|
121
163
|
|
|
122
164
|
const popover: HTMLElement = component.shadowRoot.querySelector(
|
|
123
165
|
"dx-popover"
|
|
124
166
|
);
|
|
125
167
|
expect(popover).not.toBeNull();
|
|
126
168
|
popover.dispatchEvent(new CustomEvent("close"));
|
|
127
|
-
|
|
128
|
-
expect(component.open).toBe(false);
|
|
169
|
+
expect(component.focusedValue).toBeNull();
|
|
129
170
|
});
|
|
130
171
|
});
|
|
131
172
|
});
|
|
@@ -23,6 +23,7 @@ export default class Dropdown extends LightningElement {
|
|
|
23
23
|
@api ariaLabel: string | null = null;
|
|
24
24
|
@api tempId: string | null = null;
|
|
25
25
|
@api offset?: "small" | "medium";
|
|
26
|
+
@api open: boolean | null = null;
|
|
26
27
|
@api pagePadding?: number = 16; // padding between dropdown and the edge of the page
|
|
27
28
|
@api placement?: PopperPlacement = "bottom-start";
|
|
28
29
|
@api small?: boolean = false;
|
|
@@ -44,12 +45,8 @@ export default class Dropdown extends LightningElement {
|
|
|
44
45
|
}
|
|
45
46
|
|
|
46
47
|
@api
|
|
47
|
-
get
|
|
48
|
-
return this.
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
set open(value) {
|
|
52
|
-
this._open = value;
|
|
48
|
+
get focusedValue() {
|
|
49
|
+
return this._focusedValue;
|
|
53
50
|
}
|
|
54
51
|
|
|
55
52
|
@track
|
|
@@ -57,8 +54,7 @@ export default class Dropdown extends LightningElement {
|
|
|
57
54
|
|
|
58
55
|
// PRIVATE VARS
|
|
59
56
|
|
|
60
|
-
private
|
|
61
|
-
private _open = false;
|
|
57
|
+
private _focusedValue: string | null = null;
|
|
62
58
|
private popoverEl: HTMLElement | null = null;
|
|
63
59
|
|
|
64
60
|
constructor() {
|
|
@@ -98,18 +94,16 @@ export default class Dropdown extends LightningElement {
|
|
|
98
94
|
// CLASS FNS
|
|
99
95
|
|
|
100
96
|
private onKeyDown = (e: KeyboardEvent) => {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
default:
|
|
112
|
-
}
|
|
97
|
+
switch (e.key) {
|
|
98
|
+
case "ArrowDown":
|
|
99
|
+
e.preventDefault();
|
|
100
|
+
this.incrementOptionFocus(1);
|
|
101
|
+
break;
|
|
102
|
+
case "ArrowUp":
|
|
103
|
+
e.preventDefault();
|
|
104
|
+
this.incrementOptionFocus(-1);
|
|
105
|
+
break;
|
|
106
|
+
default:
|
|
113
107
|
}
|
|
114
108
|
};
|
|
115
109
|
|
|
@@ -125,7 +119,7 @@ export default class Dropdown extends LightningElement {
|
|
|
125
119
|
private onOptionFocus(e: PointerEvent) {
|
|
126
120
|
if (e.target) {
|
|
127
121
|
// @ts-ignore
|
|
128
|
-
this.
|
|
122
|
+
this._focusedValue = e.target.option.id;
|
|
129
123
|
}
|
|
130
124
|
}
|
|
131
125
|
|
|
@@ -137,13 +131,13 @@ export default class Dropdown extends LightningElement {
|
|
|
137
131
|
}
|
|
138
132
|
|
|
139
133
|
private incrementOptionFocus(indexChange: number) {
|
|
140
|
-
if (!this.
|
|
134
|
+
if (!this._focusedValue) {
|
|
141
135
|
this.focusDefaultOption();
|
|
142
136
|
return;
|
|
143
137
|
}
|
|
144
138
|
|
|
145
139
|
const focusedOptionIndex = this.findOptionElementIndex(
|
|
146
|
-
this.
|
|
140
|
+
this._focusedValue
|
|
147
141
|
);
|
|
148
142
|
|
|
149
143
|
let nextIndex = focusedOptionIndex + indexChange;
|
|
@@ -160,13 +154,8 @@ export default class Dropdown extends LightningElement {
|
|
|
160
154
|
}
|
|
161
155
|
}
|
|
162
156
|
|
|
163
|
-
private onOpen(): void {
|
|
164
|
-
this._open = true;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
157
|
private onClose(): void {
|
|
168
|
-
this.
|
|
169
|
-
this._open = false;
|
|
158
|
+
this._focusedValue = null;
|
|
170
159
|
}
|
|
171
160
|
|
|
172
161
|
private focusDefaultOption() {
|
|
@@ -179,7 +168,7 @@ export default class Dropdown extends LightningElement {
|
|
|
179
168
|
];
|
|
180
169
|
if (optionToFocus) {
|
|
181
170
|
optionToFocus.focus();
|
|
182
|
-
this.
|
|
171
|
+
this._focusedValue = optionToFocus.option.id;
|
|
183
172
|
}
|
|
184
173
|
}
|
|
185
174
|
|
|
@@ -8,10 +8,16 @@ import {
|
|
|
8
8
|
mockPropsEmployees,
|
|
9
9
|
mockPropsNoNavigation
|
|
10
10
|
} from "./mockProps";
|
|
11
|
+
import { track } from "dx/instrumentation";
|
|
11
12
|
|
|
12
13
|
const TAG = "dx-header";
|
|
13
14
|
const render = createRenderComponent(TAG, Header);
|
|
14
15
|
|
|
16
|
+
jest.mock("dx/instrumentation");
|
|
17
|
+
|
|
18
|
+
const GTM_EVENT_NAME = "custEv_signUpClick";
|
|
19
|
+
const SIGN_UP_LABEL = "Sign Up";
|
|
20
|
+
|
|
15
21
|
describe("dx-header", () => {
|
|
16
22
|
it("renders", () => {
|
|
17
23
|
const subtitle = "testsubtitle";
|
|
@@ -195,4 +201,19 @@ describe("dx-header", () => {
|
|
|
195
201
|
expect(headerSearch).toBeNull();
|
|
196
202
|
return expect(element).toBeAccessible();
|
|
197
203
|
});
|
|
204
|
+
|
|
205
|
+
it("signup button track is beign called", () => {
|
|
206
|
+
const element = render(mockPropsDevelopers);
|
|
207
|
+
|
|
208
|
+
const button: HTMLElement = element.shadowRoot.querySelector(
|
|
209
|
+
"dx-button"
|
|
210
|
+
);
|
|
211
|
+
|
|
212
|
+
button.click();
|
|
213
|
+
|
|
214
|
+
expect(track).toBeCalledTimes(1);
|
|
215
|
+
expect(track).toBeCalledWith(button, GTM_EVENT_NAME, {
|
|
216
|
+
clickText: SIGN_UP_LABEL
|
|
217
|
+
});
|
|
218
|
+
});
|
|
198
219
|
});
|
|
@@ -24,7 +24,7 @@ const COVEO_CONFIG = {
|
|
|
24
24
|
reducers: searchAppReducers
|
|
25
25
|
};
|
|
26
26
|
|
|
27
|
-
const REDIRECT_URL = "https://
|
|
27
|
+
const REDIRECT_URL = "https://developer.salesforce.com";
|
|
28
28
|
|
|
29
29
|
const TAG = "dx-header-search";
|
|
30
30
|
const render = createRenderComponent(TAG, HeaderSearch);
|
|
@@ -80,7 +80,7 @@ export default class HeaderSearch extends LightningElement {
|
|
|
80
80
|
private instantiateSearchbox() {
|
|
81
81
|
const options: StandaloneSearchBoxOptions = {
|
|
82
82
|
numberOfSuggestions: 3,
|
|
83
|
-
redirectionUrl: "https://
|
|
83
|
+
redirectionUrl: "https://developer.salesforce.com"
|
|
84
84
|
};
|
|
85
85
|
|
|
86
86
|
const engine = new HeadlessEngine({
|
|
@@ -37,6 +37,7 @@ export default class Popover extends LightningElement {
|
|
|
37
37
|
return this._open;
|
|
38
38
|
}
|
|
39
39
|
set open(value: boolean | null) {
|
|
40
|
+
this.controlled = typeof value === "boolean";
|
|
40
41
|
if (value !== this._open) {
|
|
41
42
|
if (value) {
|
|
42
43
|
this.openPopover();
|
|
@@ -101,6 +102,7 @@ export default class Popover extends LightningElement {
|
|
|
101
102
|
|
|
102
103
|
// PRIVATE VARS
|
|
103
104
|
|
|
105
|
+
private controlled: boolean = false;
|
|
104
106
|
private _open: boolean = false;
|
|
105
107
|
private _rendered: boolean = isPrerender();
|
|
106
108
|
private _role: string | null = null;
|
|
@@ -152,19 +154,26 @@ export default class Popover extends LightningElement {
|
|
|
152
154
|
|
|
153
155
|
private addControlListeners() {
|
|
154
156
|
if (this.control) {
|
|
155
|
-
this.control.addEventListener("click", this.onControlClick);
|
|
156
157
|
this.control.addEventListener("keydown", this.onControlKeydown);
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
this.
|
|
160
|
-
|
|
158
|
+
|
|
159
|
+
if (!this.openOnHover) {
|
|
160
|
+
this.control.addEventListener("click", this.onControlClick);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (this.openOnHover) {
|
|
164
|
+
this.control.addEventListener(
|
|
165
|
+
"mouseenter",
|
|
166
|
+
this.onControlMouseEnter
|
|
167
|
+
);
|
|
168
|
+
}
|
|
161
169
|
}
|
|
162
170
|
}
|
|
163
171
|
|
|
164
172
|
private removeControlListeners() {
|
|
165
173
|
if (this.control) {
|
|
166
|
-
this.control.removeEventListener("click", this.onControlClick);
|
|
167
174
|
this.control.removeEventListener("keydown", this.onControlKeydown);
|
|
175
|
+
|
|
176
|
+
this.control.removeEventListener("click", this.onControlClick);
|
|
168
177
|
this.control.removeEventListener(
|
|
169
178
|
"mouseenter",
|
|
170
179
|
this.onControlMouseEnter
|
|
@@ -186,11 +195,7 @@ export default class Popover extends LightningElement {
|
|
|
186
195
|
// @ts-ignore something weird happening here with debounce types
|
|
187
196
|
debounce(this._interactOutsideListener(e), 100);
|
|
188
197
|
|
|
189
|
-
private onControlMouseEnter = () =>
|
|
190
|
-
if (this.openOnHover) {
|
|
191
|
-
this.openPopover();
|
|
192
|
-
}
|
|
193
|
-
};
|
|
198
|
+
private onControlMouseEnter = () => this.openPopover();
|
|
194
199
|
|
|
195
200
|
private onControlKeydown = (e: KeyboardEvent) => {
|
|
196
201
|
switch (e.key) {
|
|
@@ -207,13 +212,13 @@ export default class Popover extends LightningElement {
|
|
|
207
212
|
};
|
|
208
213
|
|
|
209
214
|
private onControlClick = () => {
|
|
210
|
-
if (this.
|
|
211
|
-
this.
|
|
215
|
+
if (this.controlled) {
|
|
216
|
+
this.dispatchRequestCloseEvent("click-control");
|
|
212
217
|
return;
|
|
213
218
|
}
|
|
214
219
|
|
|
215
220
|
if (this.open) {
|
|
216
|
-
this.
|
|
221
|
+
this.closePopover();
|
|
217
222
|
return;
|
|
218
223
|
}
|
|
219
224
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import Button from "dx/button";
|
|
2
2
|
import Input from "dx/input";
|
|
3
|
+
import { track } from "dx/instrumentation";
|
|
3
4
|
import Sidebar from "dx/sidebar";
|
|
4
5
|
import Tree from "dx/tree";
|
|
5
6
|
import { TreeNode } from "typings/custom";
|
|
@@ -7,14 +8,21 @@ import { createMediaMock } from "utils/jest";
|
|
|
7
8
|
import { createRenderComponent } from "utils/tests";
|
|
8
9
|
import { SAMPLE_TREES } from "./mockProps";
|
|
9
10
|
|
|
11
|
+
jest.mock("dx/instrumentation");
|
|
12
|
+
|
|
10
13
|
const TAG = "dx-sidebar";
|
|
11
14
|
const renderComponent = createRenderComponent(TAG, Sidebar);
|
|
12
15
|
|
|
13
16
|
const COLLAPSED_CLASS = "collapsed";
|
|
14
|
-
|
|
15
17
|
const EXPECTED_QUERY = "(max-width: 768px)";
|
|
18
|
+
const GTM_EVENT_NAME = "custEv_leftNavLinkClick";
|
|
19
|
+
const TOGGLE_BUTTON_LABEL = "Toggle Sidebar";
|
|
16
20
|
|
|
17
21
|
describe(TAG, () => {
|
|
22
|
+
afterEach(() => {
|
|
23
|
+
jest.clearAllMocks();
|
|
24
|
+
});
|
|
25
|
+
|
|
18
26
|
describe("desktop", () => {
|
|
19
27
|
describe("component render", () => {
|
|
20
28
|
it("should render as expanded with all the elements that sidebar includes", () => {
|
|
@@ -160,6 +168,12 @@ describe(TAG, () => {
|
|
|
160
168
|
);
|
|
161
169
|
toggleButton.click();
|
|
162
170
|
|
|
171
|
+
expect(track).toBeCalledTimes(1);
|
|
172
|
+
expect(track).toBeCalledWith(toggleButton, GTM_EVENT_NAME, {
|
|
173
|
+
sidebarNavAction: "collapse",
|
|
174
|
+
clickText: TOGGLE_BUTTON_LABEL
|
|
175
|
+
});
|
|
176
|
+
|
|
163
177
|
return Promise.resolve()
|
|
164
178
|
.then(() => {
|
|
165
179
|
expect(container.classList).toContain(COLLAPSED_CLASS);
|
|
@@ -185,6 +199,16 @@ describe(TAG, () => {
|
|
|
185
199
|
expect(trees).toBeNull();
|
|
186
200
|
|
|
187
201
|
toggleButton.click();
|
|
202
|
+
|
|
203
|
+
expect(track).toBeCalledTimes(2);
|
|
204
|
+
expect(track).toHaveBeenLastCalledWith(
|
|
205
|
+
toggleButton,
|
|
206
|
+
GTM_EVENT_NAME,
|
|
207
|
+
{
|
|
208
|
+
sidebarNavAction: "expand",
|
|
209
|
+
clickText: TOGGLE_BUTTON_LABEL
|
|
210
|
+
}
|
|
211
|
+
);
|
|
188
212
|
})
|
|
189
213
|
.then(() => {
|
|
190
214
|
expect(container.classList).not.toContain(
|
|
@@ -337,6 +361,12 @@ describe(TAG, () => {
|
|
|
337
361
|
);
|
|
338
362
|
toggleDiv.click();
|
|
339
363
|
|
|
364
|
+
expect(track).toBeCalledTimes(1);
|
|
365
|
+
expect(track).toBeCalledWith(toggleDiv, GTM_EVENT_NAME, {
|
|
366
|
+
sidebarNavAction: "expand",
|
|
367
|
+
clickText: TOGGLE_BUTTON_LABEL
|
|
368
|
+
});
|
|
369
|
+
|
|
340
370
|
return Promise.resolve()
|
|
341
371
|
.then(() => {
|
|
342
372
|
expect(container.classList).not.toContain(
|
|
@@ -382,6 +412,16 @@ describe(TAG, () => {
|
|
|
382
412
|
expect(toggleButtonDesktop).toBeNull();
|
|
383
413
|
|
|
384
414
|
toggleDiv.click();
|
|
415
|
+
|
|
416
|
+
expect(track).toBeCalledTimes(2);
|
|
417
|
+
expect(track).toHaveBeenLastCalledWith(
|
|
418
|
+
toggleDiv,
|
|
419
|
+
GTM_EVENT_NAME,
|
|
420
|
+
{
|
|
421
|
+
sidebarNavAction: "collapse",
|
|
422
|
+
clickText: TOGGLE_BUTTON_LABEL
|
|
423
|
+
}
|
|
424
|
+
);
|
|
385
425
|
})
|
|
386
426
|
.then(() => {
|
|
387
427
|
expect(container.classList).toContain(COLLAPSED_CLASS);
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
+
import cx from "classnames";
|
|
2
|
+
import { track } from "dx/instrumentation";
|
|
1
3
|
import { LightningElement, api } from "lwc";
|
|
2
4
|
|
|
3
|
-
import { TreeNode } from "typings/custom";
|
|
4
|
-
import cx from "classnames";
|
|
5
|
+
import { TreeNode, SidebarGtmAction } from "typings/custom";
|
|
5
6
|
import { toJson } from "utils/normalizers";
|
|
6
7
|
|
|
7
8
|
const WAIT_TIME = 500;
|
|
8
9
|
const MOBILE_SIZE_MATCH = "768px";
|
|
10
|
+
const TOGGLE_BUTTON_LABEL = "Toggle Sidebar";
|
|
9
11
|
|
|
10
12
|
export default class Sidebar extends LightningElement {
|
|
11
13
|
@api header: string = "";
|
|
@@ -89,9 +91,16 @@ export default class Sidebar extends LightningElement {
|
|
|
89
91
|
this._value = event.detail.name;
|
|
90
92
|
}
|
|
91
93
|
|
|
92
|
-
private onToggleClick() {
|
|
94
|
+
private onToggleClick(event: Event) {
|
|
93
95
|
this.expanded = !this.expanded;
|
|
94
96
|
this._toggleHovered = false;
|
|
97
|
+
const sidebarNavAction: SidebarGtmAction = this.expanded
|
|
98
|
+
? "expand"
|
|
99
|
+
: "collapse";
|
|
100
|
+
track(event.currentTarget!, "custEv_leftNavLinkClick", {
|
|
101
|
+
sidebarNavAction,
|
|
102
|
+
clickText: TOGGLE_BUTTON_LABEL
|
|
103
|
+
});
|
|
95
104
|
}
|
|
96
105
|
|
|
97
106
|
private onToggleMouseEnter() {
|
|
@@ -1,66 +1,23 @@
|
|
|
1
1
|
import Tooltip from "dx/tooltip";
|
|
2
2
|
import { createRenderComponent } from "utils/tests";
|
|
3
|
-
import createTooltip from "tippy.js";
|
|
4
|
-
|
|
5
|
-
const mockSetProps = jest.fn();
|
|
6
|
-
jest.mock("tippy.js", () =>
|
|
7
|
-
jest.fn().mockImplementation(() => {
|
|
8
|
-
return {
|
|
9
|
-
setProps: mockSetProps
|
|
10
|
-
};
|
|
11
|
-
})
|
|
12
|
-
);
|
|
13
3
|
|
|
14
4
|
const TAG = "dx-tooltip";
|
|
15
5
|
const render = createRenderComponent(TAG, Tooltip);
|
|
16
6
|
|
|
17
7
|
describe(TAG, () => {
|
|
18
|
-
afterEach(() => {
|
|
19
|
-
jest.clearAllMocks();
|
|
20
|
-
});
|
|
21
|
-
|
|
22
8
|
it("calls tippy constructor with correct parameters", () => {
|
|
23
|
-
const element = render({ label: "First Label",
|
|
9
|
+
const element = render({ label: "First Label", placement: "top" });
|
|
24
10
|
|
|
25
|
-
const slotContainer = element.shadowRoot.querySelector(
|
|
26
|
-
"div
|
|
11
|
+
const slotContainer: HTMLElement = element.shadowRoot.querySelector(
|
|
12
|
+
"div"
|
|
27
13
|
);
|
|
28
14
|
|
|
29
15
|
expect(slotContainer).not.toBeNull();
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
expect(createTooltip).toBeCalledWith(slotContainer, {
|
|
33
|
-
content: "First Label",
|
|
34
|
-
placement: "top",
|
|
35
|
-
hideOnClick: false,
|
|
36
|
-
appendTo: slotContainer
|
|
37
|
-
});
|
|
38
|
-
expect(mockSetProps).not.toBeCalled();
|
|
39
|
-
|
|
40
|
-
return expect(element).toBeAccessible();
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
it("doesn't call tippy if label is not provided", () => {
|
|
44
|
-
const element = render();
|
|
45
|
-
|
|
46
|
-
const slotContainer = element.shadowRoot.querySelector(
|
|
47
|
-
"div.slot-container"
|
|
16
|
+
expect(slotContainer.getAttribute("data-microtip-position")).toEqual(
|
|
17
|
+
"top"
|
|
48
18
|
);
|
|
49
|
-
expect(slotContainer).
|
|
50
|
-
|
|
51
|
-
expect(createTooltip).not.toBeCalled();
|
|
52
|
-
expect(mockSetProps).not.toBeCalled();
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
it("changes label after creation", () => {
|
|
56
|
-
const element = render({ label: "First Label" });
|
|
57
|
-
|
|
58
|
-
expect(createTooltip).toBeCalledTimes(1);
|
|
59
|
-
element.label = "New label";
|
|
19
|
+
expect(slotContainer.getAttribute("aria-label")).toEqual("First Label");
|
|
60
20
|
|
|
61
|
-
expect(createTooltip).toBeCalledTimes(1);
|
|
62
|
-
expect(mockSetProps).toBeCalledTimes(1);
|
|
63
|
-
expect(mockSetProps).toBeCalledWith({ content: "New label" });
|
|
64
21
|
return expect(element).toBeAccessible();
|
|
65
22
|
});
|
|
66
23
|
});
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
/* Code generated by scripts/postinstall.js DO NOT EDIT*/
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
/* -------------------------------------------------------------------
|
|
5
|
+
Microtip
|
|
6
|
+
|
|
7
|
+
Modern, lightweight css-only tooltips
|
|
8
|
+
Just 1kb minified and gzipped
|
|
9
|
+
|
|
10
|
+
@author Ghosh
|
|
11
|
+
@package Microtip
|
|
12
|
+
|
|
13
|
+
----------------------------------------------------------------------
|
|
14
|
+
1. Base Styles
|
|
15
|
+
2. Direction Modifiers
|
|
16
|
+
3. Position Modifiers
|
|
17
|
+
--------------------------------------------------------------------*/
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
/* ------------------------------------------------
|
|
21
|
+
[1] Base Styles
|
|
22
|
+
-------------------------------------------------*/
|
|
23
|
+
|
|
24
|
+
[aria-label][role~="tooltip"] {
|
|
25
|
+
position: relative;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
[aria-label][role~="tooltip"]::before,
|
|
29
|
+
[aria-label][role~="tooltip"]::after {
|
|
30
|
+
transform: translate3d(0, 0, 0);
|
|
31
|
+
-webkit-backface-visibility: hidden;
|
|
32
|
+
backface-visibility: hidden;
|
|
33
|
+
will-change: transform;
|
|
34
|
+
opacity: 0;
|
|
35
|
+
pointer-events: none;
|
|
36
|
+
transition: all var(--microtip-transition-duration, .18s) var(--microtip-transition-easing, ease-in-out) var(--microtip-transition-delay, 0s);
|
|
37
|
+
position: absolute;
|
|
38
|
+
box-sizing: border-box;
|
|
39
|
+
z-index: 10;
|
|
40
|
+
transform-origin: top;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
[aria-label][role~="tooltip"]::before {
|
|
44
|
+
background-size: 100% auto !important;
|
|
45
|
+
content: "";
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
[aria-label][role~="tooltip"]::after {
|
|
49
|
+
background: rgba(17, 17, 17, .9);
|
|
50
|
+
border-radius: 4px;
|
|
51
|
+
color: #ffffff;
|
|
52
|
+
content: attr(aria-label);
|
|
53
|
+
font-size: var(--microtip-font-size, 13px);
|
|
54
|
+
font-weight: var(--microtip-font-weight, normal);
|
|
55
|
+
text-transform: var(--microtip-text-transform, none);
|
|
56
|
+
padding: .5em 1em;
|
|
57
|
+
white-space: nowrap;
|
|
58
|
+
box-sizing: content-box;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
[aria-label][role~="tooltip"]:hover::before,
|
|
62
|
+
[aria-label][role~="tooltip"]:hover::after,
|
|
63
|
+
[aria-label][role~="tooltip"]:focus::before,
|
|
64
|
+
[aria-label][role~="tooltip"]:focus::after {
|
|
65
|
+
opacity: 1;
|
|
66
|
+
pointer-events: auto;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
/* ------------------------------------------------
|
|
72
|
+
[2] Position Modifiers
|
|
73
|
+
-------------------------------------------------*/
|
|
74
|
+
|
|
75
|
+
[role~="tooltip"][data-microtip-position|="top"]::before {
|
|
76
|
+
background: url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2236px%22%20height%3D%2212px%22%3E%3Cpath%20fill%3D%22rgba%2817,%2017,%2017,%200.9%29%22%20transform%3D%22rotate%280%29%22%20d%3D%22M2.658,0.000%20C-13.615,0.000%2050.938,0.000%2034.662,0.000%20C28.662,0.000%2023.035,12.002%2018.660,12.002%20C14.285,12.002%208.594,0.000%202.658,0.000%20Z%22/%3E%3C/svg%3E") no-repeat;
|
|
77
|
+
height: 6px;
|
|
78
|
+
width: 18px;
|
|
79
|
+
margin-bottom: 5px;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
[role~="tooltip"][data-microtip-position|="top"]::after {
|
|
83
|
+
margin-bottom: 11px;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
[role~="tooltip"][data-microtip-position|="top"]::before {
|
|
87
|
+
transform: translate3d(-50%, 0, 0);
|
|
88
|
+
bottom: 100%;
|
|
89
|
+
left: 50%;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
[role~="tooltip"][data-microtip-position|="top"]:hover::before {
|
|
93
|
+
transform: translate3d(-50%, -5px, 0);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
[role~="tooltip"][data-microtip-position|="top"]::after {
|
|
97
|
+
transform: translate3d(-50%, 0, 0);
|
|
98
|
+
bottom: 100%;
|
|
99
|
+
left: 50%;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
[role~="tooltip"][data-microtip-position="top"]:hover::after {
|
|
103
|
+
transform: translate3d(-50%, -5px, 0);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/* ------------------------------------------------
|
|
107
|
+
[2.1] Top Left
|
|
108
|
+
-------------------------------------------------*/
|
|
109
|
+
[role~="tooltip"][data-microtip-position="top-left"]::after {
|
|
110
|
+
transform: translate3d(calc(-100% + 16px), 0, 0);
|
|
111
|
+
bottom: 100%;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
[role~="tooltip"][data-microtip-position="top-left"]:hover::after {
|
|
115
|
+
transform: translate3d(calc(-100% + 16px), -5px, 0);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
/* ------------------------------------------------
|
|
120
|
+
[2.2] Top Right
|
|
121
|
+
-------------------------------------------------*/
|
|
122
|
+
[role~="tooltip"][data-microtip-position="top-right"]::after {
|
|
123
|
+
transform: translate3d(calc(0% + -16px), 0, 0);
|
|
124
|
+
bottom: 100%;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
[role~="tooltip"][data-microtip-position="top-right"]:hover::after {
|
|
128
|
+
transform: translate3d(calc(0% + -16px), -5px, 0);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
/* ------------------------------------------------
|
|
133
|
+
[2.3] Bottom
|
|
134
|
+
-------------------------------------------------*/
|
|
135
|
+
[role~="tooltip"][data-microtip-position|="bottom"]::before {
|
|
136
|
+
background: url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2236px%22%20height%3D%2212px%22%3E%3Cpath%20fill%3D%22rgba%2817,%2017,%2017,%200.9%29%22%20transform%3D%22rotate%28180%2018%206%29%22%20d%3D%22M2.658,0.000%20C-13.615,0.000%2050.938,0.000%2034.662,0.000%20C28.662,0.000%2023.035,12.002%2018.660,12.002%20C14.285,12.002%208.594,0.000%202.658,0.000%20Z%22/%3E%3C/svg%3E") no-repeat;
|
|
137
|
+
height: 6px;
|
|
138
|
+
width: 18px;
|
|
139
|
+
margin-top: 5px;
|
|
140
|
+
margin-bottom: 0;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
[role~="tooltip"][data-microtip-position|="bottom"]::after {
|
|
144
|
+
margin-top: 11px;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
[role~="tooltip"][data-microtip-position|="bottom"]::before {
|
|
148
|
+
transform: translate3d(-50%, -10px, 0);
|
|
149
|
+
bottom: auto;
|
|
150
|
+
left: 50%;
|
|
151
|
+
top: 100%;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
[role~="tooltip"][data-microtip-position|="bottom"]:hover::before {
|
|
155
|
+
transform: translate3d(-50%, 0, 0);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
[role~="tooltip"][data-microtip-position|="bottom"]::after {
|
|
159
|
+
transform: translate3d(-50%, -10px, 0);
|
|
160
|
+
top: 100%;
|
|
161
|
+
left: 50%;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
[role~="tooltip"][data-microtip-position="bottom"]:hover::after {
|
|
165
|
+
transform: translate3d(-50%, 0, 0);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
/* ------------------------------------------------
|
|
170
|
+
[2.4] Bottom Left
|
|
171
|
+
-------------------------------------------------*/
|
|
172
|
+
[role~="tooltip"][data-microtip-position="bottom-left"]::after {
|
|
173
|
+
transform: translate3d(calc(-100% + 16px), -10px, 0);
|
|
174
|
+
top: 100%;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
[role~="tooltip"][data-microtip-position="bottom-left"]:hover::after {
|
|
178
|
+
transform: translate3d(calc(-100% + 16px), 0, 0);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
/* ------------------------------------------------
|
|
183
|
+
[2.5] Bottom Right
|
|
184
|
+
-------------------------------------------------*/
|
|
185
|
+
[role~="tooltip"][data-microtip-position="bottom-right"]::after {
|
|
186
|
+
transform: translate3d(calc(0% + -16px), -10px, 0);
|
|
187
|
+
top: 100%;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
[role~="tooltip"][data-microtip-position="bottom-right"]:hover::after {
|
|
191
|
+
transform: translate3d(calc(0% + -16px), 0, 0);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
/* ------------------------------------------------
|
|
196
|
+
[2.6] Left
|
|
197
|
+
-------------------------------------------------*/
|
|
198
|
+
[role~="tooltip"][data-microtip-position="left"]::before,
|
|
199
|
+
[role~="tooltip"][data-microtip-position="left"]::after {
|
|
200
|
+
bottom: auto;
|
|
201
|
+
left: auto;
|
|
202
|
+
right: 100%;
|
|
203
|
+
top: 50%;
|
|
204
|
+
transform: translate3d(10px, -50%, 0);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
[role~="tooltip"][data-microtip-position="left"]::before {
|
|
208
|
+
background: url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2212px%22%20height%3D%2236px%22%3E%3Cpath%20fill%3D%22rgba%2817,%2017,%2017,%200.9%29%22%20transform%3D%22rotate%28-90%2018%2018%29%22%20d%3D%22M2.658,0.000%20C-13.615,0.000%2050.938,0.000%2034.662,0.000%20C28.662,0.000%2023.035,12.002%2018.660,12.002%20C14.285,12.002%208.594,0.000%202.658,0.000%20Z%22/%3E%3C/svg%3E") no-repeat;
|
|
209
|
+
height: 18px;
|
|
210
|
+
width: 6px;
|
|
211
|
+
margin-right: 5px;
|
|
212
|
+
margin-bottom: 0;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
[role~="tooltip"][data-microtip-position="left"]::after {
|
|
216
|
+
margin-right: 11px;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
[role~="tooltip"][data-microtip-position="left"]:hover::before,
|
|
220
|
+
[role~="tooltip"][data-microtip-position="left"]:hover::after {
|
|
221
|
+
transform: translate3d(0, -50%, 0);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
/* ------------------------------------------------
|
|
226
|
+
[2.7] Right
|
|
227
|
+
-------------------------------------------------*/
|
|
228
|
+
[role~="tooltip"][data-microtip-position="right"]::before,
|
|
229
|
+
[role~="tooltip"][data-microtip-position="right"]::after {
|
|
230
|
+
bottom: auto;
|
|
231
|
+
left: 100%;
|
|
232
|
+
top: 50%;
|
|
233
|
+
transform: translate3d(-10px, -50%, 0);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
[role~="tooltip"][data-microtip-position="right"]::before {
|
|
237
|
+
background: url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2212px%22%20height%3D%2236px%22%3E%3Cpath%20fill%3D%22rgba%2817,%2017,%2017,%200.9%29%22%20transform%3D%22rotate%2890%206%206%29%22%20d%3D%22M2.658,0.000%20C-13.615,0.000%2050.938,0.000%2034.662,0.000%20C28.662,0.000%2023.035,12.002%2018.660,12.002%20C14.285,12.002%208.594,0.000%202.658,0.000%20Z%22/%3E%3C/svg%3E") no-repeat;
|
|
238
|
+
height: 18px;
|
|
239
|
+
width: 6px;
|
|
240
|
+
margin-bottom: 0;
|
|
241
|
+
margin-left: 5px;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
[role~="tooltip"][data-microtip-position="right"]::after {
|
|
245
|
+
margin-left: 11px;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
[role~="tooltip"][data-microtip-position="right"]:hover::before,
|
|
249
|
+
[role~="tooltip"][data-microtip-position="right"]:hover::after {
|
|
250
|
+
transform: translate3d(0, -50%, 0);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/* ------------------------------------------------
|
|
254
|
+
[3] Size
|
|
255
|
+
-------------------------------------------------*/
|
|
256
|
+
[role~="tooltip"][data-microtip-size="small"]::after {
|
|
257
|
+
white-space: initial;
|
|
258
|
+
width: 80px;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
[role~="tooltip"][data-microtip-size="medium"]::after {
|
|
262
|
+
white-space: initial;
|
|
263
|
+
width: 150px;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
[role~="tooltip"][data-microtip-size="large"]::after {
|
|
267
|
+
white-space: initial;
|
|
268
|
+
width: 260px;
|
|
269
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
@import "./
|
|
1
|
+
@import "./microtip.css";
|
|
2
2
|
|
|
3
3
|
:host {
|
|
4
4
|
display: inline-block;
|
|
@@ -8,17 +8,29 @@
|
|
|
8
8
|
display: inherit;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
[role~="tooltip"][data-microtip-position|="bottom"]::before {
|
|
12
|
+
background: url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2236px%22%20height%3D%2212px%22%3E%3Cpath%20fill%3D%22rgba%28116,%20116,%20116,%201%29%22%20transform%3D%22rotate%28180%2018%206%29%22%20d%3D%22M2.658,0.000%20C-13.615,0.000%2050.938,0.000%2034.662,0.000%20C28.662,0.000%2023.035,12.002%2018.660,12.002%20C14.285,12.002%208.594,0.000%202.658,0.000%20Z%22/%3E%3C/svg%3E")
|
|
13
|
+
no-repeat;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
[role~="tooltip"][data-microtip-position|="top"]::before {
|
|
17
|
+
background: url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2236px%22%20height%3D%2212px%22%3E%3Cpath%20fill%3D%22rgba%28116,%20116,%20116,%201%29%22%20transform%3D%22rotate%280%29%22%20d%3D%22M2.658,0.000%20C-13.615,0.000%2050.938,0.000%2034.662,0.000%20C28.662,0.000%2023.035,12.002%2018.660,12.002%20C14.285,12.002%208.594,0.000%202.658,0.000%20Z%22/%3E%3C/svg%3E")
|
|
18
|
+
no-repeat;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
[role~="tooltip"][data-microtip-position|="left"]::before {
|
|
22
|
+
background: url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2212px%22%20height%3D%2236px%22%3E%3Cpath%20fill%3D%22rgba%28116,%20116,%20116,%201%29%22%20transform%3D%22rotate%28-90%2018%2018%29%22%20d%3D%22M2.658,0.000%20C-13.615,0.000%2050.938,0.000%2034.662,0.000%20C28.662,0.000%2023.035,12.002%2018.660,12.002%20C14.285,12.002%208.594,0.000%202.658,0.000%20Z%22/%3E%3C/svg%3E")
|
|
23
|
+
no-repeat;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
[role~="tooltip"][data-microtip-position|="right"]::before {
|
|
27
|
+
background: url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2212px%22%20height%3D%2236px%22%3E%3Cpath%20fill%3D%22rgba%28116,%20116,%20116,%201%29%22%20transform%3D%22rotate%2890%206%206%29%22%20d%3D%22M2.658,0.000%20C-13.615,0.000%2050.938,0.000%2034.662,0.000%20C28.662,0.000%2023.035,12.002%2018.660,12.002%20C14.285,12.002%208.594,0.000%202.658,0.000%20Z%22/%3E%3C/svg%3E")
|
|
28
|
+
no-repeat;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
[aria-label][role~="tooltip"]::after {
|
|
16
32
|
background-color: var(--dx-g-gray-50);
|
|
17
33
|
font-family: var(--dx-g-font-sans);
|
|
18
34
|
font-size: var(--dx-g-text-xs);
|
|
19
35
|
color: white;
|
|
20
36
|
}
|
|
21
|
-
|
|
22
|
-
.tippy-arrow {
|
|
23
|
-
color: var(--dx-g-gray-50);
|
|
24
|
-
}
|
|
@@ -5,29 +5,18 @@ export default {
|
|
|
5
5
|
component: "dx-tooltip",
|
|
6
6
|
argTypes: {
|
|
7
7
|
placement: {
|
|
8
|
-
defaultValue: "top
|
|
8
|
+
defaultValue: "top",
|
|
9
9
|
control: {
|
|
10
10
|
type: "select",
|
|
11
11
|
options: [
|
|
12
|
-
"
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
|
|
12
|
+
"top",
|
|
13
|
+
"top-left",
|
|
14
|
+
"top-right",
|
|
16
15
|
"bottom",
|
|
17
|
-
"bottom-
|
|
18
|
-
"bottom-
|
|
19
|
-
|
|
16
|
+
"bottom-left",
|
|
17
|
+
"bottom-right",
|
|
20
18
|
"left",
|
|
21
|
-
"
|
|
22
|
-
"left-start",
|
|
23
|
-
|
|
24
|
-
"right",
|
|
25
|
-
"right-end",
|
|
26
|
-
"right-start",
|
|
27
|
-
|
|
28
|
-
"top",
|
|
29
|
-
"top-end",
|
|
30
|
-
"top-start"
|
|
19
|
+
"right"
|
|
31
20
|
]
|
|
32
21
|
}
|
|
33
22
|
},
|
|
@@ -55,11 +44,3 @@ export const Default = (args: any) => html `${createStyles()}
|
|
|
55
44
|
<button>Hover</button>
|
|
56
45
|
</dx-tooltip>
|
|
57
46
|
</div>`;
|
|
58
|
-
|
|
59
|
-
// prettier-ignore
|
|
60
|
-
export const PersistOnClick = (args: any) => html `${createStyles()}
|
|
61
|
-
<div class="story-container">
|
|
62
|
-
<dx-tooltip label="${args.label}" persist=${true} placement="${args.placement}">
|
|
63
|
-
<button>Hover and click</button>
|
|
64
|
-
</dx-tooltip>
|
|
65
|
-
</div>`;
|
|
@@ -1,42 +1,6 @@
|
|
|
1
1
|
import { LightningElement, api } from "lwc";
|
|
2
|
-
import tippy from "tippy.js";
|
|
3
|
-
import { Placement } from "@popperjs/core";
|
|
4
|
-
export default class Tooltip extends LightningElement {
|
|
5
|
-
@api placement?: Placement = "top";
|
|
6
|
-
@api persist: Boolean = false;
|
|
7
|
-
|
|
8
|
-
@api
|
|
9
|
-
set label(value: string) {
|
|
10
|
-
const isChanged: boolean = this._label !== value;
|
|
11
|
-
this._label = value;
|
|
12
|
-
if (this.tooltip && isChanged) {
|
|
13
|
-
this.tooltip.setProps({ content: this._label });
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
get label(): string {
|
|
18
|
-
return this._label;
|
|
19
|
-
}
|
|
20
2
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
renderedCallback() {
|
|
26
|
-
if (!this.container) {
|
|
27
|
-
this.container = this.template.querySelector(".slot-container");
|
|
28
|
-
this.addTooltip();
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
private addTooltip() {
|
|
33
|
-
if (this.container && this.label) {
|
|
34
|
-
this.tooltip = tippy(this.container, {
|
|
35
|
-
content: this.label,
|
|
36
|
-
appendTo: this.container,
|
|
37
|
-
placement: this.placement,
|
|
38
|
-
hideOnClick: !this.persist
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
}
|
|
3
|
+
export default class Tooltip extends LightningElement {
|
|
4
|
+
@api placement?: String = "top";
|
|
5
|
+
@api label: string = "";
|
|
42
6
|
}
|
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
NODE_WITH_CHILDREN,
|
|
4
4
|
SINGLE_NODE_WITH_LINK
|
|
5
5
|
} from "./mockProps";
|
|
6
|
+
import { track } from "dx/instrumentation";
|
|
6
7
|
import TreeItem from "dx/treeItem";
|
|
7
8
|
import TreeTile from "dx/treeTile";
|
|
8
9
|
import { createRenderComponent } from "utils/tests";
|
|
@@ -10,6 +11,10 @@ import { createRenderComponent } from "utils/tests";
|
|
|
10
11
|
const TAG = "dx-tree-item";
|
|
11
12
|
const renderComponent = createRenderComponent(TAG, TreeItem);
|
|
12
13
|
|
|
14
|
+
jest.mock("dx/instrumentation");
|
|
15
|
+
|
|
16
|
+
const GTM_EVENT_NAME = "custEv_leftNavLinkClick";
|
|
17
|
+
|
|
13
18
|
const assertTile = (tile: TreeTile, properties: { [key: string]: any }) =>
|
|
14
19
|
Object.keys(properties).forEach((key) =>
|
|
15
20
|
expect(tile).toHaveProperty(key, properties[key])
|
|
@@ -167,7 +172,7 @@ describe(TAG, () => {
|
|
|
167
172
|
const mockTileSelected = jest.fn();
|
|
168
173
|
|
|
169
174
|
afterEach(() => {
|
|
170
|
-
jest.
|
|
175
|
+
jest.clearAllMocks();
|
|
171
176
|
});
|
|
172
177
|
|
|
173
178
|
it("should render the children when the dx-tree-tile emits iconclick", () => {
|
|
@@ -189,6 +194,12 @@ describe(TAG, () => {
|
|
|
189
194
|
expect(tile).toHaveProperty("isExpanded", false);
|
|
190
195
|
tile.dispatchEvent(new CustomEvent("iconclick"));
|
|
191
196
|
|
|
197
|
+
expect(track).toBeCalledTimes(1);
|
|
198
|
+
expect(track).toBeCalledWith(tile, GTM_EVENT_NAME, {
|
|
199
|
+
clickText: NODE_WITH_CHILDREN.label,
|
|
200
|
+
sidebarNavAction: "expand"
|
|
201
|
+
});
|
|
202
|
+
|
|
192
203
|
return Promise.resolve().then(() => {
|
|
193
204
|
const children: Array<TreeItem> = component.shadowRoot.querySelectorAll(
|
|
194
205
|
"dx-tree-item"
|
|
@@ -233,6 +244,12 @@ describe(TAG, () => {
|
|
|
233
244
|
|
|
234
245
|
tile.dispatchEvent(new CustomEvent("iconclick"));
|
|
235
246
|
|
|
247
|
+
expect(track).toBeCalledTimes(1);
|
|
248
|
+
expect(track).toBeCalledWith(tile, GTM_EVENT_NAME, {
|
|
249
|
+
clickText: NODE_WITH_CHILDREN.label,
|
|
250
|
+
sidebarNavAction: "collapse"
|
|
251
|
+
});
|
|
252
|
+
|
|
236
253
|
return Promise.resolve().then(() => {
|
|
237
254
|
expect(tile).toHaveProperty("isExpanded", false);
|
|
238
255
|
|
|
@@ -269,6 +286,12 @@ describe(TAG, () => {
|
|
|
269
286
|
expect(button).not.toBeNull();
|
|
270
287
|
button.click();
|
|
271
288
|
|
|
289
|
+
expect(track).toBeCalledTimes(1);
|
|
290
|
+
expect(track).toBeCalledWith(button, GTM_EVENT_NAME, {
|
|
291
|
+
clickText: NODE_WITH_CHILDREN.label,
|
|
292
|
+
sidebarNavAction: "click"
|
|
293
|
+
});
|
|
294
|
+
|
|
272
295
|
return Promise.resolve().then(() => {
|
|
273
296
|
expect(mockExpandCollapse).toBeCalledTimes(1);
|
|
274
297
|
const [expandCall] = mockExpandCollapse.mock.calls[0];
|
|
@@ -366,5 +389,24 @@ describe(TAG, () => {
|
|
|
366
389
|
expect(trees).toHaveLength(NODE_WITH_CHILDREN.children!.length);
|
|
367
390
|
});
|
|
368
391
|
});
|
|
392
|
+
|
|
393
|
+
it("should call track from dx/instrumentation when link is clicked", () => {
|
|
394
|
+
const component = renderComponent({
|
|
395
|
+
treeNode: SINGLE_NODE_WITH_LINK
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
const link: HTMLAnchorElement = component.shadowRoot.querySelector(
|
|
399
|
+
"a"
|
|
400
|
+
);
|
|
401
|
+
expect(link).not.toBeNull();
|
|
402
|
+
|
|
403
|
+
link.click();
|
|
404
|
+
|
|
405
|
+
expect(track).toBeCalledTimes(1);
|
|
406
|
+
expect(track).toBeCalledWith(link, GTM_EVENT_NAME, {
|
|
407
|
+
clickText: SINGLE_NODE_WITH_LINK.label,
|
|
408
|
+
sidebarNavAction: "click"
|
|
409
|
+
});
|
|
410
|
+
});
|
|
369
411
|
});
|
|
370
412
|
});
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { LightningElement, api } from "lwc";
|
|
2
2
|
import { InternalTreeNode } from "typings/custom";
|
|
3
|
+
import { track } from "dx/instrumentation";
|
|
4
|
+
import { SidebarGtmAction } from "typings/custom";
|
|
3
5
|
|
|
4
6
|
const DEFAULT_TARGET = "_self";
|
|
5
7
|
|
|
@@ -55,18 +57,24 @@ export default class TreeItem extends LightningElement {
|
|
|
55
57
|
}
|
|
56
58
|
}
|
|
57
59
|
|
|
58
|
-
private onIconClick(): void {
|
|
60
|
+
private onIconClick(event: CustomEvent): void {
|
|
59
61
|
this.doExpand();
|
|
62
|
+
this.sendGtm(event, this.isExpanded ? "expand" : "collapse");
|
|
60
63
|
}
|
|
61
64
|
|
|
62
|
-
private onButtonClick(): void {
|
|
65
|
+
private onButtonClick(event: Event): void {
|
|
63
66
|
if (this.hasChildren) {
|
|
64
67
|
this.doExpand();
|
|
65
68
|
}
|
|
66
69
|
|
|
70
|
+
this.sendGtm(event, "click");
|
|
67
71
|
this.fireEvent("tileselected", { name: this._treeNode.name });
|
|
68
72
|
}
|
|
69
73
|
|
|
74
|
+
private onLinkClick(event: Event): void {
|
|
75
|
+
this.sendGtm(event, "click");
|
|
76
|
+
}
|
|
77
|
+
|
|
70
78
|
private doExpand(): void {
|
|
71
79
|
this.isExpanded = !this.isExpanded;
|
|
72
80
|
this.fireEvent("expandcollapse");
|
|
@@ -88,4 +96,11 @@ export default class TreeItem extends LightningElement {
|
|
|
88
96
|
private setExpanded(value: boolean): void {
|
|
89
97
|
this.isExpanded = value;
|
|
90
98
|
}
|
|
99
|
+
|
|
100
|
+
private sendGtm(event: Event, sidebarNavAction: SidebarGtmAction) {
|
|
101
|
+
track(event.currentTarget!, "custEv_leftNavLinkClick", {
|
|
102
|
+
clickText: this._treeNode.label,
|
|
103
|
+
sidebarNavAction
|
|
104
|
+
});
|
|
105
|
+
}
|
|
91
106
|
}
|
|
@@ -2,6 +2,7 @@ import { LightningElement, api } from "lwc";
|
|
|
2
2
|
import cx from "classnames";
|
|
3
3
|
import { Brand, Option } from "typings/custom";
|
|
4
4
|
import { toJson } from "utils/normalizers";
|
|
5
|
+
import { track } from "dx/instrumentation";
|
|
5
6
|
|
|
6
7
|
const VALID_BRANDS = [
|
|
7
8
|
"analytics",
|
|
@@ -17,6 +18,7 @@ const VALID_BRANDS = [
|
|
|
17
18
|
"service",
|
|
18
19
|
"success"
|
|
19
20
|
];
|
|
21
|
+
const SIGN_UP_LABEL = "Sign Up";
|
|
20
22
|
|
|
21
23
|
export abstract class HeaderBase extends LightningElement {
|
|
22
24
|
@api bailHref?: string | null = null;
|
|
@@ -178,6 +180,12 @@ export abstract class HeaderBase extends LightningElement {
|
|
|
178
180
|
}
|
|
179
181
|
};
|
|
180
182
|
|
|
183
|
+
private handleSignUpClick(e: PointerEvent) {
|
|
184
|
+
track(e.currentTarget!, "custEv_signUpClick", {
|
|
185
|
+
clickText: SIGN_UP_LABEL
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
|
|
181
189
|
protected additionalClasses(): string {
|
|
182
190
|
return "";
|
|
183
191
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
/* Code generated by scripts/postinstall.js DO NOT EDIT */.tippy-box[data-animation=fade][data-state=hidden]{opacity:0}[data-tippy-root]{max-width:calc(100vw - 10px)}.tippy-box{position:relative;background-color:#333;color:#fff;border-radius:4px;font-size:14px;line-height:1.4;outline:0;transition-property:transform,visibility,opacity}.tippy-box[data-placement^=top]>.tippy-arrow{bottom:0}.tippy-box[data-placement^=top]>.tippy-arrow:before{bottom:-7px;left:0;border-width:8px 8px 0;border-top-color:initial;transform-origin:center top}.tippy-box[data-placement^=bottom]>.tippy-arrow{top:0}.tippy-box[data-placement^=bottom]>.tippy-arrow:before{top:-7px;left:0;border-width:0 8px 8px;border-bottom-color:initial;transform-origin:center bottom}.tippy-box[data-placement^=left]>.tippy-arrow{right:0}.tippy-box[data-placement^=left]>.tippy-arrow:before{border-width:8px 0 8px 8px;border-left-color:initial;right:-7px;transform-origin:center left}.tippy-box[data-placement^=right]>.tippy-arrow{left:0}.tippy-box[data-placement^=right]>.tippy-arrow:before{left:-7px;border-width:8px 8px 8px 0;border-right-color:initial;transform-origin:center right}.tippy-box[data-inertia][data-state=visible]{transition-timing-function:cubic-bezier(.54,1.5,.38,1.11)}.tippy-arrow{width:16px;height:16px;color:#333}.tippy-arrow:before{content:"";position:absolute;border-color:transparent;border-style:solid}.tippy-content{position:relative;padding:5px 9px;z-index:1}
|