@salesforcedevs/dx-components 0.10.0 → 0.10.1-alpha.100

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.
Files changed (88) hide show
  1. package/lwc.config.json +3 -3
  2. package/package.json +3 -4
  3. package/src/.DS_Store +0 -0
  4. package/src/assets/svg/docs-empty-state-small.svg +72 -0
  5. package/src/assets/svg/sidebar-loading.svg +34 -0
  6. package/src/modules/.DS_Store +0 -0
  7. package/src/modules/dx/.DS_Store +0 -0
  8. package/src/modules/dx/cardGrid/__tests__/cardMockProps.ts +78 -148
  9. package/src/modules/dx/cardGrid/cardGrid.css +0 -32
  10. package/src/modules/dx/cardGrid/cardGrid.html +5 -11
  11. package/src/modules/dx/codeBlock/__tests__/codeBlock.test.ts +47 -5
  12. package/src/modules/dx/codeBlock/codeBlock.stories.ts +2 -69
  13. package/src/modules/dx/codeBlock/codeBlock.ts +43 -22
  14. package/src/modules/dx/codeBlock/darkTheme.css +0 -1
  15. package/src/modules/dx/codeBlock/lightTheme.css +0 -1
  16. package/src/modules/dx/emptyState/__tests__/emptyState.test.ts +29 -10
  17. package/src/modules/dx/emptyState/__tests__/mockProps.ts +1 -3
  18. package/src/modules/dx/emptyState/emptyState.css +45 -13
  19. package/src/modules/dx/emptyState/emptyState.html +6 -4
  20. package/src/modules/dx/emptyState/emptyState.stories.ts +18 -38
  21. package/src/modules/dx/emptyState/emptyState.ts +11 -20
  22. package/src/modules/dx/footer/links.ts +3 -5
  23. package/src/modules/dx/header/__tests__/mockProps.ts +7 -1
  24. package/src/modules/dx/headerNav/__tests__/headerNav.test.ts +2 -4
  25. package/src/modules/dx/headerNav/headerNav.html +8 -6
  26. package/src/modules/dx/headerNav/headerNav.ts +2 -2
  27. package/src/modules/dx/headerSearch/headerSearch.html +2 -4
  28. package/src/modules/dx/headerSearch/headerSearch.ts +19 -25
  29. package/src/modules/dx/newsletterForm/newsletterForm.html +5 -3
  30. package/src/modules/dx/popover/popover.ts +11 -7
  31. package/src/modules/dx/searchResults/coveo.css +314 -111
  32. package/src/modules/dx/sidebar/__tests__/sidebar.test.ts +0 -70
  33. package/src/modules/dx/sidebar/sidebar.css +42 -23
  34. package/src/modules/dx/sidebar/sidebar.html +62 -40
  35. package/src/modules/dx/sidebar/sidebar.stories.ts +54 -4
  36. package/src/modules/dx/sidebar/sidebar.ts +126 -66
  37. package/src/modules/dx/sidebarSearch/__tests__/preloadedState.ts +3459 -0
  38. package/src/modules/dx/sidebarSearch/__tests__/sidebarSearch.test.ts +44 -0
  39. package/src/modules/dx/sidebarSearch/sidebarSearch.css +3 -0
  40. package/src/modules/dx/sidebarSearch/sidebarSearch.html +26 -0
  41. package/src/modules/dx/sidebarSearch/sidebarSearch.ts +358 -0
  42. package/src/modules/dx/sidebarSearch/utils.ts +2 -0
  43. package/src/modules/dx/sidebarSearchResult/__tests__/sidebarSearchResult.test.ts +55 -0
  44. package/src/modules/dx/sidebarSearchResult/sidebarSearchResult.css +36 -0
  45. package/src/modules/dx/sidebarSearchResult/sidebarSearchResult.html +14 -0
  46. package/src/modules/dx/sidebarSearchResult/sidebarSearchResult.ts +56 -0
  47. package/src/modules/dx/spinner/__tests__/spinner.test.ts +37 -0
  48. package/src/modules/dx/spinner/spinner.css +750 -0
  49. package/src/modules/dx/spinner/spinner.html +6 -0
  50. package/src/modules/dx/spinner/spinner.stories.ts +69 -0
  51. package/src/modules/dx/spinner/spinner.ts +20 -0
  52. package/src/modules/dx/tab/__tests__/tab.test.ts +112 -54
  53. package/src/modules/dx/tab/tab.css +91 -16
  54. package/src/modules/dx/tab/tab.html +10 -12
  55. package/src/modules/dx/tab/tab.stories.ts +57 -0
  56. package/src/modules/dx/tab/tab.ts +35 -28
  57. package/src/modules/dx/tooltip/tippy.css +1 -0
  58. package/src/modules/dx/treeTile/__tests__/treeTile.test.ts +1 -1
  59. package/src/modules/dx/treeTile/treeTile.css +3 -19
  60. package/src/modules/dx/treeTile/treeTile.html +4 -1
  61. package/src/modules/dx/treeTile/treeTile.ts +2 -2
  62. package/src/modules/helpers/sidebar/sidebar.css +21 -0
  63. package/src/modules/helpers/table/table.css +23 -7
  64. package/src/modules/utils/coveo/coveo.ts +60 -0
  65. package/src/modules/utils/highlight/highlight.ts +31 -0
  66. package/src/modules/utils/normalizers/normalizers.ts +3 -0
  67. package/src/modules/utils/recentSearches/__tests__/recentSearches.test.ts +79 -0
  68. package/src/modules/utils/recentSearches/recentSearches.ts +57 -0
  69. package/src/modules/utils/regexps/regexps.ts +5 -0
  70. package/LICENSE +0 -12
  71. package/src/modules/dx/headerNavOption/__tests__/headerNavOption.test.ts +0 -113
  72. package/src/modules/dx/headerNavOption/headerNavOption.css +0 -91
  73. package/src/modules/dx/headerNavOption/headerNavOption.html +0 -9
  74. package/src/modules/dx/headerNavOption/headerNavOption.ts +0 -31
  75. package/src/modules/dx/headerSearch/__tests__/mockProps.ts +0 -11
  76. package/src/modules/dx/tab/__tests__/mockProps.ts +0 -4
  77. package/src/modules/dx/tabPanel/__tests__/mockProps.ts +0 -4
  78. package/src/modules/dx/tabPanel/__tests__/tabPanel.test.ts +0 -46
  79. package/src/modules/dx/tabPanel/tabPanel.css +0 -9
  80. package/src/modules/dx/tabPanel/tabPanel.html +0 -13
  81. package/src/modules/dx/tabPanel/tabPanel.ts +0 -27
  82. package/src/modules/dx/tabs/__tests__/mockProps.ts +0 -3
  83. package/src/modules/dx/tabs/__tests__/tabs.test.ts +0 -47
  84. package/src/modules/dx/tabs/tabs.css +0 -7
  85. package/src/modules/dx/tabs/tabs.html +0 -21
  86. package/src/modules/dx/tabs/tabs.stories.ts +0 -74
  87. package/src/modules/dx/tabs/tabs.ts +0 -112
  88. package/src/modules/dx/tabs/uniqueId.ts +0 -6
