@salesforcedevs/dx-components 1.40.6 → 1.40.7-tlv-alpha

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 (29) hide show
  1. package/lwc.config.json +3 -2
  2. package/package.json +46 -47
  3. package/src/modules/dx/button/button.css +2 -2
  4. package/src/modules/dx/dropdown/dropdown.css +29 -1
  5. package/src/modules/dx/dropdown/dropdown.html +1 -1
  6. package/src/modules/dx/dropdown/dropdown.ts +16 -1
  7. package/src/modules/dx/dropdownOption/dropdownOption.css +29 -6
  8. package/src/modules/dx/popover/popover.ts +119 -7
  9. package/src/modules/dx/searchHybrid/searchHybrid.html +1 -1
  10. package/src/modules/dx/searchHybrid/searchHybrid.ts +4 -0
  11. package/src/modules/dx/sidebar/sidebar.html +1 -0
  12. package/src/modules/dx/sidebarOld/sidebarOld.html +1 -0
  13. package/src/modules/dx/tree/tree.html +1 -0
  14. package/src/modules/dx/tree/tree.ts +5 -1
  15. package/src/modules/dx/tree/treeHandler.ts +85 -11
  16. package/src/modules/dx/treeItem/treeItem.css +30 -0
  17. package/src/modules/dx/treeItem/treeItem.html +17 -2
  18. package/src/modules/dx/treeItem/treeItem.ts +109 -11
  19. package/src/modules/dx/treeTile/treeTile.css +4 -0
  20. package/src/modules/dx/treeTile/treeTile.ts +12 -3
  21. package/src/modules/dx/typeBadge/typeBadge.ts +23 -2
  22. package/src/modules/dx/versionPicker/versionPicker.css +248 -0
  23. package/src/modules/dx/versionPicker/versionPicker.html +73 -0
  24. package/src/modules/dx/versionPicker/versionPicker.ts +157 -0
  25. package/src/modules/dxHelpers/commonSidebar/commonSidebar.css +3 -3
  26. package/src/modules/dxHelpers/commonTreeItem/commonTreeItem.css +4 -0
  27. package/src/modules/dxHelpers/typeBadge/typeBadge.css +22 -0
  28. package/src/modules/dxUtils/topicVersion/topicVersion.ts +511 -0
  29. package/LICENSE +0 -12
