@salesforcedevs/dx-components 1.3.76 → 1.3.78

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 CHANGED
@@ -98,6 +98,7 @@
98
98
  "dxUtils/analytics",
99
99
  "dxUtils/async",
100
100
  "dxUtils/constants",
101
+ "dxUtils/contentTypes",
101
102
  "dxUtils/coveo",
102
103
  "dxUtils/dates",
103
104
  "dxUtils/highlight",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforcedevs/dx-components",
3
- "version": "1.3.76",
3
+ "version": "1.3.78",
4
4
  "description": "DX Lightning web components",
5
5
  "license": "MIT",
6
6
  "engines": {
@@ -40,5 +40,5 @@
40
40
  "eventsourcemock": "^2.0.0",
41
41
  "luxon": "^3.1.0"
42
42
  },
43
- "gitHead": "14f72dacd30bd66b65033fbf972f24510568296e"
43
+ "gitHead": "e5b62beb3fc195ec6d6d947fe5d5c84a26d141da"
44
44
  }
@@ -2,7 +2,6 @@
2
2
  <dx-modal
3
3
  if:true={hasTwoButtons}
4
4
  open={_modalOpen}
5
- ontogglemodal={toggleModal}
6
5
  onclosemodal={closeModal}
7
6
  >
8
7
  <dx-card-trial-expanded
@@ -24,6 +23,7 @@
24
23
  title={title}
25
24
  type-badge-value={modalTypeBadgeValue}
26
25
  type-badge-dark={modalTypeBadgeDark}
26
+ onclickclose={closeModal}
27
27
  ></dx-card-trial-expanded>
28
28
  </dx-modal>
29
29
  <div class="recommended-container" if:true={recommended}>
@@ -94,7 +94,7 @@
94
94
  <dx-button
95
95
  class="button-two"
96
96
  size="large"
97
- onclick={toggleModal}
97
+ onclick={openModal}
98
98
  variant="secondary"
99
99
  font="sans"
100
100
  icon-symbol={buttonTwoIcon}
@@ -96,8 +96,8 @@ export default class CardTrial extends LightningElement {
96
96
  return cx("details", this.hasButtons && "details_top-margin");
97
97
  }
98
98
 
