@salesforcedevs/dx-components 1.32.1-alpha.4 → 1.33.0

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 CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@salesforcedevs/dx-components",
3
- "version": "1.32.1-alpha.4",
3
+ "version": "1.33.0",
4
4
  "description": "DX Lightning web components",
5
5
  "license": "MIT",
6
6
  "engines": {
7
- "node": "20.x"
7
+ "node": "22.x"
8
8
  },
9
9
  "publishConfig": {
10
10
  "access": "public"
@@ -44,5 +44,5 @@
44
44
  "luxon": "3.4.4",
45
45
  "msw": "^2.12.4"
46
46
  },
47
- "gitHead": "e64bce535a62d5e89c1c3bfe226c424e99d28379"
47
+ "gitHead": "f3e8e2c6ae6c8792b316e41021344648d4a07bec"
48
48
  }
@@ -23,34 +23,25 @@ async function ensureMiawScriptAndDefinition(): Promise<void> {
23
23
  `script[src="${SCRIPT_SRC}"]`
24
24
  ) as HTMLScriptElement | null;
25
25
 
26
- if (script) {
27
- await waitUntilResolved(
28
- customElements.whenDefined(HOSTED_MIAW_UI_TAG),
29
- DEFINE_TIMEOUT_MS,
30
- WHEN_DEFINED_TIMEOUT_MESSAGE
31
- );
32
- return;
26
+ if (!script) {
27
+ script = document.createElement("script");
28
+ script.type = "module";
29
+ script.src = SCRIPT_SRC;
30
+ await new Promise<void>((resolve, reject) => {
31
+ script!.addEventListener("load", () => resolve(), { once: true });
32
+ script!.addEventListener(
33
+ "error",
34
+ () =>
35
+ reject(
36
+ new Error(
37
+ `Failed to load MIAW UI embed script (${SCRIPT_SRC}). Check status code and referrer rules.`
38
+ )
39
+ ),
40
+ { once: true }
41
+ );
42
+ document.head.appendChild(script!);
43
+ });
33
44
  }
34
-
35
- script = document.createElement("script");
36
- script.type = "module";
37
- script.src = SCRIPT_SRC;
38
-
39
- await new Promise<void>((resolve, reject) => {
40
- script!.addEventListener("load", () => resolve(), { once: true });
41
- script!.addEventListener(
42
- "error",
43
- () =>
44
- reject(
45
- new Error(
46
- `Failed to load MIAW UI embed script (${SCRIPT_SRC}). Check status code and referrer rules.`
47
- )
48
- ),
49
- { once: true }
50
- );
51
- document.head.appendChild(script!);
52
- });
53
-
54
45
  await waitUntilResolved(
55
46
  customElements.whenDefined(HOSTED_MIAW_UI_TAG),
56
47
  DEFINE_TIMEOUT_MS,
@@ -67,12 +58,17 @@ function loadMiawUiScript(): Promise<void> {
67
58
  }
68
59
 
69
60
  export default class AgentMiawUi extends LightningElement {
61
+ private static readonly SIDEBAR_OPEN_ATTR = "data-xsf-agent-sidebar-open";
62
+ private static readonly AGENT_ROOT_SELECTOR = '[data-testid="agent-root"]';
63
+ private static readonly SIDEBAR_OPEN_CLASS = "view-sidebar";
64
+
70
65
  /** Salesforce org id (15- or 18-character Id). */
71
66
  @api orgId!: string;
72
67
  /** Messaging endpoint host URL (e.g. https://org62.my.salesforce-scrt.com). */
73
68
  @api messagingUrl!: string;
74
69
  @api deploymentDevName = "page_builder_miaw_ui";
75
70
  @api richComponentVersion = "v1-stable";
71
+ @api isOnDigitalDomain = "true";
76
72
  @api routingAttributes?: string;
77
73
  /**
78
74
  * JSON array of suggested prompt strings for the MIAW UI (e.g.
@@ -81,18 +77,11 @@ export default class AgentMiawUi extends LightningElement {
81
77
  @api prompts?: string;
82
78
  /** When set, forwarded to the embed as `welcome-text` (greeting / headline copy). */
83
79
  @api welcomeText?: string;
84
- /**
85
- * When set, bar gradient start (CSS color); sets `--wes-color-af-bar-gradient-from` on the
86
- * hosted `page-builder-miaw-ui` element when it exists.
87
- */
88
- @api gradientFrom?: string;
89
- /**
90
- * When set, bar gradient end (CSS color); sets `--wes-color-af-bar-gradient-to` on that element.
91
- */
92
- @api gradientTo?: string;
93
80
 
94
81
  /** After first mount attempt is scheduled, we do not run it again for this instance. */
95
82
  private hasRendered = false;
83
+ private sidebarStateObserver: MutationObserver | null = null;
84
+ private sidebarStateTargetSelector = "#main-content";
96
85
 
97
86
  renderedCallback(): void {
98
87
  if (!this.hasRendered) {
@@ -101,19 +90,9 @@ export default class AgentMiawUi extends LightningElement {
101
90
  }
102
91
  }
103
92
 
104
- private setGradientColors(element: HTMLElement | null): void {
105
- const from = this.gradientFrom?.trim();
106
- const to = this.gradientTo?.trim();
107
-
108
- if (from) {
109
- element?.style?.setProperty(
110
- "--wes-color-af-bar-gradient-from",
111
- from!
112
- );
113
- }
114
- if (to) {
115
- element?.style?.setProperty("--wes-color-af-bar-gradient-to", to!);
116
- }
93
+ disconnectedCallback(): void {
94
+ this.sidebarStateObserver?.disconnect();
95
+ this.sidebarStateObserver = null;
117
96
  }
118
97
 
119
98
  private async mountMiawHost(): Promise<void> {
@@ -128,7 +107,7 @@ export default class AgentMiawUi extends LightningElement {
128
107
  el.setAttribute("messaging-url", this.messagingUrl);
129
108
  el.setAttribute("deployment-dev-name", this.deploymentDevName);
130
109
  el.setAttribute("input-variant", "mini-sidebar");
131
- el.setAttribute("is-on-digital-domain", "false");
110
+ el.setAttribute("is-on-digital-domain", this.isOnDigitalDomain);
132
111
  el.setAttribute(
133
112
  "rich-component-version",
134
113
  this.richComponentVersion
@@ -146,9 +125,43 @@ export default class AgentMiawUi extends LightningElement {
146
125
  el.setAttribute("welcome-text", this.welcomeText);
147
126
  }
148
127
  container.appendChild(el);
149
- this.setGradientColors(el);
128
+ this.bridgeSidebarState(el);
150
129
  } catch (e) {
151
130
  console.error(e);
152
131
  }
153
132
  }
133
+
134
+ private setSidebarOpenState(isOpen: boolean): void {
135
+ const targets = document.querySelectorAll(this.sidebarStateTargetSelector);
136
+ targets.forEach((target) => {
137
+ target.setAttribute(
138
+ AgentMiawUi.SIDEBAR_OPEN_ATTR,
139
+ isOpen ? "true" : "false"
140
+ );
141
+ });
142
+ }
143
+
144
+ private bridgeSidebarState(el: Element): void {
145
+ const host = el as HTMLElement;
146
+ const root = host.shadowRoot?.querySelector(
147
+ AgentMiawUi.AGENT_ROOT_SELECTOR
148
+ ) as HTMLElement | null;
149
+ if (!root) {
150
+ window.requestAnimationFrame(() => this.bridgeSidebarState(el));
151
+ return;
152
+ }
153
+
154
+ const isOpen = () =>
155
+ root.classList.contains(AgentMiawUi.SIDEBAR_OPEN_CLASS);
156
+ this.setSidebarOpenState(isOpen());
157
+
158
+ this.sidebarStateObserver?.disconnect();
159
+ this.sidebarStateObserver = new MutationObserver(() => {
160
+ this.setSidebarOpenState(isOpen());
161
+ });
162
+ this.sidebarStateObserver.observe(root, {
163
+ attributes: true,
164
+ attributeFilter: ["class"]
165
+ });
166
+ }
154
167
  }
@@ -17,6 +17,8 @@
17
17
  --dx-c-button-opacity: 1;
18
18
  --dx-c-button-font-size: var(--dx-g-text-sm);
19
19
  --dx-c-button-font-weight: var(--dx-g-font-normal);
20
+ --dx-c-button-line-height: inherit;
21
+ --dx-c-button-letter-spacing: inherit;
20
22
  --dx-c-button-display: flex;
21
23
  }
22
24
 
@@ -35,6 +37,8 @@
35
37
  var(--dx-c-button-horizontal-spacing, var(--dx-g-spacing-md));
36
38
  border-radius: var(--dx-g-spacing-xs);
37
39
  font-weight: var(--dx-c-button-font-weight);
40
+ line-height: var(--dx-c-button-line-height);
41
+ letter-spacing: var(--dx-c-button-letter-spacing);
38
42
  }
39
43
 
40
44
  .button:focus {
@@ -63,6 +67,7 @@
63
67
  .button.variant_inline-inherit dx-icon,
64
68
  .button.variant_icon-only dx-icon {
65
69
  display: inline-block;
70
+ vertical-align: var(--dx-c-button-icon-vertical-align, 0.1em);
66
71
  }
67
72
 
68
73
  .button > span {
@@ -143,6 +143,13 @@ code[class*="shiki"] {
143
143
  padding: 0 var(--dx-g-spacing-md) 0 var(--dx-g-spacing-sm);
144
144
  text-align: right;
145
145
  user-select: none;
146
+ }
147
+
148
+ .dx-theme-light .code-line-number {
149
+ color: var(--dx-g-gray-40);
150
+ }
151
+
152
+ .dx-theme-dark .code-line-number {
146
153
  color: var(--dx-g-gray-60);
147
154
  }
148
155
 
@@ -1,22 +1,43 @@
1
1
  import kebabCase from "lodash.kebabcase";
2
2
  import { LightningElement, api } from "lwc";
3
3
 
4
- const defaultDomain = "https://developer.salesforce.com";
4
+ const defaultDomain = ""; // empty domain means the header settings will be loaded from the same domain as the current page
5
5
  const defaultLocale = "en-us";
6
6
  const defaultHeaderSettingsBasePath = "/c/public/header-settings";
7
+ const defaultPropertyTitle = "Developers";
7
8
  const headerSettingsJsonKeys = [
8
9
  "regionSelectorOverride",
9
10
  "contactLinksOverride"
10
11
  ];
11
12
 
12
13
  export default class DevExNavigation extends LightningElement {
13
- static renderMode = "light";
14
+ static renderMode = "light"; // Light DOM currently required due to other elements reading from this element's DOM; we should fix that and use existing nav CSS variables in those other elements (TODO)
14
15
 
15
16
  @api locale: string = defaultLocale;
16
17
  @api path: string = defaultHeaderSettingsBasePath;
17
18
  @api domain: string = defaultDomain;
19
+ @api propertyTitle: string = defaultPropertyTitle; // used only as a fallback in the "barebones" nav
20
+
21
+ // Fallback basic nav config used when the header settings are not available
22
+ private get barebonesNavConfig() {
23
+ return {
24
+ headerSettings: {
25
+ origin: "",
26
+ contextNavEnabled: "true"
27
+ },
28
+ navItems: {
29
+ variation: "static",
30
+ propertyTitle: {
31
+ label: this.propertyTitle,
32
+ url: "/"
33
+ },
34
+ menuGroup: {}
35
+ }
36
+ };
37
+ }
18
38
 
19
39
  async connectedCallback(): Promise<void> {
40
+ let navConfig = null;
20
41
  try {
21
42
  const headerSettingsResponse = await fetch(
22
43
  `${this.domain}${this.path}/${this.locale}.json`,
@@ -27,13 +48,12 @@ export default class DevExNavigation extends LightningElement {
27
48
  }
28
49
  );
29
50
  if (headerSettingsResponse.ok) {
30
- this.createFullNav(await headerSettingsResponse.json());
31
- } else {
32
- this.createBarebonesNav();
51
+ navConfig = await headerSettingsResponse.json();
33
52
  }
34
53
  } catch (ex) {
35
- console.error(`Navigation error: ${ex}`);
36
- this.createBarebonesNav();
54
+ console.error(`Header settings error: ${ex}`);
55
+ } finally {
56
+ this.createFullNav(navConfig || this.barebonesNavConfig);
37
57
  }
38
58
  }
39
59
 
@@ -63,22 +83,4 @@ export default class DevExNavigation extends LightningElement {
63
83
  containerEl.appendChild(hgfNav);
64
84
  containerEl.appendChild(hgfNavContext);
65
85
  }
66
-
67
- private createBarebonesNav(): void {
68
- const hgfNav = this.createGlobalNav({
69
- origin: "",
70
- contextNavEnabled: "true"
71
- });
72
- const hgfNavContext = this.createContextNav({
73
- variation: "static",
74
- propertyTitle: {
75
- label: "Developers",
76
- url: "/"
77
- },
78
- menuGroup: {}
79
- });
80
- const containerEl = this.refs.globalNavContainer as Element;
81
- containerEl.appendChild(hgfNav);
82
- containerEl.appendChild(hgfNavContext);
83
- }
84
86
  }
@@ -64,7 +64,8 @@ export class TreeHandler {
64
64
  isExpanded: node.isExpanded || false,
65
65
  isChildrenLoading: node.isChildrenLoading || false,
66
66
  link: node.link,
67
- method: node.method
67
+ method: node.method,
68
+ showForwardArrow: node.showForwardArrow
68
69
  };
69
70
 
70
71
  const mapItem = { node: convertedNode, parent };
@@ -58,6 +58,10 @@
58
58
  margin-left: var(--dx-g-spacing-xs);
59
59
  }
60
60
 
61
+ .tile-forward-arrow {
62
+ margin-left: auto;
63
+ }
64
+
61
65
  .whitespace-nowrap {
62
66
  white-space: nowrap;
63
67
  }
@@ -37,6 +37,16 @@
37
37
  value={methodText}
38
38
  color={metadataBadgeColor}
39
39
  ></dx-metadata-badge>
40
+ <div
41
+ class="flex tile-icon tile-forward-arrow"
42
+ if:true={showForwardArrow}
43
+ >
44
+ <dx-icon
45
+ sprite="utility"
46
+ symbol="forward"
47
+ size={iconSize}
48
+ ></dx-icon>
49
+ </div>
40
50
  </div>
41
51
  </a>
42
52
  </template>
@@ -52,6 +52,10 @@ export default class TreeTile extends LightningElement {
52
52
  return this.treeNode.method && !this.hasChildren;
53
53
  }
54
54
 
55
+ private get showForwardArrow() {
56
+ return this.treeNode.showForwardArrow;
57
+ }
58
+
55
59
  private get methodText() {
56
60
  if (this.treeNode.method && this.treeNode.method in methodTextMap) {
57
61
  return methodTextMap[this.treeNode.method];