@@ -0,0 +1,248 @@
1
+ @import "dxHelpers/reset";
2
+
3
+ /* NOTE: dx-version-picker-width is used by both dx-button and dx-dropdown to maintain a consistent width. */
4
+ :host {
5
+ /* Always positioned so the popover's containing block stays the picker.
6
+ Toggling position with aria-expanded lets the menu jump to the sidebar
7
+ (top of the ToC) for a frame before LWC hides it. */
8
+ position: relative;
9
+
10
+ --dx-c-dropdown-option-font-weight: normal;
11
+ --dx-c-dropdown-option-font-size: var(--dx-g-text-base);
12
+ --dx-c-dropdown-option-label-color: var(--dx-g-gray-10);
13
+ --dx-c-dropdown-option-active-label-color: var(--dx-g-gray-10);
14
+ --dx-c-dropdown-option-padding: var(--dx-g-spacing-sm)
15
+ var(--dx-g-spacing-lg);
16
+ --dx-c-popover-padding: var(--dx-g-spacing-sm) 0;
17
+ --popover-container-open-transform: translateY(4px);
18
+ --dx-c-version-picker-focus-ring: 0 0 0 2px white,
19
+ 0 0 0 4px var(--dx-g-blue-vibrant-60);
20
+ }
21
+
22
+ /* Open menus must stack above later sibling pickers in the sidebar. */
23
+ :host(:has([aria-expanded="true"])) {
24
+ z-index: 2;
25
+ }
26
+
27
+ .version-picker-container {
28
+ /* Override --dx-version-picker-padding to change the inset (e.g. when the
29
+ picker sits inside an already-padded container). */
30
+ padding: var(
31
+ --dx-version-picker-padding,
32
+ var(--dx-g-spacing-sm) var(--dx-g-spacing-lg) var(--dx-g-spacing-sm)
33
+ var(--dx-g-global-header-padding-horizontal)
34
+ );
35
+
36
+ /* Override --dx-version-picker-divider (e.g. `none`) to restyle dividers. */
37
+ border-top: var(--dx-version-picker-divider, 1px solid var(--dx-g-gray-90));
38
+ border-bottom: var(
39
+ --dx-version-picker-divider,
40
+ 1px solid var(--dx-g-gray-90)
41
+ );
42
+ }
43
+
44
+ /* Inline sidebar variant: drop the header-slot chrome so the picker sits
45
+ beside a tree node without extra padding or divider lines. */
46
+ .version-picker-container-small {
47
+ display: flex;
48
+ align-items: center;
49
+ padding: 0;
50
+ border: none;
51
+ }
52
+
53
+ .version-picker-button {
54
+ display: flex;
55
+ width: var(--dx-version-picker-width, 296px);
56
+ overflow: visible;
57
+
58
+ --dx-c-button-horizontal-spacing: var(--dx-g-spacing-sm);
59
+ --dx-g-button-icon-color: var(--dx-g-gray-50);
60
+ }
61
+
62
+ .version-picker-button:hover,
63
+ .version-picker-button[aria-expanded="true"] {
64
+ --dx-g-button-icon-color: var(--dx-g-blue-vibrant-20);
65
+ }
66
+
67
+ /**
68
+ * NOTE: This CSS ensures the span inside the button stays within the parent's width, avoiding overflow.
69
+ * Not keeping this in common component to ensure that existing functionality works as it is.
70
+ */
71
+ dx-button::part(content) {
72
+ width: inherit;
73
+ overflow: hidden;
74
+ }
75
+
76
+ /* Border width stays 1px in every state. Hover, open, and focus paint the
77
+ 2px blue stroke with an inset shadow so the box does not grow.
78
+ Tertiary's hover border is overridden. */
79
+ .version-picker-button::part(container) {
80
+ box-sizing: border-box;
81
+ background: white;
82
+ border: 1px solid var(--dx-g-gray-50);
83
+ border-radius: var(--dx-g-spacing-xs);
84
+ box-shadow: none;
85
+ color: var(--dx-g-gray-10);
86
+ outline: none;
87
+ transition: var(--dx-g-transition-hue-1x), box-shadow 0.15s linear;
88
+ }
89
+
90
+ /* Hover only (not open): 2px #032D60 on #EEF4FF, no ring.
91
+ Border color matches the fill so the 1px border does not add a third
92
+ pixel around the inset stroke.
93
+ :focus-visible is included so click-open + Escape (which upgrades the
94
+ trigger to keyboard focus) still looks like hover while the pointer is on
95
+ the picker. */
96
+ .version-picker-button:hover:not([aria-expanded="true"])::part(container),
97
+ .version-picker-button:hover:not([aria-expanded="true"])::part(
98
+ container
99
+ ):focus-visible {
100
+ background: var(--dx-g-blue-vibrant-95);
101
+ border: 1px solid var(--dx-g-blue-vibrant-95);
102
+ box-shadow: inset 0 0 0 2px var(--dx-g-blue-vibrant-20);
103
+ }
104
+
105
+ /* Open keeps the fill and the 2px stroke. The focus ring is keyboard-only,
106
+ on the closed picker below. */
107
+ .version-picker-button[aria-expanded="true"]::part(container) {
108
+ background: var(--dx-g-blue-vibrant-95);
109
+ border: 1px solid var(--dx-g-blue-vibrant-95);
110
+ border-radius: var(--dx-g-spacing-xs);
111
+ box-shadow: inset 0 0 0 2px var(--dx-g-blue-vibrant-20);
112
+ }
113
+
114
+ /* Keyboard focus while closed. */
115
+ .version-picker-button:not([aria-expanded="true"])::part(
116
+ container
117
+ ):focus-visible {
118
+ --dx-g-button-icon-color: var(--dx-g-blue-vibrant-20);
119
+
120
+ background: var(--dx-g-blue-vibrant-95);
121
+ border: 1px solid var(--dx-g-blue-vibrant-95);
122
+ border-radius: var(--dx-g-spacing-xs);
123
+ box-shadow: inset 0 0 0 2px var(--dx-g-blue-vibrant-20),
124
+ var(--dx-c-version-picker-focus-ring);
125
+ }
126
+
127
+ .selected-version {
128
+ display: flex;
129
+ flex-direction: row;
130
+ align-items: center;
131
+ }
132
+
133
+ .selected-version-label {
134
+ flex: 1;
135
+ overflow: hidden;
136
+ text-align: left;
137
+ text-overflow: ellipsis;
138
+ white-space: nowrap;
139
+ }
140
+
141
+ dx-type-badge.latest-badge,
142
+ dx-type-badge.not-latest-badge {
143
+ margin-left: var(--dx-g-spacing-sm);
144
+ }
145
+
146
+ /* ------------------------------------------------------------------ *
147
+ * Small "dot" variant (opt-in via `small`). Additive
148
+ * ------------------------------------------------------------------ */
149
+
150
+ /* Menu is capped at the ToC width (296px), not the 104px trigger, so options
151
+ keep the same 16px / 8px 24px / gray-10 type as the default picker. */
152
+ .version-picker-dropdown-small {
153
+ --dx-c-dropdown-option-font-size: var(--dx-g-text-base);
154
+ --dx-c-dropdown-option-padding: var(--dx-g-spacing-sm)
155
+ var(--dx-g-spacing-lg);
156
+ --dx-c-dropdown-option-label-color: var(--dx-g-gray-10);
157
+ --dx-c-dropdown-option-border-radius: 0;
158
+ --dx-c-popover-border: none;
159
+
160
+ /* Hug the labels (down to the shortest) but never wider than the ToC
161
+ content: 296px on desktop, and on the smallest breakpoint the sidebar
162
+ variable grows with the viewport up to 720px. Long labels wrap inside
163
+ that cap. */
164
+ --dx-c-dropdown-menu-max-width: var(--dx-version-picker-width, 296px);
165
+ --dx-c-dropdown-fit-white-space: normal;
166
+ --dx-c-dropdown-fit-overflow: hidden;
167
+ --dx-c-dropdown-fit-text-overflow: clip;
168
+ --dx-c-dropdown-option-overflow-wrap: anywhere;
169
+ }
170
+
171
+ .version-picker-button-small {
172
+ width: fit-content;
173
+ max-width: 104px;
174
+
175
+ --dx-c-button-font-size: var(--dx-g-text-xs);
176
+ --dx-c-button-font-weight: var(--dx-g-font-normal);
177
+ --dx-c-button-line-height: var(--dx-g-spacing-lg);
178
+ --dx-c-button-icon-gap: var(--dx-g-spacing-2xs);
179
+ }
180
+
181
+ /* min-width: 0 on each flex ancestor lets the label truncate: a flex item's
182
+ default min-width: auto refuses to shrink below its content and overrides the
183
+ host's max-width, so without this the trigger overflows instead. */
184
+ .version-picker-button-small::part(content) {
185
+ display: flex;
186
+ flex: 1;
187
+ min-width: 0;
188
+ width: auto;
189
+ overflow: hidden;
190
+ }
191
+
192
+ /* width:100% re-ties to the 104px-capped host (container is width:inherit,
193
+ which copies width but not max-width). Border/bg/states are shared above. */
194
+ .version-picker-button-small::part(container) {
195
+ width: 100%;
196
+ height: var(--dx-g-spacing-lg);
197
+ padding: 0 var(--dx-g-spacing-xs);
198
+ }
199
+
200
+ .selected-version-small {
201
+ flex: 1;
202
+ min-width: 0;
203
+ }
204
+
205
+ .version-picker-dot {
206
+ flex: 0 0 auto;
207
+ width: var(--dx-g-spacing-sm);
208
+ height: var(--dx-g-spacing-sm);
209
+ margin-right: var(--dx-g-spacing-xs);
210
+ border-radius: 50%;
211
+ }
212
+
213
+ .version-picker-dot-latest {
214
+ background: var(--dx-g-green-vibrant-60);
215
+ }
216
+
217
+ .version-picker-dot-not-latest {
218
+ background: var(--dx-g-yellow-vibrant-80);
219
+ }
220
+
221
+ /* inline-block (not flex) so the label can truncate; line-height centers it. */
222
+ .version-picker-readonly {
223
+ box-sizing: border-box;
224
+ display: inline-block;
225
+ width: var(--dx-version-picker-width, 296px);
226
+ height: var(--dx-g-spacing-xl);
227
+ margin: 0;
228
+ padding: 0 var(--dx-g-spacing-sm);
229
+ border: 1px solid var(--dx-g-gray-80);
230
+ border-radius: var(--dx-g-spacing-xs);
231
+ overflow: hidden;
232
+ color: var(--dx-g-gray-10);
233
+ text-overflow: ellipsis;
234
+ white-space: nowrap;
235
+ font: var(--dx-g-font-normal) var(--dx-g-text-sm) / var(--dx-g-spacing-xl)
236
+ var(--dx-g-font-sans),
237
+ sans-serif;
238
+ }
239
+
240
+ .version-picker-readonly-small {
241
+ width: fit-content;
242
+ max-width: 104px;
243
+ height: var(--dx-g-spacing-lg);
244
+ padding: 0 var(--dx-g-spacing-xs);
245
+ font: var(--dx-g-font-normal) var(--dx-g-text-xs) / var(--dx-g-spacing-lg)
246
+ var(--dx-g-font-sans),
247
+ sans-serif;
248
+ }
@@ -0,0 +1,73 @@
1
+ <template>
2
+ <div lwc:if={showVersionPicker} class={containerClass}>
3
+ <!-- Small read-only: plain value, no dropdown -->
4
+ <p
5
+ lwc:if={readOnly}
6
+ class={readOnlyClass}
7
+ title={selectedVersion.label}
8
+ >
9
+ {selectedVersion.label}
10
+ </p>
11
+
12
+ <dx-dropdown
13
+ lwc:else
14
+ class={dropdownClass}
15
+ options={versions}
16
+ analytics-event="custEv_docVersionSelect"
17
+ analytics-payload={analyticsPayload}
18
+ value={selectedVersion.id}
19
+ width-mode={dropdownWidthMode}
20
+ onchange={onVersionChange}
21
+ >
22
+ <dx-button
23
+ class={triggerClass}
24
+ variant="tertiary"
25
+ size="small"
26
+ font="sans"
27
+ icon-symbol="chevrondown"
28
+ icon-size={triggerIconSize}
29
+ aria-label={triggerAriaLabel}
30
+ >
31
+ <div class={selectedVersionClass}>
32
+ <!-- Small: leading colored dot -->
33
+ <template lwc:if={small}>
34
+ <template lwc:if={showLatestTag}>
35
+ <span class={dotClass} aria-hidden="true"></span>
36
+ </template>
37
+ <p
38
+ class="selected-version-label"
39
+ title={selectedVersion.label}
40
+ >
41
+ {selectedVersion.label}
42
+ </p>
43
+ </template>
44
+ <!-- Default: trailing Latest/Not-Latest badge -->
45
+ <template lwc:else>
46
+ <p
47
+ class="selected-version-label"
48
+ title={selectedVersion.label}
49
+ >
50
+ {selectedVersion.label}
51
+ </p>
52
+ <template lwc:if={showLatestTag}>
53
+ <dx-type-badge
54
+ class="latest-badge"
55
+ lwc:if={latestVersion}
56
+ variant="status-success"
57
+ value="Latest"
58
+ size="small"
59
+ ></dx-type-badge>
60
+ <dx-type-badge
61
+ class="not-latest-badge"
62
+ lwc:else
63
+ variant="status-warning"
64
+ value="Not Latest"
65
+ size="small"
66
+ ></dx-type-badge>
67
+ </template>
68
+ </template>
69
+ </div>
70
+ </dx-button>
71
+ </dx-dropdown>
72
+ </div>
73
+ </template>
@@ -0,0 +1,157 @@
1
+ import { LightningElement, api, track } from "lwc";
2
+ import cx from "classnames";
3
+
4
+ import { AnalyticsPayload, OptionWithNested } from "typings/custom";
5
+
6
+ import { toJson, normalizeBoolean } from "dxUtils/normalizers";
7
+
8
+ export default class VersionPicker extends LightningElement {
9
+ @api analyticsEvent?: string;
10
+ @api analyticsPayload?: AnalyticsPayload;
11
+
12
+ @track private _versions!: OptionWithNested[];
13
+ private _selectedVersion?: OptionWithNested;
14
+ private _latestVersion: boolean = false;
15
+ private _hideBadge: boolean = false;
16
+ private _small: boolean = false;
17
+ private _readOnly: boolean = false;
18
+
19
+ @api
20
+ get versions() {
21
+ return this._versions;
22
+ }
23
+
24
+ set versions(value: OptionWithNested[]) {
25
+ this._versions = toJson(value);
26
+ }
27
+
28
+ @api
29
+ get selectedVersion(): OptionWithNested | undefined {
30
+ return this._selectedVersion || this.versions[0];
31
+ }
32
+
33
+ set selectedVersion(value: OptionWithNested) {
34
+ if (value) {
35
+ this._selectedVersion = toJson(value);
36
+ }
37
+ }
38
+
39
+ @api
40
+ get latestVersion() {
41
+ return this._latestVersion;
42
+ }
43
+
44
+ set latestVersion(value) {
45
+ this._latestVersion = normalizeBoolean(value);
46
+ }
47
+
48
+ @api
49
+ get hideBadge() {
50
+ return this._hideBadge;
51
+ }
52
+
53
+ set hideBadge(value) {
54
+ this._hideBadge = normalizeBoolean(value);
55
+ }
56
+
57
+ // Opt-in compact "dot" variant (24px, abbreviated label). Off by default so
58
+ // existing consumers render the default trigger unchanged.
59
+ @api
60
+ get small() {
61
+ return this._small;
62
+ }
63
+
64
+ set small(value) {
65
+ this._small = normalizeBoolean(value);
66
+ }
67
+
68
+ // Opt-in read-only state: plain value, no dropdown menu.
69
+ @api
70
+ get readOnly() {
71
+ return this._readOnly;
72
+ }
73
+
74
+ set readOnly(value) {
75
+ this._readOnly = normalizeBoolean(value);
76
+ }
77
+
78
+ private get showVersionPicker() {
79
+ return this._versions && this._versions.length !== 0;
80
+ }
81
+
82
+ private get containerClass(): string {
83
+ return this.small
84
+ ? "version-picker-container-small"
85
+ : "version-picker-container";
86
+ }
87
+
88
+ private get showLatestTag(): boolean {
89
+ return !this.hideBadge;
90
+ }
91
+
92
+ private get readOnlyClass(): string {
93
+ return cx(
94
+ "version-picker-readonly",
95
+ this.small && "version-picker-readonly-small"
96
+ );
97
+ }
98
+
99
+ private get dotClass(): string {
100
+ return `version-picker-dot ${
101
+ this.latestVersion
102
+ ? "version-picker-dot-latest"
103
+ : "version-picker-dot-not-latest"
104
+ }`;
105
+ }
106
+
107
+ // Accessible name for the small trigger: includes the latest state so it
108
+ // isn't conveyed by the dot's color alone (WCAG 1.4.1). Omits the state
109
+ // when the indicator is hidden.
110
+ private get smallTriggerAriaLabel(): string {
111
+ const label = this.selectedVersion?.label ?? "";
112
+ if (!this.showLatestTag) {
113
+ return label;
114
+ }
115
+ return `${label}, ${this.latestVersion ? "Latest" : "Not Latest"}`;
116
+ }
117
+
118
+ // --- Per-variant values for the shared dropdown/button markup below. The
119
+ // small variant opts into extra classes and a compact chevron.
120
+
121
+ // Not cx(): the default must have NO class attribute (cx returns "", which
122
+ // would render class="" and break the frozen consumer snapshots).
123
+ private get dropdownClass(): string | undefined {
124
+ return this.small ? "version-picker-dropdown-small" : undefined;
125
+ }
126
+
127
+ // "full" matches the trigger (ToC width). "fit-end" sizes to the labels,
128
+ // caps at the ToC width, and opens inward.
129
+ private get dropdownWidthMode(): "full" | "fit-end" {
130
+ return this.small ? "fit-end" : "full";
131
+ }
132
+
133
+ private get triggerClass(): string {
134
+ return cx(
135
+ "version-picker-button",
136
+ this.small && "version-picker-button-small"
137
+ );
138
+ }
139
+
140
+ private get triggerIconSize(): string {
141
+ return this.small ? "xsmall" : "medium";
142
+ }
143
+
144
+ // Default returns "" (dx-button's own default) so the trigger's rendered
145
+ // aria-label is unchanged for the default variant.
146
+ private get triggerAriaLabel(): string {
147
+ return this.small ? this.smallTriggerAriaLabel : "";
148
+ }
149
+
150
+ private get selectedVersionClass(): string {
151
+ return cx("selected-version", this.small && "selected-version-small");
152
+ }
153
+
154
+ private onVersionChange(e: CustomEvent) {
155
+ this.dispatchEvent(new CustomEvent("change", { detail: e.detail }));
156
+ }
157
+ }
@@ -11,7 +11,7 @@
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
+ --dx-version-picker-width: 296px;
15
15
  }
16
16
 
17
17
  .header {
@@ -170,9 +170,9 @@
170
170
  margin-bottom: var(--dx-g-spacing-2xl);
171
171
  }
172
172
 
173
- @media screen and (max-width: 767px) {
173
+ @media screen and (max-width: 768px) {
174
174
  :host {
175
- --doc-version-picker-width: calc(
175
+ --dx-version-picker-width: calc(
176
176
  100vw - var(--dx-c-sidebar-left-padding) - var(--dx-g-spacing-lg)
177
177
  );
178
178
  }
@@ -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);