Skip to content
This repository was archived by the owner on Dec 18, 2024. It is now read-only.

Commit 122e253

Browse files
committed
feat: show deprecated related information in material/tooltip
previously we weren't showing any other information other than `breaking-change` for deprecated fields, this commit adds a component that protrays information regarding deprecation in tooltips rather than `title` attribute closes angular/components#29839
1 parent 6a6db1c commit 122e253

File tree

4 files changed

+83
-4
lines changed

4 files changed

+83
-4
lines changed
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import {Component, Input} from '@angular/core';
2+
import {MatTooltipModule} from '@angular/material/tooltip';
3+
4+
/**
5+
* This component is responsible for showing the
6+
* deprecated fields throughout API from material repo,
7+
*
8+
* When deprecated docs content is generated like:
9+
*
10+
* <div class="docs-api-class-deprecated-marker"
11+
* title="Will be removed in v21.0.0 or later">
12+
* Deprecated
13+
* </div>
14+
*
15+
* It uses `title` attribute to show information regarding
16+
* depreciation and other information regarding depreciation
17+
* isnt shown either.
18+
*
19+
* We are gonna use this component to show deprecation
20+
* information using the `material/tooltip`, the information
21+
* would contain when the field is being deprecated and what
22+
* are the alternatives to it which both are extracted from
23+
* `deprecated` and `breaking-change`.
24+
*/
25+
@Component({
26+
selector: 'deprecated-field',
27+
template: `<div class="deprecated-content"
28+
[matTooltip]="message">
29+
</div>`,
30+
standalone: true,
31+
imports: [MatTooltipModule],
32+
})
33+
export class DeprecatedFieldComponent {
34+
/** Message regarding the deprecation */
35+
@Input() message!: string;
36+
}

src/app/shared/doc-viewer/doc-viewer-module.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {PortalModule} from '@angular/cdk/portal';
99
import {NgModule} from '@angular/core';
1010
import {HeaderLink} from './header-link';
1111
import {CodeSnippet} from '../example-viewer/code-snippet';
12+
import {DeprecatedFieldComponent} from './deprecated-tooltip';
1213

1314

1415
// ExampleViewer is included in the DocViewerModule because they have a circular dependency.
@@ -23,8 +24,9 @@ import {CodeSnippet} from '../example-viewer/code-snippet';
2324
DocViewer,
2425
ExampleViewer,
2526
HeaderLink,
26-
CodeSnippet
27+
CodeSnippet,
28+
DeprecatedFieldComponent
2729
],
28-
exports: [DocViewer, ExampleViewer, HeaderLink]
30+
exports: [DocViewer, ExampleViewer, HeaderLink, DeprecatedFieldComponent]
2931
})
3032
export class DocViewerModule { }

src/app/shared/doc-viewer/doc-viewer.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import {Observable, Subscription} from 'rxjs';
2121
import {shareReplay, take, tap} from 'rxjs/operators';
2222
import {ExampleViewer} from '../example-viewer/example-viewer';
2323
import {HeaderLink} from './header-link';
24+
import {DeprecatedFieldComponent} from './deprecated-tooltip';
2425

2526
@Injectable({providedIn: 'root'})
2627
class DocFetcher {
@@ -121,6 +122,9 @@ export class DocViewer implements OnDestroy {
121122
this._loadComponents('material-docs-example', ExampleViewer);
122123
this._loadComponents('header-link', HeaderLink);
123124

125+
// Create tooltips for the deprecated fields
126+
this._createTooltipsForDeprecated();
127+
124128
// Resolving and creating components dynamically in Angular happens synchronously, but since
125129
// we want to emit the output if the components are actually rendered completely, we wait
126130
// until the Angular zone becomes stable.
@@ -166,4 +170,30 @@ export class DocViewer implements OnDestroy {
166170
this._clearLiveExamples();
167171
this._documentFetchSubscription?.unsubscribe();
168172
}
173+
174+
_createTooltipsForDeprecated() {
175+
// all of the deprecated markers end with `deprecated-marker`
176+
// in their class name
177+
const deprecatedElements =
178+
this._elementRef.nativeElement.querySelectorAll(`[class$=deprecated-marker]`);
179+
180+
[...deprecatedElements].forEach((element: Element) => {
181+
// the deprecation message, it will include alternative to deprecated item
182+
// and breaking change if there is one included.
183+
const deprecationTitle = element.getAttribute('deprecated-message');
184+
185+
const elementPortalOutlet = new DomPortalOutlet(
186+
element, this._componentFactoryResolver, this._appRef, this._injector);
187+
188+
const tooltipPortal = new ComponentPortal(DeprecatedFieldComponent, this._viewContainerRef);
189+
const tooltipOutlet = elementPortalOutlet.attach(tooltipPortal);
190+
191+
192+
if (deprecationTitle) {
193+
tooltipOutlet.instance.message = deprecationTitle;
194+
}
195+
196+
this._portalHosts.push(elementPortalOutlet);
197+
});
198+
}
169199
}

src/styles/_api.scss

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,19 @@
100100
.docs-api-interface-deprecated-marker {
101101
display: inline-block;
102102
font-weight: bold;
103-
104-
&[title] {
103+
position: relative;
104+
105+
// We want to set width and height according to our parent
106+
// deprecated marker element because the component that presents
107+
// the tooltip for depcreated message is empty by default and
108+
// empty element can not be able to show up therefore the tooltip
109+
// wont show either. This makes sure that our tooltip component
110+
// is aligned with deprecated marker in position and size.
111+
& .deprecated-content {
112+
position: absolute;
113+
width: 100%;
114+
height: 100%;
115+
top: 0;
105116
border-bottom: 1px dotted grey;
106117
cursor: help;
107118
}

0 commit comments

Comments
 (0)