@salesforcedevs/dx-components 1.40.4 → 1.40.5-topic-alpha.2

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.
@@ -2,9 +2,24 @@ import { LightningElement, api } from "lwc";
2
2
  import { InternalTreeNode } from "typings/custom";
3
3
  import { track } from "dxUtils/analytics";
4
4
  import { isInViewport } from "dxUtils/browser";
5
+ import type { TopicVersionOption } from "dxUtils/topicVersion";
6
+ import {
7
+ firstContentNode,
8
+ getTopicVersionKey,
9
+ getVersionPickerOptions,
10
+ isParentOnlyTopic,
11
+ normalizePath,
12
+ persistTopicVersion,
13
+ resolveSelectedVersion,
14
+ shouldShowTopicVersionPicker
15
+ } from "dxUtils/topicVersion";
5
16
 
6
17
  const DEFAULT_TARGET = "_self";
7
18
 
19
+ type VersionedInternalTreeNode = InternalTreeNode & {
20
+ versions?: TopicVersionOption[];
21
+ };
22
+
8
23
  export default class TreeItem extends LightningElement {
9
24
  @api selectedKey?: string;
10
25
  @api isRoot: boolean = false;
@@ -20,7 +35,7 @@ export default class TreeItem extends LightningElement {
20
35
  this.isChildrenLoading = (node && node.isChildrenLoading) || false;
21
36
  }
22
37
 
23
- private _treeNode!: InternalTreeNode;
38
+ private _treeNode!: VersionedInternalTreeNode;
24
39
  private isExpanded: boolean = false;
25
40
  private isChildrenLoading: boolean = false;
26
41
  private rootParentLabel: string = "";
@@ -30,9 +45,22 @@ export default class TreeItem extends LightningElement {
30
45
  }
31
46
 
32
47
  private get isSelected(): boolean {
48
+ if (isParentOnlyTopic(this._treeNode)) {
49
+ return false;
50
+ }
33
51
  return this._treeNode.key === this.selectedKey && !this.isExternalLink;
34
52
  }
35
53
 
54
+ private get rowClass(): string {
55
+ return this.isSelected && this.showVersionPicker
56
+ ? "tree-item-row tree-item-row-selected"
57
+ : "tree-item-row";
58
+ }
59
+
60
+ private get isContainedSelection(): boolean {
61
+ return this.isSelected && this.showVersionPicker;
62
+ }
63
+
36
64
  private get hasChildren(): boolean {
37
65
  return !!(
38
66
  this.treeNode &&
@@ -83,8 +111,44 @@ export default class TreeItem extends LightningElement {
83
111
  return `${parentLabels.reverse().join(":")}:${this.treeNode.label}`;
84
112
  }
85
113
 
114
+ private get versions(): TopicVersionOption[] | undefined {
115
+ return this._treeNode?.versions;
116
+ }
117
+
118
+ private get versionPickerOptions(): TopicVersionOption[] | undefined {
119
+ return getVersionPickerOptions(this._treeNode);
120
+ }
121
+
122
+ private get showVersionPicker(): boolean {
123
+ return shouldShowTopicVersionPicker(
124
+ this.versions,
125
+ this._treeNode?.showForwardArrow
126
+ );
127
+ }
128
+
129
+ private get selectedVersion(): TopicVersionOption | undefined {
130
+ return resolveSelectedVersion(this._treeNode);
131
+ }
132
+
133
+ private get isLatestVersion(): boolean {
134
+ return (
135
+ !!this.selectedVersion &&
136
+ this.selectedVersion.id === this.versions?.[0]?.id
137
+ );
138
+ }
139
+
86
140
  private get href(): string | undefined {
141
+ if (isParentOnlyTopic(this._treeNode)) {
142
+ const contentNode = firstContentNode(this._treeNode);
143
+ return (
144
+ contentNode?.link?.href ||
145
+ contentNode?.name ||
146
+ this.selectedVersion?.link?.href ||
147
+ ""
148
+ );
149
+ }
87
150
  return (
151
+ this.selectedVersion?.link?.href ||
88
152
  (this._treeNode.link && this._treeNode.link.href) ||
89
153
  this._treeNode.name ||
90
154
  ""
@@ -104,6 +168,23 @@ export default class TreeItem extends LightningElement {
104
168
  setExpanded: this.setExpanded.bind(this)
105
169
  });
106
170
  }
171
+
172
+ // Remember this topic's resolved version (own URL, descendant URL, or
173
+ // session) so sibling pickers stay independent for the tab.
174
+ const selected = resolveSelectedVersion(this._treeNode);
175
+ const topicKey = getTopicVersionKey(this._treeNode);
176
+ if (this.versions?.length && selected && topicKey) {
177
+ persistTopicVersion(topicKey, selected.id);
178
+ }
179
+ }
180
+
181
+ private onVersionChange(event: CustomEvent): void {
182
+ event.stopPropagation();
183
+ persistTopicVersion(getTopicVersionKey(this._treeNode), event.detail);
184
+ }
185
+
186
+ private onVersionPickerClick(event: Event): void {
187
+ event.stopPropagation();
107
188
  }
108
189
 
109
190
  renderedCallback(): void {
@@ -134,8 +215,8 @@ export default class TreeItem extends LightningElement {
134
215
  private preventDefaultLinkBehavior(event: Event) {
135
216
  // prevent page refresh if href isn't present or link is already active
136
217
  if (
137
- !this._treeNode.link?.href ||
138
- this._treeNode.link?.href === window.location.pathname
218
+ !this.href ||
219
+ normalizePath(this.href) === normalizePath(window.location.pathname)
139
220
  ) {
140
221
  event.preventDefault();
141
222
  }
@@ -167,8 +248,12 @@ export default class TreeItem extends LightningElement {
167
248
  }
168
249
 
169
250
  this.sendGtm(event);
251
+ const contentNode = isParentOnlyTopic(this._treeNode)
252
+ ? firstContentNode(this._treeNode)
253
+ : undefined;
170
254
  this.fireEvent("tileselected", {
171
- name: this._treeNode.name,
255
+ name: contentNode?.name || this._treeNode.name,
256
+ ...(contentNode?.key ? { key: contentNode.key } : {}),
172
257
  isExternalLink: this.isExternalLink
173
258
  });
174
259
  }
@@ -186,8 +271,8 @@ export default class TreeItem extends LightningElement {
186
271
  this.dispatchEvent(
187
272
  new CustomEvent(type, {
188
273
  detail: {
189
- ...detail,
190
- key: this._treeNode.key
274
+ key: this._treeNode.key,
275
+ ...detail
191
276
  },
192
277
  bubbles: true,
193
278
  composed: true
@@ -66,6 +66,10 @@
66
66
  white-space: nowrap;
67
67
  }
68
68
 
69
+ .tile-with-version-picker {
70
+ padding-right: var(--dx-g-spacing-xs);
71
+ }
72
+
69
73
  .tile-with-children .tile-label {
70
74
  order: 2;
71
75
  }
@@ -28,10 +28,12 @@ export default class TreeTile extends LightningElement {
28
28
  @api isExpanded = false;
29
29
  @api hasChildren = false;
30
30
  @api isSelected = false;
31
+ @api isContainedSelection = false;
31
32
  @api href!: string;
32
33
  @api showArrow = false;
33
34
  @api target!: string;
34
35
  @api isExternalLink = false;
36
+ @api hasVersionPicker = false;
35
37
 
36
38
  get tileAriaLevel() {
37
39
  return this.treeNode.level + 2;
@@ -101,7 +103,11 @@ export default class TreeTile extends LightningElement {
101
103
  "tile-root": this.isRoot,
102
104
  "tile-with-children": !this.isRoot && this.hasChildren,
103
105
  "tile-root-with-child": this.isRoot && this.showArrow,
104
- "sidebar-item-selected": this.isSelected
106
+ "sidebar-item-selected":
107
+ this.isSelected && !this.isContainedSelection,
108
+ "sidebar-item-selected-text":
109
+ this.isSelected && this.isContainedSelection,
110
+ "tile-with-version-picker": this.hasVersionPicker
105
111
  });
106
112
  }
107
113
 
@@ -7,6 +7,7 @@ import {
7
7
  IconSprite,
8
8
  IconData,
9
9
  IconSymbol,
10
+ StatusBadgeVariant,
10
11
  TypeBadgeSize
11
12
  } from "typings/custom";
12
13
  import { colorToDxColors, buildStyleColorVariables } from "dxUtils/css";
@@ -20,9 +21,16 @@ import {
20
21
  getContentTypeColorVariables
21
22
  } from "dxUtils/contentTypes";
22
23
 
24
+ // Opt-in solid status variants (status-success/-warning/-error).
25
+ export const STATUS_BADGE_VARIANTS: StatusBadgeVariant[] = [
26
+ "status-success",
27
+ "status-warning",
28
+ "status-error"
29
+ ];
30
+
23
31
  export default class TypeBadge extends LightningElement {
24
32
  @api size: TypeBadgeSize = "default";
25
- @api variant: Brand | ContentType = "default";
33
+ @api variant: Brand | ContentType | StatusBadgeVariant = "default";
26
34
  @api color?: Color;
27
35
  @api dark?: false;
28
36
 
@@ -87,11 +95,24 @@ export default class TypeBadge extends LightningElement {
87
95
  return isContentType(this.variant);
88
96
  }
89
97
 
98
+ private get isStatus(): boolean {
99
+ return STATUS_BADGE_VARIANTS.includes(
100
+ this.variant as StatusBadgeVariant
101
+ );
102
+ }
103
+
90
104
  private get className(): string {
91
- return cx("dx-badge", `size-${this.size}`);
105
+ return cx(
106
+ "dx-badge",
107
+ `size-${this.size}`,
108
+ this.isStatus && this.variant
109
+ );
92
110
  }
93
111
 
94
112
  private get style(): string {
113
+ if (this.isStatus) {
114
+ return "";
115
+ }
95
116
  if (this.dark) {
96
117
  return buildStyleColorVariables({
97
118
  background: "--dx-g-purple-vibrant-40",
@@ -2,7 +2,7 @@
2
2
  @import "dxHelpers/text";
3
3
 
4
4
  :host {
5
- --dx-c-sidebar-width: 337px;
5
+ --dx-c-sidebar-width: 336px;
6
6
  --dx-c-sidebar-button-color: var(--dx-g-blue-vibrant-50);
7
7
  --dx-c-sidebar-button-background: white;
8
8
  --dx-c-sidebar-button-border: white;
@@ -11,7 +11,13 @@
11
11
  --dx-c-sidebar-button-border-hover: var(--dx-g-blue-vibrant-50);
12
12
  --dx-c-sidebar-left-padding: var(--dx-g-global-header-padding-horizontal);
13
13
  --dx-c-sidebar-vertical-padding: var(--dx-g-spacing-md);
14
- --doc-version-picker-width: 296px;
14
+
15
+ /* Width of the sidebar content (search field, version pickers): the
16
+ sidebar minus its 16px left and 24px right insets. 296px on desktop. */
17
+ --doc-version-picker-width: calc(
18
+ var(--dx-c-sidebar-width) - var(--dx-g-spacing-md) -
19
+ var(--dx-g-spacing-lg)
20
+ );
15
21
  }
16
22
 
17
23
  .header {
@@ -13,6 +13,10 @@
13
13
  color: var(--dx-g-blue-vibrant-40) !important;
14
14
  }
15
15
 
16
+ .sidebar-item-selected-text {
17
+ color: var(--dx-g-blue-vibrant-40) !important;
18
+ }
19
+
16
20
  .sidebar-item {
17
21
  padding: 6px var(--dx-g-spacing-lg) 6px
18
22
  var(--dx-g-global-header-padding-horizontal);
@@ -26,6 +26,28 @@
26
26
  --height: var(--dx-g-spacing-mlg);
27
27
  }
28
28
 
29
+ .dx-badge.status-success,
30
+ .dx-badge.status-warning,
31
+ .dx-badge.status-error {
32
+ /* No spacing token maps to 10px; status badges need this exact padding. */
33
+ --horizontal-spacing: 10px;
34
+ }
35
+
36
+ .dx-badge.status-success {
37
+ --color: var(--sds-g-gray-1);
38
+ --background: var(--dx-g-green-vibrant-50);
39
+ }
40
+
41
+ .dx-badge.status-warning {
42
+ --color: var(--dx-g-gray-15);
43
+ --background: var(--dx-g-yellow-vibrant-80);
44
+ }
45
+
46
+ .dx-badge.status-error {
47
+ --color: var(--sds-g-gray-1);
48
+ --background: var(--dx-g-red-vibrant-40);
49
+ }
50
+
29
51
  svg,
30
52
  dx-icon {
31
53
  margin-right: var(--dx-g-spacing-sm);