@salesforcedevs/dx-components 1.3.366 → 1.3.367

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
@@ -37,6 +37,7 @@
37
37
  "dx/checkboxNative",
38
38
  "dx/codeBlock",
39
39
  "dx/coveoRecommendations",
40
+ "dx/darkModeManager",
40
41
  "dx/dropdown",
41
42
  "dx/embeddedVideo",
42
43
  "dx/emptyState",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforcedevs/dx-components",
3
- "version": "1.3.366",
3
+ "version": "1.3.367",
4
4
  "description": "DX Lightning web components",
5
5
  "license": "MIT",
6
6
  "engines": {
@@ -46,5 +46,5 @@
46
46
  "volta": {
47
47
  "node": "18.18.0"
48
48
  },
49
- "gitHead": "879600edad044c730d365d3737f72f9f5eaec399"
49
+ "gitHead": "bed257f995a2a4bd7b377a7431a1b7c51b133602"
50
50
  }
@@ -11,7 +11,8 @@
11
11
  --dx-c-button-secondary-color-hover: var(
12
12
  --dx-g-button-secondary-color-hover
13
13
  );
14
- --dx-c-button-inline-color-hover: var(--dx-g-blue-vibrant-30);
14
+ --dx-c-button-inline-color: var(--dx-g-button-inline-color);
15
+ --dx-c-button-inline-color-hover: var(--dx-g-button-inline-color-hover);
15
16
  --dx-c-button-justify-content: center;
16
17
  --dx-c-button-opacity: 1;
17
18
  --dx-c-button-font-size: var(--dx-g-text-sm);
@@ -168,7 +169,7 @@
168
169
  .button.variant_tertiary,
169
170
  .button.variant_inline,
170
171
  .button.variant_inline-inherit {
171
- color: var(--dx-c-button-primary-color);
172
+ color: var(--dx-c-button-inline-color);
172
173
  border: 1px solid transparent;
173
174
  }
174
175
 
@@ -49,7 +49,7 @@
49
49
  <div class="toolbar-item">
50
50
  <dx-tooltip label={updateThemeBtnText} placement="top-left">
51
51
  <dx-button
52
- onclick={updateTheme}
52
+ onclick={updateThemeClicked}
53
53
  type="button"
54
54
  icon-symbol="away"
55
55
  variant="tertiary"
@@ -1,13 +1,16 @@
1
- import { LightningElement, api, wire, track } from "lwc";
1
+ import { LightningElement, api } from "lwc";
2
2
  import { CodeBlockTheme, CodeBlockLanguage } from "typings/custom";
3
3
  import cx from "classnames";
4
- import {
5
- getLocalStorageData,
6
- setLocalStorageData
7
- } from "@salesforcedevs/sfdocs-wires";
8
4
  import { track as gtmTrack } from "dxUtils/analytics";
9
5
  import prism from "dxUtils/prismjs";
10
6
  import { ampscript, sqlDocsTemplate } from "./customLanguages";
7
+ import {
8
+ DARK_MODE_THEMES,
9
+ DARKMODE_TOGGLE_EVENT_NAME,
10
+ dispatchDarkModeToggleEvent,
11
+ getLocalStorageDarkModeSetting,
12
+ setLocalStorageDarkModeSetting
13
+ } from "dx/darkModeManager";
11
14
 
