@salesforcedevs/docs-components 1.34.0-docs-feedback → 1.35.0-ver-picker-1

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,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforcedevs/docs-components",
3
- "version": "1.34.0-docs-feedback",
3
+ "version": "1.35.0-ver-picker-1",
4
4
  "description": "Docs Lightning web components for DSC",
5
5
  "license": "MIT",
6
6
  "main": "index.js",
@@ -77,12 +77,6 @@ header:not(.has-brand) > .header_l2 {
77
77
  border-top: 1px solid var(--dx-g-gray-90);
78
78
  }
79
79
 
80
- @media (max-width: 1280px) {
81
- .no-header-content {
82
- border-top: 0;
83
- }
84
- }
85
-
86
80
  @media (max-width: 768px) {
87
81
  .header_l2 {
88
82
  padding: 0;
@@ -10,34 +10,11 @@ import type { OptionWithLink, TreeNode } from "typings/custom";
10
10
  */
11
11
  const TOPIC_TYPE_SPEC = "spec";
12
12
 
13
- function findFirstContentDescendant(node: TreeNode): TreeNode | undefined {
14
- for (const child of node.children ?? []) {
15
- const isSpec =
16
- (child as { topicType?: string }).topicType === TOPIC_TYPE_SPEC;
17
- const isExternal = child.link?.target === "_blank";
18
- if (isSpec || isExternal) {
19
- continue;
20
- }
21
-
22
- if (child.link?.href) {
23
- return child;
24
- }
25
-
26
- const descendant = findFirstContentDescendant(child);
27
- if (descendant) {
28
- return descendant;
29
- }
30
- }
31
-
32
- return undefined;
33
- }
34
-
35
13
  /**
36
14
  * Translates per-topic `topicType` into the generic `showForwardArrow` flag
37
- * that `dx-tree-tile` reads (spec topics get the forward arrow icon for Redoc),
38
- * and redirects content-less parent topics to their first content descendant.
15
+ * that `dx-tree-tile` reads (spec topics get the forward arrow icon for Redoc).
39
16
  */
40
- function decorateTopics(
17
+ function decorateTopicsWithForwardArrow(
41
18
  topics: Array<TreeNode & { topicType?: string }> | undefined
42
19
  ): TreeNode[] | undefined {
43
20
  return topics?.map((topic) => {
@@ -46,21 +23,10 @@ function decorateTopics(
46
23
  decorated.showForwardArrow = true;
47
24
  }
48
25
  if (decorated.children) {
49
- decorated.children = decorateTopics(decorated.children);
50
- }
51
-
52
- // Redirect parent topics without their own content to their first
53
- // available content descendant.
54
- const isContentlessParent =
55
- !!decorated.children?.length && !decorated.link?.href;
56
-
57
- if (isContentlessParent) {
58
- const firstContent = findFirstContentDescendant(topic);
59
- if (firstContent?.link) {
60
- decorated.link = { ...firstContent.link };
61
- }
26
+ decorated.children = decorateTopicsWithForwardArrow(
27
+ decorated.children
28
+ );
62
29
  }
63
-
64
30
  return decorated;
65
31
  });
66
32
  }
@@ -111,7 +77,9 @@ export default class UnifiedContentLayout extends LightningElement {
111
77
  }
112
78
 
113
79
  set sidebarContent(value: string) {
114
- this._sidebarContent = decorateTopics(toJson(value)?.topics);
80
+ this._sidebarContent = decorateTopicsWithForwardArrow(
81
+ toJson(value)?.topics
82
+ );
115
83
  }
116
84
 
117
85
  private get enableFooter(): boolean {
@@ -62,3 +62,117 @@ dx-type-badge.not-latest-badge {
62
62
 
63
63
  margin-left: var(--dx-g-spacing-sm);
64
64
  }
65
+
66
+ /* ------------------------------------------------------------------ *
67
+ * Small "dot" variant (opt-in via `small`). Additive
68
+ * ------------------------------------------------------------------ */
69
+
70
+ /* Scoped hooks so the shared dx-popover/dx-dropdown-option keep their defaults. */
71
+ .version-picker-dropdown-small {
72
+ --dx-c-dropdown-option-font-size: var(--dx-g-text-xs);
73
+ --dx-c-dropdown-option-padding: var(--dx-g-spacing-sm)
74
+ var(--dx-g-spacing-lg);
75
+ --dx-c-dropdown-option-border-radius: 0;
76
+ --dx-c-popover-border: none;
77
+ --dx-c-popover-padding: var(--dx-g-spacing-sm) 0;
78
+ }
79
+
80
+ .version-picker-button-small {
81
+ display: flex;
82
+ width: fit-content;
83
+ max-width: 104px;
84
+ border-radius: var(--dx-g-spacing-xs);
85
+
86
+ --dx-c-button-font-size: var(--dx-g-text-xs);
87
+ --dx-c-button-font-weight: var(--dx-g-font-normal);
88
+ --dx-c-button-line-height: 18px;
89
+ --dx-g-button-icon-color: var(--dx-g-gray-50);
90
+ --dx-g-spacing-sm: var(--dx-g-spacing-2xs);
91
+ }
92
+
93
+ /* min-width: 0 on each flex ancestor lets the label truncate: a flex item's
94
+ default min-width: auto refuses to shrink below its content and overrides the
95
+ host's max-width, so without this the trigger overflows instead. */
96
+ .version-picker-button-small::part(content) {
97
+ display: flex;
98
+ flex: 1;
99
+ min-width: 0;
100
+ width: auto;
101
+ overflow: hidden;
102
+ }
103
+
104
+ /* Border is an inset box-shadow, not a real border, so thickening it on
105
+ hover/focus doesn't widen the fit-content box (no horizontal shift). */
106
+ .version-picker-button-small::part(container) {
107
+ box-sizing: border-box;
108
+
109
+ /* width:100% re-ties to the 104px-capped host (container is width:inherit,
110
+ which copies width but not max-width). */
111
+ width: 100%;
112
+ height: 24px;
113
+ padding: 0 var(--dx-g-spacing-xs);
114
+ border-radius: var(--dx-g-spacing-xs);
115
+ background: #fff;
116
+ box-shadow: inset 0 0 0 1px var(--dx-g-gray-50);
117
+ color: var(--dx-g-gray-10);
118
+ }
119
+
120
+ .version-picker-button-small::part(container):hover {
121
+ background: var(--dx-g-blue-vibrant-95);
122
+ box-shadow: inset 0 0 0 2px var(--dx-g-blue-vibrant-20);
123
+ }
124
+
125
+ .version-picker-button-small:hover,
126
+ .version-picker-button-small:focus-within,
127
+ .version-picker-button-small[aria-expanded="true"] {
128
+ --dx-g-button-icon-color: var(--dx-g-blue-vibrant-20);
129
+ }
130
+
131
+ /* Also matches aria-expanded so the ring stays while the menu is open (opening
132
+ moves focus into the menu, which would otherwise drop :focus-within). */
133
+ .version-picker-button-small:focus-within::part(container),
134
+ .version-picker-button-small[aria-expanded="true"]::part(container) {
135
+ background: var(--dx-g-blue-vibrant-95);
136
+ box-shadow: inset 0 0 0 2px var(--dx-g-blue-vibrant-20), 0 0 0 2px #fff,
137
+ 0 0 0 4px var(--dx-g-blue-vibrant-60);
138
+ }
139
+
140
+ .selected-version-small {
141
+ flex: 1;
142
+ min-width: 0;
143
+ }
144
+
145
+ .version-picker-dot {
146
+ flex: 0 0 auto;
147
+ width: 8px;
148
+ height: 8px;
149
+ margin-right: var(--dx-g-spacing-xs);
150
+ border-radius: 50%;
151
+ }
152
+
153
+ .version-picker-dot-latest {
154
+ background: var(--dx-g-green-vibrant-60);
155
+ }
156
+
157
+ .version-picker-dot-not-latest {
158
+ background: var(--dx-g-yellow-vibrant-80);
159
+ }
160
+
161
+ .version-picker-readonly-small {
162
+ display: inline-flex;
163
+ align-items: center;
164
+ box-sizing: border-box;
165
+ width: fit-content;
166
+ max-width: 104px;
167
+ height: 24px;
168
+ margin: 0;
169
+ padding: 0 var(--dx-g-spacing-xs);
170
+ border: 1px solid var(--dx-g-gray-80);
171
+ border-radius: var(--dx-g-spacing-xs);
172
+ overflow: hidden;
173
+ color: var(--dx-g-gray-10);
174
+ text-overflow: ellipsis;
175
+ white-space: nowrap;
176
+ font: var(--dx-g-font-normal) var(--dx-g-text-xs) / 18px
177
+ var(--dx-g-font-sans), sans-serif;
178
+ }
@@ -1,6 +1,43 @@
1
1
  <template>
2
2
  <div lwc:if={showVersionPicker} class="version-picker-container">
3
+ <!-- Small read-only: plain value, no dropdown -->
4
+ <p lwc:if={readOnly} class="version-picker-readonly-small">
5
+ {selectedVersion.label}
6
+ </p>
7
+
8
+ <!-- Small "dot" variant -->
3
9
  <dx-dropdown
10
+ lwc:elseif={small}
11
+ class="version-picker-dropdown-small"
12
+ options={versions}
13
+ analytics-event="custEv_docVersionSelect"
14
+ analytics-payload={analyticsPayload}
15
+ value={selectedVersion.id}
16
+ onchange={onVersionChange}
17
+ >
18
+ <dx-button
19
+ class="version-picker-button version-picker-button-small"
20
+ variant="tertiary"
21
+ size="small"
22
+ font="sans"
23
+ icon-symbol="chevrondown"
24
+ icon-size="xsmall"
25
+ aria-label={smallTriggerAriaLabel}
26
+ >
27
+ <div class="selected-version selected-version-small">
28
+ <template lwc:if={showLatestTag}>
29
+ <span class={dotClass} aria-hidden="true"></span>
30
+ </template>
31
+ <p class="selected-version-label">
32
+ {selectedVersion.label}
33
+ </p>
34
+ </div>
35
+ </dx-button>
36
+ </dx-dropdown>
37
+
38
+ <!-- Default (existing) -->
39
+ <dx-dropdown
40
+ lwc:else
4
41
  options={versions}
5
42
  analytics-event="custEv_docVersionSelect"
6
43
  analytics-payload={analyticsPayload}
@@ -12,6 +12,8 @@ export default class VersionPicker extends LightningElement {
12
12
  private _selectedVersion?: OptionWithNested;
13
13
  private _latestVersion: boolean = false;
14
14
  private _hideBadge: boolean = false;
15
+ private _small: boolean = false;
16
+ private _readOnly: boolean = false;
15
17
 
16
18
  @api
17
19
  get versions() {
@@ -51,6 +53,27 @@ export default class VersionPicker extends LightningElement {
51
53
  this._hideBadge = normalizeBoolean(value);
52
54
  }
53
55
 
56
+ // Opt-in compact "dot" variant (24px, abbreviated label). Off by default so
57
+ // existing consumers render the default trigger unchanged.
58
+ @api
59
+ get small() {
60
+ return this._small;
61
+ }
62
+
63
+ set small(value) {
64
+ this._small = normalizeBoolean(value);
65
+ }
66
+
67
+ // Opt-in read-only state: plain value, no dropdown menu.
68
+ @api
69
+ get readOnly() {
70
+ return this._readOnly;
71
+ }
72
+
73
+ set readOnly(value) {
74
+ this._readOnly = normalizeBoolean(value);
75
+ }
76
+
54
77
  private get showVersionPicker() {
55
78
  return this._versions && this._versions.length !== 0;
56
79
  }
@@ -59,6 +82,25 @@ export default class VersionPicker extends LightningElement {
59
82
  return !this.hideBadge;
60
83
  }
61
84
 
85
+ private get dotClass(): string {
86
+ return `version-picker-dot ${
87
+ this.latestVersion
88
+ ? "version-picker-dot-latest"
89
+ : "version-picker-dot-not-latest"
90
+ }`;
91
+ }
92
+
93
+ // Accessible name for the small trigger: includes the latest state so it
94
+ // isn't conveyed by the dot's color alone (WCAG 1.4.1). Omits the state
95
+ // when the indicator is hidden.
96
+ private get smallTriggerAriaLabel(): string {
97
+ const label = this.selectedVersion?.label ?? "";
98
+ if (!this.showLatestTag) {
99
+ return label;
100
+ }
101
+ return `${label}, ${this.latestVersion ? "Latest" : "Not Latest"}`;
102
+ }
103
+
62
104
  private onVersionChange(e: CustomEvent) {
63
105
  this.dispatchEvent(new CustomEvent("change", { detail: e.detail }));
64
106
  }