@@ -0,0 +1,6 @@
1
+ <template>
2
+ <div role="status" class={containerClass}>
3
+ <div class="spinner_dot-a"></div>
4
+ <div class="spinner_dot-b"></div>
5
+ </div>
6
+ </template>
@@ -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,71 +1,129 @@
1
1
  import Tab from "dx/tab";
2
+ import Icon from "dx/icon";
3
+ import { track } from "dx/instrumentation";
2
4
  import { createRenderComponent } from "utils/tests";
3
- import mockProps from "./mockProps";
5
+
6
+ jest.mock("dx/instrumentation");
4
7
 
5
8
  const TAG = "dx-tab";
6
9
  const render = createRenderComponent(TAG, Tab);
7
10
 
8
- const makeAccessibleTab = (element: HTMLElement) => {
9
- const tablist = document.createElement("div");
10
- document.body.appendChild(tablist);
11
- tablist.setAttribute("role", "tablist");
12
- tablist.appendChild(element);
13
-
14
- const shadowRoot = element.shadowRoot;
15
- const button = shadowRoot && shadowRoot.querySelector("button");
16
- if (button) {
17
- button.setAttribute("aria-label", "Label");
18
- }
11
+ const PROPS = {
12
+ label: "documentation",
13
+ href: "/test"
19
14
  };
20
15
 
21
16
  describe(TAG, () => {
22
- it("renders an active tab", () => {
23
- const element = render({
24
- ...mockProps,
25
- active: true
26
- });
27
- makeAccessibleTab(element);
28
-
29
- const buttonEl = element.shadowRoot.querySelector("button");
30
- expect(buttonEl).not.toBeNull();
31
- // Using `startsWith` here instead of exactly matching the attribute
32
- // because something is auto-suffixing the id with `-${nextIndex}`
33
- expect(
34
- buttonEl.getAttribute("id").startsWith("tabs--1--tab--0")
35
- ).toEqual(true);
36
- expect(
37
- buttonEl
38
- .getAttribute("aria-controls")
39
- .startsWith("tabs--1--panel--0")
40
- ).toEqual(true);
41
- expect(buttonEl.getAttribute("aria-selected")).toEqual("true");
42
- expect(buttonEl.getAttribute("tabindex")).toEqual("0");
43
- expect(buttonEl.getAttribute("class")).toContain("tab-active");
17
+ it("renders a single link with a label", () => {
18
+ const element = render(PROPS);
19
+
20
+ const links: Array<HTMLAnchorElement> =
21
+ element.shadowRoot.querySelectorAll("a");
22
+
23
+ expect(links.length).toEqual(1);
24
+ const [singleLink] = links;
25
+ expect(singleLink.href).toMatch(PROPS.href);
26
+ expect(singleLink.classList).toHaveLength(2);
27
+ expect(singleLink.classList).toContain("nav-list-item");
28
+ expect(singleLink.classList).toContain("nav-list-item_default");
29
+
30
+ const span: HTMLElement = singleLink.querySelector("span")!;
31
+ expect(span.textContent).toBe(PROPS.label);
32
+
33
+ expect(element.shadowRoot.querySelector("button")).toBeNull();
44
34
 
45
35
  return expect(element).toBeAccessible();
46
36
  });
47
37
 
48
- it("renders an inactive panel", () => {
49
- const element = render({
50
- ...mockProps,
51
- active: false
52
- });
53
- makeAccessibleTab(element);
54
-
55
- const buttonEl = element.shadowRoot.querySelector("button");
56
- expect(buttonEl).not.toBeNull();
57
- expect(
58
- buttonEl.getAttribute("id").startsWith("tabs--1--tab--0")
59
- ).toEqual(true);
60
- expect(
61
- buttonEl
62
- .getAttribute("aria-controls")
63
- .startsWith("tabs--1--panel--0")
64
- ).toEqual(true);
65
- expect(buttonEl.getAttribute("aria-selected")).toEqual("false");
66
- expect(buttonEl.getAttribute("tabindex")).toEqual("-1");
67
- expect(buttonEl.getAttribute("class")).not.toContain("tab-active");
38
+ it("renders a link as active and small variant", () => {
39
+ const element = render({ ...PROPS, isActive: true, variant: "small" });
40
+
41
+ const link: HTMLAnchorElement = element.shadowRoot.querySelector("a");
42
+
43
+ expect(link.href).toMatch(PROPS.href);
44
+ expect(link.classList).toHaveLength(3);
45
+ expect(link.classList).toContain("nav-list-item");
46
+ expect(link.classList).toContain("nav-list-item_small");
47
+ expect(link.classList).toContain("state-active");
48
+
49
+ expect(element.shadowRoot.querySelector("button")).toBeNull();
68
50
 
69
51
  return expect(element).toBeAccessible();
70
52
  });
53
+
54
+ it("renders a button if no href provided", () => {
55
+ const label = "test button";
56
+ const element = render({ label });
57
+
58
+ const buttons: Array<HTMLButtonElement> =
59
+ element.shadowRoot.querySelectorAll("button");
60
+
61
+ expect(buttons).toHaveLength(1);
62
+ const [singleButton] = buttons;
63
+
64
+ expect(singleButton.classList).toHaveLength(2);
65
+ expect(singleButton.classList).toContain("nav-list-item");
66
+ expect(singleButton.classList).toContain("nav-list-item_default");
67
+
68
+ const span: HTMLElement = singleButton.querySelector("span")!;
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
+
87
+ const icon: Element & Icon = singleButton.querySelector("dx-icon")!;
88
+ expect(icon).not.toBeNull();
89
+ expect(icon.size).toBe("small");
90
+
91
+ return expect(element).toBeAccessible();
92
+ });
93
+
94
+ it("renders a button with label only if variant is small", () => {
95
+ const label = "test button";
96
+ const element = render({ label, variant: "small", useIcon: "true" });
97
+
98
+ const button: HTMLButtonElement =
99
+ element.shadowRoot.querySelector("button");
100
+
101
+ expect(button.classList).toHaveLength(2);
102
+ expect(button.classList).toContain("nav-list-item");
103
+ expect(button.classList).toContain("nav-list-item_small");
104
+
105
+ const span: HTMLElement = button.querySelector("span")!;
106
+ expect(span.textContent).toBe(label);
107
+
108
+ const icon: Element & Icon = button.querySelector("dx-icon")!;
109
+ expect(icon).not.toBeNull();
110
+ expect(icon.size).toBe("xsmall");
111
+
112
+ return expect(element).toBeAccessible();
113
+ });
114
+
115
+ it("calls track when the link is clicked", () => {
116
+ const element = render(PROPS);
117
+
118
+ const link: HTMLElement = element.shadowRoot.querySelector("a");
119
+ expect(link).not.toBeNull();
120
+ link.click();
121
+
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
+ });
128
+ });
71
129
  });
@@ -1,31 +1,106 @@
1
1
  @import "helpers/reset";
2
2
 
3
- .tab {
4
- color: var(--dx-g-blue-vibrant-20);
3
+ a {
4
+ text-decoration: none;
5
+ }
6
+
7
+ .nav-list-item {
8
+ --horizontal-spacing: var(
9
+ --dx-c-tab-horizontal-spacing,
10
+ var(--dx-g-spacing-md)
11
+ );
12
+
13
+ position: relative;
14
+ display: flex;
15
+ align-items: center;
16
+ height: var(--dx-g-spacing-xl);
5
17
  font-family: var(--dx-g-font-display);
6
- font-size: var(--dx-g-text-sm);
7
- text-transform: uppercase;
8
- font-weight: var(--dx-g-font-demi);
18
+ white-space: nowrap;
19
+ color: var(--dx-g-blue-vibrant-20);
9
20
  transition: var(--dx-g-transition-hue-1x);
21
+ cursor: pointer;
22
+ outline-offset: -1px;
10
23
  }
11
24
 
12
- .tab-small {
25
+ .nav-list-item_default {
26
+ border: 0;
27
+ border-radius: var(--dx-g-spacing-md);
28
+ font-size: var(--dx-g-text-sm);
29
+ padding: 0 var(--horizontal-spacing);
30
+ }
31
+
32
+ .nav-list-item_small {
33
+ --border-color: transparent;
34
+
35
+ border-bottom: 2px solid var(--border-color);
13
36
  font-size: var(--dx-g-text-xs);
37
+ height: calc(var(--dx-g-spacing-xl) - 2px);
38
+ margin: 0 var(--horizontal-spacing);
39
+ }
40
+
41
+ .nav-list-item > span {
42
+ margin-top: var(--dx-g-spacing-xs);
43
+ }
44
+
45
+ button.nav-list-item_default > dx-icon {
46
+ margin-left: var(--dx-g-spacing-sm);
47
+ }
48
+
49
+ button.nav-list-item_small > dx-icon {
50
+ margin-left: var(--dx-g-spacing-xs);
14
51
  }
15
52
 
16
- .tab-primary {
17
- border-color: var(--dx-g-blue-vibrant-20);
18
- padding-bottom: calc(var(--dx-g-spacing-xs) + var(--dx-g-spacing-2xs));
53
+ .nav-list-item_default:hover,
54
+ .nav-list-item_default:active,
55
+ :host([aria-expanded="true"]) button.nav-list-item_default {
56
+ background: var(
57
+ --dx-g-brand-current-button-color-background-inactive,
58
+ var(--dx-g-brand-default-button-color-background-inactive)
59
+ );
19
60
  }
20
61
 
21
- .tab-primary:hover {
22
- padding-bottom: var(--dx-g-spacing-xs);
23
- border-bottom-width: var(--dx-g-spacing-2xs);
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 {
65
+ transform: rotateX(180deg);
24
66
  }
25
67
 
26
- .tab-primary.tab-active {
68
+ .nav-list-item_small:hover,
69
+ .nav-list-item_small:active,
70
+ :host([aria-expanded="true"]) button.nav-list-item_small {
71
+ --border-color: var(--dx-g-blue-vibrant-40);
72
+
73
+ color: var(--dx-g-blue-vibrant-40);
74
+ }
75
+
76
+ .nav-list-item_small.state-active {
77
+ --border-color: var(--dx-g-blue-vibrant-50);
78
+
27
79
  color: var(--dx-g-blue-vibrant-50);
28
- border-color: var(--dx-g-blue-vibrant-50);
29
- padding-bottom: var(--dx-g-spacing-xs);
30
- border-bottom-width: var(--dx-g-spacing-2xs);
80
+ }
81
+
82
+ .nav-list-item_default.state-active {
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));
88
+ }
89
+
90
+ @media (max-width: 1160px) {
91
+ .nav-list-item_small {
92
+ --horizontal-spacing: var(
93
+ --dx-c-tab-horizontal-spacing,
94
+ var(--dx-g-spacing-smd)
95
+ );
96
+ }
97
+ }
98
+
99
+ @media (max-width: 1090px) {
100
+ .nav-list-item_small {
101
+ --horizontal-spacing: var(
102
+ --dx-c-tab-horizontal-spacing,
103
+ var(--dx-g-spacing-sm)
104
+ );
105
+ }
31
106
  }
@@ -1,15 +1,13 @@
1
1
  <template>
2
- <button
3
- role="tab"
4
- part="tab"
5
- id={tabId}
6
- onclick={onClick}
7
- class={className}
8
- tabindex={activeTabIndex}
9
- aria-controls={panelId}
10
- aria-label="Tab button"
11
- aria-selected={active}
12
- >
13
- <slot></slot>
2
+ <a if:true={href} class={className} href={href} onclick={sendGtm}>
3
+ <span>{label}</span>
4
+ </a>
5
+ <button if:false={href} class={className}>
6
+ <span>{label}</span>
7
+ <dx-icon
8
+ if:true={useIcon}
9
+ symbol="chevrondown"
10
+ size={iconSize}
11
+ ></dx-icon>
14
12
  </button>
15
13
  </template>
@@ -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,45 +1,52 @@
1
1
  import { LightningElement, api } from "lwc";
2
+ import { track } from "dx/instrumentation";
2
3
  import cx from "classnames";
4
+ import { TabVariant } from "typings/custom";
5
+ import { normalizeBoolean } from "utils/normalizers";
6
+
3
7
  export default class Tab extends LightningElement {
4
- @api groupId!: string;
5
- @api index!: number;
6
- @api active: boolean = false;
7
- @api small: boolean = false;
8
-
9
- @api focus() {
10
- const button = this.template.querySelector("button");
11
- if (!button) {
12
- return;
13
- }
14
- button.focus();
8
+ @api label: string | null = null;
9
+ @api href: string | null = null;
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);
15
19
  }
16
20
 
17
- private get activeTabIndex() {
18
- return this.active ? 0 : -1;
21
+ @api
22
+ get useIcon() {
23
+ return this._useIcon;
19
24
  }
20
25
 
21
- private get panelId() {
22
- return `tabs--${this.groupId}--panel--${this.index}`;
26
+ set useIcon(value) {
27
+ this._useIcon = normalizeBoolean(value);
23
28
  }
24
29
 
25
- private get tabId() {
26
- return `tabs--${this.groupId}--tab--${this.index}`;
30
+ _useIcon = false;
31
+ _isActive = false;
32
+
33
+ private sendGtm(e: PointerEvent) {
34
+ track(e.currentTarget!, "custEv_topNavLinkClick", {
35
+ navHeading: this.label || undefined,
36
+ clickText: this.href || undefined,
37
+ pageLocation: window.location.pathname
38
+ });
27
39
  }
28
40
 
29
- private get className() {
41
+ get className() {
30
42
  return cx(
31
- "tab",
32
- "tab-primary",
33
- this.small && "tab-small",
34
- this.active && "tab-active"
43
+ "nav-list-item",
44
+ this.isActive && "state-active",
45
+ `nav-list-item_${this.variant}`
35
46
  );
36
47
  }
37
48
 
38
- private onClick() {
39
- this.dispatchEvent(
40
- new CustomEvent("select", {
41
- detail: this.index
42
- })
43
- );
49
+ get iconSize() {
50
+ return this.variant === "small" ? "xsmall" : "small";
44
51
  }
45
52
  }
@@ -0,0 +1 @@
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}
@@ -109,7 +109,7 @@ describe(TAG, () => {
109
109
  isSelected: true
110
110
  });
111
111
  const tileAnchor: HTMLElement = component.shadowRoot.querySelector(
112
- "a.tile.tile-selected"
112
+ "a.tile.sidebar-item-selected"
113
113
  );
114
114
  expect(tileAnchor).not.toBeNull();
115
115
  expect(tileAnchor.classList).toHaveLength(2);
@@ -1,3 +1,6 @@
1
+ @import "helpers/reset";
2
+ @import "helpers/sidebar";
3
+
1
4
  :host {
2
5
  display: block;
3
6
 
@@ -22,11 +25,6 @@
22
25
  font-family: var(--dx-g-font-sans);
23
26
  font-size: 13px;
24
27
  line-height: var(--tile-height);
25
- padding: 6px var(--dx-g-spacing-md);
26
- }
27
-
28
- .tile:not(.tile-selected):hover {
29
- background-color: var(--dx-g-gray-90);
30
28
  }
31
29
 
32
30
  .tile-root {
@@ -37,20 +35,6 @@
37
35
  display: block;
38
36
  }
39
37
 
40
- .tile-selected {
41
- background: var(--dx-g-cloud-blue-vibrant-95);
42
- box-shadow: inset var(--dx-g-spacing-xs) 0 0 0 var(--dx-g-blue-vibrant-60);
43
- border-radius: 0;
44
- }
45
-
46
- .truncate {
47
- display: -webkit-box;
48
- overflow: hidden;
49
- word-break: break-word;
50
- -webkit-box-orient: vertical;
51
- -webkit-line-clamp: 2;
52
- }
53
-
54
38
  .tile-icon {
55
39
  align-items: center;
56
40
  height: var(--tile-height);
@@ -1,7 +1,10 @@
1
1
  <template>
2
2
  <a href={href} class={tileClass}>
3
3
  <div class="flex indentation" aria-level={tileAriaLevel}>
4
- <span class="tile-label truncate" title={treeNode.label}>
4
+ <span
5
+ class="tile-label sidebar-item-truncate-text"
6
+ title={treeNode.label}
7
+ >
5
8
  {treeNode.label}
6
9
  </span>
7
10
  <div class="flex tile-expand-icon tile-icon" if:true={hasChildren}>
@@ -44,10 +44,10 @@ export default class TreeTile extends LightningElement {
44
44
  }
45
45
 
46
46
  private get tileClass() {
47
- return cx("tile", {
47
+ return cx("tile", "sidebar-item", {
48
48
  "tile-root": this.isRoot,
49
49
  "tile-with-children": !this.isRoot && this.hasChildren,
50
- "tile-selected": this.isSelected
50
+ "sidebar-item-selected": this.isSelected
51
51
  });
52
52
  }
53
53
 
@@ -0,0 +1,21 @@
1
+ .sidebar-item-truncate-text {
2
+ display: -webkit-box;
3
+ overflow: hidden;
4
+ word-break: break-word;
5
+ -webkit-box-orient: vertical;
6
+ -webkit-line-clamp: 2;
7
+ }
8
+
9
+ .sidebar-item-selected {
10
+ background: var(--dx-g-cloud-blue-vibrant-95);
11
+ box-shadow: inset var(--dx-g-spacing-xs) 0 0 0 var(--dx-g-blue-vibrant-60);
12
+ border-radius: 0;
13
+ }
14
+
15
+ .sidebar-item {
16
+ padding: 6px var(--dx-g-spacing-md);
17
+ }
18
+
19
+ .sidebar-item:not(.sidebar-item-selected):hover {
20
+ background-color: var(--dx-g-gray-90);
21
+ }