@mdit/plugin-field
Plugin for creating block-level custom field containers.
Installation
# pnpm
pnpm add @mdit/plugin-field
# npm
npm install @mdit/plugin-field
# yarn
yarn add @mdit/plugin-fieldUsage
import MarkdownIt from "markdown-it";
import { field } from "@mdit/plugin-field";
const mdIt = new MarkdownIt().use(field, {
// your options
});
mdIt.render(`
::: fields
@\`prop1\` type="string" required
Description 1
:::
`);Syntax
Container
You can create a field container using ::: fields and :::. The name fields can be customized via the name option.
You can also provide an ID for the container using ::: fields #id.
Items
Inside the container, a line starting with @ followed by an inline code is a field item. You can add attributes after the closing backtick.
::: fields
@`prop1` type="string" required
Description 1
:::Any contents after a marker and before the container closing marker or a new marker at the same level will be considered as the field content.
Name
The name is an inline code, fully following Markdown's inline code syntax:
@`locales.<localePath>.latestUpdateAt` type=string
@`config[*].matches[*]` type=`RegExp`The name must be closed on the same line, otherwise the line is not a field item.
Template literals
A backtick needs escaping when the content is written inside a JavaScript template literal, like the mdIt.render example above:
@\`prop1\`Attributes
Attributes are key-value pairs separated by =. Values can be quoted or unquoted.
@`prop1` type="string" required default="value"- For unquoted values, the value will end at the first space or whitespace.
- Values can be quoted with
",'or`. - Backslashes inside a
"or'quoted value follow Markdown's escaping rules: a backslash before an ASCII punctuation character is removed, while any other backslash is kept as-is. Sodefault="^\d+$"anddefault="C:\new"keep their backslashes, whiledefault="hello \"world\""giveshello "world". Unquoted values are taken literally. Since a backslash also escapes the closing quote, writedefault="C:\\"to end a value with a backslash. - If an attribute exists without
=, it will be treated as a boolean attribute with the valuetrue.
Backtick Values
A backtick value is an inline code, fully following Markdown's inline code syntax:
@`prop1` default=`['a', 'b']`Values quoted with " or ' are still parsed as Markdown by other tools, so [a][b] inside them may be reported as an undefined reference by linters. A backtick value is an inline code to those tools, which avoids that.
A value that is not closed by a backtick falls back to an unquoted value, which starts with the opening backtick.
Allowed Attributes
By default, all attributes are allowed and displayed as-is. You can restrict and customize attribute display using the allowedAttributes option.
If allowedAttributes is provided:
- Only attributes defined in the array will be displayed.
- Attributes will be displayed in the order they appear in the array.
- You can provide a custom
namefor each attribute to change its label in the header. - You can mark an attribute as
booleanto always treat it as a flag (ignoring any value).
field(md, {
allowedAttributes: [
{ attr: "type", name: "Property Type" },
{ attr: "required", boolean: true },
],
});Nesting
Same or different containers can be nested inside items at the same indentation or partial indentation (less than code fence indentation) level.
:::: fields
@`option`
Parent description.
::: props
@`prop1` type="string"
Key description.
@`prop2` type="number"
Key description.
:::
@`option2`
Another parent description.
::::To create a field item inside another field, increase the starting @ by one for each level of nesting:
::: fields
@`prop1`
Parent description.
@@`prop1.key1` type="string"
Key description.
@@`prop1.key2` type="number"
Key description.
@`prop2`
Another parent description.
:::Now prop1 has two nested keys key1 and key2, while prop2 has no nested keys.
Though common tools like prettier is not happy with indention less than 4, the plugin is designed to be flexible with indentation as long as it is less than code fence indentation (4 spaces by default). This allows for more natural nesting without strict indentation requirements.
<!-- prettier-ignore-start -->
::: fields
@`prop1`
Parent description.
@@`prop1.key1` type="string"
Key description.
@@`prop1.key2` type="number"
Key description.
:::
<!-- prettier-ignore-end -->Escaping
A line inside a field container that starts with @ followed by an inline code is a field item. Escape the @ with \ to keep it as content:
\@`not-a-field`Options
name
- Type:
string - Default:
"fields" - Details: Field container name.
classPrefix
- Type:
string - Default:
"field-" - Details: CSS class prefix for generated class names.
parseAttributes
- Type:
boolean - Default:
true - Details: Whether to parse
key="val"attributes after the field marker.
allowedAttributes
- Type:
FieldAttr[]
interface FieldAttr {
/**
* attribute name
*/
attr: string;
/**
* Display name of the attribute, if not provided, will use `attr` as display name with first letter capitalized.
*/
name?: string;
/**
* boolean attribute, any attribute existence will be treated as true, and value will be ignored.
*
* @default false
*/
boolean?: boolean;
}- Details: Allowed attributes for fields. If not provided, all attributes will be allowed and displayed as-is.
fieldsOpenRenderer
- Type:
RendererRule
/**
* @param tokens - List of tokens.
* @param index - Current token index.
* @param options - Markdown-it options.
* @param env - Markdown-it environment.
* @param self - Markdown-it renderer instance.
*
* @returns Rendered HTML string.
*/
type RendererRule = (
tokens: Token[],
index: number,
options: Required<MarkdownItOptions>,
env: Env | undefined,
self: Renderer,
) => string;- Details: Fields container open render.
fieldsCloseRenderer
- Type:
RendererRule
/**
* @param tokens - List of tokens.
* @param index - Current token index.
* @param options - Markdown-it options.
* @param env - Markdown-it environment.
* @param self - Markdown-it renderer instance.
*
* @returns Rendered HTML string.
*/
type RendererRule = (
tokens: Token[],
index: number,
options: Required<MarkdownItOptions>,
env: Env | undefined,
self: Renderer,
) => string;- Details: Fields container close render.
fieldOpenRenderer
- Type:
MarkdownItFieldOpenRenderer
type FieldAttrQuote = "none" | "single" | "double" | "backtick";
interface FieldAttrItem {
/**
* attribute name
*/
attr: string;
/**
* attribute display name
*/
name: string;
/**
* attribute value
*/
value: string | true;
/**
* quote style used in source
*/
quote: FieldAttrQuote;
}
interface FieldMeta {
/**
* field name
*/
name: string;
/**
* field level, starting from 1
*/
level: number;
/**
* sorted field attributes
*/
attributes: FieldAttrItem[];
}
type MarkdownItFieldOpenRenderer = (
meta: FieldMeta,
tokens: Token[],
index: number,
options: Required<MarkdownItOptions>,
env: Env | undefined,
self: Renderer,
) => string;- Details: Field item open render.
fieldCloseRenderer
- Type:
RendererRule
/**
* @param tokens - List of tokens.
* @param index - Current token index.
* @param options - Markdown-it options.
* @param env - Markdown-it environment.
* @param self - Markdown-it renderer instance.
*
* @returns Rendered HTML string.
*/
type RendererRule = (
tokens: Token[],
index: number,
options: Required<MarkdownItOptions>,
env: Env | undefined,
self: Renderer,
) => string;- Details: Field item close render.
Demo
- prop1
- Type: stringRequired
Description 1
- prop2
- Type: number
Description 2
::: fields
@`prop1` type="string" required
Description 1
@`prop2` type="number"
Description 2
:::- parent
Parent description.
- child
Child description.
::: fields
@`parent`
Parent description.
@@`child`
Child description.
:::import MarkdownIt from "markdown-it";
import { field } from "@mdit/plugin-field";
const mdIt = new MarkdownIt().use(field, {
name: "props",
allowedAttributes: [
{ attr: "type", name: "Property Type" },
{ attr: "required", boolean: true },
],
});- prop1
- Property Type: stringRequired
This is a required string property.
- prop2
- Property Type: number
This is a number property.
```ts
import MarkdownIt from "markdown-it";
import { field } from "@mdit/plugin-field";
const mdIt = new MarkdownIt().use(field, {
name: "props",
allowedAttributes: [
{ attr: "type", name: "Property Type" },
{ attr: "required", boolean: true },
],
});
```
::: props
@`prop1` type="string" required
This is a required string property.
@`prop2` type="number"
This is a number property.
:::