Skip to content

Commit

Permalink
feat: show deprecated related information in material/tooltip
Browse files Browse the repository at this point in the history
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
  • Loading branch information
naaajii committed Oct 14, 2024
1 parent 6a6db1c commit 33d57e7
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 4 deletions.
45 changes: 45 additions & 0 deletions src/app/shared/doc-viewer/deprecated-tooltip.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import {Component, Input} from '@angular/core';
import {MatTooltipModule} from '@angular/material/tooltip';

/**
* This component is responsible for showing the
* deprecated fields throughout API from material repo,
*
* When deprecated docs content is generated like:
*
* <div class="docs-api-class-deprecated-marker"
* title="Will be removed in v21.0.0 or later">
* Deprecated
* </div>
*
* It uses `title` attribute to show information regarding
* depreciation and other information regarding depreciation
* isnt shown either.
*
* We are gonna use this component to show deprecation
* information using the `material/tooltip`, the information
* would contain when the field is being deprecated and what
* are the alternatives to it which both are extracted from
* `deprecated` and `breaking-change`.
*/
@Component({
selector: 'deprecated-field',
template: `<div class="deprecated-content"
[attr.aria-label]="message"
[matTooltip]="message">
{{ htmlContent }}
</div>`,
standalone: true,
imports: [MatTooltipModule],
})
export class DeprecatedFieldComponent {
/** Message regarding the deprecation */
@Input() message!: string;
/** Inner content for our element, it could be either
* `Deprecated` which is shown mostly in most of the case
* but we can not show class names with just `Deprecated` label
* so otherwise the value is going to be name of whatever
* is being deprecated, so we can show the deprecation alternative
* description on hover */
@Input() htmlContent!: string;
}
6 changes: 4 additions & 2 deletions src/app/shared/doc-viewer/doc-viewer-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {PortalModule} from '@angular/cdk/portal';
import {NgModule} from '@angular/core';
import {HeaderLink} from './header-link';
import {CodeSnippet} from '../example-viewer/code-snippet';
import {DeprecatedFieldComponent} from './deprecated-tooltip';


// ExampleViewer is included in the DocViewerModule because they have a circular dependency.
Expand All @@ -23,8 +24,9 @@ import {CodeSnippet} from '../example-viewer/code-snippet';
DocViewer,
ExampleViewer,
HeaderLink,
CodeSnippet
CodeSnippet,
DeprecatedFieldComponent
],
exports: [DocViewer, ExampleViewer, HeaderLink]
exports: [DocViewer, ExampleViewer, HeaderLink, DeprecatedFieldComponent]
})
export class DocViewerModule { }
37 changes: 37 additions & 0 deletions src/app/shared/doc-viewer/doc-viewer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {Observable, Subscription} from 'rxjs';
import {shareReplay, take, tap} from 'rxjs/operators';
import {ExampleViewer} from '../example-viewer/example-viewer';
import {HeaderLink} from './header-link';
import {DeprecatedFieldComponent} from './deprecated-tooltip';

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

// Create tooltips for the deprecated fields
this._createTooltipsForDeprecated();

// Resolving and creating components dynamically in Angular happens synchronously, but since
// we want to emit the output if the components are actually rendered completely, we wait
// until the Angular zone becomes stable.
Expand Down Expand Up @@ -166,4 +170,37 @@ export class DocViewer implements OnDestroy {
this._clearLiveExamples();
this._documentFetchSubscription?.unsubscribe();
}

_createTooltipsForDeprecated() {
// all of the deprecated markers end with `deprecated-marker`
// in their class name
const deprecatedElements =
this._elementRef.nativeElement.querySelectorAll(`[class$=deprecated-marker]`);

[...deprecatedElements].forEach((element: Element) => {
// the deprecation message, it will include alternative to deprecated item
// and breaking change if there is one included.
const deprecationTitle = element.getAttribute('deprecated-message');
// In case of a class being deprecated we can not just show `Deprecated`
// text, this attribute contains the text we need to show tooltip against.
const innerText = element.getAttribute('inner-text');

const elementPortalOutlet = new DomPortalOutlet(
element, this._componentFactoryResolver, this._appRef, this._injector);

const tooltipPortal = new ComponentPortal(DeprecatedFieldComponent, this._viewContainerRef);
const tooltipOutlet = elementPortalOutlet.attach(tooltipPortal);


if (deprecationTitle) {
tooltipOutlet.instance.message = deprecationTitle;
}

if (innerText) {
tooltipOutlet.instance.htmlContent = innerText;
}

this._portalHosts.push(elementPortalOutlet);
});
}
}
5 changes: 3 additions & 2 deletions src/styles/_api.scss
Original file line number Diff line number Diff line change
Expand Up @@ -101,12 +101,13 @@
display: inline-block;
font-weight: bold;

&[title] {
& .deprecated-content {
border-bottom: 1px dotted grey;
cursor: help;
}
}

.docs-api-deprecated-marker + .docs-api-property-name {
.docs-api-deprecated-marker + .docs-api-property-name,
.docs-api-class-deprecated-marker {
text-decoration: line-through;
}

0 comments on commit 33d57e7

Please sign in to comment.