Shared utility functions for frameworks to implement docs in Storybook
—
Helper functions for string manipulation, value summarization, length validation, and formatting within the Storybook documentation system.
Core utility for creating structured summary objects with optional detailed information.
/**
* Creates a structured summary value with optional detail
* @param summary - Brief summary text
* @param detail - Optional detailed information
* @returns PropSummaryValue object with summary and optional detail
*/
function createSummaryValue(summary?: string, detail?: string): PropSummaryValue;
interface PropSummaryValue {
/** Brief summary text */
summary?: string;
/** Optional detailed information */
detail?: string;
}This function handles the common pattern of providing both brief and detailed representations of type information.
Usage Examples:
import { createSummaryValue } from "@storybook/docs-tools";
// Create simple summary
const basicSummary = createSummaryValue('string');
console.log(basicSummary);
// { summary: 'string' }
// Create summary with detail
const detailedSummary = createSummaryValue('union', 'string | number | boolean');
console.log(detailedSummary);
// { summary: 'union', detail: 'string | number | boolean' }
// Handle identical summary and detail
const identicalSummary = createSummaryValue('CustomType', 'CustomType');
console.log(identicalSummary);
// { summary: 'CustomType' } - detail omitted when identical
// Use in type processing
function processTypeInfo(typeData: any) {
const { name, raw } = typeData;
if (raw && raw !== name) {
return createSummaryValue(name, raw);
}
return createSummaryValue(name);
}
// Create summary for complex types
const complexType = createSummaryValue(
'Array<T>',
'Array<{ id: string; name: string; active: boolean }>'
);Utilities for checking whether strings exceed recommended display length limits.
/**
* Maximum recommended length for type summaries
*/
const MAX_TYPE_SUMMARY_LENGTH: 90;
/**
* Maximum recommended length for default value summaries
*/
const MAX_DEFAULT_VALUE_SUMMARY_LENGTH: 50;
/**
* Checks if a value exceeds the type summary length limit
* @param value - String to check
* @returns true if value is too long for type summary display
*/
function isTooLongForTypeSummary(value: string): boolean;
/**
* Checks if a value exceeds the default value summary length limit
* @param value - String to check
* @returns true if value is too long for default value display
*/
function isTooLongForDefaultValueSummary(value: string): boolean;These functions help determine when to truncate or show detailed views of type and value information.
Usage Examples:
import {
isTooLongForTypeSummary,
isTooLongForDefaultValueSummary,
MAX_TYPE_SUMMARY_LENGTH,
MAX_DEFAULT_VALUE_SUMMARY_LENGTH
} from "@storybook/docs-tools";
// Check type summary length
const longType = 'Array<{ id: string; name: string; description: string; tags: string[]; metadata: Record<string, any> }>';
if (isTooLongForTypeSummary(longType)) {
console.log('Type summary too long, showing truncated version');
const truncated = longType.substring(0, MAX_TYPE_SUMMARY_LENGTH) + '...';
console.log(truncated);
}
// Check default value length
const longDefaultValue = '{ name: "John Doe", email: "john.doe@example.com", preferences: { theme: "dark", notifications: true } }';
if (isTooLongForDefaultValueSummary(longDefaultValue)) {
console.log('Default value too long for inline display');
// Show in collapsible detail section instead
}
// Smart display logic
function formatForDisplay(value: string, type: 'type' | 'defaultValue') {
const isTooLong = type === 'type'
? isTooLongForTypeSummary(value)
: isTooLongForDefaultValueSummary(value);
if (isTooLong) {
const maxLength = type === 'type'
? MAX_TYPE_SUMMARY_LENGTH
: MAX_DEFAULT_VALUE_SUMMARY_LENGTH;
return {
summary: value.substring(0, maxLength) + '...',
detail: value,
truncated: true
};
}
return {
summary: value,
truncated: false
};
}
// Usage in UI components
function TypeDisplay({ typeString }: { typeString: string }) {
const formatted = formatForDisplay(typeString, 'type');
return (
<span title={formatted.truncated ? formatted.detail : undefined}>
{formatted.summary}
</span>
);
}Utility for normalizing newline characters in strings for consistent display.
/**
* Normalizes newline characters by converting \r\n to \n
* @param string - Input string with potentially mixed newlines
* @returns String with normalized newline characters
*/
function normalizeNewlines(string: string): string;Usage Examples:
import { normalizeNewlines } from "@storybook/docs-tools";
// Normalize Windows-style newlines
const windowsText = 'First line\r\nSecond line\r\nThird line';
const normalized = normalizeNewlines(windowsText);
console.log(normalized);
// 'First line\nSecond line\nThird line'
// Handle mixed newline formats
const mixedText = 'Line 1\nLine 2\r\nLine 3\rLine 4';
const cleanText = normalizeNewlines(mixedText);
// Use in text processing
function processDescription(description: string): string {
// Normalize newlines first
let processed = normalizeNewlines(description);
// Additional processing
processed = processed.trim();
processed = processed.replace(/\n\s*\n/g, '\n\n'); // Normalize paragraph breaks
return processed;
}
// File content processing
function processFileContent(content: string): string {
const normalized = normalizeNewlines(content);
return normalized
.split('\n')
.map(line => line.trim())
.filter(line => line.length > 0)
.join('\n');
}Additional string processing functions that complement the core utilities.
/**
* Removes surrounding quotes from strings
* @param str - String that may have quotes
* @returns String with quotes removed
*/
function trimQuotes(str: string): string;
/**
* Checks if a string contains quotes
* @param str - String to check
* @returns true if string includes quotes
*/
function includesQuotes(str: string): boolean;
/**
* Parses literal values from strings, converting to appropriate types
* @param str - String representation of a literal value
* @returns Parsed value as string or number
*/
function parseLiteral(str: string): string | number;Usage Examples:
import { trimQuotes, includesQuotes, parseLiteral } from "@storybook/docs-tools";
// Handle quoted strings from docgen
const quotedValue = '"default value"';
if (includesQuotes(quotedValue)) {
const cleaned = trimQuotes(quotedValue);
console.log(cleaned); // "default value"
}
// Parse different literal types
const numberValue = parseLiteral("42");
console.log(numberValue, typeof numberValue); // 42, "number"
const stringValue = parseLiteral("'hello world'");
console.log(stringValue); // "hello world"
// Use in default value processing
function processDefaultValue(rawValue: string) {
let processed = rawValue;
// Remove quotes if present
if (includesQuotes(processed)) {
processed = trimQuotes(processed);
}
// Try to parse as literal
const parsed = parseLiteral(processed);
return {
raw: rawValue,
processed,
parsed,
type: typeof parsed
};
}
// Example with various input types
const examples = [
'"string value"',
"'another string'",
"123",
"true",
"null"
];
examples.forEach(example => {
const result = processDefaultValue(example);
console.log(`${example} -> ${JSON.stringify(result)}`);
});These utilities are commonly used together in documentation processing workflows.
import {
createSummaryValue,
isTooLongForTypeSummary,
normalizeNewlines
} from "@storybook/docs-tools";
// Complete type processing workflow
function processTypeDefinition(typeInfo: any): PropSummaryValue {
const { name, raw, description } = typeInfo;
// Normalize description text
const cleanDescription = description ? normalizeNewlines(description) : '';
// Determine summary and detail
let summary = name || 'unknown';
let detail = raw || '';
// Check if we need to truncate
if (detail && isTooLongForTypeSummary(detail)) {
// Keep original detail, use shorter summary
summary = name || detail.substring(0, 20) + '...';
} else if (detail === summary) {
// Don't duplicate identical values
detail = '';
}
return createSummaryValue(summary, detail || undefined);
}
// Documentation formatting helper
function formatDocumentationValue(value: string, maxLength: number): PropSummaryValue {
const normalized = normalizeNewlines(value.trim());
if (normalized.length <= maxLength) {
return createSummaryValue(normalized);
}
const truncated = normalized.substring(0, maxLength).trim() + '...';
return createSummaryValue(truncated, normalized);
}
// Batch processing utility
function processMultipleValues(values: string[]) {
return values.map(value => {
const normalized = normalizeNewlines(value);
const isTooLong = isTooLongForTypeSummary(normalized);
return {
original: value,
normalized,
summary: createSummaryValue(
isTooLong ? normalized.substring(0, 50) + '...' : normalized,
isTooLong ? normalized : undefined
),
truncated: isTooLong
};
});
}Install with Tessl CLI
npx tessl i tessl/npm-storybook--docs-tools