mirror of
https://github.com/angular/angular
synced 2026-05-24 09:28:37 +00:00
Block entries (@if, @defer, @for,@let, @switch) were falling back to the generic DocsReference template, causing the description to appear twice - once in the header section and once in the main content area. This commit adds a dedicated rendering path for block entries: - Creates BlockEntryRenderable type and associated transforms - Adds BlockReference template that uses RawHtml directly - Modifies HeaderApi to accept hideDescription prop - Updates processing and rendering pipelines to handle blocks The fix ensures block documentation displays only one description section while preserving the existing behavior for all other API entry types. Update adev/shared-docs/pipeline/api-gen/rendering/transforms/block-transforms.mts Co-authored-by: Matthieu Riegler <kyro38@gmail.com>
155 lines
4.6 KiB
TypeScript
155 lines
4.6 KiB
TypeScript
/*!
|
|
* @license
|
|
* Copyright Google LLC All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by an MIT-style license that can be
|
|
* found in the LICENSE file at https://angular.dev/license
|
|
*/
|
|
|
|
import {Fragment, h, HTMLAttributes} from 'preact';
|
|
import {EntryType, isDocEntryWithSourceInfo, PipeEntry} from '../entities.mjs';
|
|
import {DocEntryRenderable, PipeEntryRenderable} from '../entities/renderables.mjs';
|
|
import {
|
|
HEADER_CLASS_NAME,
|
|
HEADER_ENTRY_CATEGORY,
|
|
HEADER_ENTRY_LABEL,
|
|
HEADER_ENTRY_TITLE,
|
|
} from '../styling/css-classes.mjs';
|
|
import {DocsPillRow} from './docs-pill-row';
|
|
|
|
/** Component to render a header of the API page. */
|
|
export function HeaderApi(props: {
|
|
entry: DocEntryRenderable | PipeEntryRenderable;
|
|
showFullDescription?: boolean;
|
|
hideDescription?: boolean;
|
|
}) {
|
|
const entry = props.entry;
|
|
|
|
// TODO: This link point to the main branch.
|
|
// When ADEV is not deployed on the main branch branch anymore,
|
|
// We should update it to point to the tag of the released version which ADEV runs on.
|
|
|
|
const sourceUrl = sourceUrlForEntry(entry);
|
|
|
|
return (
|
|
<header className={HEADER_CLASS_NAME}>
|
|
<span className={HEADER_ENTRY_CATEGORY}>{entry.moduleName}</span>
|
|
|
|
<div className={HEADER_ENTRY_TITLE}>
|
|
<div>
|
|
<h1>{entry.name}</h1>
|
|
<div className={`${HEADER_ENTRY_LABEL} type-${entry.entryType.toLowerCase()} full`}>
|
|
{getEntryTypeDisplayName(entry.entryType)}
|
|
</div>
|
|
{statusTag(entry)}
|
|
{entry.entryType === EntryType.Pipe && !(entry as PipeEntry).isPure && (
|
|
<div className={`${HEADER_ENTRY_LABEL} type-impure-pipe full`}>Impure</div>
|
|
)}
|
|
</div>
|
|
{sourceUrl && (
|
|
<a
|
|
class="docs-github-links"
|
|
target="_blank"
|
|
href={sourceUrl}
|
|
title="View source"
|
|
aria-label="View source"
|
|
>
|
|
<i role="presentation" aria-hidden="true" class="material-symbols-outlined">
|
|
code
|
|
</i>
|
|
</a>
|
|
)}
|
|
</div>
|
|
|
|
{!props.hideDescription && (
|
|
<section
|
|
className={'docs-reference-description'}
|
|
dangerouslySetInnerHTML={{
|
|
__html: props.showFullDescription ? entry.htmlDescription : entry.shortHtmlDescription,
|
|
}}
|
|
></section>
|
|
)}
|
|
|
|
<DocsPillRow links={entry.additionalLinks} />
|
|
</header>
|
|
);
|
|
}
|
|
|
|
function statusTag(entry: DocEntryRenderable) {
|
|
let tag: HTMLAttributes<HTMLDivElement> | null = null;
|
|
|
|
// Cascading Deprecated > Stable > Developer Preview > Experimental
|
|
|
|
if (entry.deprecated) {
|
|
tag = (
|
|
<div className={`${HEADER_ENTRY_LABEL} type-stable full`}>
|
|
{tagInVersionString('deprecated', entry.deprecated)}
|
|
</div>
|
|
);
|
|
} else if (entry.stable) {
|
|
tag = (
|
|
<div className={`${HEADER_ENTRY_LABEL} type-stable full`}>
|
|
{tagInVersionString('stable', entry.stable)}
|
|
</div>
|
|
);
|
|
} else if (entry.developerPreview) {
|
|
tag = (
|
|
<div className={`${HEADER_ENTRY_LABEL} type-developer_preview full`}>
|
|
<a href="/reference/releases#developer-preview">
|
|
{tagInVersionString('developer preview', entry.developerPreview)}
|
|
</a>
|
|
</div>
|
|
);
|
|
} else if (entry.experimental) {
|
|
tag = (
|
|
<div className={`${HEADER_ENTRY_LABEL} type-experimental full`}>
|
|
<a href="/reference/releases#experimental">
|
|
{tagInVersionString('experimental', entry.experimental)}
|
|
</a>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return tag;
|
|
}
|
|
|
|
function tagInVersionString(label: string, tag: {version: string | undefined} | undefined) {
|
|
if (tag?.version) {
|
|
return (
|
|
<>
|
|
<span className="status-label">{label}</span>
|
|
<span className="status-version">since v{tag.version}</span>
|
|
</>
|
|
);
|
|
}
|
|
|
|
return <>{label}</>;
|
|
}
|
|
|
|
function getEntryTypeDisplayName(entryType: EntryType | string): string {
|
|
switch (entryType) {
|
|
case EntryType.NgModule:
|
|
return 'NgModule';
|
|
case EntryType.TypeAlias:
|
|
return 'Type Alias';
|
|
case EntryType.UndecoratedClass:
|
|
return 'Class';
|
|
case EntryType.InitializerApiFunction:
|
|
return 'Initializer API';
|
|
}
|
|
return entryType;
|
|
}
|
|
|
|
function sourceUrlForEntry(entry: DocEntryRenderable): string | null {
|
|
if (!isDocEntryWithSourceInfo(entry)) {
|
|
return null;
|
|
}
|
|
|
|
if (entry.source.filePath.includes('node_modules')) {
|
|
// We don't know the source path in external repos link the CLI
|
|
return null;
|
|
} else {
|
|
const filePath = entry.source.filePath.replace(/^\//, '');
|
|
return `https://github.com/${entry.repo}/blob/main/${filePath}#L${entry.source.startLine}-L${entry.source.endLine}`;
|
|
}
|
|
}
|