@salesforcedevs/docs-components 1.34.0-tlv-alpha → 1.34.1-ai-toolbar-action
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 +3 -2
- package/src/modules/doc/contentActionToolbar/contentActionToolbar.css +58 -4
- package/src/modules/doc/contentActionToolbar/contentActionToolbar.html +60 -28
- package/src/modules/doc/contentActionToolbar/contentActionToolbar.ts +281 -56
- package/src/modules/doc/contentActionToolbar/contentActionToolbarMocks.ts +1 -1
- package/src/modules/doc/contentLayout/contentLayout.ts +2 -1
- package/src/modules/doc/header/header.ts +14 -3
- package/src/modules/doc/unifiedContentLayout/unifiedContentLayout.ts +46 -8
- package/src/modules/doc/versionPicker/versionPicker.css +0 -112
- package/src/modules/doc/versionPicker/versionPicker.html +20 -41
- package/src/modules/doc/versionPicker/versionPicker.ts +0 -91
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@salesforcedevs/docs-components",
|
|
3
|
-
"version": "1.34.
|
|
3
|
+
"version": "1.34.1-ai-toolbar-action",
|
|
4
4
|
"description": "Docs Lightning web components for DSC",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "index.js",
|
|
@@ -25,5 +25,6 @@
|
|
|
25
25
|
"@types/lodash.orderby": "4.6.9",
|
|
26
26
|
"@types/lodash.uniqby": "4.7.9"
|
|
27
27
|
},
|
|
28
|
-
"gitHead": "4629fdd9ca18a13480044ad43515b91945d16aad"
|
|
28
|
+
"gitHead": "4629fdd9ca18a13480044ad43515b91945d16aad",
|
|
29
|
+
"stableVersion": "1.34.1"
|
|
29
30
|
}
|
|
@@ -24,9 +24,63 @@
|
|
|
24
24
|
background-color: var(--dx-g-gray-70);
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
27
|
+
.toolbar-button_view-markdown,
|
|
28
|
+
.divider_view-markdown,
|
|
29
|
+
.toolbar-button_view-llms,
|
|
30
|
+
.divider_view-llms {
|
|
31
|
+
display: none;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.toolbar_no-markdown .toolbar-button_view-llms {
|
|
35
|
+
display: inline-flex;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.toolbar:not(.toolbar_no-markdown) .divider_menu {
|
|
39
|
+
display: none;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.menu-trigger-wrap {
|
|
43
|
+
position: relative;
|
|
44
|
+
display: inline-flex;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.menu-trigger {
|
|
48
|
+
--dx-c-button-custom-color: var(--dx-g-gray-50);
|
|
49
|
+
--dx-c-button-custom-color-hover: var(--dx-g-gray-10);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.menu-trigger-copied {
|
|
53
|
+
position: absolute;
|
|
54
|
+
bottom: 100%;
|
|
55
|
+
right: calc(-1 * var(--dx-g-spacing-xs));
|
|
56
|
+
margin-bottom: var(--dx-g-spacing-xs);
|
|
57
|
+
padding: var(--dx-g-spacing-2xs) var(--dx-g-spacing-sm);
|
|
58
|
+
background: var(--dx-g-gray-50);
|
|
59
|
+
color: white;
|
|
60
|
+
font-family: var(--dx-g-font-sans);
|
|
61
|
+
font-size: var(--dx-g-text-xs);
|
|
62
|
+
white-space: nowrap;
|
|
63
|
+
border-radius: 4px;
|
|
64
|
+
pointer-events: none;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
@media screen and (min-width: 480px) {
|
|
68
|
+
.toolbar-button_view-markdown,
|
|
69
|
+
.divider_view-markdown {
|
|
70
|
+
display: inline-flex;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.toolbar:not(.toolbar_no-markdown) .divider_menu {
|
|
74
|
+
display: block;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
@media screen and (min-width: 768px) {
|
|
79
|
+
.toolbar-button_view-llms {
|
|
80
|
+
display: inline-flex;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.toolbar:not(.toolbar_no-markdown) .divider_view-llms {
|
|
84
|
+
display: inline-flex;
|
|
31
85
|
}
|
|
32
86
|
}
|
|
@@ -1,53 +1,85 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div class=
|
|
3
|
-
<
|
|
2
|
+
<div class={toolbarClass}>
|
|
3
|
+
<template lwc:if={hasMarkdown}>
|
|
4
|
+
<dx-tooltip placement="top-right" label={copyMarkdownTooltipLabel}>
|
|
5
|
+
<dx-button
|
|
6
|
+
class="toolbar-button"
|
|
7
|
+
variant="inline"
|
|
8
|
+
size="small"
|
|
9
|
+
icon-sprite="utility"
|
|
10
|
+
icon-symbol="copy"
|
|
11
|
+
icon-size="medium"
|
|
12
|
+
icon-position="right"
|
|
13
|
+
aria-label={copyMarkdownButtonText}
|
|
14
|
+
onclick={handleCopyMarkdown}
|
|
15
|
+
>
|
|
16
|
+
{copyMarkdownButtonText}
|
|
17
|
+
</dx-button>
|
|
18
|
+
</dx-tooltip>
|
|
19
|
+
|
|
20
|
+
<div class="divider divider_view-markdown"></div>
|
|
21
|
+
|
|
4
22
|
<dx-button
|
|
5
|
-
class="toolbar-button"
|
|
23
|
+
class="toolbar-button toolbar-button_view-markdown"
|
|
6
24
|
variant="inline"
|
|
7
25
|
size="small"
|
|
8
26
|
icon-sprite="utility"
|
|
9
|
-
icon-symbol="
|
|
27
|
+
icon-symbol="new_window"
|
|
10
28
|
icon-size="medium"
|
|
11
29
|
icon-position="right"
|
|
12
|
-
aria-label={
|
|
13
|
-
onclick={
|
|
30
|
+
aria-label={viewMarkdownButtonText}
|
|
31
|
+
onclick={handleViewMarkdown}
|
|
14
32
|
>
|
|
15
|
-
{
|
|
33
|
+
{viewMarkdownButtonText}
|
|
16
34
|
</dx-button>
|
|
17
|
-
</
|
|
35
|
+
</template>
|
|
18
36
|
|
|
19
|
-
<div class="divider"></div>
|
|
37
|
+
<div class="divider divider_view-llms"></div>
|
|
20
38
|
|
|
21
39
|
<dx-button
|
|
22
|
-
class="toolbar-button"
|
|
40
|
+
class="toolbar-button toolbar-button_view-llms"
|
|
23
41
|
variant="inline"
|
|
24
42
|
size="small"
|
|
25
43
|
icon-sprite="utility"
|
|
26
44
|
icon-symbol="new_window"
|
|
27
45
|
icon-size="medium"
|
|
28
46
|
icon-position="right"
|
|
29
|
-
aria-label={
|
|
30
|
-
onclick={
|
|
47
|
+
aria-label={viewLlmsButtonText}
|
|
48
|
+
onclick={handleViewLlms}
|
|
31
49
|
>
|
|
32
|
-
{
|
|
50
|
+
{viewLlmsButtonText}
|
|
33
51
|
</dx-button>
|
|
34
52
|
|
|
35
|
-
<div class="divider
|
|
53
|
+
<div class="divider divider_menu"></div>
|
|
36
54
|
|
|
37
|
-
<
|
|
38
|
-
<dx-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
55
|
+
<span class="menu-trigger-wrap">
|
|
56
|
+
<dx-tooltip placement="top-right" label={moreActionsLabel}>
|
|
57
|
+
<dx-dropdown
|
|
58
|
+
class="toolbar-menu"
|
|
59
|
+
options={menuOptions}
|
|
60
|
+
placement="bottom-end"
|
|
61
|
+
width-mode="fit-content"
|
|
62
|
+
aria-label={moreActionsLabel}
|
|
63
|
+
onchange={handleMenuSelect}
|
|
64
|
+
>
|
|
65
|
+
<dx-button
|
|
66
|
+
class="menu-trigger"
|
|
67
|
+
variant="icon-only"
|
|
68
|
+
size="small"
|
|
69
|
+
icon-sprite="utility"
|
|
70
|
+
icon-symbol="threedots"
|
|
71
|
+
icon-size="medium"
|
|
72
|
+
aria-label={moreActionsLabel}
|
|
73
|
+
></dx-button>
|
|
74
|
+
</dx-dropdown>
|
|
75
|
+
</dx-tooltip>
|
|
76
|
+
<span
|
|
77
|
+
class="menu-trigger-copied"
|
|
78
|
+
if:true={showCopiedFlash}
|
|
79
|
+
role="status"
|
|
48
80
|
>
|
|
49
|
-
{
|
|
50
|
-
</
|
|
51
|
-
</
|
|
81
|
+
{copiedLabel}
|
|
82
|
+
</span>
|
|
83
|
+
</span>
|
|
52
84
|
</div>
|
|
53
85
|
</template>
|
|
@@ -1,14 +1,39 @@
|
|
|
1
1
|
import { LightningElement, api } from "lwc";
|
|
2
|
+
import cx from "classnames";
|
|
3
|
+
import { OptionWithNested } from "typings/custom";
|
|
2
4
|
import { track } from "dxUtils/analytics";
|
|
3
5
|
|
|
4
|
-
const
|
|
6
|
+
const DEFAULT_TOOLTIP_LABEL = "Click to copy";
|
|
5
7
|
const COPIED_TOOLTIP_LABEL = "Copied!";
|
|
6
|
-
const
|
|
8
|
+
const COPIED_RESET_MS = 1000;
|
|
7
9
|
|
|
8
10
|
const ANALYTICS_CONTENT_CATEGORY = "content action toolbar";
|
|
11
|
+
const MORE_ACTIONS_LABEL = "More actions";
|
|
12
|
+
|
|
9
13
|
const COPY_MARKDOWN_LABEL = "Copy as Markdown";
|
|
10
14
|
const VIEW_MARKDOWN_LABEL = "View as Markdown";
|
|
11
|
-
const
|
|
15
|
+
const COPY_MARKDOWN_URL_LABEL = "Copy URL to Markdown";
|
|
16
|
+
const VIEW_LLMS_LABEL = "View llms.txt";
|
|
17
|
+
const COPY_LLMS_URL_LABEL = "Copy URL to llms.txt";
|
|
18
|
+
const OPEN_CHATGPT_LABEL = "Open in ChatGPT";
|
|
19
|
+
const OPEN_CLAUDE_LABEL = "Open in Claude";
|
|
20
|
+
const OPEN_PERPLEXITY_LABEL = "Open in Perplexity";
|
|
21
|
+
|
|
22
|
+
const LLMS_TXT_PATH = "/docs/llms.txt";
|
|
23
|
+
const CHATGPT_URL = "https://chatgpt.com/";
|
|
24
|
+
const CLAUDE_URL = "https://claude.ai/new";
|
|
25
|
+
const PERPLEXITY_URL = "https://www.perplexity.ai/search";
|
|
26
|
+
|
|
27
|
+
const LLMS_TXT_CONTEXT_URL = "https://developer.salesforce.com/docs/llms.txt";
|
|
28
|
+
|
|
29
|
+
const ACTION_COPY_MARKDOWN = "copy-markdown";
|
|
30
|
+
const ACTION_VIEW_MARKDOWN = "view-markdown";
|
|
31
|
+
const ACTION_COPY_MARKDOWN_URL = "copy-markdown-url";
|
|
32
|
+
const ACTION_VIEW_LLMS = "view-llms";
|
|
33
|
+
const ACTION_COPY_LLMS_URL = "copy-llms-url";
|
|
34
|
+
const ACTION_OPEN_CHATGPT = "open-chatgpt";
|
|
35
|
+
const ACTION_OPEN_CLAUDE = "open-claude";
|
|
36
|
+
const ACTION_OPEN_PERPLEXITY = "open-perplexity";
|
|
12
37
|
|
|
13
38
|
export default class ContentActionToolbar extends LightningElement {
|
|
14
39
|
@api
|
|
@@ -23,17 +48,15 @@ export default class ContentActionToolbar extends LightningElement {
|
|
|
23
48
|
}
|
|
24
49
|
private _pageUrl?: string;
|
|
25
50
|
|
|
26
|
-
|
|
27
|
-
copyUrlLabel: string = DEFAULT_COPY_TOOLTIP_LABEL;
|
|
51
|
+
@api pageTitle?: string;
|
|
28
52
|
|
|
29
|
-
|
|
53
|
+
copyMarkdownTooltipLabel: string = DEFAULT_TOOLTIP_LABEL;
|
|
54
|
+
copiedLabel: string | null = null;
|
|
30
55
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
*/
|
|
36
|
-
get markdownUrl(): string | null {
|
|
56
|
+
private copyMarkdownResetTimeout: number | null = null;
|
|
57
|
+
private menuCopiedResetTimeout: number | null = null;
|
|
58
|
+
|
|
59
|
+
private get absolutePageUrl(): string | null {
|
|
37
60
|
if (!this.pageUrl) {
|
|
38
61
|
return null;
|
|
39
62
|
}
|
|
@@ -41,7 +64,15 @@ export default class ContentActionToolbar extends LightningElement {
|
|
|
41
64
|
const url = new URL(this.pageUrl, window.location.href);
|
|
42
65
|
url.hash = "";
|
|
43
66
|
url.search = "";
|
|
67
|
+
return url.toString();
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
get markdownUrl(): string | null {
|
|
71
|
+
if (!this.absolutePageUrl) {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
44
74
|
|
|
75
|
+
const url = new URL(this.absolutePageUrl);
|
|
45
76
|
if (!url.pathname.endsWith(".html")) {
|
|
46
77
|
return null;
|
|
47
78
|
}
|
|
@@ -50,6 +81,57 @@ export default class ContentActionToolbar extends LightningElement {
|
|
|
50
81
|
return url.toString();
|
|
51
82
|
}
|
|
52
83
|
|
|
84
|
+
get llmsUrl(): string {
|
|
85
|
+
return new URL(LLMS_TXT_PATH, window.location.href).toString();
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
get chatGptUrl(): string | null {
|
|
89
|
+
return this.buildAiAssistantUrl(CHATGPT_URL);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
get claudeUrl(): string | null {
|
|
93
|
+
return this.buildAiAssistantUrl(CLAUDE_URL);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
get perplexityUrl(): string | null {
|
|
97
|
+
return this.buildAiAssistantUrl(PERPLEXITY_URL);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
private buildAiAssistantUrl(base: string): string | null {
|
|
101
|
+
if (!this.absolutePageUrl) {
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const title = this.pageTitle?.trim();
|
|
106
|
+
const intro = title
|
|
107
|
+
? `I'm reading "${title}" at ${this.absolutePageUrl}.`
|
|
108
|
+
: `I'm reading ${this.absolutePageUrl}.`;
|
|
109
|
+
|
|
110
|
+
const url = new URL(base);
|
|
111
|
+
url.searchParams.set(
|
|
112
|
+
"q",
|
|
113
|
+
`${intro} Read this page so I can ask questions about it. ` +
|
|
114
|
+
`For broader context, see ${LLMS_TXT_CONTEXT_URL}`
|
|
115
|
+
);
|
|
116
|
+
return url.toString();
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
get hasMarkdown(): boolean {
|
|
120
|
+
return Boolean(this.markdownUrl);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
get toolbarClass(): string {
|
|
124
|
+
return cx("toolbar", !this.hasMarkdown && "toolbar_no-markdown");
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
get moreActionsLabel(): string {
|
|
128
|
+
return MORE_ACTIONS_LABEL;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
get showCopiedFlash(): boolean {
|
|
132
|
+
return this.copiedLabel !== null;
|
|
133
|
+
}
|
|
134
|
+
|
|
53
135
|
get copyMarkdownButtonText(): string {
|
|
54
136
|
return COPY_MARKDOWN_LABEL;
|
|
55
137
|
}
|
|
@@ -58,98 +140,241 @@ export default class ContentActionToolbar extends LightningElement {
|
|
|
58
140
|
return VIEW_MARKDOWN_LABEL;
|
|
59
141
|
}
|
|
60
142
|
|
|
61
|
-
get
|
|
62
|
-
return
|
|
143
|
+
get viewLlmsButtonText(): string {
|
|
144
|
+
return VIEW_LLMS_LABEL;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
get menuOptions(): OptionWithNested[] {
|
|
148
|
+
const groups: OptionWithNested[] = [];
|
|
149
|
+
|
|
150
|
+
if (this.hasMarkdown) {
|
|
151
|
+
groups.push({
|
|
152
|
+
id: "this-page",
|
|
153
|
+
label: "This Page",
|
|
154
|
+
options: [
|
|
155
|
+
{
|
|
156
|
+
id: ACTION_COPY_MARKDOWN,
|
|
157
|
+
label: COPY_MARKDOWN_LABEL,
|
|
158
|
+
iconSprite: "utility",
|
|
159
|
+
iconSymbol: "copy"
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
id: ACTION_VIEW_MARKDOWN,
|
|
163
|
+
label: VIEW_MARKDOWN_LABEL,
|
|
164
|
+
iconSprite: "utility",
|
|
165
|
+
iconSymbol: "new_window"
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
id: ACTION_COPY_MARKDOWN_URL,
|
|
169
|
+
label: COPY_MARKDOWN_URL_LABEL,
|
|
170
|
+
iconSprite: "utility",
|
|
171
|
+
iconSymbol: "link"
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
id: ACTION_OPEN_CHATGPT,
|
|
175
|
+
label: OPEN_CHATGPT_LABEL,
|
|
176
|
+
iconSprite: "utility",
|
|
177
|
+
iconSymbol: "new_window"
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
id: ACTION_OPEN_CLAUDE,
|
|
181
|
+
label: OPEN_CLAUDE_LABEL,
|
|
182
|
+
iconSprite: "utility",
|
|
183
|
+
iconSymbol: "new_window"
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
id: ACTION_OPEN_PERPLEXITY,
|
|
187
|
+
label: OPEN_PERPLEXITY_LABEL,
|
|
188
|
+
iconSprite: "utility",
|
|
189
|
+
iconSymbol: "new_window"
|
|
190
|
+
}
|
|
191
|
+
]
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
groups.push({
|
|
196
|
+
id: "all-documentation",
|
|
197
|
+
label: "All Documentation",
|
|
198
|
+
options: [
|
|
199
|
+
{
|
|
200
|
+
id: ACTION_VIEW_LLMS,
|
|
201
|
+
label: VIEW_LLMS_LABEL,
|
|
202
|
+
iconSprite: "utility",
|
|
203
|
+
iconSymbol: "new_window"
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
id: ACTION_COPY_LLMS_URL,
|
|
207
|
+
label: COPY_LLMS_URL_LABEL,
|
|
208
|
+
iconSprite: "utility",
|
|
209
|
+
iconSymbol: "link"
|
|
210
|
+
}
|
|
211
|
+
]
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
return groups;
|
|
63
215
|
}
|
|
64
216
|
|
|
65
217
|
async handleCopyMarkdown(event: Event) {
|
|
218
|
+
if (await this.copyMarkdown(event)) {
|
|
219
|
+
this.flashCopyMarkdownTooltip();
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
handleViewMarkdown(event: Event) {
|
|
66
224
|
if (!this.markdownUrl) {
|
|
67
225
|
return;
|
|
68
226
|
}
|
|
69
227
|
|
|
70
|
-
this.trackToolbarEvent(
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
);
|
|
228
|
+
this.trackToolbarEvent(event, VIEW_MARKDOWN_LABEL, this.markdownUrl);
|
|
229
|
+
window.open(this.markdownUrl, "_blank", "noopener,noreferrer");
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
handleViewLlms(event: Event) {
|
|
233
|
+
this.trackToolbarEvent(event, VIEW_LLMS_LABEL, this.llmsUrl);
|
|
234
|
+
window.open(this.llmsUrl, "_blank", "noopener,noreferrer");
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
private handleOpenAiAssistant(
|
|
238
|
+
event: Event,
|
|
239
|
+
label: string,
|
|
240
|
+
url: string | null
|
|
241
|
+
) {
|
|
242
|
+
if (!url) {
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
this.trackToolbarEvent(event, label, url);
|
|
247
|
+
window.open(url, "_blank", "noopener,noreferrer");
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
async handleMenuSelect(event: CustomEvent) {
|
|
251
|
+
switch (event.detail) {
|
|
252
|
+
case ACTION_COPY_MARKDOWN:
|
|
253
|
+
if (await this.copyMarkdown(event)) {
|
|
254
|
+
this.flashMenuCopied();
|
|
255
|
+
}
|
|
256
|
+
return;
|
|
257
|
+
case ACTION_VIEW_MARKDOWN:
|
|
258
|
+
this.handleViewMarkdown(event);
|
|
259
|
+
return;
|
|
260
|
+
case ACTION_COPY_MARKDOWN_URL:
|
|
261
|
+
await this.handleCopyMarkdownUrl(event);
|
|
262
|
+
return;
|
|
263
|
+
case ACTION_VIEW_LLMS:
|
|
264
|
+
this.handleViewLlms(event);
|
|
265
|
+
return;
|
|
266
|
+
case ACTION_COPY_LLMS_URL:
|
|
267
|
+
await this.handleCopyLlmsUrl(event);
|
|
268
|
+
return;
|
|
269
|
+
case ACTION_OPEN_CHATGPT:
|
|
270
|
+
this.handleOpenAiAssistant(
|
|
271
|
+
event,
|
|
272
|
+
OPEN_CHATGPT_LABEL,
|
|
273
|
+
this.chatGptUrl
|
|
274
|
+
);
|
|
275
|
+
return;
|
|
276
|
+
case ACTION_OPEN_CLAUDE:
|
|
277
|
+
this.handleOpenAiAssistant(
|
|
278
|
+
event,
|
|
279
|
+
OPEN_CLAUDE_LABEL,
|
|
280
|
+
this.claudeUrl
|
|
281
|
+
);
|
|
282
|
+
return;
|
|
283
|
+
case ACTION_OPEN_PERPLEXITY:
|
|
284
|
+
this.handleOpenAiAssistant(
|
|
285
|
+
event,
|
|
286
|
+
OPEN_PERPLEXITY_LABEL,
|
|
287
|
+
this.perplexityUrl
|
|
288
|
+
);
|
|
289
|
+
break;
|
|
290
|
+
default:
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
private async copyMarkdown(event: Event): Promise<boolean> {
|
|
295
|
+
if (!this.markdownUrl) {
|
|
296
|
+
return false;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
this.trackToolbarEvent(event, COPY_MARKDOWN_LABEL, this.markdownUrl);
|
|
76
300
|
|
|
77
301
|
try {
|
|
78
302
|
const response = await fetch(this.markdownUrl);
|
|
79
303
|
if (!response.ok) {
|
|
80
|
-
return;
|
|
304
|
+
return false;
|
|
81
305
|
}
|
|
82
306
|
const markdown = await response.text();
|
|
83
307
|
await navigator.clipboard.writeText(markdown);
|
|
84
|
-
|
|
308
|
+
return true;
|
|
85
309
|
} catch (error) {
|
|
86
310
|
console.error(error);
|
|
311
|
+
return false;
|
|
87
312
|
}
|
|
88
313
|
}
|
|
89
314
|
|
|
90
|
-
|
|
315
|
+
private async handleCopyMarkdownUrl(event: Event) {
|
|
91
316
|
if (!this.markdownUrl) {
|
|
92
317
|
return;
|
|
93
318
|
}
|
|
94
319
|
|
|
95
320
|
this.trackToolbarEvent(
|
|
96
321
|
event,
|
|
97
|
-
|
|
98
|
-
VIEW_MARKDOWN_LABEL,
|
|
322
|
+
COPY_MARKDOWN_URL_LABEL,
|
|
99
323
|
this.markdownUrl
|
|
100
324
|
);
|
|
101
325
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
return;
|
|
326
|
+
try {
|
|
327
|
+
await navigator.clipboard.writeText(this.markdownUrl);
|
|
328
|
+
this.flashMenuCopied();
|
|
329
|
+
} catch (error) {
|
|
330
|
+
console.error(error);
|
|
108
331
|
}
|
|
332
|
+
}
|
|
109
333
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
"custEv_linkClick",
|
|
113
|
-
COPY_URL_LABEL,
|
|
114
|
-
this.markdownUrl
|
|
115
|
-
);
|
|
334
|
+
private async handleCopyLlmsUrl(event: Event) {
|
|
335
|
+
this.trackToolbarEvent(event, COPY_LLMS_URL_LABEL, this.llmsUrl);
|
|
116
336
|
|
|
117
337
|
try {
|
|
118
|
-
await navigator.clipboard.writeText(this.
|
|
119
|
-
this.
|
|
338
|
+
await navigator.clipboard.writeText(this.llmsUrl);
|
|
339
|
+
this.flashMenuCopied();
|
|
120
340
|
} catch (error) {
|
|
121
341
|
console.error(error);
|
|
122
342
|
}
|
|
123
343
|
}
|
|
124
344
|
|
|
125
|
-
private trackToolbarEvent(
|
|
126
|
-
event
|
|
127
|
-
eventName: "custEv_linkClick",
|
|
128
|
-
label: string,
|
|
129
|
-
url: string
|
|
130
|
-
): void {
|
|
131
|
-
track(event.currentTarget!, eventName, {
|
|
345
|
+
private trackToolbarEvent(event: Event, label: string, url: string): void {
|
|
346
|
+
track(event.currentTarget!, "custEv_linkClick", {
|
|
132
347
|
click_text: label,
|
|
133
348
|
click_url: url,
|
|
134
349
|
element_type: "button_link",
|
|
135
350
|
element_title: label,
|
|
136
351
|
content_category: ANALYTICS_CONTENT_CATEGORY,
|
|
137
352
|
// Source page the CTA was clicked from; `click_url` above is the
|
|
138
|
-
//
|
|
353
|
+
// destination. Uses the same `page_path` expression as the
|
|
139
354
|
// amfReference doc_page_view events.
|
|
140
355
|
page_path: window.location.pathname + window.location.search
|
|
141
356
|
});
|
|
142
357
|
}
|
|
143
358
|
|
|
144
|
-
private
|
|
145
|
-
if (this.
|
|
146
|
-
window.clearTimeout(this.
|
|
359
|
+
private flashCopyMarkdownTooltip() {
|
|
360
|
+
if (this.copyMarkdownResetTimeout !== null) {
|
|
361
|
+
window.clearTimeout(this.copyMarkdownResetTimeout);
|
|
362
|
+
}
|
|
363
|
+
this.copyMarkdownTooltipLabel = COPIED_TOOLTIP_LABEL;
|
|
364
|
+
this.copyMarkdownResetTimeout = window.setTimeout(() => {
|
|
365
|
+
this.copyMarkdownTooltipLabel = DEFAULT_TOOLTIP_LABEL;
|
|
366
|
+
this.copyMarkdownResetTimeout = null;
|
|
367
|
+
}, COPIED_RESET_MS);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
private flashMenuCopied() {
|
|
371
|
+
if (this.menuCopiedResetTimeout !== null) {
|
|
372
|
+
window.clearTimeout(this.menuCopiedResetTimeout);
|
|
147
373
|
}
|
|
148
|
-
this
|
|
149
|
-
this.
|
|
150
|
-
this.
|
|
151
|
-
this.
|
|
152
|
-
|
|
153
|
-
}, COPIED_TOOLTIP_RESET_MS);
|
|
374
|
+
this.copiedLabel = COPIED_TOOLTIP_LABEL;
|
|
375
|
+
this.menuCopiedResetTimeout = window.setTimeout(() => {
|
|
376
|
+
this.copiedLabel = null;
|
|
377
|
+
this.menuCopiedResetTimeout = null;
|
|
378
|
+
}, COPIED_RESET_MS);
|
|
154
379
|
}
|
|
155
380
|
}
|
|
@@ -40,7 +40,7 @@ export function interceptWindowOpenForContentActionToolbar() {
|
|
|
40
40
|
const originalOpen = window.open.bind(window);
|
|
41
41
|
window.open = ((url?: string | URL, target?: string, features?: string) => {
|
|
42
42
|
const stringUrl = url?.toString() ?? "";
|
|
43
|
-
if (stringUrl.endsWith(".md")) {
|
|
43
|
+
if (stringUrl.endsWith(".md") || stringUrl.endsWith("/llms.txt")) {
|
|
44
44
|
return originalOpen(DUMMY_MARKDOWN_DATA_URL, target, features);
|
|
45
45
|
}
|
|
46
46
|
return originalOpen(url ?? "", target, features);
|
|
@@ -307,9 +307,10 @@ export default class ContentLayout extends LightningElement {
|
|
|
307
307
|
const toolbar = (this.contentActionToolbarElement ??
|
|
308
308
|
createElement(CONTENT_ACTION_TOOLBAR_TAG, {
|
|
309
309
|
is: ContentActionToolbar
|
|
310
|
-
})) as HTMLElement & { pageUrl?: string };
|
|
310
|
+
})) as HTMLElement & { pageUrl?: string; pageTitle?: string };
|
|
311
311
|
|
|
312
312
|
toolbar.pageUrl = this.sidebarValue;
|
|
313
|
+
toolbar.pageTitle = heading.textContent?.trim() || undefined;
|
|
313
314
|
|
|
314
315
|
if (toolbar.previousElementSibling !== heading) {
|
|
315
316
|
heading.parentNode?.insertBefore(toolbar, heading.nextSibling);
|
|
@@ -74,6 +74,13 @@ 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
|
+
|
|
77
84
|
connectedCallback(): void {
|
|
78
85
|
super.connectedCallback();
|
|
79
86
|
this.tabletMatchMedia = window.matchMedia(
|
|
@@ -83,9 +90,7 @@ export default class Header extends HeaderBase {
|
|
|
83
90
|
this.tabletMatchMedia.addEventListener("change", this.onTabletChange);
|
|
84
91
|
|
|
85
92
|
if (
|
|
86
|
-
(!this.shouldHideHeader &&
|
|
87
|
-
window.location.pathname.includes("/docs/") &&
|
|
88
|
-
window.location.pathname !== "/docs/apis") ||
|
|
93
|
+
(!this.shouldHideHeader && this.isDocsPath) ||
|
|
89
94
|
window.location.pathname ===
|
|
90
95
|
"/tableau/embedding-playground/overview" ||
|
|
91
96
|
isStorybook()
|
|
@@ -109,6 +114,12 @@ export default class Header extends HeaderBase {
|
|
|
109
114
|
);
|
|
110
115
|
}
|
|
111
116
|
|
|
117
|
+
renderedCallback(): void {
|
|
118
|
+
if (this.hideDocHeader) {
|
|
119
|
+
this.shouldRender = !this.shouldHideHeader && this.isDocsPath;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
112
123
|
private onTabletChange = (e: MediaQueryListEvent | MediaQueryList) =>
|
|
113
124
|
(this.tablet = e.matches);
|
|
114
125
|
|
|
@@ -10,11 +10,38 @@ 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
|
+
|
|
13
39
|
/**
|
|
14
40
|
* Translates per-topic `topicType` into the generic `showForwardArrow` flag
|
|
15
|
-
* that `dx-tree-tile` reads (spec topics get the forward arrow icon for Redoc)
|
|
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
|
|
16
43
|
*/
|
|
17
|
-
function
|
|
44
|
+
function decorateTopics(
|
|
18
45
|
topics: Array<TreeNode & { topicType?: string }> | undefined
|
|
19
46
|
): TreeNode[] | undefined {
|
|
20
47
|
return topics?.map((topic) => {
|
|
@@ -23,10 +50,23 @@ function decorateTopicsWithForwardArrow(
|
|
|
23
50
|
decorated.showForwardArrow = true;
|
|
24
51
|
}
|
|
25
52
|
if (decorated.children) {
|
|
26
|
-
decorated.children =
|
|
27
|
-
decorated.children
|
|
28
|
-
);
|
|
53
|
+
decorated.children = decorateTopics(decorated.children);
|
|
29
54
|
}
|
|
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
|
+
|
|
30
70
|
return decorated;
|
|
31
71
|
});
|
|
32
72
|
}
|
|
@@ -77,9 +117,7 @@ export default class UnifiedContentLayout extends LightningElement {
|
|
|
77
117
|
}
|
|
78
118
|
|
|
79
119
|
set sidebarContent(value: string) {
|
|
80
|
-
this._sidebarContent =
|
|
81
|
-
toJson(value)?.topics
|
|
82
|
-
);
|
|
120
|
+
this._sidebarContent = decorateTopics(toJson(value)?.topics);
|
|
83
121
|
}
|
|
84
122
|
|
|
85
123
|
private get enableFooter(): boolean {
|
|
@@ -62,115 +62,3 @@ 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,58 +1,37 @@
|
|
|
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
|
-
|
|
8
3
|
<dx-dropdown
|
|
9
|
-
lwc:else
|
|
10
|
-
class={dropdownClass}
|
|
11
4
|
options={versions}
|
|
12
5
|
analytics-event="custEv_docVersionSelect"
|
|
13
6
|
analytics-payload={analyticsPayload}
|
|
14
7
|
value={selectedVersion.id}
|
|
15
|
-
width=
|
|
8
|
+
width="var(--doc-version-picker-width)"
|
|
16
9
|
onchange={onVersionChange}
|
|
17
10
|
>
|
|
18
11
|
<dx-button
|
|
19
|
-
class=
|
|
12
|
+
class="version-picker-button"
|
|
20
13
|
variant="tertiary"
|
|
21
14
|
size="small"
|
|
22
|
-
font={triggerFont}
|
|
23
15
|
icon-symbol="chevrondown"
|
|
24
|
-
icon-size=
|
|
25
|
-
aria-label={triggerAriaLabel}
|
|
16
|
+
icon-size="medium"
|
|
26
17
|
>
|
|
27
|
-
<div class=
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
{
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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>
|
|
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>
|
|
56
35
|
</template>
|
|
57
36
|
</div>
|
|
58
37
|
</dx-button>
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { LightningElement, api, track } from "lwc";
|
|
2
|
-
import cx from "classnames";
|
|
3
2
|
|
|
4
3
|
import { AnalyticsPayload, OptionWithNested } from "typings/custom";
|
|
5
4
|
|
|
@@ -13,8 +12,6 @@ export default class VersionPicker extends LightningElement {
|
|
|
13
12
|
private _selectedVersion?: OptionWithNested;
|
|
14
13
|
private _latestVersion: boolean = false;
|
|
15
14
|
private _hideBadge: boolean = false;
|
|
16
|
-
private _small: boolean = false;
|
|
17
|
-
private _readOnly: boolean = false;
|
|
18
15
|
|
|
19
16
|
@api
|
|
20
17
|
get versions() {
|
|
@@ -54,27 +51,6 @@ export default class VersionPicker extends LightningElement {
|
|
|
54
51
|
this._hideBadge = normalizeBoolean(value);
|
|
55
52
|
}
|
|
56
53
|
|
|
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
54
|
private get showVersionPicker() {
|
|
79
55
|
return this._versions && this._versions.length !== 0;
|
|
80
56
|
}
|
|
@@ -83,73 +59,6 @@ export default class VersionPicker extends LightningElement {
|
|
|
83
59
|
return !this.hideBadge;
|
|
84
60
|
}
|
|
85
61
|
|
|
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
|
-
|
|
153
62
|
private onVersionChange(e: CustomEvent) {
|
|
154
63
|
this.dispatchEvent(new CustomEvent("change", { detail: e.detail }));
|
|
155
64
|
}
|