@salesforcedevs/docs-components 1.34.0-docs-feedback-3 → 1.34.0-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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforcedevs/docs-components",
3
- "version": "1.34.0-docs-feedback-3",
3
+ "version": "1.34.0-tlv-alpha",
4
4
  "description": "Docs Lightning web components for DSC",
5
5
  "license": "MIT",
6
6
  "main": "index.js",
@@ -25,6 +25,5 @@
25
25
  "@types/lodash.orderby": "4.6.9",
26
26
  "@types/lodash.uniqby": "4.7.9"
27
27
  },
28
- "gitHead": "4629fdd9ca18a13480044ad43515b91945d16aad",
29
- "stableVersion": "1.34.0"
28
+ "gitHead": "4629fdd9ca18a13480044ad43515b91945d16aad"
30
29
  }
@@ -74,13 +74,6 @@ export default class Header extends HeaderBase {
74
74
  return (this.hideDocHeader && !this.mobile) || this.showDocDivider;
75
75
  }
76
76
 
77
- private get isDocsPath(): boolean {
78
- return (
79
- window.location.pathname.includes("/docs/") &&
80
- window.location.pathname !== "/docs/apis"
81
- );
82
- }
83
-
84
77
  connectedCallback(): void {
85
78
  super.connectedCallback();
86
79
  this.tabletMatchMedia = window.matchMedia(
@@ -90,7 +83,9 @@ export default class Header extends HeaderBase {
90
83
  this.tabletMatchMedia.addEventListener("change", this.onTabletChange);
91
84
 
92
85
  if (
93
- (!this.shouldHideHeader && this.isDocsPath) ||
86
+ (!this.shouldHideHeader &&
87
+ window.location.pathname.includes("/docs/") &&
88
+ window.location.pathname !== "/docs/apis") ||
94
89
  window.location.pathname ===
95
90
  "/tableau/embedding-playground/overview" ||
96
91
  isStorybook()
@@ -114,12 +109,6 @@ export default class Header extends HeaderBase {
114
109
  );
115
110
  }
116
111
 
117
- renderedCallback(): void {
118
- if (this.hideDocHeader) {
119
- this.shouldRender = !this.shouldHideHeader && this.isDocsPath;
120
- }
121
- }
122
-
123
112
  private onTabletChange = (e: MediaQueryListEvent | MediaQueryList) =>
124
113
  (this.tablet = e.matches);
125
114
 
@@ -10,38 +10,11 @@ import type { OptionWithLink, TreeNode } from "typings/custom";
10
10
  */
11
11
  const TOPIC_TYPE_SPEC = "spec";
12
12
 
13
- /**
14
- * Walks down the first-child chain and returns the first markdown content
15
- * page found, descending through nested content-less parents. Returns
16
- * undefined if the chain breaks on a spec or external link before reaching a
17
- * content page.
18
- */
19
- function firstChildContentPage(node: TreeNode): TreeNode | undefined {
20
- const firstChild = node.children?.[0];
21
- if (!firstChild) {
22
- return undefined;
23
- }
24
-
25
- const isSpec =
26
- (firstChild as { topicType?: string }).topicType === TOPIC_TYPE_SPEC;
27
- const isExternal = firstChild.link?.target === "_blank";
28
- if (isSpec || isExternal) {
29
- return undefined;
30
- }
31
-
32
- if (firstChild.link?.href) {
33
- return firstChild;
34
- }
35
-
36
- return firstChildContentPage(firstChild);
37
- }
38
-
39
13
  /**
40
14
  * Translates per-topic `topicType` into the generic `showForwardArrow` flag
41
- * that `dx-tree-tile` reads (spec topics get the forward arrow icon for Redoc),
42
- * and redirects content-less parent topics whose first child is a content page
15
+ * that `dx-tree-tile` reads (spec topics get the forward arrow icon for Redoc).
43
16
  */
44
- function decorateTopics(
17
+ function decorateTopicsWithForwardArrow(
45
18
  topics: Array<TreeNode & { topicType?: string }> | undefined
46
19
  ): TreeNode[] | undefined {
47
20
  return topics?.map((topic) => {
@@ -50,23 +23,10 @@ function decorateTopics(
50
23
  decorated.showForwardArrow = true;
51
24
  }
52
25
  if (decorated.children) {
53
- decorated.children = decorateTopics(decorated.children);
26
+ decorated.children = decorateTopicsWithForwardArrow(
27
+ decorated.children
28
+ );
54
29
  }
55
-
56
- /** Redirect a parent that has no content of its own to its first child
57
- * but only when that first child is itself a content page
58
- */
59
- const isContentlessParent =
60
- !!decorated.children?.length && !decorated.link?.href;
61
-
62
- if (isContentlessParent) {
63
- decorated.redirectToChild = true;
64
- const firstChild = firstChildContentPage(topic);
65
- if (firstChild?.link) {
66
- decorated.link = { ...firstChild.link };
67
- }
68
- }
69
-
70
30
  return decorated;
71
31
  });
72
32
  }
@@ -117,7 +77,9 @@ export default class UnifiedContentLayout extends LightningElement {
117
77
  }
118
78
 
119
79
  set sidebarContent(value: string) {
120
- this._sidebarContent = decorateTopics(toJson(value)?.topics);
80
+ this._sidebarContent = decorateTopicsWithForwardArrow(
81
+ toJson(value)?.topics
82
+ );
121
83
  }
122
84
 
123
85
  private get enableFooter(): boolean {
@@ -62,3 +62,115 @@ 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-c-button-icon-gap: 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
+ .version-picker-button-small::part(container),
105
+ .version-picker-readonly-small {
106
+ box-sizing: border-box;
107
+ height: var(--dx-g-spacing-lg);
108
+ padding: 0 var(--dx-g-spacing-xs);
109
+ border-radius: var(--dx-g-spacing-xs);
110
+ }
111
+
112
+ /* Border is an inset box-shadow, not a real border, so thickening it on
113
+ hover/focus doesn't widen the fit-content box (no horizontal shift). */
114
+ .version-picker-button-small::part(container) {
115
+ /* width:100% re-ties to the 104px-capped host (container is width:inherit,
116
+ which copies width but not max-width). */
117
+ width: 100%;
118
+ background: white;
119
+ box-shadow: inset 0 0 0 1px var(--dx-g-gray-50);
120
+ color: var(--dx-g-gray-10);
121
+ }
122
+
123
+ .version-picker-button-small::part(container):hover {
124
+ background: var(--dx-g-blue-vibrant-95);
125
+ box-shadow: inset 0 0 0 2px var(--dx-g-blue-vibrant-20);
126
+ }
127
+
128
+ .version-picker-button-small:hover,
129
+ .version-picker-button-small:focus-within,
130
+ .version-picker-button-small[aria-expanded="true"] {
131
+ --dx-g-button-icon-color: var(--dx-g-blue-vibrant-20);
132
+ }
133
+
134
+ /* Also matches aria-expanded so the ring stays while the menu is open (opening
135
+ moves focus into the menu, which would otherwise drop :focus-within). */
136
+ .version-picker-button-small:focus-within::part(container),
137
+ .version-picker-button-small[aria-expanded="true"]::part(container) {
138
+ background: var(--dx-g-blue-vibrant-95);
139
+ box-shadow: inset 0 0 0 2px var(--dx-g-blue-vibrant-20), 0 0 0 2px white,
140
+ 0 0 0 4px var(--dx-g-blue-vibrant-60);
141
+ }
142
+
143
+ .selected-version-small {
144
+ flex: 1;
145
+ min-width: 0;
146
+ }
147
+
148
+ .version-picker-dot {
149
+ flex: 0 0 auto;
150
+ width: var(--dx-g-spacing-sm);
151
+ height: var(--dx-g-spacing-sm);
152
+ margin-right: var(--dx-g-spacing-xs);
153
+ border-radius: 50%;
154
+ }
155
+
156
+ .version-picker-dot-latest {
157
+ background: var(--dx-g-green-vibrant-60);
158
+ }
159
+
160
+ .version-picker-dot-not-latest {
161
+ background: var(--dx-g-yellow-vibrant-80);
162
+ }
163
+
164
+ .version-picker-readonly-small {
165
+ display: inline-block;
166
+ width: fit-content;
167
+ max-width: 104px;
168
+ margin: 0;
169
+ border: 1px solid var(--dx-g-gray-80);
170
+ overflow: hidden;
171
+ color: var(--dx-g-gray-10);
172
+ text-overflow: ellipsis;
173
+ white-space: nowrap;
174
+ font: var(--dx-g-font-normal) var(--dx-g-text-xs) /
175
+ var(--dx-g-spacing-lg) var(--dx-g-font-sans), sans-serif;
176
+ }
@@ -1,37 +1,58 @@
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={readOnlyClass}>
5
+ {selectedVersion.label}
6
+ </p>
7
+
3
8
  <dx-dropdown
9
+ lwc:else
10
+ class={dropdownClass}
4
11
  options={versions}
5
12
  analytics-event="custEv_docVersionSelect"
6
13
  analytics-payload={analyticsPayload}
7
14
  value={selectedVersion.id}
8
- width="var(--doc-version-picker-width)"
15
+ width={dropdownWidth}
9
16
  onchange={onVersionChange}
10
17
  >
11
18
  <dx-button
12
- class="version-picker-button"
19
+ class={triggerClass}
13
20
  variant="tertiary"
14
21
  size="small"
22
+ font={triggerFont}
15
23
  icon-symbol="chevrondown"
16
- icon-size="medium"
24
+ icon-size={triggerIconSize}
25
+ aria-label={triggerAriaLabel}
17
26
  >
18
- <div class="selected-version">
19
- <p class="selected-version-label">
20
- {selectedVersion.label}
21
- </p>
22
- <template lwc:if={showLatestTag}>
23
- <dx-type-badge
24
- class="latest-badge"
25
- lwc:if={latestVersion}
26
- value="Latest"
27
- size="small"
28
- ></dx-type-badge>
29
- <dx-type-badge
30
- class="not-latest-badge"
31
- lwc:else
32
- value="Not Latest"
33
- size="small"
34
- ></dx-type-badge>
27
+ <div class={selectedVersionClass}>
28
+ <!-- Small: leading colored dot -->
29
+ <template lwc:if={small}>
30
+ <template lwc:if={showLatestTag}>
31
+ <span class={dotClass} aria-hidden="true"></span>
32
+ </template>
33
+ <p class="selected-version-label">
34
+ {selectedVersion.label}
35
+ </p>
36
+ </template>
37
+ <!-- Default: trailing Latest/Not-Latest badge -->
38
+ <template lwc:else>
39
+ <p class="selected-version-label">
40
+ {selectedVersion.label}
41
+ </p>
42
+ <template lwc:if={showLatestTag}>
43
+ <dx-type-badge
44
+ class="latest-badge"
45
+ lwc:if={latestVersion}
46
+ value="Latest"
47
+ size="small"
48
+ ></dx-type-badge>
49
+ <dx-type-badge
50
+ class="not-latest-badge"
51
+ lwc:else
52
+ value="Not Latest"
53
+ size="small"
54
+ ></dx-type-badge>
55
+ </template>
35
56
  </template>
36
57
  </div>
37
58
  </dx-button>
@@ -1,4 +1,5 @@
1
1
  import { LightningElement, api, track } from "lwc";
2
+ import cx from "classnames";
2
3
 
3
4
  import { AnalyticsPayload, OptionWithNested } from "typings/custom";
4
5
 
@@ -12,6 +13,8 @@ export default class VersionPicker extends LightningElement {
12
13
  private _selectedVersion?: OptionWithNested;
13
14
  private _latestVersion: boolean = false;
14
15
  private _hideBadge: boolean = false;
16
+ private _small: boolean = false;
17
+ private _readOnly: boolean = false;
15
18
 
16
19
  @api
17
20
  get versions() {
@@ -51,6 +54,27 @@ export default class VersionPicker extends LightningElement {
51
54
  this._hideBadge = normalizeBoolean(value);
52
55
  }
53
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
+
54
78
  private get showVersionPicker() {
55
79
  return this._versions && this._versions.length !== 0;
56
80
  }
@@ -59,6 +83,73 @@ export default class VersionPicker extends LightningElement {
59
83
  return !this.hideBadge;
60
84
  }
61
85
 
86
+ // Read-only currently only has a small-variant style.
87
+ private get readOnlyClass(): string {
88
+ return "version-picker-readonly-small";
89
+ }
90
+
91
+ private get dotClass(): string {
92
+ return `version-picker-dot ${
93
+ this.latestVersion
94
+ ? "version-picker-dot-latest"
95
+ : "version-picker-dot-not-latest"
96
+ }`;
97
+ }
98
+
99
+ // Accessible name for the small trigger: includes the latest state so it
100
+ // isn't conveyed by the dot's color alone (WCAG 1.4.1). Omits the state
101
+ // when the indicator is hidden.
102
+ private get smallTriggerAriaLabel(): string {
103
+ const label = this.selectedVersion?.label ?? "";
104
+ if (!this.showLatestTag) {
105
+ return label;
106
+ }
107
+ return `${label}, ${this.latestVersion ? "Latest" : "Not Latest"}`;
108
+ }
109
+
110
+ // --- Per-variant values for the shared dropdown/button markup below. The
111
+ // small variant opts into extra classes and a compact chevron; the default
112
+ // returns undefined so those attributes are omitted (keeps default output
113
+ // unchanged for xmlContent/amfReference).
114
+
115
+ // Not cx(): the default must have NO class attribute (cx returns "", which
116
+ // would render class="" and break the frozen consumer snapshots).
117
+ private get dropdownClass(): string | undefined {
118
+ return this.small ? "version-picker-dropdown-small" : undefined;
119
+ }
120
+
121
+ private get dropdownWidth(): string | undefined {
122
+ return this.small ? undefined : "var(--doc-version-picker-width)";
123
+ }
124
+
125
+ private get triggerClass(): string {
126
+ return cx(
127
+ "version-picker-button",
128
+ this.small && "version-picker-button-small"
129
+ );
130
+ }
131
+
132
+ private get triggerFont(): string {
133
+ return this.small ? "sans" : "display";
134
+ }
135
+
136
+ private get triggerIconSize(): string {
137
+ return this.small ? "xsmall" : "medium";
138
+ }
139
+
140
+ // Default returns "" (dx-button's own default) so the trigger's rendered
141
+ // aria-label is unchanged for the default variant.
142
+ private get triggerAriaLabel(): string {
143
+ return this.small ? this.smallTriggerAriaLabel : "";
144
+ }
145
+
146
+ private get selectedVersionClass(): string {
147
+ return cx(
148
+ "selected-version",
149
+ this.small && "selected-version-small"
150
+ );
151
+ }
152
+
62
153
  private onVersionChange(e: CustomEvent) {
63
154
  this.dispatchEvent(new CustomEvent("change", { detail: e.detail }));
64
155
  }