99
- private toggleModal() {
100
- this._modalOpen = !this._modalOpen;
99
+ private openModal() {
100
+ this._modalOpen = true;
101
101
  }
102
102
 
103
103
  private closeModal() {
@@ -5,7 +5,7 @@
5
5
  class="button-close"
6
6
  variant="secondary"
7
7
  icon-symbol="close"
8
- onclick={handleModalClose}
8
+ onclick={onClickClose}
9
9
  >
10
10
  Close
11
11
  </dx-button>
@@ -40,13 +40,6 @@ export default class CardTrial extends LightningElement {
40
40
  private _colTwoDetails!: string[];
41
41
  private stickyCloseObserver!: IntersectionObserver;
42
42
 
43
- connectedCallback(): void {
44
- this.template.addEventListener(
45
- "keydown",
46
- this.handleKeyDown.bind(this)
47
- );
48
- }
49
-
50
43
  renderedCallback(): void {
51
44
  this.observeStickyClose();
52
45
  }
@@ -71,26 +64,8 @@ export default class CardTrial extends LightningElement {
71
64
  }
72
65
  }
73
66
 
74
- private handleKeyDown(event: KeyboardEvent): void {
75
- if (event.key === "Escape") {
76
- this.handleModalClose();
77
- }
78
- }
79
-
80
- private handleModalToggle() {
81
- this.dispatchEvent(
82
- new CustomEvent("togglemodal", {
83
- bubbles: true
84
- })
85
- );
86
- }
87
-
88
- private handleModalClose() {
89
- this.dispatchEvent(
90
- new CustomEvent("closemodal", {
91
- bubbles: true
92
- })
93
- );
67
+ private onClickClose() {
68
+ this.dispatchEvent(new CustomEvent("clickclose"));
94
69
  }
95
70
 
96
71
  private handleSignUpClick(e: PointerEvent) {
@@ -1,40 +1,7 @@
1
- :host {
2
- --dx-c-modal-drawer-z-index: 5000;
1
+ .dx-modal-drawer_container {
2
+ display: none !important;
3
3
  }
4
4
 
5
- .modal-drawer_container {
6
- display: none;
7
- }
8
-
9
- .modal-drawer_container.modal-drawer_active {
10
- position: fixed;
11
- top: 50%;
12
- left: 50%;
13
- transform: translate(-50%, -50%);
14
- display: grid;
15
- justify-content: center;
16
- align-items: center;
17
- z-index: var(--dx-c-modal-drawer-z-index);
18
- height: 100%;
19
- width: 100%;
20
- pointer-events: none;
21
- }
22
-
23
- .modal-drawer_overlay {
24
- background-color: #195594;
25
- bottom: 0;
26
- height: 100%;
27
- left: 0;
28
- opacity: 0.62;
29
- position: fixed;
30
- right: 0;
31
- top: 0;
32
- width: 100%;
33
- z-index: calc(var(--dx-c-modal-drawer-z-index) - 1);
34
- }
35
-
36
- @media screen and (max-width: 768px) {
37
- .modal-drawer_container.modal-drawer_active {
38
- pointer-events: all;
39
- }
5
+ .dx-modal-drawer_overlay {
6
+ display: none !important;
40
7
  }
@@ -1,10 +1,13 @@
1
1
  <template>
2
- <div class={containerClass} tabindex="0" role="dialog">
3
- <slot></slot>
4
- </div>
5
2
  <div
6
- if:true={open}
7
- class="modal-drawer_overlay"
8
- onclick={handleCloseModal}
9
- ></div>
3
+ class={containerClass}
4
+ onclick={onClickModal}
5
+ tabindex="0"
6
+ role="dialog"
7
+ >
8
+ <div style="pointer-events: all">
9
+ <slot onslotchange={onSlotChange}></slot>
10
+ </div>
11
+ </div>
12
+ <div class={overlayClass} onclick={onClickModal}></div>
10
13
  </template>
@@ -1,55 +1,98 @@
1
- import cx from "classnames";
2
1
  import { LightningElement, api } from "lwc";
3
2
  import { normalizeBoolean } from "dxUtils/normalizers";
3
+ import { LightningSlotElement } from "typings/custom";
4
+
5
+ const CONTAINER_CLASS = "dx-modal-drawer_container";
6
+ const OVERLAY_CLASS = "dx-modal-drawer_overlay";
7
+
8
+ const modalStyle =
9
+ "position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); display: grid; justify-content: center; align-items: center; z-index: 5000; height: 100%; width: 100%; pointer-events: none;";
10
+ const overlayStyle =
11
+ "background-color: #195594; bottom: 0; height: 100%; left: 0; opacity: 0.62; position: fixed; right: 0; top: 0; width: 100%; z-index: calc(5000 - 1);";
4
12
 
5
13
  export default class Modal extends LightningElement {
6
14
  private _open = false;
7
-
8
15
  @api get open() {
9
16
  return this._open;
10
17
  }
11
-
12
18
  set open(value) {
13
19
  this._open = normalizeBoolean(value);
20
+ if (this._open) {
21
+ this.openModal();
22
+ } else {
23
+ this.closeModal();
24
+ }
14
25
  }
15
26
 
27
+ private overlayClass = OVERLAY_CLASS;
28
+ private modal: HTMLElement | null = null;
29
+ private overlay: HTMLElement | null = null;
30
+ private root: HTMLElement | null = null;
31
+ private modalContent: HTMLElement | null = null;
32
+ private keydownListener: Event | null = null;
33
+
16
34
  get containerClass(): string {
17
- return cx(
18
- "modal-drawer_container",
19
- this._open && "modal-drawer_active"
20
- );
35
+ return CONTAINER_CLASS;
21
36
  }
22
37
 
23
- renderedCallback(): void {
24
- if (this._open) {
25
- this.focusFirstElement();
38
+ private onSlotChange = (e: LightningSlotElement) => {
39
+ // @ts-ignore
40
+ this.modalContent = e.target.assignedElements()[0];
41
+ if (!this.modal && !this.overlay) {
42
+ this.appendModalToHTML();
26
43
  }
27
- }
44
+ };
28
45
 
29
- connectedCallback(): void {
30
- this.template.addEventListener(
31
- "keydown",
32
- this.handleKeyDown.bind(this)
33
- );
46
+ private connectedCallback(): void {
47
+ document.addEventListener("keydown", this.handleKeyDown.bind(this));
34
48
  }
35
49
 
36
- focusFirstElement(): void {
37
- this.template.querySelector("div")!.focus();
50
+ private disconnectedCallback(): void {
51
+ window.removeEventListener("keydown", this.handleKeyDown.bind(this));
52
+ this.modal?.remove();
53
+ this.overlay?.remove();
38
54
  }
39
55
 
40
- handleKeyDown(event: KeyboardEvent): void {
56
+ private handleKeyDown(event: KeyboardEvent): void {
41
57
  if (event.key === "Escape") {
42
- this.handleCloseModal();
58
+ this.closeModal();
43
59
  }
44
60
  }
45
61
 
46
- handleToggleModal() {
47
- this._open = !this._open;
48
- this.dispatchEvent(new CustomEvent("togglemodal"));
62
+ private appendModalToHTML = () => {
63
+ // @ts-ignore
64
+ this.root = document.querySelector("html");
65
+ this.modal = this.template.querySelector(`.${CONTAINER_CLASS}`);
66
+ this.overlay = this.template.querySelector(`.${OVERLAY_CLASS}`);
67
+ if (this.overlay && this.modal && this.modalContent && this.root) {
68
+ this.modal.setAttribute("style", modalStyle);
69
+ this.overlay.setAttribute("style", overlayStyle);
70
+ this.modal.querySelector("div")?.appendChild(this.modalContent);
71
+ if (this.open) {
72
+ this.openModal();
73
+ }
74
+ }
75
+ };
76
+
77
+ private onClickModal(e) {
78
+ if (e?.target?.className === OVERLAY_CLASS) {
79
+ this.closeModal();
80
+ }
49
81
  }
50
82
 
51
- handleCloseModal() {
52
- this._open = false;
53
- this.dispatchEvent(new CustomEvent("closemodal"));
83
+ private openModal() {
84
+ if (this.overlay && this.modal) {
85
+ this.root?.appendChild(this.modal);
86
+ this.root?.appendChild(this.overlay);
87
+ this.modal.querySelector("div")?.focus();
88
+ }
54
89
  }
90
+
91
+ private closeModal = () => {
92
+ if (this.modal && this.overlay) {
93
+ this.modal.remove();
94
+ this.overlay.remove();
95
+ this.dispatchEvent(new CustomEvent("closemodal"));
96
+ }
97
+ };
55
98
  }
@@ -1,4 +1,5 @@
1
1
  @import "dxHelpers/reset";
2
+ @import "dxHelpers/typeBadge";
2
3
  @import "./coveo.css";
3
4
 
4
5
  /* stylelint-disable selector-class-pattern */
@@ -385,3 +386,8 @@ a.CoveoResultLink,
385
386
  margin: 0 auto;
386
387
  width: fit-content;
387
388
  }
389
+
390
+ .dx-badge {
391
+ display: block;
392
+ margin-bottom: var(--dx-g-spacing-smd);
393
+ }
@@ -1,6 +1,8 @@
1
1
  import { LightningElement, api, track } from "lwc";
2
2
  import type * as CoveoSDK from "coveo-search-ui";
3
3
  import { track as trackGTM } from "dxUtils/analytics";
4
+ import { CONTENT_TYPE_LABELS } from "dxConstants/contentTypes";
5
+ import { getContentTypeColorVariables } from "dxUtils/contentTypes";
4
6
 
5
7
  interface CoveoSearch {
6
8
  state: typeof CoveoSDK.state;
@@ -40,6 +42,7 @@ const resultsTemplatesInnerHtml = `
40
42
  data-field-publicurl=""
41
43
  >
42
44
  <div class="dx-result">
45
+ <span class="CoveoFieldValue" data-field="@content_type" data-helper="badge" data-html-value="true"></span>
43
46
  <p class="dx-result-title">
44
47
  <a
45
48
  class="CoveoResultLink"
@@ -55,6 +58,7 @@ const resultsTemplatesInnerHtml = `
55
58
  type="text/html"
56
59
  >
57
60
  <div class="dx-result">
61
+ <span class="CoveoFieldValue" data-field="@content_type" data-helper="badge" data-html-value="true"></span>
58
62
  <p class="dx-result-title">
59
63
  <a class="CoveoResultLink"></a>
60
64
  </p>
@@ -173,6 +177,15 @@ export default class SearchResults extends LightningElement {
173
177
 
174
178
  this.attachListeners(this.root);
175
179
 
180
+ Coveo.TemplateHelpers.registerTemplateHelper(
181
+ "badge",
182
+ (value: string) => {
183
+ const style = getContentTypeColorVariables(value);
184
+ const label = CONTENT_TYPE_LABELS[value];
185
+ return `<div style="${style}" class="dx-badge"><span>${label}</span></div>`;
186
+ }
187
+ );
188
+
176
189
  Coveo.init(this.root);
177
190
  }
178
191
 
@@ -1,33 +1,2 @@
1
1
  @import "dxHelpers/reset";
2
-
3
- .badge {
4
- --background: var(--sds-g-gray-3);
5
- --border-radius: var(--dx-g-spacing-smd);
6
- --color: var(--sds-g-gray-10);
7
- --height: var(--dx-g-spacing-lg);
8
- --horizontal-spacing: var(--dx-g-spacing-smd);
9
- --vertical-spacing: var(--dx-g-spacing-xs);
10
-
11
- color: var(--dx-c-type-badge-color, var(--color));
12
- background: var(--dx-c-type-badge-background, var(--background));
13
- border-radius: var(--border-radius);
14
- display: flex;
15
- align-items: center;
16
- justify-content: center;
17
- height: var(--height);
18
- width: min-content;
19
- text-align: center;
20
- white-space: nowrap;
21
- font-family: var(--dx-g-font-sans);
22
- font-size: 10px;
23
- font-weight: var(--dx-g-font-bold);
24
- padding: var(--vertical-spacing) var(--horizontal-spacing);
25
- }
26
-
27
- .badge.size-small {
28
- --height: var(--dx-g-spacing-mlg);
29
- }
30
-
31
- dx-icon {
32
- margin-right: var(--dx-g-spacing-sm);
33
- }
2
+ @import "dxHelpers/typeBadge";
@@ -5,65 +5,20 @@ import {
5
5
  Color,
6
6
  ContentType,
7
7
  IconSprite,
8
+ IconData,
8
9
  IconSymbol,
9
10
  TypeBadgeSize
10
11
  } from "typings/custom";
11
12
  import { colorToDxColors, buildStyleColorVariables } from "dxUtils/css";
12
- import { BRANDS } from "dxConstants/brands";
13
- import { CONTENT_TYPES } from "dxConstants/contentTypes";
14
-
15
- const contentTypeLabels = {
16
- documentation: "Documentation",
17
- trailhead: "Trailhead",
18
- blog: "Blog",
19
- forum: "Forum",
20
- api: "API",
21
- event: "Event",
22
- website: "Website",
23
- podcast: "Podcast"
24
- };
25
-
26
- type IconData = {
27
- iconSymbol: IconSymbol;
28
- iconSprite: IconSprite;
29
- };
30
-
31
- const contentTypeIcons: {
32
- [K in ContentType]: IconData;
33
- } = {
34
- documentation: {
35
- iconSprite: "utility",
36
- iconSymbol: "knowledge_base"
37
- },
38
- trailhead: {
39
- iconSprite: "salesforcebrand",
40
- iconSymbol: "learning"
41
- },
42
- blog: {
43
- iconSprite: "utility",
44
- iconSymbol: "comments"
45
- },
46
- forum: {
47
- iconSprite: "general",
48
- iconSymbol: "question-circle"
49
- },
50
- api: {
51
- iconSprite: "utility",
52
- iconSymbol: "settings"
53
- },
54
- event: {
55
- iconSprite: "utility",
56
- iconSymbol: "event"
57
- },
58
- website: {
59
- iconSprite: "utility",
60
- iconSymbol: "home"
61
- },
62
- podcast: {
63
- iconSprite: "utility",
64
- iconSymbol: "unmuted"
65
- }
66
- };
13
+ import {
14
+ isContentType,
15
+ getContentTypeColorScope,
16
+ getContentTypeColorVariables
17
+ } from "dxUtils/contentTypes";
18
+ import {
19
+ CONTENT_TYPE_LABELS,
20
+ CONTENT_TYPE_ICONS
21
+ } from "dxConstants/contentTypes";
67
22
 
68
23
  export default class TypeBadge extends LightningElement {
69
24
  @api size: TypeBadgeSize = "default";
@@ -111,39 +66,29 @@ export default class TypeBadge extends LightningElement {
111
66
  private _iconSymbol?: IconSymbol;
112
67
 
113
68
  private get variantIconData(): IconData | null {
114
- if (this.variant && this.variant in contentTypeIcons) {
115
- return contentTypeIcons[this.variant as ContentType];
69
+ if (this.variant && this.variant in CONTENT_TYPE_ICONS) {
70
+ return CONTENT_TYPE_ICONS[this.variant as ContentType];
116
71
  }
117
72
  return null;
118
73
  }
119
74
 
120
75
  private get variantLabel(): string | null {
121
76
  if (this.isContentType) {
122
- return contentTypeLabels[this.variant as ContentType];
77
+ return CONTENT_TYPE_LABELS[this.variant as ContentType];
123
78
  }
124
79
  return null;
125
80
  }
126
81
 
127
82
  private get variantColorScope(): string | null {
128
- if (this.isContentType) {
129
- return "content-type";
130
- }
131
- if (this.isBrand) {
132
- return "brand";
133
- }
134
- return null;
83
+ return getContentTypeColorScope(this.variant);
135
84
  }
136
85
 
137
86
  private get isContentType(): boolean {
138
- return CONTENT_TYPES.includes(this.variant as ContentType);
139
- }
140
-
141
- private get isBrand(): boolean {
142
- return BRANDS.includes(this.variant as ContentType);
87
+ return isContentType(this.variant);
143
88
  }
144
89
 
145
90
  private get className(): string {
146
- return cx("badge", `size-${this.size}`);
91
+ return cx("dx-badge", `size-${this.size}`);
147
92
  }
148
93
 
149
94
  private get style(): string {
@@ -154,10 +99,7 @@ export default class TypeBadge extends LightningElement {
154
99
  });
155
100
  }
156
101
  if (this.variantColorScope) {
157
- return buildStyleColorVariables({
158
- background: `--dx-g-${this.variantColorScope}-${this.variant}-color-background`,
159
- color: `--dx-g-${this.variantColorScope}-${this.variant}-color`
160
- });
102
+ return getContentTypeColorVariables(this.variant);
161
103
  }
162
104
  if (this.color) {
163
105
  const variables = colorToDxColors(this.color as Color);
@@ -1,3 +1,53 @@
1
+ import { ContentType, IconData } from "typings/custom";
2
+
3
+ export const CONTENT_TYPE_LABELS = {
4
+ documentation: "Documentation",
5
+ trailhead: "Trailhead",
6
+ blog: "Blog",
7
+ forum: "Forum",
8
+ api: "API",
9
+ event: "Event",
10
+ website: "Website",
11
+ podcast: "Podcast"
12
+ };
13
+
14
+ export const CONTENT_TYPE_ICONS: {
15
+ [K in ContentType]: IconData;
16
+ } = {
17
+ documentation: {
18
+ iconSprite: "utility",
19
+ iconSymbol: "knowledge_base"
20
+ },
21
+ trailhead: {
22
+ iconSprite: "salesforcebrand",
23
+ iconSymbol: "learning"
24
+ },
25
+ blog: {
26
+ iconSprite: "utility",
27
+ iconSymbol: "comments"
28
+ },
29
+ forum: {
30
+ iconSprite: "general",
31
+ iconSymbol: "question-circle"
32
+ },
33
+ api: {
34
+ iconSprite: "utility",
35
+ iconSymbol: "settings"
36
+ },
37
+ event: {
38
+ iconSprite: "utility",
39
+ iconSymbol: "event"
40
+ },
41
+ website: {
42
+ iconSprite: "utility",
43
+ iconSymbol: "home"
44
+ },
45
+ podcast: {
46
+ iconSprite: "utility",
47
+ iconSymbol: "unmuted"
48
+ }
49
+ };
50
+
1
51
  export const CONTENT_TYPES = [
2
52
  "documentation",
3
53
  "trailhead",
@@ -0,0 +1,31 @@
1
+ .dx-badge {
2
+ --background: var(--sds-g-gray-3);
3
+ --border-radius: var(--dx-g-spacing-smd);
4
+ --color: var(--sds-g-gray-10);
5
+ --height: var(--dx-g-spacing-lg);
6
+ --horizontal-spacing: var(--dx-g-spacing-smd);
7
+ --vertical-spacing: var(--dx-g-spacing-xs);
8
+
9
+ color: var(--dx-c-type-badge-color, var(--color));
10
+ background: var(--dx-c-type-badge-background, var(--background));
11
+ border-radius: var(--border-radius);
12
+ display: flex;
13
+ align-items: center;
14
+ justify-content: center;
15
+ height: var(--height);
16
+ width: min-content;
17
+ text-align: center;
18
+ white-space: nowrap;
19
+ font-family: var(--dx-g-font-sans);
20
+ font-size: 10px;
21
+ font-weight: var(--dx-g-font-bold);
22
+ padding: var(--vertical-spacing) var(--horizontal-spacing);
23
+ }
24
+
25
+ .dx-badge.size-small {
26
+ --height: var(--dx-g-spacing-mlg);
27
+ }
28
+
29
+ dx-icon {
30
+ margin-right: var(--dx-g-spacing-sm);
31
+ }
@@ -0,0 +1,30 @@
1
+ import { CONTENT_TYPES } from "dxConstants/contentTypes";
2
+ import { BRANDS } from "dxConstants/brands";
3
+ import { ContentType } from "typings/custom";
4
+ import { buildStyleColorVariables } from "dxUtils/css";
5
+
6
+ export const isBrand = (id: string): boolean => {
7
+ return BRANDS.includes(id as ContentType);
8
+ };
9
+
10
+ export const isContentType = (id: string): boolean => {
11
+ return CONTENT_TYPES.includes(id as ContentType);
12
+ };
13
+
14
+ export const getContentTypeColorScope = (id: string): string | null => {
15
+ if (isContentType(id)) {
16
+ return "content-type";
17
+ }
18
+ if (isBrand(id)) {
19
+ return "brand";
20
+ }
21
+ return null;
22
+ };
23
+
24
+ export const getContentTypeColorVariables = (id: string): string => {
25
+ const scope = getContentTypeColorScope(id);
26
+ return buildStyleColorVariables({
27
+ background: `--dx-g-${scope}-${id}-color-background`,
28
+ color: `--dx-g-${scope}-${id}-color`
29
+ });
30
+ };