This guide is specifically for AI assistants and LLMs working on the React Mosaic codebase.
- Read
claude.mdfirst - This contains comprehensive context about the project - Check
.claudeignore- Know what files to skip - Review key files - Start with
libs/react-mosaic-component/src/index.tsfor public API
React Mosaic is fundamentally about tree manipulation:
Tree Node → Visual Layout
├── Split Node → Divides space between children
├── Tab Node → Stacks children as tabs
└── Leaf Node → Individual panel
- Trees are immutable - Always create new tree instances, never mutate
- Paths are numeric arrays -
[0, 1, 2]means root → first child → second child → third child - Type guards are essential - Use
isSplitNode()andisTabsNode()to safely narrow types - Context provides actions - Don't manipulate trees directly in components
- Legacy support exists - Binary trees auto-convert to n-ary trees
When exploring the codebase, read in this order:
- Types (
types.ts) - Understand data structures - Utilities (
util/mosaicUtilities.ts) - Learn tree operations - Root component (
Mosaic.tsx) - See how it all comes together - Window component (
MosaicWindow.tsx) - Understand individual panels - Updates (
util/mosaicUpdates.ts) - Learn tree mutations
- Read the file(s) you're about to modify
- Read related test files
- Understand the existing pattern
- Check if there's a utility function that does what you need
Type Safety
// ✅ Good - Use type guards
if (isSplitNode(node)) {
node.children.forEach(child => ...);
}
// ❌ Bad - Unsafe type assumption
if (node.type === 'split') {
(node as any).children.forEach(...);
}Tree Manipulation
// ✅ Good - Use utility functions
const newTree = updateTree(currentTree, [
createRemoveUpdate(path)
]);
// ❌ Bad - Manual manipulation
const newTree = { ...currentTree };
delete newTree.children[0]; // Wrong!Path Operations
// ✅ Good - Numeric paths
const path: MosaicPath = [0, 1, 2];
const node = getNodeAtPath(tree, path);
// ❌ Bad - String paths (legacy only)
const path = ['first', 'second']; // Don't use!Context Usage
// ✅ Good - Use context actions
const { mosaicActions } = useContext(MosaicContext);
mosaicActions.remove(path);
// ❌ Bad - Direct state manipulation
setTree(removeNodeFromTree(tree, path)); // Avoid!When adding/modifying code:
- Unit tests - Add tests for new utilities in
*.spec.tsfiles - Type tests - Ensure TypeScript compilation passes
- Visual tests - Test in the website playground (
npm start) for component changes - Edge cases - Test with empty trees, single nodes, deeply nested trees
- Use TypeScript strict mode (no
any, explicit types) - Follow existing naming conventions (PascalCase for components, camelCase for functions)
- Add JSDoc comments for public APIs
- Use functional components with hooks
- Avoid side effects in render functions
- Keep functions small and focused (prefer multiple small functions)
interface MyComponentProps<T> {
value: T;
onChange: (newValue: T) => void;
className?: string;
}
export function MyComponent<T>({
value,
onChange,
className
}: MyComponentProps<T>) {
// Implementation
return <div className={className}>...</div>;
}/**
* Description of what this function does
* @param param1 Description
* @returns Description
*/
export function utilityFunction<T>(
param1: MosaicNode<T>
): MosaicNode<T> {
// Guard clauses first
if (!param1) {
throw new Error('param1 is required');
}
// Main logic
// ...
return result;
}import { describe, it, expect } from 'vitest';
describe('MyUtility', () => {
it('should handle normal case', () => {
const input = createTestTree();
const result = myUtility(input);
expect(result).toEqual(expectedOutput);
});
it('should handle edge case', () => {
const input = null;
expect(() => myUtility(input)).toThrow();
});
});- Use
/add-featurecommand - Ask clarifying questions if needed
- Explore related code
- Create implementation plan
- Write tests first (TDD)
- Implement feature
- Run tests
- Update documentation
- Use
/fix-issuecommand - Reproduce the issue
- Write a failing test
- Find root cause
- Fix the bug
- Verify test passes
- Check for similar issues
- Update documentation if needed
- Use
/refactorcommand - Understand current implementation
- Write tests for current behavior
- Make incremental changes
- Run tests after each change
- Verify no functionality changes
- Update comments/docs
- Use
/review-componentcommand - Check type safety
- Check for proper error handling
- Check for accessibility
- Check for performance issues
- Check for security issues
- Suggest improvements
// Get all panel IDs
const panels = getLeaves(tree);
// Get node at specific location
const node = getNodeAtPath(tree, [0, 1]);
// Check node type
if (isSplitNode(node)) {
console.log('Direction:', node.direction);
console.log('Children:', node.children.length);
}// Remove a node
const removeUpdate = createRemoveUpdate([0, 1]);
const newTree = updateTree(tree, [removeUpdate]);
// Expand a node
const expandUpdate = createExpandUpdate([0], 75);
const newTree = updateTree(tree, [expandUpdate]);
// Multiple updates
const newTree = updateTree(tree, [
removeUpdate,
expandUpdate,
]);// Balanced tree from panels
const panels = ['a', 'b', 'c', 'd'];
const tree = createBalancedTreeFromLeaves(panels);
// Manual tree construction
const tree: MosaicNode<string> = {
type: 'split',
direction: 'row',
splitPercentages: [40, 60],
children: [
'panel1',
{
type: 'tabs',
tabs: ['panel2', 'panel3'],
activeTabIndex: 0,
},
],
};- ✅ Use
React.memofor tile components - ✅ Memoize expensive calculations with
useMemo - ✅ Use stable callback references with
useCallback - ✅ Minimize tree updates (batch when possible)
- ✅ Use path-based operations (O(path depth))
- ❌ Don't traverse entire tree on every render
- ❌ Don't create new callbacks in render
- ❌ Don't use inline object literals in props
- ❌ Don't update tree on every mouse move (throttle)
- ❌ Don't create deep tree nesting (>10 levels)
- Log the tree:
console.log(JSON.stringify(tree, null, 2)) - Log paths:
console.log('Path:', path.join(' → ')) - Verify tree structure: Check for invalid nodes
- Use type guards: Ensure correct node types
- Use React DevTools
- Check context values
- Verify props are stable
- Check for unnecessary re-renders
- Log lifecycle events
- Check drag-drop context setup
- Verify backend initialization
- Check drop target positions
- Log drag events
- Verify update generation
When creating new files:
Components
- Location:
libs/react-mosaic-component/src/lib/ - Naming:
ComponentName.tsx - Tests:
ComponentName.spec.tsx(co-located)
Utilities
- Location:
libs/react-mosaic-component/src/lib/util/ - Naming:
utilityName.ts - Tests:
utilityName.spec.ts(co-located)
Types
- Public types:
types.ts - Context types:
contextTypes.ts - Internal types:
internalTypes.ts
Styles
- Location:
libs/react-mosaic-component/src/lib/styles/ - Naming:
component-name.less - Entry: Import in
index.less
- Use conventional commits format
- Keep commits focused and atomic
- Write descriptive commit messages
- Create feature branches from
master - Use descriptive branch names:
feature/add-keyboard-shortcuts - Keep branches up to date with master
- Reference related issues
- Include description of changes
- Add screenshots for UI changes
- Ensure CI passes
When unsure about implementation:
-
"Is there an existing utility function for this?"
- Check
mosaicUtilities.tsandmosaicUpdates.ts
- Check
-
"What's the existing pattern for this?"
- Look for similar components/functions
-
"Does this handle all node types?"
- Consider split nodes, tab nodes, and leaf nodes
-
"Is this type-safe?"
- Use type guards, avoid
any
- Use type guards, avoid
-
"Does this need tests?"
- Yes, if it's not purely presentational
-
"Will this work with controlled and uncontrolled modes?"
- Check if it affects state management
-
"Is this accessible?"
- Consider keyboard navigation, screen readers, focus management
-
"What about edge cases?"
- Empty trees, single nodes, deeply nested, maximum depth
- Main docs:
claude.md - User docs:
README.md - Type reference:
libs/react-mosaic-component/src/lib/types.ts - Utility reference:
libs/react-mosaic-component/src/lib/util/ - Demo examples:
apps/website/src/components/Playground/
# Development
npm start # Start Docusaurus site (with live playground)
npm test # Run tests
npm run test:watch # Watch mode
npm run build:lib # Build library
npm run lint # Check linting
npm run format # Format code
# Type checking
npm run build-lib:check # TypeScript check
# Specific tests
npm test -- --testNamePattern="TreeUtils"
npm test -- libs/react-mosaic-component/src/lib/util/mosaicUtilities.spec.ts- Using string paths - Always use numeric paths (
[0, 1]not['first', 'second']) - Mutating trees - Always return new tree instances
- Skipping type guards - Always check node types before accessing properties
- Forgetting edge cases - Test with empty, single, and deeply nested trees
- Not reading existing code - Always read files before modifying
- Over-engineering - Keep solutions simple and focused
- Breaking changes - Maintain backward compatibility with public APIs
- Ignoring TypeScript errors - Fix all type errors, don't use
any
Your changes are successful when:
- All tests pass
- TypeScript compiles without errors
- Linting passes
- Visual testing in demo app works
- Edge cases are handled
- Documentation is updated
- Code follows existing patterns
- No console errors/warnings
- Accessible (keyboard navigation, ARIA)
- Performance is acceptable
If stuck:
- Read
claude.mdfor context - Use
/explain-conceptto understand core concepts - Use
/analyze-treeto understand tree utilities - Ask specific questions about the codebase
- Review similar existing code for patterns
Remember: The codebase is well-structured and follows consistent patterns. When in doubt, look for existing examples and follow the same approach.