Improve readability of complex API types / default values in component documentation
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 6.9k
- Forks
- 1.1k
- Avg merge
- 1d 7h
- Merged PRs (30d)
- 57
Description
Package
v4.x
Description
First of all, thank you for this great Nuxt Module and a comprehensive documentation.
I just found it a bit difficult to read some complex component prop type with inline code, and I think that we can make the documentation easier to read.
Problem
For example:
| Component | Prop | Column | Screenshot |
|---|---|---|---|
LocaleSelect |
virtualize |
Type | |
LocaleSelect |
createItem |
Type | |
LocaleSelect |
ui |
Type | |
LocaleSelect |
content |
Default | |
Table |
virtualize |
Type | |
Table |
defaultColumn |
Type | |
Tree |
- | Slots Type |
Sometimes, we have inline code block with long content in:
- API Props Type
- API Props Default
- API Slots Type
- (haven't confirmed, but maybe API Emits Type as well)
Their contents can be:
- Nested type
- Union with a lot of members
- Many properties
- etc.
For props with nested type like LocaleSelect.virtualize and LocaleSelect.createItem, we can click "Show properties" to view detail.
But for props like ui, which is usually a type with a lot of properties, it's hard to read and find what properties there are.
Solution suggestion
All of the above example are rendered with <HighlightInlineType> component.
1. Use Markdown code block + format content with prettier
Screenshots
- ✅ Complex type / value looks better now
- ⚠️ We need to do some string processing to the formatted content like the implementation below
- ⚠️ We might need to give min-width to each table column, otherwise some code block will be shrinked
- ⚠️ This component is called
<HighlightInlineType>, but now it can produce type with code block - ❌ Prettier might be too opinionated and sometimes make the type more difficult to read. (e.g. line wrap)
- ❌ Even for simple type like
boolean, it will become a code block, which takes more spaces- In the screenshot of my prototype, I've tried to add a multiline check to keep simple type inline.
- ❌ It looks ugly for prop name a inline text, while prop type in the row a code block. Their margin-top are different.
- Maybe we can fix by give them universal margin
- ❓ Not sure about how performance of page rendering will be affected.
- I've measured the
formatTypefunction withpreformance.now(), and it takes about 30ms in average.
- I've measured the
- ❓ Not sure about what is the appropriate value of the
printWidthprettier config
Implementation
import prettier from 'prettier/standalone'
import typescriptPlugin from 'prettier/plugins/typescript'
import estreePlugin from 'prettier/plugins/estree'
const formatType = async (type: string) => {
const TYPE_WRAPPER = 'type __Formatted'
const INDENT = ' '
let formatted: string
try {
formatted = await prettier.format(
`${TYPE_WRAPPER} = ${type}`,
{
parser: 'typescript',
plugins: [typescriptPlugin, estreePlugin],
tabWidth: 2,
semi: false,
printWidth: 40
}
)
} catch {
return null
}
formatted = formatted
.replace(/^type\s+__Formatted\s*=\s*/m, '')
.replace(/^\|\s*/m, '') // Remove leading `|` added by union formatting
const allLinesShareIndent = formatted
.split('\n')
.every(line => line.trim() === '' || line.startsWith(INDENT))
return allLinesShareIndent
? formatted.replace(new RegExp(`^${INDENT}`, 'gm'), '')
: formatted
}
onMounted(async () => {
const formattedType = await formatType(type.value) ?? ''
const md = formattedType.split('\n').length > 2
? `\`\`\`ts-type\n${formattedType}\n\`\`\`` // Code block
: `\`\` ${type.value} \`\`{lang="ts-type"}` // Inline code
ast.value = await parseMarkdown(md)
})
2. Use Markdown code block + simple string processing
Screenshot
- Simply do line break for union
- For
ui, simply change it toPartial<Record<TKeys, ClassNameValue>>
- ✅ No need to execute runtime prettier format
- ❌ Corner cases like union in nested properties are not considered
- Others are same as ## 1.
Implementation
const formatType = (type: string) => {
if (!type.includes('?: ClassNameValue;')) return type.replaceAll(' | ', '\n | ')
const keys = type.matchAll(/\s(\S+?)\?/g)
.map(match => match[1])
.map(key => JSON.stringify(key))
.toArray()
.join('\n | ')
return `Partial<Record<\n ${keys},\n ClassNameValue\n>>`
}
3. Convert only type of ui prop to <Partial<Record<TKeys, ClassNameValue>> + render in code block
Actually this is the main motivation of creating this issue. I want to have at least the ui prop to be easier to read.
Any ideas are appreciated.
Additional context
No response
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the HighlightInlineType component and the API documentation rendering for the LocaleSelect, Table, and Tree examples named in the issue. Compare the proposed formatting approaches, including the TypeScript formatting and Markdown code-block behavior, before choosing an implementation. Done should make complex prop types, defaults, and slot types easier to scan without making simple values unnecessarily large.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- nuxt, typescript
- Domain
- documentation, frontend
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100