12
15
  /*
13
16
  Here we create custom syntax highlighting rules for proprietary languages
@@ -41,8 +44,6 @@ const preTagRegexp: RegExp = /^<pre.*?>(.*)<\/pre>$/is;
41
44
 
42
45
  export const LIGHT = "light";
43
46
  export const DARK = "dark";
44
- const themes: CodeBlockTheme[] = [LIGHT, DARK];
45
- const LOCAL_STORAGE_KEY = "dx-codeblock-theme";
46
47
 
47
48
  export default class CodeBlock extends LightningElement {
48
49
  @api defaultTheme: CodeBlockTheme = LIGHT;
@@ -52,6 +53,8 @@ export default class CodeBlock extends LightningElement {
52
53
  // if it is true, it renders code as is coming instead of wrapping it into html/xml comments tags.
53
54
  @api isEncoded = false;
54
55
 
56
+ theme: CodeBlockTheme | null = null;
57
+
55
58
  private markupLangs = ["visualforce", "html", "xml"];
56
59
  private _codeBlockRendered: boolean = false;
57
60
  private componentLoaded: boolean = false;
@@ -95,10 +98,20 @@ export default class CodeBlock extends LightningElement {
95
98
  { label: "SQL Documentation", id: "sql_docs_template" }
96
99
  ];
97
100
 
101
+ private initializeDarkMode() {
102
+ window.addEventListener(DARKMODE_TOGGLE_EVENT_NAME, this.toggleTheme);
103
+ const darkModeSetting =
104
+ getLocalStorageDarkModeSetting() as CodeBlockTheme;
105
+ if (DARK_MODE_THEMES.includes(darkModeSetting)) {
106
+ this.theme = darkModeSetting;
107
+ }
108
+ }
109
+
98
110
  connectedCallback() {
99
111
  if (!this.theme) {
100
112
  this.theme = this.defaultTheme;
101
113
  }
114
+ this.initializeDarkMode();
102
115
  }
103
116
 
104
117
  _codeBlock: string = "";
@@ -117,20 +130,6 @@ export default class CodeBlock extends LightningElement {
117
130
  return this._codeBlock;
118
131
  }
119
132
 
120
- @track private theme: CodeBlockTheme | null = null;
121
-
122
- @wire(getLocalStorageData, { key: "dx-codeblock-theme" })
123
- updateThemeForCodeblock(value: any) {
124
- if (themes.includes(value)) {
125
- this.theme = value;
126
- } else {
127
- setLocalStorageData(
128
- LOCAL_STORAGE_KEY,
129
- this.theme || this.defaultTheme
130
- );
131
- }
132
- }
133
-
134
133
  get updateThemeBtnText(): string {
135
134
  return `Switch to ${this.theme === DARK ? "Light" : "Dark"} mode`;
136
135
  }
@@ -247,8 +246,8 @@ export default class CodeBlock extends LightningElement {
247
246
  * Note: There is a known issue in storybook@6.1.13 where some apis are not available if you access Storybook through IP address.
248
247
  * https://github.com/storybookjs/storybook/issues/13529
249
248
  */
250
- async copySource(event: any) {
251
- gtmTrack(event.target, "custEv_iconClick", {
249
+ async copySource(event: Event) {
250
+ gtmTrack(event.target!, "custEv_iconClick", {
252
251
  click_text: this.copyBtnText,
253
252
  element_type: "icon",
254
253
  element_title: this.copyBtnText,
@@ -272,18 +271,21 @@ export default class CodeBlock extends LightningElement {
272
271
  }
273
272
  }
274
273
 
275
- updateTheme(event: any) {
276
- this.theme = this.theme === DARK ? LIGHT : DARK;
277
- setLocalStorageData(LOCAL_STORAGE_KEY, this.theme);
278
-
279
- gtmTrack(event.target, "custEv_iconClick", {
274
+ updateThemeClicked(event: Event) {
275
+ gtmTrack(event.target!, "custEv_iconClick", {
280
276
  click_text: this.updateThemeBtnText,
281
277
  element_type: "icon",
282
278
  element_title: this.updateThemeBtnText,
283
279
  content_category: "code block"
284
280
  });
281
+ dispatchDarkModeToggleEvent();
285
282
  }
286
283
 
284
+ private toggleTheme = () => {
285
+ this.theme = this.theme === DARK ? LIGHT : DARK;
286
+ setLocalStorageDarkModeSetting(this.theme);
287
+ };
288
+
287
289
  renderedCallback() {
288
290
  if (this._codeBlockRendered) {
289
291
  return;
@@ -297,4 +299,11 @@ export default class CodeBlock extends LightningElement {
297
299
  this.formatCodeBlock();
298
300
  this._codeBlockRendered = true;
299
301
  }
302
+
303
+ disconnectedCallback(): void {
304
+ window.removeEventListener(
305
+ DARKMODE_TOGGLE_EVENT_NAME,
306
+ this.toggleTheme
307
+ );
308
+ }
300
309
  }
@@ -0,0 +1 @@
1
+ <template></template>
@@ -0,0 +1,77 @@
1
+ /* eslint-disable @lwc/lwc/no-document-query */
2
+ import { LightningElement } from "lwc";
3
+
4
+ export const LOCAL_STORAGE_KEY = "dx-dark-mode-theme";
5
+
6
+ function setTheme(theme: string) {
7
+ const DWONavSelector = document.querySelector("hgf-c360contextnav");
8
+
9
+ document.body.setAttribute("class", theme);
10
+ DWONavSelector?.setAttribute("dark-mode", String(theme === "dark"));
11
+ localStorage.setItem(LOCAL_STORAGE_KEY, theme);
12
+ }
13
+
14
+ function isDarkMode() {
15
+ return document.body.getAttribute("class") === "dark";
16
+ }
17
+
18
+ function onDarkModeToggle() {
19
+ if (isDarkMode()) {
20
+ setTheme("light");
21
+ } else {
22
+ setTheme("dark");
23
+ }
24
+ }
25
+
26
+ declare module globalThis {
27
+ let singletonDarkModeManagerRendered: boolean;
28
+ }
29
+
30
+ export const DARK_MODE_THEMES = ["dark", "light"];
31
+ export const DARKMODE_TOGGLE_EVENT_NAME = "UPDATE_DARK_MODE";
32
+
33
+ export const isDarkModeEnabled = () => {
34
+ return process.env.DARK_MODE;
35
+ };
36
+
37
+ export const dispatchDarkModeToggleEvent = () => {
38
+ window.dispatchEvent(new Event(DARKMODE_TOGGLE_EVENT_NAME));
39
+ };
40
+
41
+ export const getLocalStorageDarkModeSetting = () => {
42
+ return localStorage.getItem(LOCAL_STORAGE_KEY);
43
+ };
44
+
45
+ export const setLocalStorageDarkModeSetting = (theme: string) => {
46
+ localStorage.setItem(LOCAL_STORAGE_KEY, theme);
47
+ };
48
+
49
+ export default class DarkModeManager extends LightningElement {
50
+ renderedCallback(): void {
51
+ if (
52
+ isDarkModeEnabled() &&
53
+ !globalThis.singletonDarkModeManagerRendered
54
+ ) {
55
+ const theme = getLocalStorageDarkModeSetting();
56
+ if (theme) {
57
+ if (DARK_MODE_THEMES.includes(theme)) {
58
+ setTheme(theme);
59
+ }
60
+ }
61
+ window.addEventListener(
62
+ DARKMODE_TOGGLE_EVENT_NAME,
63
+ onDarkModeToggle
64
+ );
65
+ globalThis.singletonDarkModeManagerRendered = true;
66
+ }
67
+ }
68
+
69
+ disconnectedCallback(): void {
70
+ if (isDarkModeEnabled()) {
71
+ window.removeEventListener(
72
+ DARKMODE_TOGGLE_EVENT_NAME,
73
+ onDarkModeToggle
74
+ );
75
+ }
76
+ }
77
+ }
@@ -34,6 +34,43 @@
34
34
  var(--dx-c-featured-content-header-padding-horizontal);
35
35
  }
36
36
 
37
+ .title-bar {
38
+ padding: 0 var(--dx-c-featured-content-header-padding-horizontal);
39
+ height: 100px;
40
+ display: flex;
41
+ align-items: center;
42
+ justify-content: space-between;
43
+ box-shadow: 0 0 0 2px #0003;
44
+ color: var(--label-color);
45
+ }
46
+
47
+ .title-bar h1 {
48
+ color: var(--label-color);
49
+ }
50
+
51
+ .title-bar p {
52
+ color: var(--label-color);
53
+ }
54
+
55
+ .dark-mode-button {
56
+ width: 44px;
57
+ height: 44px;
58
+ display: flex;
59
+ justify-content: center;
60
+ align-items: center;
61
+ background-color: var(--dx-g-dark-mode-toggle-button-color);
62
+ border: var(--dx-g-dark-mode-toggle-button-border);
63
+ border-radius: 4px;
64
+ cursor: pointer;
65
+ }
66
+
67
+ .dark-mode-icon {
68
+ height: 20px;
69
+ width: 20px;
70
+ background-size: 20px 20px;
71
+ background-image: var(--dx-g-dark-mode-toggle-icon);
72
+ }
73
+
37
74
  .container {
38
75
  --image-radius: var(--dx-g-spacing-smd);
39
76
 
@@ -161,46 +198,6 @@
161
198
  }
162
199
  }
163
200
 
164
- .custom-bg-blog::after {
165
- content: "";
166
- position: absolute;
167
- top: 0;
168
- left: 0;
169
- width: 100%;
170
- height: 100%;
171
- background-image: url("https://a.sfdcstatic.com/developer-website/images/fch-blog-cloud-1.png"),
172
- url("https://a.sfdcstatic.com/developer-website/images/fch-blog-cloud-2.png"),
173
- url("https://a.sfdcstatic.com/developer-website/images/fch-blog-planet.png");
174
- background-position: calc(100% + -60px) -80px, 67% calc(100% + -100px),
175
- 54% 70px;
176
- background-repeat: no-repeat, no-repeat, no-repeat;
177
- }
178
- @media screen and (max-width: 1024px) {
179
- .custom-bg-blog::after {
180
- background-image: url("https://a.sfdcstatic.com/developer-website/images/fch-blog-cloud-1.png");
181
- background-position: calc(100% + 78px) -60px;
182
- }
183
-
184
- .custom-bg-blog::before {
185
- content: "";
186
- position: absolute;
187
- width: 100%;
188
- height: 100%;
189
- background-image: url("https://a.sfdcstatic.com/developer-website/images/fch-blog-cloud-2.png");
190
- background-repeat: no-repeat;
191
- background-position: bottom left;
192
- transform: rotate(180deg);
193
- left: -96%;
194
- bottom: -90%;
195
- }
196
- }
197
- @media screen and (max-width: 600px) {
198
- .custom-bg-blog::after {
199
- background-size: 225px;
200
- background-position: calc(100% + 58px) -60px;
201
- }
202
- }
203
-
204
201
  .custom-bg-trial::after {
205
202
  content: "";
206
203
  background-image: url("https://a.sfdcstatic.com/developer-website/images/trial-left.svg"),
@@ -326,7 +323,6 @@ a.image-container > img {
326
323
  .label {
327
324
  grid-area: label;
328
325
  color: var(--label-color);
329
- padding-bottom: var(--dx-g-spacing-lg);
330
326
  }
331
327
 
332
328
  .dx-text-display-2 {
@@ -1,18 +1,32 @@
1
1
  <template>
2
2
  <div class={classname} part="container" style={style}>
3
+ <div class="title-bar" lwc:if={label}>
4
+ <div>
5
+ <template lwc:if={labelAsPrimaryHeading}>
6
+ <h1 class="label dx-text-display-6">{label}</h1>
7
+ </template>
8
+ <template lwc:else>
9
+ <p class="label dx-text-display-6">{label}</p>
10
+ </template>
11
+ </div>
12
+ <div>
13
+ <template lwc:if={isDarkModeEnabled}>
14
+ <div
15
+ class="dark-mode-button"
16
+ onclick={onDarkModeButtonClick}
17
+ >
18
+ <div class="dark-mode-icon"></div>
19
+ </div>
20
+ </template>
21
+ </div>
22
+ </div>
3
23
  <div class="container-layout">
4
- <template if:true={labelAsPrimaryHeading}>
5
- <h1 if:true={label} class="label dx-text-display-6">{label}</h1>
6
- </template>
7
- <template if:false={labelAsPrimaryHeading}>
8
- <p if:true={label} class="label dx-text-display-6">{label}</p>
9
- </template>
10
24
  <div class="featured-content-main-content">
11
- <template if:false={labelAsPrimaryHeading}>
12
- <h1 class="title dx-text-display-2">
25
+ <template lwc:if={labelAsPrimaryHeading}>
26
+ <h2 class="title dx-text-display-2">
13
27
  <a
14
28
  class="title-link"
15
- if:true={href}
29
+ lwc:if={href}
16
30
  href={href}
17
31
  target={target}
18
32
  onmouseenter={setLinkHovered}
@@ -20,14 +34,14 @@
20
34
  >
21
35
  {header}
22
36
  </a>
23
- <template if:false={href}>{header}</template>
24
- </h1>
37
+ <template lwc:else>{header}</template>
38
+ </h2>
25
39
  </template>
26
- <template if:true={labelAsPrimaryHeading}>
27
- <h2 class="title dx-text-display-2">
40
+ <template lwc:else>
41
+ <h1 class="title dx-text-display-2">
28
42
  <a
29
43
  class="title-link"
30
- if:true={href}
44
+ lwc:if={href}
31
45
  href={href}
32
46
  target={target}
33
47
  onmouseenter={setLinkHovered}
@@ -35,10 +49,10 @@
35
49
  >
36
50
  {header}
37
51
  </a>
38
- <template if:false={href}>{header}</template>
39
- </h2>
52
+ <template lwc:else>{header}</template>
53
+ </h1>
40
54
  </template>
41
- <div class="authors" if:true={authors}>
55
+ <div class="authors" lwc:if={authors}>
42
56
  <template for:each={authors} for:item="author">
43
57
  <dx-image-and-label
44
58
  key={author.key}
@@ -50,9 +64,9 @@
50
64
  </template>
51
65
  </div>
52
66
  <span class="body dx-text-body-1">{body}</span>
53
- <div class="buttons" if:true={hasButtons}>
67
+ <div class="buttons" lwc:if={hasButtons}>
54
68
  <dx-button
55
- if:true={ctaPrimaryLabel}
69
+ lwc:if={ctaPrimaryLabel}
56
70
  href={ctaPrimaryHref}
57
71
  icon-symbol={ctaPrimarySymbol}
58
72
  target={ctaPrimaryTarget}
@@ -61,7 +75,7 @@
61
75
  {ctaPrimaryLabel}
62
76
  </dx-button>
63
77
  <dx-button
64
- if:true={ctaSecondaryLabel}
78
+ lwc:if={ctaSecondaryLabel}
65
79
  href={ctaSecondaryHref}
66
80
  variant="quaternary"
67
81
  icon-symbol={ctaSecondarySymbol}
@@ -76,15 +90,15 @@
76
90
  </div>
77
91
  <div
78
92
  class={backgroundImageClass}
79
- if:true={hasBackgroundImage}
93
+ lwc:if={hasBackgroundImage}
80
94
  lwc:dom="manual"
81
95
  ></div>
82
96
  </div>
83
- <div if:true={hasPlainImage} class="image-container">
97
+ <div lwc:if={hasPlainImage} class="image-container">
84
98
  <img src={imgSrc} alt={imgAlt} />
85
99
  </div>
86
100
  <a
87
- if:true={hasLinkedImage}
101
+ lwc:if={hasLinkedImage}
88
102
  href={href}
89
103
  target={target}
90
104
  class="image-container"
@@ -94,7 +108,7 @@
94
108
  <img src={imgSrc} alt={imgAlt} />
95
109
  </a>
96
110
  </div>
97
- <div class="blue-circle" if:true={hasIcon}>
111
+ <div class="blue-circle" lwc:if={hasIcon}>
98
112
  <dx-icon
99
113
  class="icon"
100
114
  size="2xlarge"
@@ -5,6 +5,10 @@ import { toJson } from "dxUtils/normalizers";
5
5
  import { track } from "dxUtils/analytics";
6
6
  import svgs from "./svgs";
7
7
  import ImageAndLabel from "dx/imageAndLabel";
8
+ import {
9
+ dispatchDarkModeToggleEvent,
10
+ isDarkModeEnabled
11
+ } from "dx/darkModeManager";
8
12
 
9
13
  export default class FeaturedContentHeader extends LightningElement {
10
14
  @api label?: string | null = null;
@@ -89,6 +93,10 @@ export default class FeaturedContentHeader extends LightningElement {
89
93
  );
90
94
  }
91
95
 
96
+ private get isDarkModeEnabled() {
97
+ return isDarkModeEnabled();
98
+ }
99
+
92
100
  private get hasPlainImage() {
93
101
  return this.imgSrc && !this.href;
94
102
  }
@@ -120,6 +128,10 @@ export default class FeaturedContentHeader extends LightningElement {
120
128
  this.isLinkHovered = false;
121
129
  }
122
130
 
131
+ private onDarkModeButtonClick() {
132
+ dispatchDarkModeToggleEvent();
133
+ }
134
+
123
135
  private onSlotChange(e: any): void {
124
136
  this.isSlotEmpty = isSlotEmpty(e);
125
137
  const slot = e.target;
@@ -378,6 +378,7 @@ footer.signup-variant-no-signup {
378
378
  .content-container_top > .subheading {
379
379
  text-align: center;
380
380
  margin-right: unset;
381
+ margin-bottom: var(--dx-g-spacing-lg);
381
382
  }
382
383
 
383
384
  .content-container_top > dx-input {