@salesforcedevs/dx-components 0.10.1-alpha.13 → 0.10.1-alpha.133
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/lwc.config.json +3 -1
- package/package.json +2 -2
- package/src/assets/svg/docs-empty-state-small.svg +72 -0
- package/src/assets/svg/sidebar-loading.svg +34 -0
- package/src/modules/dx/cardGrid/__tests__/cardMockProps.ts +78 -148
- package/src/modules/dx/codeBlock/codeBlock.stories.ts +2 -69
- package/src/modules/dx/codeBlock/codeBlock.ts +5 -1
- package/src/modules/dx/codeBlock/darkTheme.css +0 -1
- package/src/modules/dx/codeBlock/lightTheme.css +0 -1
- package/src/modules/dx/emptyState/__tests__/emptyState.test.ts +29 -9
- package/src/modules/dx/emptyState/emptyState.css +14 -0
- package/src/modules/dx/emptyState/emptyState.html +2 -2
- package/src/modules/dx/emptyState/emptyState.stories.ts +8 -0
- package/src/modules/dx/emptyState/emptyState.ts +14 -0
- package/src/modules/dx/footer/links.ts +3 -5
- package/src/modules/dx/headerNav/__tests__/headerNav.test.ts +2 -4
- package/src/modules/dx/headerNav/headerNav.html +8 -6
- package/src/modules/dx/headerNav/headerNav.ts +2 -2
- package/src/modules/dx/lazy/lazy.ts +0 -7
- package/src/modules/dx/newsletterForm/newsletterForm.html +5 -3
- package/src/modules/dx/searchResults/coveo.css +314 -111
- package/src/modules/dx/sidebar/__tests__/mockDocContent.ts +48 -0
- package/src/modules/dx/sidebar/__tests__/mockPageReference.ts +8 -0
- package/src/modules/dx/sidebar/sidebar.css +38 -17
- package/src/modules/dx/sidebar/sidebar.html +62 -58
- package/src/modules/dx/sidebar/sidebar.stories.ts +53 -54
- package/src/modules/dx/sidebar/sidebar.ts +99 -10
- package/src/modules/dx/sidebarSearch/__tests__/mockPreloadedState.ts +8843 -0
- package/src/modules/dx/sidebarSearch/__tests__/sidebarSearch.test.ts +121 -0
- package/src/modules/dx/sidebarSearch/sidebarSearch.ts +282 -120
- package/src/modules/dx/sidebarSearch/utils.ts +2 -0
- package/src/modules/dx/sidebarSearchResult/__tests__/sidebarSearchResult.test.ts +55 -0
- package/src/modules/dx/sidebarSearchResult/sidebarSearchResult.css +12 -2
- package/src/modules/dx/sidebarSearchResult/sidebarSearchResult.html +1 -1
- package/src/modules/dx/sidebarSearchResult/sidebarSearchResult.ts +8 -2
- package/src/modules/dx/spinner/__tests__/spinner.test.ts +37 -0
- package/src/modules/dx/spinner/spinner.css +750 -0
- package/src/modules/dx/spinner/spinner.html +6 -0
- package/src/modules/dx/spinner/spinner.stories.ts +69 -0
- package/src/modules/dx/spinner/spinner.ts +20 -0
- package/src/modules/dx/{headerNavOption/__tests__/headerNavOption.test.ts → tab/__tests__/tab.test.ts} +40 -24
- package/src/modules/dx/{headerNavOption/headerNavOption.css → tab/tab.css} +24 -9
- package/src/modules/dx/{headerNavOption/headerNavOption.html → tab/tab.html} +5 -1
- package/src/modules/dx/tab/tab.stories.ts +57 -0
- package/src/modules/dx/{headerNavOption/headerNavOption.ts → tab/tab.ts} +26 -5
- package/src/modules/helpers/table/table.css +23 -7
- package/src/modules/utils/coveo/coveo.ts +50 -12
- package/src/modules/utils/highlight/__tests__/highlight.test.ts +154 -0
- package/src/modules/utils/highlight/highlight.ts +32 -0
- package/src/modules/utils/jest/jest.ts +35 -0
- package/src/modules/utils/normalizers/normalizers.ts +3 -0
- package/src/modules/utils/recentSearches/__tests__/recentSearches.test.ts +79 -0
- package/src/modules/utils/recentSearches/recentSearches.ts +12 -17
- package/src/modules/utils/regexps/regexps.ts +5 -0
- package/src/modules/utils/tests/tests.ts +18 -11
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { html } from "lit-html";
|
|
2
|
+
import { SpinnerSize, SpinnerVariant } from "typings/custom";
|
|
3
|
+
|
|
4
|
+
type SpinnerStoryArgs = {
|
|
5
|
+
size: SpinnerSize;
|
|
6
|
+
variant: SpinnerVariant;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
const sizeOptions: Array<SpinnerSize> = ["medium", "x-small", "small", "large"];
|
|
10
|
+
const variantOptions: Array<SpinnerVariant> = ["base", "brand", "inverse"];
|
|
11
|
+
const variantToBackgroundColor: { [key: string]: string } = {
|
|
12
|
+
inverse: "black"
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export default {
|
|
16
|
+
title: "dx/dx-spinner",
|
|
17
|
+
component: "dx-spinner",
|
|
18
|
+
argTypes: {
|
|
19
|
+
size: {
|
|
20
|
+
control: {
|
|
21
|
+
type: "select",
|
|
22
|
+
options: sizeOptions
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
variant: {
|
|
26
|
+
control: {
|
|
27
|
+
type: "select",
|
|
28
|
+
options: variantOptions
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const style = (variant: SpinnerVariant = "base") => html`
|
|
35
|
+
<style>
|
|
36
|
+
.spinner-wrapper {
|
|
37
|
+
position: relative;
|
|
38
|
+
height: 100vh;
|
|
39
|
+
background-color: ${variantToBackgroundColor[variant] || "white"};
|
|
40
|
+
}
|
|
41
|
+
</style>
|
|
42
|
+
`;
|
|
43
|
+
|
|
44
|
+
const [defaultSize] = sizeOptions;
|
|
45
|
+
const [defaultVariant] = variantOptions;
|
|
46
|
+
|
|
47
|
+
const Template = ({ size, variant }: SpinnerStoryArgs) => html`
|
|
48
|
+
${style(variant)}
|
|
49
|
+
<div class="spinner-wrapper">
|
|
50
|
+
<dx-spinner
|
|
51
|
+
size="${size || defaultSize}"
|
|
52
|
+
variant="${variant || defaultVariant}"
|
|
53
|
+
></dx-spinner>
|
|
54
|
+
</div>
|
|
55
|
+
`;
|
|
56
|
+
|
|
57
|
+
export const Base = Template;
|
|
58
|
+
|
|
59
|
+
export const BrandLarge = (args: SpinnerStoryArgs) => Template(args);
|
|
60
|
+
BrandLarge.args = {
|
|
61
|
+
size: "large",
|
|
62
|
+
variant: "brand"
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export const InverseSmall = (args: SpinnerStoryArgs) => Template(args);
|
|
66
|
+
InverseSmall.args = {
|
|
67
|
+
size: "small",
|
|
68
|
+
variant: "inverse"
|
|
69
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { LightningElement, api } from "lwc";
|
|
2
|
+
import cx from "classnames";
|
|
3
|
+
import type { SpinnerSize, SpinnerVariant } from "typings/custom";
|
|
4
|
+
|
|
5
|
+
export default class Spinner extends LightningElement {
|
|
6
|
+
@api size: SpinnerSize = "medium";
|
|
7
|
+
@api variant: SpinnerVariant = "base";
|
|
8
|
+
|
|
9
|
+
connectedCallback() {
|
|
10
|
+
this.classList.add("spinner_container");
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
get containerClass(): string {
|
|
14
|
+
return cx(
|
|
15
|
+
"spinner",
|
|
16
|
+
this.size && `spinner_${this.size}`,
|
|
17
|
+
this.variant && this.variant !== "base" && `spinner_${this.variant}`
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
import
|
|
1
|
+
import Tab from "dx/tab";
|
|
2
2
|
import Icon from "dx/icon";
|
|
3
|
+
import { track } from "dx/instrumentation";
|
|
3
4
|
import { createRenderComponent } from "utils/tests";
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
|
|
6
|
+
jest.mock("dx/instrumentation");
|
|
7
|
+
|
|
8
|
+
const TAG = "dx-tab";
|
|
9
|
+
const render = createRenderComponent(TAG, Tab);
|
|
7
10
|
|
|
8
11
|
const PROPS = {
|
|
9
12
|
label: "documentation",
|
|
@@ -14,9 +17,8 @@ describe(TAG, () => {
|
|
|
14
17
|
it("renders a single link with a label", () => {
|
|
15
18
|
const element = render(PROPS);
|
|
16
19
|
|
|
17
|
-
const links: Array<HTMLAnchorElement> =
|
|
18
|
-
"a"
|
|
19
|
-
);
|
|
20
|
+
const links: Array<HTMLAnchorElement> =
|
|
21
|
+
element.shadowRoot.querySelectorAll("a");
|
|
20
22
|
|
|
21
23
|
expect(links.length).toEqual(1);
|
|
22
24
|
const [singleLink] = links;
|
|
@@ -53,9 +55,8 @@ describe(TAG, () => {
|
|
|
53
55
|
const label = "test button";
|
|
54
56
|
const element = render({ label });
|
|
55
57
|
|
|
56
|
-
const buttons: Array<HTMLButtonElement> =
|
|
57
|
-
"button"
|
|
58
|
-
);
|
|
58
|
+
const buttons: Array<HTMLButtonElement> =
|
|
59
|
+
element.shadowRoot.querySelectorAll("button");
|
|
59
60
|
|
|
60
61
|
expect(buttons).toHaveLength(1);
|
|
61
62
|
const [singleButton] = buttons;
|
|
@@ -66,6 +67,23 @@ describe(TAG, () => {
|
|
|
66
67
|
|
|
67
68
|
const span: HTMLElement = singleButton.querySelector("span")!;
|
|
68
69
|
expect(span.textContent).toBe(label);
|
|
70
|
+
|
|
71
|
+
return expect(element).toBeAccessible();
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it("renders a button with an icon if useIcon is passed as true", () => {
|
|
75
|
+
const label = "test button";
|
|
76
|
+
const element = render({ label, useIcon: true });
|
|
77
|
+
|
|
78
|
+
const buttons: Array<HTMLButtonElement> =
|
|
79
|
+
element.shadowRoot.querySelectorAll("button");
|
|
80
|
+
|
|
81
|
+
expect(buttons).toHaveLength(1);
|
|
82
|
+
const [singleButton] = buttons;
|
|
83
|
+
|
|
84
|
+
const span: HTMLElement = singleButton.querySelector("span")!;
|
|
85
|
+
expect(span.textContent).toBe(label);
|
|
86
|
+
|
|
69
87
|
const icon: Element & Icon = singleButton.querySelector("dx-icon")!;
|
|
70
88
|
expect(icon).not.toBeNull();
|
|
71
89
|
expect(icon.size).toBe("small");
|
|
@@ -75,11 +93,10 @@ describe(TAG, () => {
|
|
|
75
93
|
|
|
76
94
|
it("renders a button with label only if variant is small", () => {
|
|
77
95
|
const label = "test button";
|
|
78
|
-
const element = render({ label, variant: "small" });
|
|
96
|
+
const element = render({ label, variant: "small", useIcon: "true" });
|
|
79
97
|
|
|
80
|
-
const button: HTMLButtonElement =
|
|
81
|
-
"button"
|
|
82
|
-
);
|
|
98
|
+
const button: HTMLButtonElement =
|
|
99
|
+
element.shadowRoot.querySelector("button");
|
|
83
100
|
|
|
84
101
|
expect(button.classList).toHaveLength(2);
|
|
85
102
|
expect(button.classList).toContain("nav-list-item");
|
|
@@ -95,19 +112,18 @@ describe(TAG, () => {
|
|
|
95
112
|
return expect(element).toBeAccessible();
|
|
96
113
|
});
|
|
97
114
|
|
|
98
|
-
it("
|
|
99
|
-
const
|
|
100
|
-
const element = render({
|
|
101
|
-
...PROPS,
|
|
102
|
-
onclick: sendGtmMock
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
const link = element.shadowRoot.querySelector("a");
|
|
115
|
+
it("calls track when the link is clicked", () => {
|
|
116
|
+
const element = render(PROPS);
|
|
106
117
|
|
|
118
|
+
const link: HTMLElement = element.shadowRoot.querySelector("a");
|
|
119
|
+
expect(link).not.toBeNull();
|
|
107
120
|
link.click();
|
|
108
121
|
|
|
109
|
-
expect(
|
|
110
|
-
|
|
111
|
-
|
|
122
|
+
expect(track).toHaveBeenCalledTimes(1);
|
|
123
|
+
expect(track).toBeCalledWith(link, "custEv_topNavLinkClick", {
|
|
124
|
+
navHeading: PROPS.label,
|
|
125
|
+
clickText: PROPS.href,
|
|
126
|
+
pageLocation: window.location.pathname
|
|
127
|
+
});
|
|
112
128
|
});
|
|
113
129
|
});
|
|
@@ -5,7 +5,10 @@ a {
|
|
|
5
5
|
}
|
|
6
6
|
|
|
7
7
|
.nav-list-item {
|
|
8
|
-
--horizontal-spacing: var(
|
|
8
|
+
--horizontal-spacing: var(
|
|
9
|
+
--dx-c-tab-horizontal-spacing,
|
|
10
|
+
var(--dx-g-spacing-md)
|
|
11
|
+
);
|
|
9
12
|
|
|
10
13
|
position: relative;
|
|
11
14
|
display: flex;
|
|
@@ -50,12 +53,15 @@ button.nav-list-item_small > dx-icon {
|
|
|
50
53
|
.nav-list-item_default:hover,
|
|
51
54
|
.nav-list-item_default:active,
|
|
52
55
|
:host([aria-expanded="true"]) button.nav-list-item_default {
|
|
53
|
-
background: var(
|
|
56
|
+
background: var(
|
|
57
|
+
--dx-g-brand-current-button-color-background-inactive,
|
|
58
|
+
var(--dx-g-brand-default-button-color-background-inactive)
|
|
59
|
+
);
|
|
54
60
|
}
|
|
55
61
|
|
|
56
|
-
button.nav-list-item:hover >
|
|
57
|
-
button.nav-list-item:active >
|
|
58
|
-
:host([aria-expanded="true"]) button.nav-list-item >
|
|
62
|
+
button.nav-list-item:hover > dx-icon,
|
|
63
|
+
button.nav-list-item:active > dx-icon,
|
|
64
|
+
:host([aria-expanded="true"]) button.nav-list-item > dx-icon {
|
|
59
65
|
transform: rotateX(180deg);
|
|
60
66
|
}
|
|
61
67
|
|
|
@@ -74,18 +80,27 @@ button.nav-list-item:active > *:last-child,
|
|
|
74
80
|
}
|
|
75
81
|
|
|
76
82
|
.nav-list-item_default.state-active {
|
|
77
|
-
background: var(
|
|
78
|
-
|
|
83
|
+
background: var(
|
|
84
|
+
--dx-g-brand-current-button-color-background-active,
|
|
85
|
+
var(--dx-g-brand-default-button-color-background-active)
|
|
86
|
+
);
|
|
87
|
+
color: var(--dx-g-brand-current-color, var(--dx-g-brand-default-color));
|
|
79
88
|
}
|
|
80
89
|
|
|
81
90
|
@media (max-width: 1160px) {
|
|
82
91
|
.nav-list-item_small {
|
|
83
|
-
--horizontal-spacing: var(
|
|
92
|
+
--horizontal-spacing: var(
|
|
93
|
+
--dx-c-tab-horizontal-spacing,
|
|
94
|
+
var(--dx-g-spacing-smd)
|
|
95
|
+
);
|
|
84
96
|
}
|
|
85
97
|
}
|
|
86
98
|
|
|
87
99
|
@media (max-width: 1090px) {
|
|
88
100
|
.nav-list-item_small {
|
|
89
|
-
--horizontal-spacing: var(
|
|
101
|
+
--horizontal-spacing: var(
|
|
102
|
+
--dx-c-tab-horizontal-spacing,
|
|
103
|
+
var(--dx-g-spacing-sm)
|
|
104
|
+
);
|
|
90
105
|
}
|
|
91
106
|
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { html } from "lit-html";
|
|
2
|
+
import { TabVariant } from "typings/custom";
|
|
3
|
+
|
|
4
|
+
type StoryArgs = {
|
|
5
|
+
isActive: boolean;
|
|
6
|
+
label: string;
|
|
7
|
+
useIcon: boolean;
|
|
8
|
+
variant: TabVariant;
|
|
9
|
+
};
|
|
10
|
+
const VARIANT_OPTIONS: Array<TabVariant> = ["default", "small"];
|
|
11
|
+
|
|
12
|
+
export default {
|
|
13
|
+
title: "dx/dx-tab",
|
|
14
|
+
component: "dx-tab",
|
|
15
|
+
argTypes: {
|
|
16
|
+
variant: {
|
|
17
|
+
control: {
|
|
18
|
+
type: "select",
|
|
19
|
+
options: VARIANT_OPTIONS
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const Template = ({ variant, label, isActive, useIcon }: StoryArgs) => html`
|
|
26
|
+
<dx-tab
|
|
27
|
+
label="${label}"
|
|
28
|
+
is-active="${isActive}"
|
|
29
|
+
variant="${variant}"
|
|
30
|
+
use-icon="${useIcon}"
|
|
31
|
+
></dx-tab>
|
|
32
|
+
`;
|
|
33
|
+
|
|
34
|
+
export const Base = (args: StoryArgs) => Template(args);
|
|
35
|
+
Base.args = {
|
|
36
|
+
isActive: false,
|
|
37
|
+
useIcon: false,
|
|
38
|
+
label: "Banana",
|
|
39
|
+
variant: VARIANT_OPTIONS[0]
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export const TabGroup = ({ variant }: { variant: TabVariant }) => html`
|
|
43
|
+
<style>
|
|
44
|
+
.container {
|
|
45
|
+
display: flex;
|
|
46
|
+
--dx-c-tab-horizontal-spacing: var(--dx-g-spacing-xs);
|
|
47
|
+
}
|
|
48
|
+
</style>
|
|
49
|
+
<nav class="container">
|
|
50
|
+
<dx-tab label="Banana" variant="${variant}"></dx-tab>
|
|
51
|
+
<dx-tab label="Apple" variant="${variant}"></dx-tab>
|
|
52
|
+
</nav>
|
|
53
|
+
`;
|
|
54
|
+
|
|
55
|
+
TabGroup.args = {
|
|
56
|
+
variant: VARIANT_OPTIONS[0]
|
|
57
|
+
};
|
|
@@ -1,19 +1,40 @@
|
|
|
1
1
|
import { LightningElement, api } from "lwc";
|
|
2
2
|
import { track } from "dx/instrumentation";
|
|
3
3
|
import cx from "classnames";
|
|
4
|
-
import {
|
|
4
|
+
import { TabVariant } from "typings/custom";
|
|
5
|
+
import { normalizeBoolean } from "utils/normalizers";
|
|
5
6
|
|
|
6
|
-
export default class
|
|
7
|
-
@api isActive: boolean = false;
|
|
7
|
+
export default class Tab extends LightningElement {
|
|
8
8
|
@api label: string | null = null;
|
|
9
9
|
@api href: string | null = null;
|
|
10
|
-
@api variant:
|
|
10
|
+
@api variant: TabVariant = "default";
|
|
11
|
+
|
|
12
|
+
@api
|
|
13
|
+
get isActive() {
|
|
14
|
+
return this._isActive;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
set isActive(value) {
|
|
18
|
+
this._isActive = normalizeBoolean(value);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
@api
|
|
22
|
+
get useIcon() {
|
|
23
|
+
return this._useIcon;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
set useIcon(value) {
|
|
27
|
+
this._useIcon = normalizeBoolean(value);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
_useIcon = false;
|
|
31
|
+
_isActive = false;
|
|
11
32
|
|
|
12
33
|
private sendGtm(e: PointerEvent) {
|
|
13
34
|
track(e.currentTarget!, "custEv_topNavLinkClick", {
|
|
14
35
|
navHeading: this.label || undefined,
|
|
15
36
|
clickText: this.href || undefined,
|
|
16
|
-
pageLocation: window.location.pathname
|
|
37
|
+
pageLocation: window.location.pathname
|
|
17
38
|
});
|
|
18
39
|
}
|
|
19
40
|
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
table {
|
|
2
2
|
--table-border-radius: 4px;
|
|
3
|
+
--table-cell-text-base: var(--dx-g-text-sm);
|
|
4
|
+
--table-cell-line-height: var(--dx-g-text-lg);
|
|
3
5
|
|
|
4
6
|
display: block;
|
|
5
7
|
overflow-x: scroll;
|
|
@@ -16,13 +18,13 @@ table tr {
|
|
|
16
18
|
th,
|
|
17
19
|
td {
|
|
18
20
|
padding: var(--dx-g-spacing-md);
|
|
19
|
-
font-size: var(--
|
|
20
|
-
line-height: var(--
|
|
21
|
+
font-size: var(--table-cell-text-base);
|
|
22
|
+
line-height: var(--table-cell-line-height);
|
|
21
23
|
}
|
|
22
24
|
|
|
23
25
|
th {
|
|
24
26
|
background-color: var(--dx-g-indigo-vibrant-95);
|
|
25
|
-
font-weight:
|
|
27
|
+
font-weight: var(--dx-g-font-bold);
|
|
26
28
|
border-bottom: 3px solid var(--dx-g-indigo-vibrant-30);
|
|
27
29
|
}
|
|
28
30
|
|
|
@@ -40,10 +42,6 @@ table tbody tr td {
|
|
|
40
42
|
border-bottom: 1px solid var(--dx-g-gray-90);
|
|
41
43
|
}
|
|
42
44
|
|
|
43
|
-
th:first-of-type {
|
|
44
|
-
font-weight: var(--dx-g-font-bold);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
45
|
tr th:first-of-type,
|
|
48
46
|
td:first-of-type {
|
|
49
47
|
min-width: 110px;
|
|
@@ -85,6 +83,24 @@ tr td[colspan]:not([colspan="1"]) {
|
|
|
85
83
|
text-align: center;
|
|
86
84
|
}
|
|
87
85
|
|
|
86
|
+
/**
|
|
87
|
+
* Inside of a <td>, we want font size not to increase as it otherwise would
|
|
88
|
+
* for standard inline/"prose-level" elements (e.g., <p>, <li>). But we *do*
|
|
89
|
+
* want to leave font size increases in place for *other* elements inside <td>,
|
|
90
|
+
* like callouts, headings (<h1>, <h2>, etc.), and so on. In order not to
|
|
91
|
+
* "stomp" on too much -- and because we don't control the markup, so can't
|
|
92
|
+
* easily add new CSS classes, etc. -- we try to pick out the specific
|
|
93
|
+
* structures only here. (See https://gus.lightning.force.com/lightning/r/ADM_Work__c/a07EE0000081MGTYA2/view)
|
|
94
|
+
*/
|
|
95
|
+
td :is(.li, p, .p, dd) {
|
|
96
|
+
font-size: var(--table-cell-text-base);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
td doc-content-callout :is(.li, p, .p, dd) {
|
|
100
|
+
/* Override/reset for callouts -- see https://gus.lightning.force.com/lightning/r/ADM_Work__c/a07EE0000081MGTYA2/view */
|
|
101
|
+
font-size: var(--dx-g-text-base);
|
|
102
|
+
}
|
|
103
|
+
|
|
88
104
|
table :not(thead + tbody) tr:first-of-type td:first-of-type {
|
|
89
105
|
border-top-left-radius: var(--table-border-radius);
|
|
90
106
|
}
|
|
@@ -1,22 +1,60 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
buildSearchEngine as _buildSearchEngine,
|
|
3
|
+
SearchAppState,
|
|
4
|
+
SearchEngineOptions
|
|
5
|
+
} from "@coveo/headless";
|
|
2
6
|
|
|
3
7
|
export const buildSearchEngine = ({
|
|
4
8
|
organizationId,
|
|
9
|
+
preloadedState,
|
|
5
10
|
publicAccessToken,
|
|
6
|
-
|
|
7
|
-
|
|
11
|
+
searchHub,
|
|
12
|
+
searchPipeline
|
|
8
13
|
}: {
|
|
9
14
|
organizationId: string;
|
|
10
15
|
publicAccessToken: string;
|
|
11
|
-
searchPipeline
|
|
16
|
+
searchPipeline?: string;
|
|
12
17
|
searchHub: string;
|
|
18
|
+
preloadedState?: SearchAppState;
|
|
13
19
|
}) => {
|
|
14
|
-
const search =
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
const search = searchPipeline
|
|
21
|
+
? { pipeline: searchPipeline, searchHub }
|
|
22
|
+
: { searchHub };
|
|
23
|
+
|
|
24
|
+
const configuration = {
|
|
25
|
+
accessToken: publicAccessToken,
|
|
26
|
+
organizationId,
|
|
27
|
+
search
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const engineConfiguration: SearchEngineOptions = preloadedState
|
|
31
|
+
? { configuration, preloadedState }
|
|
32
|
+
: { configuration };
|
|
33
|
+
|
|
34
|
+
return _buildSearchEngine(engineConfiguration);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export const getSidebarSearchParams = () =>
|
|
38
|
+
new URLSearchParams(window.location.search).get("q");
|
|
39
|
+
|
|
40
|
+
export const coveoXMLDocsConfig = {
|
|
41
|
+
coveoOrganizationId: "coveosalesforcetestakshatha",
|
|
42
|
+
coveoPublicAccessToken: "xxfeb39525-e402-4e41-a870-7132441f7875",
|
|
43
|
+
coveoSearchHub: "Developer_Docs_SS",
|
|
44
|
+
coveoAdvancedQueryConfig: JSON.stringify({
|
|
45
|
+
objecttype: "HTDeveloperDocumentsC",
|
|
46
|
+
sflanguage: "en_US",
|
|
47
|
+
sfrelease__c: "232.0",
|
|
48
|
+
sfdelivarable__c: "apexcode"
|
|
49
|
+
})
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export const coveoSFDocsConfig = {
|
|
53
|
+
coveoOrganizationId: "coveosalesforcetestakshatha",
|
|
54
|
+
coveoPublicAccessToken: "xxfeb39525-e402-4e41-a870-7132441f7875",
|
|
55
|
+
coveoSearchHub: "Developer_MdDocs_SS",
|
|
56
|
+
coveoAdvancedQueryConfig: JSON.stringify({
|
|
57
|
+
source: "Sitemap - Developer Docs",
|
|
58
|
+
path_segment_3: "pardot"
|
|
59
|
+
})
|
|
22
60
|
};
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { createElement } from "lwc";
|
|
2
|
+
import CodeBlock from "dx/codeBlock";
|
|
3
|
+
import { highlightTerms } from "utils/highlight";
|
|
4
|
+
|
|
5
|
+
const mockContent = `<div><a name='apex_dev_guide'><!-- --></a><h1 class='helpHead1'>Apex Developer Guide</h1><div class='shortdesc'>Salesforce has changed the way organizations do business by moving enterprise
|
|
6
|
+
applications that were traditionally client-server-based into the Lightning Platform, an
|
|
7
|
+
on-demand, multitenant Web environment. This environment enables you to run and customize
|
|
8
|
+
applications, such as Salesforce Automation and Service & Support, and build new custom
|
|
9
|
+
applications based on particular business needs. </div><div id='sfdc:seealso' class='related-links'>
|
|
10
|
+
<ul class='ullinks'>
|
|
11
|
+
<li class='link ulchildlink'>
|
|
12
|
+
<strong><a href='atlas.en-us.apexcode.meta/apexcode/apex_intro_get_started.htm'>Getting Started with Apex</a></strong><br>
|
|
13
|
+
Apex is a strongly typed, object-oriented programming language that allows developers to execute flow and transaction control statements on the Lightning Platform server, in conjunction with calls to the API.</li>
|
|
14
|
+
<li class='link ulchildlink'>
|
|
15
|
+
<strong><a href='atlas.en-us.apexcode.meta/apexcode/apex_writing.htm'>Writing Apex</a></strong><br>
|
|
16
|
+
Apex is like Java for Salesforce. It enables you to add and interact with data in the Lightning Platform persistence layer. It uses classes, data types, variables, and if-else statements. You can make it execute based on a condition, or have a block of code execute repeatedly.</li>
|
|
17
|
+
<li class='link ulchildlink'>
|
|
18
|
+
<strong><a href='atlas.en-us.apexcode.meta/apexcode/apex_running.htm'>Running Apex</a></strong><br>
|
|
19
|
+
You can access many features of the Salesforce user interface programmatically in Apex, and you can integrate with external SOAP and REST Web services. You can run Apex code using a variety of mechanisms. Apex code runs in atomic transactions. </li>
|
|
20
|
+
<li class='link ulchildlink'>
|
|
21
|
+
<strong><a href='atlas.en-us.apexcode.meta/apexcode/apex_debug_test_deploy.htm'>Debugging, Testing, and Deploying Apex</a></strong><br>
|
|
22
|
+
Develop your Apex code in a sandbox and debug it with the Developer Console and debug logs. Unit-test your code, then distribute it to customers using packages.</li>
|
|
23
|
+
<li class='link ulchildlink'>
|
|
24
|
+
<strong><a href='atlas.en-us.apexcode.meta/apexcode/apex_reference.htm'>Apex Language Reference</a></strong><br>
|
|
25
|
+
This Apex reference goes into detail about DML statements and the built-in Apex classes and interfaces.</li>
|
|
26
|
+
<li class='link ulchildlink'>
|
|
27
|
+
<strong><a href='atlas.en-us.apexcode.meta/apexcode/apex_appendices.htm'>Appendices</a></strong><br>
|
|
28
|
+
</li>
|
|
29
|
+
<li class='link ulchildlink'>
|
|
30
|
+
<strong><a href='atlas.en-us.apexcode.meta/apexcode/glossary_apex.htm'>Glossary</a></strong><br>
|
|
31
|
+
</li>
|
|
32
|
+
</ul>
|
|
33
|
+
</div><!--DRC 228.7--></div>`;
|
|
34
|
+
|
|
35
|
+
const allowedTags = [
|
|
36
|
+
"p",
|
|
37
|
+
".p",
|
|
38
|
+
".shortdesc",
|
|
39
|
+
"h1",
|
|
40
|
+
"h2",
|
|
41
|
+
"h3",
|
|
42
|
+
"h4",
|
|
43
|
+
"h5",
|
|
44
|
+
"h6",
|
|
45
|
+
"li",
|
|
46
|
+
"dl",
|
|
47
|
+
"th",
|
|
48
|
+
"td"
|
|
49
|
+
];
|
|
50
|
+
const container = document.createElement("div");
|
|
51
|
+
|
|
52
|
+
describe("highlight utility", () => {
|
|
53
|
+
afterEach(() => (container.innerHTML = ""));
|
|
54
|
+
|
|
55
|
+
it("highlights text that matches search criteria", () => {
|
|
56
|
+
container.innerHTML = mockContent;
|
|
57
|
+
highlightTerms(
|
|
58
|
+
container.querySelectorAll(allowedTags.join(",")),
|
|
59
|
+
"apex"
|
|
60
|
+
);
|
|
61
|
+
expect(container.querySelectorAll("mark")).toHaveLength(14);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it("doesn't highlight elements that contains dx/docs components", () => {
|
|
65
|
+
const searchTerm = "customreport";
|
|
66
|
+
const codeBlock = createElement("dx-code-block", { is: CodeBlock });
|
|
67
|
+
Object.assign(codeBlock, {
|
|
68
|
+
codeBlock: searchTerm,
|
|
69
|
+
language: "text"
|
|
70
|
+
// title: "",
|
|
71
|
+
// variant: "card"
|
|
72
|
+
});
|
|
73
|
+
container.appendChild(document.createElement("p"));
|
|
74
|
+
container.firstElementChild?.appendChild(codeBlock);
|
|
75
|
+
highlightTerms(
|
|
76
|
+
container.querySelectorAll(allowedTags.join(",")),
|
|
77
|
+
searchTerm
|
|
78
|
+
);
|
|
79
|
+
expect(container.querySelectorAll("mark")).toHaveLength(0);
|
|
80
|
+
expect(codeBlock.shadowRoot.innerHTML).toMatch(searchTerm); // sanity check
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it("doesn't highlight terms separated by html tags", () => {
|
|
84
|
+
container.innerHTML = "<p>loadData<span>within</span></p>";
|
|
85
|
+
highlightTerms(
|
|
86
|
+
container.querySelectorAll(allowedTags.join(",")),
|
|
87
|
+
"loadDatawithin"
|
|
88
|
+
);
|
|
89
|
+
expect(container.querySelectorAll("mark")).toHaveLength(0);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it("escapes regex especial characters", () => {
|
|
93
|
+
container.innerHTML = mockContent;
|
|
94
|
+
highlightTerms(
|
|
95
|
+
container.querySelectorAll(allowedTags.join(",")),
|
|
96
|
+
"apex.+"
|
|
97
|
+
);
|
|
98
|
+
expect(container.querySelectorAll("mark")).toHaveLength(0);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it("cleans previous search result before searching for a new term", () => {
|
|
102
|
+
const firstSearch = "apex";
|
|
103
|
+
const secondSearch = "salesforce";
|
|
104
|
+
|
|
105
|
+
container.innerHTML = mockContent;
|
|
106
|
+
|
|
107
|
+
highlightTerms(
|
|
108
|
+
container.querySelectorAll(allowedTags.join(",")),
|
|
109
|
+
firstSearch
|
|
110
|
+
);
|
|
111
|
+
const firstMarks = container.querySelectorAll("mark");
|
|
112
|
+
expect(firstMarks).toHaveLength(14);
|
|
113
|
+
firstMarks.forEach(({ textContent }) =>
|
|
114
|
+
expect(textContent?.toLowerCase()).toBe(firstSearch)
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
highlightTerms(
|
|
118
|
+
container.querySelectorAll(allowedTags.join(",")),
|
|
119
|
+
secondSearch
|
|
120
|
+
);
|
|
121
|
+
const secondMarks = container.querySelectorAll("mark");
|
|
122
|
+
expect(secondMarks).toHaveLength(4);
|
|
123
|
+
secondMarks.forEach(({ textContent }) =>
|
|
124
|
+
expect(textContent?.toLowerCase()).toBe(secondSearch)
|
|
125
|
+
);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it("cleans all marks if the search term is empty string", () => {
|
|
129
|
+
const firstSearch = "apex";
|
|
130
|
+
const secondSearch = "";
|
|
131
|
+
|
|
132
|
+
container.innerHTML = mockContent;
|
|
133
|
+
|
|
134
|
+
highlightTerms(
|
|
135
|
+
container.querySelectorAll(allowedTags.join(",")),
|
|
136
|
+
firstSearch
|
|
137
|
+
);
|
|
138
|
+
const firstMarks = container.querySelectorAll("mark");
|
|
139
|
+
expect(firstMarks).toHaveLength(14);
|
|
140
|
+
firstMarks.forEach(({ textContent }) =>
|
|
141
|
+
expect(textContent?.toLowerCase()).toBe(firstSearch)
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
highlightTerms(
|
|
145
|
+
container.querySelectorAll(allowedTags.join(",")),
|
|
146
|
+
secondSearch
|
|
147
|
+
);
|
|
148
|
+
const secondMarks = container.querySelectorAll("mark");
|
|
149
|
+
expect(secondMarks).toHaveLength(0);
|
|
150
|
+
secondMarks.forEach(({ textContent }) =>
|
|
151
|
+
expect(textContent?.toLowerCase()).toBe(secondSearch)
|
|
152
|
+
);
|
|
153
|
+
});
|
|
154
|
+
});
|