@salesforcedevs/docs-components 0.3.11 → 0.3.14-banner-alpha1

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 (107) hide show
  1. package/lwc.config.json +12 -3
  2. package/package.json +17 -7
  3. package/src/modules/README.md +41 -0
  4. package/src/modules/doc/amfReference/amfReference.css +5 -0
  5. package/src/modules/doc/amfReference/amfReference.html +47 -0
  6. package/src/modules/doc/amfReference/amfReference.ts +1361 -0
  7. package/src/modules/doc/amfReference/constants.ts +76 -0
  8. package/src/modules/doc/amfReference/types.ts +133 -0
  9. package/src/modules/doc/amfReference/utils.ts +669 -0
  10. package/src/modules/doc/amfTopic/amfTopic.css +1 -0
  11. package/src/modules/doc/amfTopic/amfTopic.html +3 -0
  12. package/src/modules/doc/amfTopic/amfTopic.ts +94 -0
  13. package/src/modules/doc/amfTopic/types.ts +54 -0
  14. package/src/modules/doc/amfTopic/utils.ts +130 -0
  15. package/src/modules/doc/breadcrumbItem/breadcrumbItem.css +51 -0
  16. package/src/modules/doc/breadcrumbItem/breadcrumbItem.html +5 -0
  17. package/src/modules/doc/breadcrumbItem/breadcrumbItem.ts +64 -0
  18. package/src/modules/doc/breadcrumbs/breadcrumbs.css +27 -0
  19. package/src/modules/doc/breadcrumbs/breadcrumbs.html +60 -0
  20. package/src/modules/doc/breadcrumbs/breadcrumbs.ts +187 -0
  21. package/src/modules/doc/content/content.css +58 -102
  22. package/src/modules/doc/content/content.ts +261 -174
  23. package/src/modules/doc/contentCallout/contentCallout.css +7 -24
  24. package/src/modules/doc/contentCallout/contentCallout.html +4 -2
  25. package/src/modules/doc/contentCallout/contentCallout.ts +8 -2
  26. package/src/modules/doc/contentLayout/contentLayout.css +98 -0
  27. package/src/modules/doc/contentLayout/contentLayout.html +51 -0
  28. package/src/modules/doc/contentLayout/contentLayout.ts +322 -0
  29. package/src/modules/doc/header/header.css +103 -0
  30. package/src/modules/doc/header/header.html +160 -0
  31. package/src/modules/doc/header/header.ts +146 -0
  32. package/src/modules/doc/heading/heading.css +54 -0
  33. package/src/modules/doc/heading/heading.html +14 -0
  34. package/src/modules/doc/heading/heading.ts +65 -0
  35. package/src/modules/doc/headingAnchor/headingAnchor.css +33 -0
  36. package/src/modules/doc/headingAnchor/headingAnchor.html +19 -0
  37. package/src/modules/doc/headingAnchor/headingAnchor.ts +43 -0
  38. package/src/modules/doc/headingContent/headingContent.css +53 -0
  39. package/src/modules/doc/headingContent/headingContent.html +13 -0
  40. package/src/modules/doc/headingContent/headingContent.ts +30 -0
  41. package/src/modules/doc/phase/phase.css +55 -0
  42. package/src/modules/doc/phase/phase.html +28 -0
  43. package/src/modules/doc/phase/phase.ts +57 -0
  44. package/src/modules/doc/sprigSurvey/sprigSurvey.html +20 -0
  45. package/src/modules/doc/sprigSurvey/sprigSurvey.scoped.css +12 -0
  46. package/src/modules/doc/sprigSurvey/sprigSurvey.ts +16 -0
  47. package/src/modules/doc/toc/toc.html +3 -1
  48. package/src/modules/doc/toolbar/toolbar.ts +6 -6
  49. package/src/modules/doc/xmlContent/types.ts +114 -0
  50. package/src/modules/doc/xmlContent/utils.ts +161 -0
  51. package/src/modules/doc/xmlContent/xmlContent.css +32 -0
  52. package/src/modules/doc/xmlContent/xmlContent.html +40 -0
  53. package/src/modules/doc/xmlContent/xmlContent.ts +677 -0
  54. package/src/modules/docBaseElements/lightningElementWithState/lightningElementWithState.ts +93 -0
  55. package/src/modules/docHelpers/amfStyle/amfStyle.css +355 -0
  56. package/src/modules/docHelpers/phaseContentLayout/phaseContentLayout.css +39 -0
  57. package/src/modules/docHelpers/status/status.css +22 -0
  58. package/src/modules/docUtils/SearchSyncer/SearchSyncer.ts +85 -0
  59. package/LICENSE +0 -12
  60. package/src/modules/doc/container/__benchmarks__/container.benchmark.js +0 -43
  61. package/src/modules/doc/container/__mocks__/mockAvailableLanguages.js +0 -8
  62. package/src/modules/doc/container/__mocks__/mockAvailableVersions.js +0 -122
  63. package/src/modules/doc/container/__mocks__/mockContentFetchResponse.json +0 -5
  64. package/src/modules/doc/container/__mocks__/mockDocContent.js +0 -29
  65. package/src/modules/doc/container/__mocks__/mockNavigationFetchResponse.json +0 -4061
  66. package/src/modules/doc/container/__mocks__/mockPageReference.js +0 -8
  67. package/src/modules/doc/container/__mocks__/mockPdfUrl.js +0 -1
  68. package/src/modules/doc/container/__mocks__/mockSelectedLanguage.js +0 -8
  69. package/src/modules/doc/container/__mocks__/mockSelectedVersion.js +0 -8
  70. package/src/modules/doc/container/__mocks__/mockToc.js +0 -146
  71. package/src/modules/doc/container/__tests__/container.test.ts +0 -117
  72. package/src/modules/doc/container/container.css +0 -37
  73. package/src/modules/doc/container/container.html +0 -28
  74. package/src/modules/doc/container/container.stories.ts +0 -44
  75. package/src/modules/doc/container/container.ts +0 -367
  76. package/src/modules/doc/content/__tests__/content.test.ts +0 -99
  77. package/src/modules/doc/content/__tests__/mockDocContent.ts +0 -258
  78. package/src/modules/doc/content/__tests__/mockPageReference.ts +0 -8
  79. package/src/modules/doc/content/content.stories.ts +0 -82
  80. package/src/modules/doc/contentCallout/__tests__/contentCallout.test.ts +0 -80
  81. package/src/modules/doc/contentCallout/__tests__/mockProps.ts +0 -14
  82. package/src/modules/doc/contentCallout/contentCallout.stories.ts +0 -29
  83. package/src/modules/doc/contentMedia/__tests__/contentMedia.test.ts +0 -97
  84. package/src/modules/doc/contentMedia/contentMedia.stories.ts +0 -113
  85. package/src/modules/doc/landing/__tests__/landing.test.ts +0 -60
  86. package/src/modules/doc/landing/__tests__/mockFetch.json +0 -370
  87. package/src/modules/doc/landing/landing.css +0 -63
  88. package/src/modules/doc/landing/landing.html +0 -122
  89. package/src/modules/doc/landing/landing.stories.ts +0 -21
  90. package/src/modules/doc/landing/landing.ts +0 -222
  91. package/src/modules/doc/nav/__tests__/mockAvailableLanguages.ts +0 -8
  92. package/src/modules/doc/nav/__tests__/mockAvailableVersions.ts +0 -122
  93. package/src/modules/doc/nav/__tests__/mockPageReference.ts +0 -8
  94. package/src/modules/doc/nav/__tests__/mockPdfUrl.ts +0 -1
  95. package/src/modules/doc/nav/__tests__/mockSelectedLanguage.ts +0 -8
  96. package/src/modules/doc/nav/__tests__/mockSelectedVersion.ts +0 -8
  97. package/src/modules/doc/nav/__tests__/mockToc.ts +0 -146
  98. package/src/modules/doc/nav/__tests__/nav.test.ts +0 -58
  99. package/src/modules/doc/toc/__tests__/mockPageReference.ts +0 -8
  100. package/src/modules/doc/toc/__tests__/mockToc.ts +0 -146
  101. package/src/modules/doc/toc/__tests__/toc.test.ts +0 -29
  102. package/src/modules/doc/toolbar/__tests__/mockAvailableLanguages.ts +0 -8
  103. package/src/modules/doc/toolbar/__tests__/mockAvailableVersions.ts +0 -122
  104. package/src/modules/doc/toolbar/__tests__/mockPdfUrl.ts +0 -1
  105. package/src/modules/doc/toolbar/__tests__/mockSelectedLanguage.ts +0 -8
  106. package/src/modules/doc/toolbar/__tests__/mockSelectedVersion.ts +0 -8
  107. package/src/modules/doc/toolbar/__tests__/toolbar.test.ts +0 -44
@@ -0,0 +1,160 @@
1
+ <template>
2
+ <dx-brand-theme-provider brand={brand}>
3
+ <header class={className}>
4
+ <dx-skip-nav-link></dx-skip-nav-link>
5
+ <dx-banner
6
+ if:true={showBanner}
7
+ banner-markup={bannerMarkup}
8
+ ></dx-banner>
9
+ <div class="header_l1">
10
+ <div if:true={showMenuButton} class="nav_menu-ctas">
11
+ <dx-button
12
+ aria-label="Menu Button"
13
+ class="nav_menu-button"
14
+ icon-size="large"
15
+ icon-symbol={mobileMenuIconSymbol}
16
+ variant="tertiary"
17
+ onclick={toggleMobileNavMenu}
18
+ ></dx-button>
19
+ </div>
20
+ <dx-logo label={title}></dx-logo>
21
+ <dx-header-nav
22
+ if:true={showDesktopNavItems}
23
+ aria-label="Global Navigation Bar"
24
+ nav-items={navItems}
25
+ onrequestopennavmenu={onRequestOpenNavMenu}
26
+ pathname={pathname}
27
+ variant="small"
28
+ ></dx-header-nav>
29
+ <div class="header-cta-container">
30
+ <dx-header-search
31
+ if:true={hasSearch}
32
+ coveo-organization-id={coveoOrganizationId}
33
+ coveo-public-access-token={coveoPublicAccessToken}
34
+ coveo-search-pipeline={coveoSearchPipeline}
35
+ coveo-search-hub={coveoSearchHub}
36
+ mobile={tablet}
37
+ onstatechange={handleStateChange}
38
+ ></dx-header-search>
39
+ </div>
40
+ <div
41
+ if:true={showTbidLogin}
42
+ class="header-tbid-login"
43
+ onclick={closeMobileNavMenu}
44
+ >
45
+ <dw-tbid-login-menu></dw-tbid-login-menu>
46
+ </div>
47
+ <div if:true={showSignup} class="header-login-signup">
48
+ <dx-button
49
+ aria-label="Sign Up For Salesforce Developer Edition"
50
+ size="small"
51
+ href={signupLink}
52
+ onclick={handleSignUpClick}
53
+ >
54
+ Sign Up
55
+ </dx-button>
56
+ </div>
57
+ <dx-header-mobile-nav-menu
58
+ if:true={hasNavItems}
59
+ nav-items={navItems}
60
+ open={showMobileNavMenu}
61
+ pathname={pathname}
62
+ value={mobileNavMenuValue}
63
+ onchange={onMobileNavMenuChange}
64
+ onrequestclose={closeMobileNavMenu}
65
+ >
66
+ <dx-button
67
+ aria-label={bailLabel}
68
+ if:true={hasBailLink}
69
+ href={bailHref}
70
+ variant="tertiary"
71
+ icon-symbol="new_window"
72
+ >
73
+ {bailLabel}
74
+ </dx-button>
75
+ </dx-header-mobile-nav-menu>
76
+ </div>
77
+ <div class="header_l2">
78
+ <div class="header_l2_group header_l2_group-title">
79
+ <a href={headerHref} class="home-link">
80
+ <dx-icon
81
+ class="brand-icon"
82
+ if:true={isValidBrand}
83
+ sprite="salesforcebrand"
84
+ symbol={brand}
85
+ size="xlarge"
86
+ ></dx-icon>
87
+ <span class="subtitle dx-text-heading-4">
88
+ {subtitle}
89
+ </span>
90
+ </a>
91
+ <dx-dropdown
92
+ if:true={showMobileLanguages}
93
+ class="header_lang-dropdown"
94
+ options={languages}
95
+ small
96
+ value={language}
97
+ value-path={langValuePath}
98
+ onchange={onLangChange}
99
+ >
100
+ <dx-button
101
+ aria-label="Select Language"
102
+ variant="inline"
103
+ icon-size="large"
104
+ icon-symbol="world"
105
+ ></dx-button>
106
+ </dx-dropdown>
107
+ </div>
108
+ <div
109
+ if:true={hasScopedNavItems}
110
+ class="header_l2_group header_l2_group-nav"
111
+ >
112
+ <div
113
+ class="header_l2_group-nav_overflow"
114
+ onscroll={onNavScroll}
115
+ >
116
+ <dx-header-nav
117
+ aria-label="Scoped Navigation Bar"
118
+ nav-items={scopedNavItems}
119
+ pathname={pathname}
120
+ ></dx-header-nav>
121
+ </div>
122
+ </div>
123
+ <div
124
+ if:false={smallMobile}
125
+ class="header_l2_group header_l2_group-right-ctas"
126
+ >
127
+ <dx-dropdown
128
+ if:true={hasLanguages}
129
+ class="header_lang-dropdown"
130
+ options={languages}
131
+ small
132
+ value-path={langValuePath}
133
+ value={language}
134
+ onchange={onLangChange}
135
+ >
136
+ <dx-button
137
+ aria-label="Select Language"
138
+ variant="inline"
139
+ icon-size="small"
140
+ icon-symbol="world"
141
+ >
142
+ {languageLabel}
143
+ </dx-button>
144
+ </dx-dropdown>
145
+ <dx-button
146
+ if:true={hasBailLink}
147
+ aria-label={bailLabel}
148
+ class="header_bail-link"
149
+ href={bailHref}
150
+ variant="tertiary"
151
+ icon-symbol="new_window"
152
+ target="_blank"
153
+ >
154
+ {bailLabel}
155
+ </dx-button>
156
+ </div>
157
+ </div>
158
+ </header>
159
+ </dx-brand-theme-provider>
160
+ </template>
@@ -0,0 +1,146 @@
1
+ import { api } from "lwc";
2
+ import cx from "classnames";
3
+ import type { OptionWithNested, OptionWithLink } from "typings/custom";
4
+ import { HeaderBase } from "dxBaseElements/headerBase";
5
+ import { toJson } from "dxUtils/normalizers";
6
+ import get from "lodash.get";
7
+
8
+ const TABLET_MATCH = "980px";
9
+ const MOBILE_MATCH = "880px";
10
+ const SMALL_MOBILE_MATCH = "740px";
11
+
12
+ export default class Header extends HeaderBase {
13
+ @api langValuePath: string = "id"; // allows to override how language property is interpreted, follows valuePath dropdown api.
14
+ @api headerHref: string = "/";
15
+
16
+ @api
17
+ get scopedNavItems() {
18
+ return this._scopedNavItems;
19
+ }
20
+
21
+ set scopedNavItems(value) {
22
+ this._scopedNavItems = toJson(value);
23
+ }
24
+
25
+ @api
26
+ get languages() {
27
+ return this._languages;
28
+ }
29
+
30
+ set languages(value) {
31
+ this._languages = toJson(value);
32
+ }
33
+
34
+ @api
35
+ get language() {
36
+ return this._language;
37
+ }
38
+
39
+ set language(value) {
40
+ if (this._language !== value) {
41
+ this._language = value;
42
+ }
43
+ }
44
+
45
+ private _language: string | null = null;
46
+ private _languages!: OptionWithLink[];
47
+ private _scopedNavItems!: OptionWithNested[];
48
+ private smallMobile = false;
49
+ private smallMobileMatchMedia!: MediaQueryList;
50
+ private tablet = false;
51
+ private tabletMatchMedia!: MediaQueryList;
52
+
53
+ protected mobileBreakpoint(): string {
54
+ return MOBILE_MATCH;
55
+ }
56
+
57
+ private get hasScopedNavItems(): boolean {
58
+ return this.scopedNavItems && this.scopedNavItems.length > 0;
59
+ }
60
+
61
+ private get showDesktopNavItems(): boolean {
62
+ return !this.mobile && this.hasNavItems;
63
+ }
64
+
65
+ private get showTbidLogin(): boolean {
66
+ return this.showSignup;
67
+ }
68
+
69
+ private get showSignup(): boolean {
70
+ return this.signupLink
71
+ ? (this.tablet && !this.isSearchOpen) || !this.tablet
72
+ : false;
73
+ }
74
+
75
+ private get hasLanguages(): boolean {
76
+ return !!(this.languages && this.languages.length);
77
+ }
78
+
79
+ private get showMobileLanguages(): boolean {
80
+ return this.smallMobile && this.hasLanguages;
81
+ }
82
+
83
+ private get languageLabel(): string {
84
+ return (
85
+ (this.language &&
86
+ this.languages.find(
87
+ (lang) => get(lang, this.langValuePath) === this.language
88
+ )?.label) ||
89
+ this.languages[0].label
90
+ );
91
+ }
92
+
93
+ private get showMenuButton(): boolean {
94
+ return this.mobile && this.hasNavItems;
95
+ }
96
+
97
+ connectedCallback(): void {
98
+ super.connectedCallback();
99
+ this.tabletMatchMedia = window.matchMedia(
100
+ `(max-width: ${TABLET_MATCH})`
101
+ );
102
+ this.onTabletChange(this.tabletMatchMedia);
103
+ this.tabletMatchMedia.addEventListener("change", this.onTabletChange);
104
+
105
+ this.smallMobileMatchMedia = window.matchMedia(
106
+ `(max-width: ${SMALL_MOBILE_MATCH})`
107
+ );
108
+ this.onSmallMobileChange(this.smallMobileMatchMedia);
109
+ this.smallMobileMatchMedia.addEventListener(
110
+ "change",
111
+ this.onSmallMobileChange
112
+ );
113
+ }
114
+
115
+ disconnectedCallback(): void {
116
+ super.disconnectedCallback();
117
+ this.tabletMatchMedia.removeEventListener(
118
+ "change",
119
+ this.onTabletChange
120
+ );
121
+
122
+ this.smallMobileMatchMedia.removeEventListener(
123
+ "change",
124
+ this.onSmallMobileChange
125
+ );
126
+ }
127
+
128
+ private onTabletChange = (e: MediaQueryListEvent | MediaQueryList) =>
129
+ (this.tablet = e.matches);
130
+
131
+ private onSmallMobileChange = (e: MediaQueryListEvent | MediaQueryList) =>
132
+ (this.smallMobile = e.matches);
133
+
134
+ protected additionalClasses(): string {
135
+ return cx(
136
+ this.brand && "has-brand",
137
+ this.hasScopedNavItems && "has-scoped-nav-items"
138
+ );
139
+ }
140
+
141
+ private onLangChange(event: CustomEvent<string>): void {
142
+ const { detail } = event;
143
+ this._language = detail;
144
+ this.dispatchEvent(new CustomEvent("langchange", { detail }));
145
+ }
146
+ }
@@ -0,0 +1,54 @@
1
+ h1,
2
+ h2,
3
+ h3,
4
+ h4,
5
+ h5,
6
+ h6 {
7
+ color: var(--dx-g-blue-vibrant-20);
8
+ font-family: var(--dx-g-font-display);
9
+ font-weight: var(--dx-g-font-demi);
10
+ }
11
+
12
+ .display-3 {
13
+ margin: 0 0 24px 0;
14
+ font-size: var(--dx-g-text-3xl);
15
+ letter-spacing: -0.85px;
16
+ line-height: var(--dx-g-text-4xl);
17
+ }
18
+
19
+ .display-3 doc-heading-content {
20
+ --doc-c-heading-anchor-button-bottom: 8px;
21
+ }
22
+
23
+ .display-4 {
24
+ margin: var(--dx-g-spacing-xl) 0 var(--dx-g-spacing-md) 0;
25
+ font-size: var(--dx-g-text-xl);
26
+ letter-spacing: -0.1px;
27
+ line-height: var(--dx-g-spacing-lg);
28
+ }
29
+
30
+ .display-4 doc-heading-content {
31
+ --doc-c-heading-anchor-button-bottom: -3px;
32
+ }
33
+
34
+ .display-5 {
35
+ margin: var(--dx-g-spacing-lg) 0 var(--dx-g-spacing-md) 0;
36
+ font-size: var(--dx-g-text-lg);
37
+ letter-spacing: -0.1px;
38
+ line-height: var(--dx-g-spacing-lg);
39
+ }
40
+
41
+ .display-5 doc-heading-content {
42
+ --doc-c-heading-anchor-button-bottom: -4px;
43
+ }
44
+
45
+ .display-6 {
46
+ margin: var(--dx-g-spacing-md) 0 var(--dx-g-spacing-sm) 0;
47
+ font-size: var(--dx-g-text-base);
48
+ letter-spacing: 0;
49
+ line-height: var(--dx-g-spacing-mlg);
50
+ }
51
+
52
+ .display-6 doc-heading-content {
53
+ --doc-c-heading-anchor-button-bottom: -6px;
54
+ }
@@ -0,0 +1,14 @@
1
+ <template>
2
+ <h1 class={className} if:true={isAriaLevelOne}>
3
+ <doc-heading-content title={title} hash={hash}></doc-heading-content>
4
+ </h1>
5
+ <h2 class={className} if:true={isAriaLevelTwo}>
6
+ <doc-heading-content title={title} hash={hash}></doc-heading-content>
7
+ </h2>
8
+ <h3 class={className} if:true={isAriaLevelThree}>
9
+ <doc-heading-content title={title} hash={hash}></doc-heading-content>
10
+ </h3>
11
+ <h4 class={className} if:true={isAriaLevelFour}>
12
+ <doc-heading-content title={title} hash={hash}></doc-heading-content>
13
+ </h4>
14
+ </template>
@@ -0,0 +1,65 @@
1
+ import { LightningElement, api } from "lwc";
2
+
3
+ export const displayLevels = ["3", "4", "5", "6"];
4
+
5
+ export const ariaLevels = ["1", "2", "3", "4"];
6
+
7
+ export const ariaDisplayLevels: { [key: string]: string } = {
8
+ "1": "3",
9
+ "2": "4",
10
+ "3": "5",
11
+ "4": "6"
12
+ };
13
+
14
+ export default class Heading extends LightningElement {
15
+ @api title: string = "";
16
+ @api hash: string | null = null;
17
+
18
+ @api
19
+ private get ariaLevel(): string {
20
+ return this._ariaLevel || "2";
21
+ }
22
+ private set ariaLevel(value: string | null) {
23
+ if (value && !ariaLevels.includes(value)) {
24
+ console.error(`Invalid aria-level: "${value}"`);
25
+ return;
26
+ }
27
+ if (value) {
28
+ this._ariaLevel = value;
29
+ }
30
+ }
31
+
32
+ @api
33
+ private get displayLevel(): string {
34
+ return this._displayLevel || ariaDisplayLevels[this.ariaLevel];
35
+ }
36
+ private set displayLevel(value: string | null) {
37
+ if (value && !displayLevels.includes(value)) {
38
+ console.error(`Invalid display-level: "${value}"`);
39
+ value = null;
40
+ }
41
+ if (value) {
42
+ this._displayLevel = value;
43
+ }
44
+ }
45
+
46
+ private _ariaLevel: string | null = null;
47
+ private _displayLevel: string | null = null;
48
+
49
+ private get isAriaLevelOne(): boolean {
50
+ return this.ariaLevel === "1";
51
+ }
52
+ private get isAriaLevelTwo(): boolean {
53
+ return this.ariaLevel === "2";
54
+ }
55
+ private get isAriaLevelThree(): boolean {
56
+ return this.ariaLevel === "3";
57
+ }
58
+ private get isAriaLevelFour(): boolean {
59
+ return this.ariaLevel === "4";
60
+ }
61
+
62
+ private get className(): string {
63
+ return `display-${this.displayLevel}`;
64
+ }
65
+ }
@@ -0,0 +1,33 @@
1
+ @import "dxHelpers/reset";
2
+
3
+ button {
4
+ opacity: 0;
5
+ color: rgb(11, 92, 171);
6
+ }
7
+
8
+ button:hover {
9
+ opacity: 1;
10
+ outline: none;
11
+ }
12
+
13
+ button:focus {
14
+ opacity: 1;
15
+ outline: none;
16
+ }
17
+
18
+ button:focus-visible {
19
+ border-radius: 4px;
20
+ border: 2px solid rgb(11, 92, 171);
21
+ }
22
+
23
+ .icon-wrapper {
24
+ height: 32px;
25
+ width: 32px;
26
+ display: flex;
27
+ justify-content: center;
28
+ align-items: center;
29
+ }
30
+
31
+ .icon-container {
32
+ --dx-c-icon-size: 18px;
33
+ }
@@ -0,0 +1,19 @@
1
+ <template>
2
+ <dx-tooltip placement="top" label={label}>
3
+ <button
4
+ onclick={onIconClick}
5
+ aria-label={ariaLabel}
6
+ onkeydown={onKeyDown}
7
+ part="headingAnchorIcon"
8
+ >
9
+ <div class="icon-wrapper">
10
+ <dx-icon
11
+ sprite={iconSprite}
12
+ size={iconSize}
13
+ symbol={iconSymbol}
14
+ class="icon-container"
15
+ ></dx-icon>
16
+ </div>
17
+ </button>
18
+ </dx-tooltip>
19
+ </template>
@@ -0,0 +1,43 @@
1
+ import { LightningElement, api } from "lwc";
2
+ import { IconSprite, IconSize, IconSymbol } from "typings/custom";
3
+
4
+ export default class HeadingAnchor extends LightningElement {
5
+ @api ariaLabel: string = "copy";
6
+ @api iconSize?: IconSize = "override";
7
+ @api iconSprite?: IconSprite = "utility";
8
+ @api iconSymbol?: IconSymbol;
9
+ @api title: string = "";
10
+ @api urlText: string = "";
11
+
12
+ label: string = "Copy link to clipboard";
13
+
14
+ private async onIconClick() {
15
+ await this.iconClickHandler();
16
+ }
17
+
18
+ private async iconClickHandler() {
19
+ this.label = "Copied";
20
+ setTimeout(() => {
21
+ this.label = "Copy link to clipboard";
22
+ }, 2000);
23
+
24
+ try {
25
+ if (this.title && this.urlText) {
26
+ const [hostUrl] = window.location.href.split("#");
27
+ const url = `${hostUrl}#${this.urlText}`;
28
+ await navigator.clipboard.writeText(url);
29
+ }
30
+ } catch (error) {
31
+ console.error(error);
32
+ }
33
+ }
34
+
35
+ private async onKeyDown(e: KeyboardEvent) {
36
+ switch (e.key) {
37
+ case "Enter":
38
+ await this.iconClickHandler();
39
+ break;
40
+ default:
41
+ }
42
+ }
43
+ }
@@ -0,0 +1,53 @@
1
+ @import "dxHelpers/reset";
2
+
3
+ :host {
4
+ --doc-c-heading-anchor-button-bottom: 0;
5
+ --doc-c-heading-anchor-icon-size: 18px;
6
+ --button-size: var(--dx-g-spacing-xl);
7
+ }
8
+
9
+ dx-tooltip {
10
+ line-height: var(--button-size);
11
+ padding-right: var(--dx-g-spacing-xs);
12
+ }
13
+
14
+ .button-container {
15
+ height: 100%;
16
+ margin-right: calc(var(--dx-g-spacing-xl) - 4px);
17
+ position: relative;
18
+ padding-right: var(--dx-g-spacing-xs);
19
+ }
20
+
21
+ button {
22
+ position: absolute;
23
+ bottom: var(--doc-c-heading-anchor-button-bottom);
24
+ left: 0;
25
+ opacity: 0;
26
+ color: rgb(11, 92, 171);
27
+ display: flex;
28
+ justify-content: center;
29
+ align-items: center;
30
+ height: var(--button-size);
31
+ width: var(--button-size);
32
+ border-radius: 4px;
33
+ }
34
+
35
+ dx-icon {
36
+ --dx-c-icon-size: var(--doc-c-heading-anchor-icon-size);
37
+ }
38
+
39
+ .title {
40
+ word-break: break-word;
41
+ }
42
+
43
+ button:focus {
44
+ box-shadow: 0 0 0 2px rgb(11 92 171);
45
+ }
46
+
47
+ button:focus,
48
+ button:hover,
49
+ span:hover dx-tooltip button,
50
+ span:hover ~ dx-tooltip button {
51
+ opacity: 1;
52
+ outline: none;
53
+ }
@@ -0,0 +1,13 @@
1
+ <template>
2
+ <template if:false={hash}>{title}</template>
3
+ <template if:true={hash}>
4
+ <span class="title">{title}&nbsp;</span>
5
+ <dx-tooltip placement="top" label={label}>
6
+ <span class="button-container">
7
+ <button onclick={copy} aria-label="copy">
8
+ <dx-icon size="override" symbol="link"></dx-icon>
9
+ </button>
10
+ </span>
11
+ </dx-tooltip>
12
+ </template>
13
+ </template>
@@ -0,0 +1,30 @@
1
+ import { LightningElement, api } from "lwc";
2
+
3
+ export default class HeadingContent extends LightningElement {
4
+ @api title: string = "";
5
+ @api hash: string | null = null;
6
+
7
+ label: string = "Copy link to clipboard";
8
+ timeout: number | null = null;
9
+
10
+ private async copy() {
11
+ if (this.timeout) {
12
+ window.clearTimeout(this.timeout);
13
+ }
14
+
15
+ this.label = "Copied";
16
+ this.timeout = window.setTimeout(() => {
17
+ this.label = "Copy link to clipboard";
18
+ }, 2000);
19
+
20
+ try {
21
+ if (this.title && this.hash) {
22
+ const [hostUrl] = window.location.href.split("#");
23
+ const url = `${hostUrl}#${this.hash}`;
24
+ await navigator.clipboard.writeText(url);
25
+ }
26
+ } catch (error) {
27
+ console.error(error);
28
+ }
29
+ }
30
+ }
@@ -0,0 +1,55 @@
1
+ @import "dxHelpers/reset";
2
+ @import "dxHelpers/text";
3
+ @import "docHelpers/status";
4
+
5
+ .doc-phase-container {
6
+ display: flex;
7
+ flex-direction: column;
8
+ padding-left: var(--dx-g-spacing-3xl);
9
+ padding-right: var(--dx-g-spacing-3xl);
10
+ width: 100%;
11
+ }
12
+
13
+ .doc-phase-title-container {
14
+ display: flex;
15
+ flex-direction: row;
16
+ align-items: center;
17
+ }
18
+
19
+ dx-button {
20
+ margin-left: auto;
21
+ }
22
+
23
+ /*
24
+ NOTE: Here we are assuming that indicator height won't go beyond 1000px.
25
+
26
+ It's one of the suggested way to achieve the expand/collapse animation
27
+ Ref: https://stackoverflow.com/a/41164095
28
+
29
+ Otherwise we need to change the height when user clicks on button
30
+ Ref: https://stackoverflow.com/a/11837673
31
+ */
32
+
33
+ .doc-phase-body {
34
+ max-height: 1000px;
35
+ overflow: hidden;
36
+ padding-top: var(--dx-g-spacing-smd);
37
+ transition: max-height 0.25s ease, padding 0.25s ease;
38
+ }
39
+
40
+ .doc-phase-body-hidden {
41
+ max-height: 0;
42
+ padding-top: 0;
43
+ transition: max-height 0.1s ease-out, padding 0.25s ease-out;
44
+ }
45
+
46
+ .doc-phase-body a {
47
+ color: var(--dx-g-blue-vibrant-50);
48
+ }
49
+
50
+ /* Small Devices */
51
+ @media screen and (max-width: 480px) {
52
+ .doc-phase-container {
53
+ padding: var(--doc-status-vertical-padding);
54
+ }
55
+ }