Thank you for considering contributing to Likha! This document outlines how to contribute effectively.
- Code of Conduct
- How Can I Contribute?
- Development Setup
- Project Structure
- Development Workflow
- Coding Standards
- Testing Guidelines
- Commit Guidelines
- Pull Request Process
- Plugin Development
Be respectful, inclusive, and professional. We are building an open and welcoming community.
Before creating a bug report:
- Check existing issues to avoid duplicates
- Use the latest version to verify the bug still exists
- Collect detailed information about the issue
When reporting a bug, include:
- Clear, descriptive title
- Steps to reproduce
- Expected vs actual behavior
- Screenshots or recordings if applicable
- Your environment (browser, OS, version)
- Code samples demonstrating the issue
Feature suggestions are welcome! Please:
- Check if the feature has already been suggested
- Provide a clear use case
- Explain why this feature would benefit most users
- Include mockups or examples if relevant
We welcome code contributions for:
- Bug fixes
- New features (discuss first in an issue)
- Performance improvements
- Documentation improvements
- Test coverage improvements
- New plugins
- Framework adapters
- Node.js 18+ and pnpm 8+
- Git
- A code editor (VS Code recommended)
# Clone the repository
git clone https://github.com/ProgrammerNomad/likhaeditor.git
cd likha
# Install dependencies
pnpm install
# Build all packages
pnpm build
# Run tests
pnpm test
# Start development mode
pnpm devpnpm build # Build all packages
pnpm dev # Start development mode with watch
pnpm test # Run all tests
pnpm test:watch # Run tests in watch mode
pnpm lint # Lint all packages
pnpm format # Format code with Prettier
pnpm typecheck # TypeScript type checkinglikha/
├── packages/
│ ├── core/ # Core editor engine
│ ├── ui/ # UI components
│ ├── plugins/ # Official plugins
│ ├── html/ # Plain HTML adapter
│ ├── react/ # React adapter
│ ├── laravel/ # Laravel package
│ └── livewire/ # Livewire integration
├── examples/ # Example projects
├── docs/ # Documentation
├── scripts/ # Build and utility scripts
└── tests/ # Integration tests
Each package follows this structure:
package/
├── src/
│ ├── index.ts # Main entry point
│ ├── types.ts # TypeScript types
│ └── ...
├── tests/
│ └── *.test.ts # Unit tests
├── package.json
├── tsconfig.json
├── vite.config.ts
└── README.md
git checkout -b feature/your-feature-name
# or
git checkout -b fix/bug-descriptionBranch naming conventions:
feature/- New featuresfix/- Bug fixesdocs/- Documentation changesrefactor/- Code refactoringtest/- Test additions/changeschore/- Maintenance tasks
- Write clean, readable code
- Follow existing code style
- Add tests for new functionality
- Update documentation as needed
# Run tests
pnpm test
# Run specific package tests
pnpm --filter @likhaeditor/core test
# Run linting
pnpm lint
# Type check
pnpm typecheckFollow the commit guidelines.
git add .
git commit -m "feat(core): add new feature"git push origin feature/your-feature-nameThen create a Pull Request on GitHub.
- Use TypeScript for all new code
- Enable strict mode
- Define proper types, avoid
any - Use interfaces for public APIs
- Document complex type definitions
- Use 2 spaces for indentation
- Use single quotes for strings
- Add trailing commas
- Max line length: 100 characters
- Use meaningful variable names
// Good
interface EditorOptions {
element: HTMLElement;
content?: string;
plugins?: Plugin[];
}
export class Editor {
private view: EditorView;
private plugins: Plugin[] = [];
constructor(options: EditorOptions) {
this.initializeEditor(options);
}
private initializeEditor(options: EditorOptions): void {
// Implementation
}
}
// Bad
export class Editor {
view: any;
p: any[];
constructor(opts: any) {
this.view = opts.element;
}
}- Classes: PascalCase (
EditorView,TablePlugin) - Functions: camelCase (
createEditor,getContent) - Constants: UPPER_SNAKE_CASE (
DEFAULT_CONFIG,MAX_SIZE) - Files: kebab-case (
editor-view.ts,table-plugin.ts) - Components: PascalCase (
Toolbar.tsx,MenuItem.tsx)
import { describe, it, expect } from 'vitest';
import { Editor } from '../src';
describe('Editor', () => {
it('should initialize with default options', () => {
const element = document.createElement('div');
const editor = new Editor({ element });
expect(editor).toBeDefined();
expect(editor.getHTML()).toBe('<p></p>');
});
it('should accept initial content', () => {
const element = document.createElement('div');
const editor = new Editor({
element,
content: '<p>Hello</p>'
});
expect(editor.getHTML()).toBe('<p>Hello</p>');
});
});- Public API methods
- Edge cases and error conditions
- Browser compatibility (use testing tools)
- Accessibility features
- Performance (for critical paths)
- Core packages: 90%+ coverage
- Plugins: 80%+ coverage
- Adapters: 80%+ coverage
We follow Conventional Commits.
<type>(<scope>): <subject>
<body>
<footer>
feat- New featurefix- Bug fixdocs- Documentation changesstyle- Code style changes (formatting, etc.)refactor- Code refactoringtest- Adding or updating testschore- Maintenance tasksperf- Performance improvements
core- Core editorui- UI componentsplugins- Pluginsreact- React adapterlaravel- Laravel packagelivewire- Livewire integrationdocs- Documentation
feat(core): add undo/redo functionality
fix(plugins): resolve table resize bug
docs(readme): update installation instructions
test(core): add tests for serialization
chore(deps): upgrade dependencies- Tests pass (
pnpm test) - Linting passes (
pnpm lint) - Type checking passes (
pnpm typecheck) - Documentation updated
- Changeset added (if applicable)
## Description
Brief description of changes
## Type of Change
- [ ] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update
## Testing
How has this been tested?
## Screenshots (if applicable)
## Checklist
- [ ] Tests added/updated
- [ ] Documentation updated
- [ ] No breaking changes (or documented)- Automated checks must pass (CI/CD)
- At least one maintainer review required
- Address all review comments
- Squash commits before merge (if requested)
- Delete your branch
- Pull the latest main branch
- Celebrate your contribution!
import { Plugin } from '@likhaeditor/core';
export class MyPlugin extends Plugin {
name = 'my-plugin';
init() {
// Plugin initialization
}
commands() {
return {
myCommand: () => ({ state, dispatch }) => {
// Command implementation
return true;
}
};
}
inputRules() {
// Return input rules
}
keymap() {
// Return keyboard shortcuts
}
}- One plugin, one responsibility
- Provide clear documentation
- Include examples
- Write tests
- Keep dependencies minimal
- Make it configurable
describe('MyPlugin', () => {
it('should register commands', () => {
const editor = new Editor({
plugins: [new MyPlugin()]
});
expect(editor.commands.myCommand).toBeDefined();
});
});- Check documentation
- Search existing issues
- Ask in GitHub Discussions
- Reach out to maintainers
Contributors will be:
- Listed in CONTRIBUTORS.md
- Mentioned in release notes
- Given credit in documentation
Thank you for contributing to Likha!