@hakxel/mantine-ui-server
Version:
MCP server for working with Mantine UI components - provides documentation, generation, and theme utilities
206 lines (201 loc) • 7.17 kB
JavaScript
/**
* Component templates for the Mantine UI MCP server
*/
/**
* Base template for a functional component
* @param config Component generation configuration
* @returns Generated component code
*/
export function generateBasicComponentTemplate(config) {
const { name, mantineComponent, props = {}, styling = {}, includeTests = false } = config;
// Extract styling options
const { useModule = false, responsive = false } = styling;
// Generate import statements
const importsBlock = generateImports(mantineComponent, useModule, responsive);
// Generate props interface
const propsInterface = generatePropsInterface(name, props);
// Generate component function
const componentBody = generateComponentBody(name, mantineComponent, props, styling);
// Assemble the full component code
return `${importsBlock}
${propsInterface}
export function ${name}(${props ? `{ ${Object.keys(props).join(', ')} }: ${name}Props` : ''}) {
${componentBody}
}
`;
}
/**
* Generate import statements for the component
* @param mantineComponent Mantine component to import
* @param useModule Whether to use CSS modules
* @param responsive Whether to add responsive imports
* @returns Import statements block
*/
function generateImports(mantineComponent, useModule, responsive) {
let imports = `import { ${mantineComponent} } from '@mantine/core';\n`;
if (responsive) {
imports += `import { useMediaQuery } from '@mantine/hooks';\n`;
}
if (useModule) {
imports += `import classes from './${mantineComponent.toLowerCase()}.module.css';\n`;
}
return imports;
}
/**
* Generate props interface for the component
* @param name Component name
* @param props Component props
* @returns Props interface code
*/
function generatePropsInterface(name, props) {
if (!props || Object.keys(props).length === 0) {
return ''; // No props, no interface needed
}
// Start the interface definition
let interfaceCode = `export interface ${name}Props {\n`;
// Add each prop with its type
for (const [propName, propConfig] of Object.entries(props)) {
const required = propConfig.required ? '' : '?';
const type = propConfig.type || 'any';
const comment = propConfig.description ? ` /** ${propConfig.description} */\n` : '';
interfaceCode += `${comment} ${propName}${required}: ${type};\n`;
}
// Close the interface
interfaceCode += `}`;
return interfaceCode;
}
/**
* Generate the component body
* @param name Component name
* @param mantineComponent Mantine component to use
* @param props Component props
* @param styling Styling options
* @returns Component body code
*/
function generateComponentBody(name, mantineComponent, props, styling = {}) {
const { useModule = false, responsive = false, themeOverrides = {} } = styling;
let body = '';
// Add responsive hooks if needed
if (responsive) {
body += ` const isMobile = useMediaQuery('(max-width: 768px)');\n`;
}
// Start the return statement
body += ` return (\n`;
// Generate the component JSX
const componentProps = generateComponentProps(props, themeOverrides, useModule);
body += ` <${mantineComponent}${componentProps ? ` ${componentProps}` : ''}>
{/* Your component content here */}
</${mantineComponent}>
);`;
return body;
}
/**
* Generate component props string
* @param props Component props
* @param themeOverrides Theme overrides
* @param useModule Whether to use CSS modules
* @returns Component props string
*/
function generateComponentProps(props, themeOverrides, useModule) {
const propParts = [];
// Add className if using modules
if (useModule) {
propParts.push(`className={classes.root}`);
}
// Add any theme overrides as inline styles or class names
if (Object.keys(themeOverrides).length > 0) {
const overridesStr = JSON.stringify(themeOverrides, null, 2)
.replace(/"([^"]+)":/g, '$1:')
.replace(/"/g, "'");
propParts.push(`sx={${overridesStr}}`);
}
// Add responsive props if needed
for (const [propName, propConfig] of Object.entries(props)) {
if (propConfig.responsive) {
propParts.push(`${propName}={isMobile ? ${propConfig.mobileValue} : ${propConfig.defaultValue}}`);
}
else if (propConfig.defaultValue !== undefined) {
// Add non-responsive props with default values
const value = typeof propConfig.defaultValue === 'string'
? `"${propConfig.defaultValue}"`
: propConfig.defaultValue;
propParts.push(`${propName}={${value}}`);
}
}
return propParts.join('\n ');
}
/**
* Generate a CSS module template for the component
* @param config Component generation configuration
* @returns Generated CSS module code
*/
export function generateCssModuleTemplate(config) {
const { themeOverrides = {} } = config.styling || {};
// Start with the root class
let css = `.root {\n`;
// Add any theme overrides as CSS properties
for (const [prop, value] of Object.entries(themeOverrides)) {
// Convert camelCase to kebab-case
const cssProperty = prop.replace(/([A-Z])/g, '-$1').toLowerCase();
css += ` ${cssProperty}: ${value};\n`;
}
// Close the root class
css += `}\n`;
return css;
}
/**
* Generate variant templates for a component
* @param config Component generation configuration
* @returns Object with generated variants
*/
export function generateVariants(config) {
const { name, mantineComponent, variants = [] } = config;
const result = {};
if (!variants.length) {
return result;
}
// Generate a variant for each configuration
for (const variant of variants) {
const variantConfig = {
...config,
name: `${name}${variant.name.charAt(0).toUpperCase() + variant.name.slice(1)}`,
props: {
...config.props,
...variant.props
},
};
result[variant.name] = generateBasicComponentTemplate(variantConfig);
}
return result;
}
/**
* Generate index file for exporting all components
* @param configs Component generation configurations
* @returns Generated index file content
*/
export function generateIndexFile(configs) {
let exports = '';
for (const config of configs) {
exports += `export { ${config.name} } from './${config.name}';\n`;
exports += `export type { ${config.name}Props } from './${config.name}';\n`;
}
return exports;
}
/**
* Generate test file for a component
* @param config Component generation configuration
* @returns Generated test file content
*/
export function generateTestFile(config) {
const { name } = config;
return `import { render, screen } from '@testing-library/react';
import { ${name} } from './${name}';
describe('${name}', () => {
it('renders correctly', () => {
render(<${name} />);
// Add your test assertions here
});
// Add more tests as needed
});
`;
}