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

Components: Prevent broken lists in auto-generated readmes #68301

Merged
merged 3 commits into from
Dec 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 9 additions & 12 deletions bin/api-docs/gen-components-docs/markdown/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,14 @@ import json2md from 'json2md';
import { generateMarkdownPropsJson } from './props.mjs';

/**
* If the string is contentful, ensure that it ends with a single newline.
* Otherwise normalize to `undefined`.
* Converter for strings that are already formatted as Markdown.
*
* @param {string} [str]
* @param {string} [input]
* @return {string} The trimmed input if it is contentful, otherwise an empty string.
*/
function normalizeTrailingNewline( str ) {
if ( ! str?.trim() ) {
return undefined;
}
return str.replace( /\n*$/, '\n' );
}
json2md.converters.md = ( input ) => {
return input?.trim() || '';
};
Comment on lines +17 to +19
Copy link
Member Author

Choose a reason for hiding this comment

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

I realized you can add custom converters like this, which makes things more simpler and readable overall. When you use a converter, json2md adds a trailing newline automatically.

The removal of redundant newlines is moved to the end of this file, which will clean the entire output.

Copy link
Member

Choose a reason for hiding this comment

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

TIL, this is very cool!


export function generateMarkdownDocs( { typeDocs, subcomponentTypeDocs } ) {
const mainDocsJson = [
Expand All @@ -28,7 +25,7 @@ export function generateMarkdownDocs( { typeDocs, subcomponentTypeDocs } ) {
{
p: `<p class="callout callout-info">See the <a href="https://wordpress.github.io/gutenberg/?path=/docs/components-${ typeDocs.displayName.toLowerCase() }--docs">WordPress Storybook</a> for more detailed, interactive documentation.</p>`,
},
normalizeTrailingNewline( typeDocs.description ),
{ md: typeDocs.description },
...generateMarkdownPropsJson( typeDocs.props ),
];

Expand All @@ -39,7 +36,7 @@ export function generateMarkdownDocs( { typeDocs, subcomponentTypeDocs } ) {
{
h3: subcomponentTypeDoc.displayName,
},
normalizeTrailingNewline( subcomponentTypeDoc.description ),
{ md: subcomponentTypeDoc.description },
...generateMarkdownPropsJson( subcomponentTypeDoc.props, {
headingLevel: 4,
} ),
Expand All @@ -49,5 +46,5 @@ export function generateMarkdownDocs( { typeDocs, subcomponentTypeDocs } ) {

return json2md(
[ ...mainDocsJson, ...subcomponentDocsJson ].filter( Boolean )
);
).replace( /\n+$/gm, '\n' ); // clean unnecessary consecutive newlines
Copy link
Member

Choose a reason for hiding this comment

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

Noting that this cleans up only trailing ones, maybe we want to update the comment to reflect that?

Copy link
Member Author

Choose a reason for hiding this comment

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

This is a global + multiline regex, intended to remove all excessive newlines within in the entire readme output.

}
2 changes: 1 addition & 1 deletion bin/api-docs/gen-components-docs/markdown/props.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ export function generateMarkdownPropsJson( props, { headingLevel = 2 } = {} ) {

return [
{ [ `h${ headingLevel + 1 }` ]: `\`${ key }\`` },
prop.description,
{
ul: [
`Type: \`${ renderPropType( prop.type ) }\``,
Expand All @@ -42,6 +41,7 @@ export function generateMarkdownPropsJson( props, { headingLevel = 2 } = {} ) {
`Default: \`${ prop.defaultValue.value }\``,
].filter( Boolean ),
},
{ md: prop.description },
];
} )
.filter( Boolean );
Expand Down
30 changes: 15 additions & 15 deletions packages/components/src/alignment-matrix-control/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,43 +26,43 @@ const Example = () => {

### `defaultValue`

If provided, sets the default alignment value.

- Type: `"center" | "top left" | "top center" | "top right" | "center left" | "center center" | "center right" | "bottom left" | "bottom center" | "bottom right"`
- Required: No
- Default: `'center center'`

### `label`
If provided, sets the default alignment value.

Accessible label. If provided, sets the `aria-label` attribute of the
underlying `grid` widget.
### `label`

- Type: `string`
- Required: No
- Default: `'Alignment Matrix Control'`

### `onChange`
Accessible label. If provided, sets the `aria-label` attribute of the
underlying `grid` widget.

A function that receives the updated alignment value.
### `onChange`

- Type: `(newValue: AlignmentMatrixControlValue) => void`
- Required: No

### `value`
A function that receives the updated alignment value.

The current alignment value.
### `value`

- Type: `"center" | "top left" | "top center" | "top right" | "center left" | "center center" | "center right" | "bottom left" | "bottom center" | "bottom right"`
- Required: No

### `width`
The current alignment value.

If provided, sets the width of the control.
### `width`

- Type: `number`
- Required: No
- Default: `92`

If provided, sets the width of the control.

## Subcomponents

### AlignmentMatrixControl.Icon
Expand All @@ -71,16 +71,16 @@ If provided, sets the width of the control.

##### `disablePointerEvents`

If `true`, disables pointer events on the icon.

- Type: `boolean`
- Required: No
- Default: `true`

##### `value`
If `true`, disables pointer events on the icon.

The current alignment value.
##### `value`

- Type: `"center" | "top left" | "top center" | "top right" | "center left" | "center center" | "center right" | "bottom left" | "bottom center" | "bottom right"`
- Required: No
- Default: `center`

The current alignment value.
18 changes: 9 additions & 9 deletions packages/components/src/angle-picker-control/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,30 +28,30 @@ function Example() {

### `as`

The HTML element or React component to render the component as.

- Type: `"symbol" | "object" | "a" | "abbr" | "address" | "area" | "article" | "aside" | "audio" | "b" | ...`
- Required: No

### `label`
The HTML element or React component to render the component as.

Label to use for the angle picker.
### `label`

- Type: `string`
- Required: No
- Default: `__( 'Angle' )`

### `onChange`
Label to use for the angle picker.

A function that receives the new value of the input.
### `onChange`

- Type: `(value: number) => void`
- Required: Yes

### `value`
A function that receives the new value of the input.

The current value of the input. The value represents an angle in degrees
and should be a value between 0 and 360.
### `value`

- Type: `string | number`
- Required: Yes

The current value of the input. The value represents an angle in degrees
and should be a value between 0 and 360.
8 changes: 4 additions & 4 deletions packages/components/src/badge/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@

### `children`

Text to display inside the badge.

- Type: `string`
- Required: Yes

### `intent`
Text to display inside the badge.

Badge variant.
### `intent`

- Type: `"default" | "info" | "success" | "warning" | "error"`
- Required: No
- Default: `default`

Badge variant.
41 changes: 20 additions & 21 deletions packages/components/src/base-control/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,67 +30,66 @@ const MyCustomTextareaControl = ({ children, ...baseProps }) => (

### `__nextHasNoMarginBottom`

Start opting into the new margin-free styles that will become the default in a future version.

- Type: `boolean`
- Required: No
- Default: `false`

### `as`
Start opting into the new margin-free styles that will become the default in a future version.

The HTML element or React component to render the component as.
### `as`

- Type: `"symbol" | "object" | "label" | "a" | "abbr" | "address" | "area" | "article" | "aside" | "audio" | "b" | "base" | "bdi" | "bdo" | "big" | "blockquote" | "body" | "br" | "button" | ... 516 more ... | ("view" & FunctionComponent<...>)`
- Required: No

### `className`
The HTML element or React component to render the component as.

### `className`

- Type: `string`
- Required: No

### `children`

The content to be displayed within the `BaseControl`.

- Type: `ReactNode`
- Required: Yes

The content to be displayed within the `BaseControl`.

### `help`

- Type: `ReactNode`
- Required: No

Additional description for the control.

Only use for meaningful description or instructions for the control. An element containing the description will be programmatically associated to the BaseControl by the means of an `aria-describedby` attribute.

- Type: `ReactNode`
- Required: No

### `hideLabelFromVision`

If true, the label will only be visible to screen readers.

- Type: `boolean`
- Required: No
- Default: `false`

If true, the label will only be visible to screen readers.

### `id`

- Type: `string`
- Required: No

The HTML `id` of the control element (passed in as a child to `BaseControl`) to which labels and help text are being generated.
This is necessary to accessibly associate the label with that element.

The recommended way is to use the `useBaseControlProps` hook, which takes care of generating a unique `id` for you.
Otherwise, if you choose to pass an explicit `id` to this prop, you are responsible for ensuring the uniqueness of the `id`.

- Type: `string`
- Required: No

### `label`

If this property is added, a label will be generated using label property as the content.

- Type: `ReactNode`
- Required: No

If this property is added, a label will be generated using label property as the content.

## Subcomponents

### BaseControl.VisualLabel
Expand Down Expand Up @@ -119,14 +118,14 @@ const MyBaseControl = () => (

##### `as`

The HTML element or React component to render the component as.

- Type: `"symbol" | "object" | "label" | "a" | "abbr" | "address" | "area" | "article" | "aside" | "audio" | ...`
- Required: No

##### `children`
The HTML element or React component to render the component as.

The content to be displayed within the `BaseControl.VisualLabel`.
##### `children`

- Type: `ReactNode`
- Required: Yes

The content to be displayed within the `BaseControl.VisualLabel`.
Loading
Loading