Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[docs-infra] Move API pages to TS #43199

Merged
merged 15 commits into from
Aug 13, 2024
2 changes: 1 addition & 1 deletion docs/src/modules/components/ApiPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import {
getClassApiDefinitions,
getClassesToC,
} from 'docs/src/modules/components/ApiPage/definitions/classes';
import { getSlotsApiDefinitions } from './ApiPage/definitions/slots';
import { getSlotsApiDefinitions } from 'docs/src/modules/components/ApiPage/definitions/slots';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Relative imports make more sense imo, but that's a little pet peeve of mine 😄

Copy link
Member Author

@alexfauquette alexfauquette Aug 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a post traumatic symptomes.

Did not took care of it so I've little context, but most of the files on docs/modules don't have a relative import because it was causing conflict when used in mui-x repo. Since mui-x and material-ui agree on the fact the docs/ point to this folder (in mui-x the docs folder is aliased docsx), every import start with docs/


// TODO Move this type definition to the AppLayoutDocs file when moved to TS
export interface TableOfContentsParams {
Expand Down
59 changes: 59 additions & 0 deletions docs/src/modules/components/ApiPage/processors/classes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { PropsTranslations, ComponentApiContent } from '@mui-internal/api-docs-builder';
import { Translate } from '@mui/docs/i18n';
import kebabCase from 'lodash/kebabCase';

export interface ClassDefinition {
className: string;
key: string;
hash: string;
description?: string;
isGlobal?: boolean;
isDeprecated?: boolean;
deprecationInfo?: string;
}

export type GetCssToCParams = {
classes: ClassDefinition[];
t: Translate;
hash?: string;
};

export const getClassesToC = ({ classes, t, hash }: GetCssToCParams) =>
!classes || classes.length === 0
? []
: [
{
text: t('api-docs.classes'),
hash: hash ?? 'classes',
children: [
...classes.map(({ key, hash: classeHash }) => ({
text: key,
hash: classeHash,
children: [],
})),
],
},
];

export interface ClassesApiProcessorParams {
componentClasses: ComponentApiContent['classes'];
classDescriptions: PropsTranslations['classDescriptions'];
componentName: string;
}

export function classesApiProcessor(params: ClassesApiProcessorParams): ClassDefinition[] {
const { componentClasses, classDescriptions, componentName } = params;

return componentClasses.map((classDefinition) => {
return {
...classDefinition,
description:
classDescriptions[classDefinition.key]?.description
?.replace(/{{conditions}}/, classDescriptions[classDefinition.key].conditions!)
?.replace(/{{nodeName}}/, classDescriptions[classDefinition.key].nodeName!) ??
classDefinition.description,
deprecationInfo: classDescriptions[classDefinition.key]?.deprecationInfo,
hash: `${kebabCase(componentName)}-classes-${classDefinition.className}`,
};
});
}
182 changes: 182 additions & 0 deletions docs/src/modules/components/ApiPage/processors/properties.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
import { PropsTableItem, PropsTranslations } from '@mui-internal/api-docs-builder';
import { Translate } from '@mui/docs/i18n';
import kebabCase from 'lodash/kebabCase';
import {
HookApiContent,
HooksTranslations,
} from 'packages/api-docs-builder/types/ApiBuilder.types';

export interface PropertyDefinition {
additionalInfo?: string[];
hash: string;
deprecationInfo?: string;
description?: string;
isDeprecated?: boolean;
isOptional?: boolean;
isRequired?: boolean;
propDefault?: string;
propName: string;
requiresRef?: boolean;
seeMoreDescription?: string;
signature?: string;
signatureArgs?: { argName: string; argDescription?: string }[];
signatureReturnDescription?: string;
typeName: string;
/**
* Used by MUI X interface documentation
*/
isProPlan?: boolean;
/**
* Used by MUI X interface documentation
*/
isPremiumPlan?: boolean;
}

export type GetCssToCParams = {
properties: PropertyDefinition[];
inheritance?: boolean;
themeDefaultProps?: boolean;
t: Translate;
hash?: string;
};

export const getPropertiesToC = ({
properties,
inheritance,
themeDefaultProps,
t,
hash,
}: GetCssToCParams) => ({
text: t('api-docs.props'),
hash,
children: [
...properties.map(({ propName, hash: propertyHash }) => ({
text: propName,
hash: propertyHash,
children: [],
})),
...(inheritance
? [{ text: t('api-docs.inheritance'), hash: 'inheritance', children: [] }]
: []),
...(themeDefaultProps
? [{ text: t('api-docs.themeDefaultProps'), hash: 'theme-default-props', children: [] }]
: []),
],
});

interface PropsApiProcessorParams {
componentName: string;
properties: {
[name: string]: PropsTableItem;
};
propertiesDescriptions: PropsTranslations['propDescriptions'];
/**
* Add indicators that the properties is optional instead of showing it is required.
*/
showOptionalAbbr?: boolean;
}

export function propsApiProcessor(params: PropsApiProcessorParams): PropertyDefinition[] {
const { properties, propertiesDescriptions, componentName, showOptionalAbbr = false } = params;

return Object.entries(properties).map(([propName, propData]) => {
const isRequired = propData.required && !showOptionalAbbr;
const isOptional = !propData.required && showOptionalAbbr;

const isDeprecated = propData.deprecated;
const deprecationInfo = propData.deprecationInfo;

const typeName = propData.type?.description || propData.type.name;
const propDefault = propData.default;
const propDescription = propertiesDescriptions[propName];

const additionalInfo = (
['cssApi', 'sx', 'slotsApi', 'joy-size', 'joy-color', 'joy-variant'] as const
).filter((key) => propData.additionalInfo?.[key]);

const seeMoreDescription =
propDescription?.seeMoreText &&
propData.seeMoreLink &&
propDescription.seeMoreText.replace(
'{{link}}',
`<a href="${propData.seeMoreLink.url}">${propData.seeMoreLink.text}</a>`,
);

const signature = propData.signature?.type;
const signatureArgs = propData.signature?.describedArgs?.map((argName) => ({
argName,
argDescription: propertiesDescriptions[propName].typeDescriptions?.[argName],
}));
const signatureReturnDescription =
propData.signature?.returned &&
propertiesDescriptions[propName].typeDescriptions?.[propData.signature.returned];

return {
hash: `${kebabCase(componentName)}-prop-${propName}`,
propName,
seeMoreDescription,
description: propDescription?.description,
requiresRef: propDescription?.requiresRef,
isOptional,
isRequired,
isDeprecated,
deprecationInfo,
typeName,
propDefault,
additionalInfo,
signature,
signatureArgs,
signatureReturnDescription,
};
});
}

// interface InterfaceApiProcessorParams {}

// export function InterfaceApiProcessor(params: InterfaceApiProcessorParams): PropertyDefinition[] {
// return [];
// }

interface HookCommonApiParams {
hookName: string;
}

interface HookReturnApiProcessorParams extends HookCommonApiParams {
kind: 'return';
properties: HookApiContent['returnValue'];
translations: HooksTranslations['returnValueDescriptions'];
}

interface HookParametersApiProcessorParams extends HookCommonApiParams {
kind: 'parameters';
properties: HookApiContent['parameters'];
translations: HooksTranslations['parametersDescriptions'];
}

export function hookApiProcessor(
params: HookReturnApiProcessorParams | HookParametersApiProcessorParams,
): PropertyDefinition[] {
const { properties, translations, hookName, kind } = params;

return Object.entries(properties).map(([propName, propData]) => {
const isOptional = !propData.required;

const isDeprecated = propData.deprecated;
const deprecationInfo = propData.deprecationInfo;

const typeName = propData.type?.description || propData.type.name;
const propDefault = propData.default;
const propDescription = translations[propName];

return {
hash: `${kebabCase(hookName)}-${kind === 'parameters' ? 'parameters' : 'return-value'}-${propName}`,
propName,
description: propDescription?.description,
isOptional,
isDeprecated,
deprecationInfo,
typeName,
propDefault,
};
});
}
32 changes: 32 additions & 0 deletions docs/src/modules/components/ApiPage/processors/slots.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { PropsTranslations, ComponentApiContent } from '@mui-internal/api-docs-builder';

export type SlotDefinition = {
className: string | null;
hash: string;
description?: string;
name: string;
defaultValue?: string;
};

export interface SlotsApiProcessorParams {
componentSlots: ComponentApiContent['slots'];
slotDescriptions: PropsTranslations['slotDescriptions'];
componentName: string;
}

export function slotsApiProcessor(params: SlotsApiProcessorParams): SlotDefinition[] {
const { componentSlots, slotDescriptions, componentName } = params;

if (!componentSlots) {
return [];
}
return componentSlots.map(({ class: className, name, default: defaultValue }) => {
return {
description: slotDescriptions?.[name],
className,
name,
defaultValue,
hash: `${componentName}-css-${className ?? name}`,
};
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@ export type ClassesSectionProps = (
level?: 'h2' | 'h3' | 'h4';
defaultLayout: ApiDisplayOptions;
layoutStorageKey: string;
displayClassKeys: boolean;
styleOverridesLink: string;
displayClassKeys?: boolean;
styleOverridesLink?: string;
Comment on lines +76 to +77
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The more you type pages, the more you fix inconsistencies 😅

};

export default function ClassesSection(props: ClassesSectionProps) {
Expand Down
Loading