Skip to content

Improve readability of complex API types / default values in component documentation #5815

@LuckyWindsck

Description

@LuckyWindsck

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 Image
LocaleSelect createItem Type Image
LocaleSelect ui Type Image
LocaleSelect content Default Image
Table virtualize Type Image
Table defaultColumn Type Image
Tree - Slots Type Image

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

Image Image
  • ✅ 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 formatType function with preformance.now(), and it takes about 30ms in average.
  • ❓ Not sure about what is the appropriate value of the printWidth prettier 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

Image Image
  1. Simply do line break for union
  2. For ui, simply change it to Partial<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

Metadata

Metadata

Assignees

No one assigned

    Labels

    documentationImprovements or additions to documentationenhancementNew feature or requesttriageAwaiting initial review and prioritizationv4#4488

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions