Live preview system for React and Vue components with automatic prop extraction and interactive examples.
Extracts metadata from React components including props, types, and default values.
/**
* Parses React component and extracts metadata
* @param {string} filePath - Path to the React component file
* @param {Object} doclet - JSDoc doclet containing component information
* @returns {ComponentMetadata} Component metadata with props and display information
*/
function parseReact(filePath: string, doclet: Object): ComponentMetadata;
interface ComponentMetadata {
/** Component display name */
displayName: string;
/** Path to component file */
filePath: string;
/** Component props information */
props: PropInfo[];
/** Component type (react or vue) */
type: 'react' | 'vue';
/** Vue-specific slots (only for Vue components) */
slots?: SlotInfo[];
}
interface PropInfo {
/** Property name */
name: string;
/** Property description from PropTypes or JSDoc */
description?: string;
/** Property type (string, number, boolean, etc.) */
type: string;
/** Whether the property is required */
required: boolean;
/** Default value if specified */
defaultValue?: string;
}Usage Example:
const { parseReact } = require('better-docs/component');
// Document a React component with @component tag
/**
* Button component with customizable styling
* @component
* @example
* return <Button variant="primary" size="large">Click me</Button>
*/
const Button = ({ variant = 'default', size = 'medium', children, onClick }) => {
return (
<button
className={`btn btn-${variant} btn-${size}`}
onClick={onClick}
>
{children}
</button>
);
};
Button.propTypes = {
variant: PropTypes.oneOf(['default', 'primary', 'secondary']),
size: PropTypes.oneOf(['small', 'medium', 'large']),
children: PropTypes.node.isRequired,
onClick: PropTypes.func
};Extracts metadata from Vue components including props, slots, and component options.
/**
* Parses Vue component and extracts metadata
* @param {string} filePath - Path to the Vue component file
* @param {Object} doclet - JSDoc doclet containing component information
* @returns {ComponentMetadata} Component metadata with props, slots, and display information
*/
function parseVue(filePath: string, doclet: Object): ComponentMetadata;
interface SlotInfo {
/** Slot name */
name: string;
/** Slot description */
description?: string;
}Usage Example:
<script>
/**
* Card component with header and footer slots
* @component
* @example
* <Card title="My Card">
* <template #header>Custom Header</template>
* <p>Card content goes here</p>
* <template #footer>Card footer</template>
* </Card>
*/
export default {
name: 'Card',
props: {
title: {
type: String,
required: true,
default: 'Default Title'
},
variant: {
type: String,
default: 'default',
validator: value => ['default', 'primary', 'secondary'].includes(value)
}
}
}
</script>JSDoc event handlers for processing component documentation.
interface ComponentHandlers {
/**
* Processes Vue single-file components before parsing
* @param {Object} e - Parse event
*/
beforeParse(e: ParseEvent): void;
/**
* Processes doclets to handle @component tags
* @param {Object} docletEvent - Doclet event with component information
*/
newDoclet(docletEvent: DocletEvent): void;
}
interface ParseEvent {
filename: string;
source: string;
componentInfo?: ComponentInfo;
}
interface DocletEvent {
doclet: {
tags?: Array<{
title: string;
value?: string;
}>;
component?: ComponentMetadata;
kind?: string;
memberof?: string;
undocumented?: boolean;
};
}
interface ComponentInfo {
displayName: string;
props?: Object;
slots?: Object;
}Provides iframe-based rendering and code editing for React component previews.
/**
* React wrapper component factory for live previews
* @param {Object} props - Component props including example code and unique ID
* @returns {React.Component} Wrapper component instance
*/
function ReactWrapper(props: WrapperProps): React.Component;
interface WrapperProps {
/** Unique identifier for the component instance */
uniqId: string;
/** Example code to render */
example?: string;
}
class Wrapper extends React.Component {
constructor(props: WrapperProps);
/**
* Executes JavaScript code for component rendering
* @param {string} source - JavaScript source code
*/
executeScript(source: string): void;
/**
* Handles code changes in the editor
* @param {string} code - Updated code
*/
handleChange(code: string): void;
/**
* Computes iframe height based on content
*/
computeHeight(): void;
/**
* Toggles code editor visibility
* @param {Event} event - Click event
*/
toggleEditor(event: Event): void;
render(): React.Element;
}Provides component rendering and code editing for Vue component previews.
/**
* Vue wrapper component definition for live previews
*/
interface VueWrapper {
/** Vue component template */
template: string;
/** Component props definition */
props: {
defaultCode: StringConstructor;
};
/** Component data factory */
data(): {
code: string;
userComponent: Object;
isActive: boolean;
};
/** Child components */
components: {
editor: Object;
};
/** Lifecycle and utility methods */
methods: {
toggleEditor(): void;
editorInit(): void;
renderComponent(originalCode?: string): Object;
};
}/**
* Alert component for displaying messages
* @component
* @example <caption>Basic alert</caption>
* return <Alert type="info">This is an informational message</Alert>
*
* @example <caption>Error alert</caption>
* return <Alert type="error">Something went wrong!</Alert>
*
* @example <caption>Custom styling</caption>
* return (
* <Alert
* type="success"
* dismissible={true}
* onDismiss={() => console.log('Alert dismissed')}
* >
* Operation completed successfully!
* </Alert>
* )
*/
const Alert = ({ type, children, dismissible, onDismiss }) => {
return (
<div className={`alert alert-${type}`}>
{children}
{dismissible && (
<button onClick={onDismiss} className="alert-close">×</button>
)}
</div>
);
};
Alert.propTypes = {
type: PropTypes.oneOf(['info', 'success', 'warning', 'error']).isRequired,
children: PropTypes.node.isRequired,
dismissible: PropTypes.bool,
onDismiss: PropTypes.func
};<script>
/**
* Progress bar component
* @component
* @example <caption>Basic progress bar</caption>
* <ProgressBar :value="50" :max="100" />
*
* @example <caption>With custom styling</caption>
* <ProgressBar
* :value="75"
* :max="100"
* color="success"
* :show-percentage="true"
* />
*
* @example <caption>Multiple progress bars</caption>
* {
* template: `
* <div>
* <ProgressBar :value="30" label="CPU Usage" />
* <ProgressBar :value="60" label="Memory Usage" color="warning" />
* <ProgressBar :value="90" label="Disk Usage" color="danger" />
* </div>
* `
* }
*/
export default {
name: 'ProgressBar',
props: {
value: {
type: Number,
required: true
},
max: {
type: Number,
default: 100
},
color: {
type: String,
default: 'primary',
validator: value => ['primary', 'success', 'warning', 'danger'].includes(value)
},
showPercentage: {
type: Boolean,
default: false
},
label: {
type: String
}
}
}
</script>You can use multiple documented components together in examples:
/**
* Modal dialog component
* @component
* @example <caption>Modal with alert inside</caption>
* return (
* <Modal isOpen={true} title="Confirm Action">
* <Alert type="warning">
* Are you sure you want to delete this item?
* </Alert>
* <Button variant="danger">Delete</Button>
* <Button variant="secondary">Cancel</Button>
* </Modal>
* )
*/
const Modal = ({ isOpen, title, children, onClose }) => {
if (!isOpen) return null;
return (
<div className="modal-overlay">
<div className="modal">
<div className="modal-header">
<h3>{title}</h3>
<button onClick={onClose}>×</button>
</div>
<div className="modal-body">
{children}
</div>
</div>
</div>
);
};Enable component documentation in JSDoc configuration:
{
"tags": {
"allowUnknownTags": ["component"]
},
"plugins": [
"node_modules/better-docs/component"
],
"templates": {
"better-docs": {
"component": {
"wrapper": "./path/to/wrapper-component.js",
"entry": [
"import 'babel-polyfill';",
"import 'bulma/css/bulma.css';"
]
}
}
}
}For React components that need specific context (Redux, Router, etc.):
// wrapper-component.js
import React from 'react';
import { BrowserRouter } from 'react-router-dom';
import { Provider } from 'react-redux';
import store from './store';
const WrapperComponent = ({ children }) => {
return (
<Provider store={store}>
<BrowserRouter>
<div className="component-preview">
{children}
</div>
</BrowserRouter>
</Provider>
);
};
export default WrapperComponent;The component plugin requires: