@effijs/props-manager
v2.0.14
Published
An efficient, modern way to organize the business logic of an application(@effijs/props-manager)
Readme
Property Manager
Overview
The Property Manager library is a powerful tool for managing and transforming React component props. It provides a structured way to handle complex component structures, redirect props to appropriate child components, and simplify component testing by analyzing prop interactions and results.
Key Features
- Prop Transformation: Convert incoming props into appropriate styles and properties
- Manage Design Systems: Better supporting Design systems
- Component Inheritance: Extend existing property managers to create new components
- Child Component Management: Define and manage props for child components
- Pattern Matching: Transform props based on patterns
- Provider Integration: Connect to dynamic data sources
- Testing Support: Simplified testing of component prop behaviors
Core Concepts
PropertyManager
The PropertyManager is the core class responsible for managing component prop transformations. Its key features include:
Separate Style and Prop Management
- Allows independent control of styles and props transformations
- Uses distinct
.styles()and.props()methods for clear separation
Sequential Processing
- Transformations are applied in the order they are defined
- Later transformations can override earlier ones
- This enables flexible layering of properties
Component Creation and Inheritance
const grid = PropertyManager.create('Grid')
.styles(
// Style transformations
)
.props(
// Props transformations
);
const box = PropertyManager.create('Box')
.extends('Grid') // Inheritance
.styles(
// Additional style transformations
)
.props(
// Props transformations
);Transformation Order
- Base component transformations are applied first
- Extended component transformations are applied afterward
- Final output combines all transformations in sequence
Usage Benefits
- Promotes clean and maintainable code structure
- Enables component composition through inheritance
- Provides predictable prop transformation behavior
- Simplifies complex styling patterns
This structure makes PropertyManager ideal for:
- Building consistent component libraries
- Managing complex styling systems
- Creating extensible component hierarchies
- Maintaining clear separation of styling and behavioral props
Style and Prop Transformers
The transformation system provides different ways to convert input props into desired output formats. Here's a detailed breakdown of the Prop transformer:
Prop
The Prop transformer is a versatile tool that can handle prop transformations in three main ways:
- Single Prop Renaming
Prop('color', 'backgroundColor')- Input:
{ color: 'blue' } - Output:
{ backgroundColor: 'blue' } - Process:
- Takes the value from input prop 'color'
- Creates new property with name 'backgroundColor'
- Assigns the original value to the new property
- Multiple Props Pass-through
Prop(['borderColor', 'borderWidth'])- Input:
{ borderColor: 'black', borderWidth: 2 } - Output:
{ borderColor: 'black', borderWidth: 2 } - Process:
- Takes an array of prop names
- Creates identical properties in output
- Copies values directly without transformation
- If a prop is missing in input, it's skipped in output
- Custom Transformation Function
Prop('color', ({color}) => ({ backgroundColor: color, borderColor: color }))- Input:
{ color: 'red' } - Output:
{ backgroundColor: 'red', borderColor: 'red' } - Process:
- Takes input prop name ('color')
- Executes transformation function with props object
- Function can return complex object with multiple properties
- Allows for computed values and conditional logic
Advanced Features
- Value Processing
Prop('size', (props) => ({
width: props.size * 2,
height: props.size * 2
}))- Input:
{ size: 10 } - Output:
{ width: 20, height: 20 } - Allows mathematical operations and complex calculations
- Conditional Transformations
Prop('variant', ({variant, disabled}) => ({
backgroundColor: disabled ? 'grey' : variant === 'primary' ? 'blue' : 'white'
}))- Input:
{ variant: 'primary', disabled: true } - Output:
{ backgroundColor: 'grey' } - Can access multiple props for conditional logic
- Type Safety
- Preserves TypeScript type information
- Provides autocomplete for prop names
- Validates prop types during transformation
This transformation system enables:
- Clean prop mapping
- Complex computed values
- Conditional styling
- Type-safe transformations
- Reusable transformation logic
The transformer can be used in both and methods, allowing for separation of visual styles from behavioral properties while using the same powerful transformation capabilities. .styles() .props()
Static
Applies constant styles or props:
Static({
minHeight: 48,
overflow: 'hidden'
})Pattern
The Pattern transformer is a powerful tool that generates multiple prop transformations using a template system. It's particularly useful for creating consistent, systematic prop mappings.
Core Concepts
- Pattern Definition
Pattern('{placeholder}', valuesObject)- First argument: pattern template with placeholders
- Second argument: object containing possible values
- Returns a pattern builder for defining transformations
- Value Mapping
const spacing = {
s: 8,
m: 16,
l: 24,
}- Values object defines all possible substitutions
- Keys become available for placeholder substitution
- Values are used in the resulting transformations
- Key Definition
Pattern('{size}', spacing)
.key('margin-{size}', 'margin')
.key('padding-{size}', 'padding').key()defines transformation rules- First argument: input prop pattern
- Second argument: output property name
Transformation Process
Pattern Recognition
- Identifies placeholders in curly braces
{} - Matches placeholders with values object keys
- Creates combinations for each possible value
- Identifies placeholders in curly braces
Property Generation
// Input pattern
.key('m-{size}', 'margin')
// Generates transformations for:
// m-s → { margin: 8 }
// m-m → { margin: 16 }
// m-l → { margin: 24 }- Multiple Patterns
- Can define multiple
.key()patterns - Each pattern generates its own set of transformations
- All transformations are combined into final result
- Can define multiple
Benefits
Reduced Boilerplate
- Generates multiple transformations from single pattern
- Eliminates repetitive transformer definitions
- Maintains consistency across related properties
Systematic Approach
- Creates predictable naming patterns
- Ensures consistent value mapping
- Makes style systems more maintainable
Flexible Configuration
- Easy to modify value sets
- Simple to add new patterns
- Supports complex transformation logic
The Pattern transformer is especially useful for:
- Design systems with systematic spacing
- Responsive design properties
- Consistent naming conventions
- Scale-based property systems
Provider
The Provider system is a mechanism for connecting transformers to dynamic data sources, enabling real-time updates of component properties based on changing values.
Core Components
- Provider Registration
PropertyManager.registerProvider(
name: string,
getData: () => any,
subscribeToChanges?: (callback: () => void) => void
)name: Unique identifier for the providergetData: Function that returns current provider datasubscribeToChanges: Optional function to listen for data changes
- Provider Usage
Provider(
providerName: string,
transformerFactory: (data: any) => Transformer
)providerName: References registered providertransformerFactory: Function that creates transformer using provider data
How It Works
- Registration Process
// Data structure
interface Theme {
colors: Record<string, string>;
spacing: Record<string, number>;
}
// Provider setup
const themeProvider = {
data: initialTheme,
eventEmitter: new EventEmitter()
};
// Registration
PropertyManager.registerProvider(
'theme',
() => themeProvider.data,
(onChange) => themeProvider.eventEmitter.subscribe(onChange)
);- Data Flow
// Creating transformer with provider
const componentStyles = PropertyManager.create('Component')
.styles(
Provider('theme', (theme) =>
Prop('variant', ({variant}) => ({
backgroundColor: theme.colors[variant]
}))
)
);
// Using component
const styles = componentStyles.get({ variant: 'primary' });
// → { backgroundColor: 'white' }
// When theme changes
themeProvider.data = newTheme;
themeProvider.eventEmitter.emit();
// → Automatically updates all dependent components- Update Mechanism
- Provider data changes
- Provider emits change event
- PropertyManager receives notification
- All transformers using this provider are re-evaluated
- Components using these transformers get updated properties
Use Cases
Theming
- Dynamic color schemes
- Light/dark mode switching
- Brand theme variations
Responsive Design
- Screen size-based adjustments
- Device-specific styling
- Orientation changes
Feature Flags
- Component variants
- Experimental features
- A/B testing
Localization
- RTL/LTR layouts
- Language-specific spacing
- Cultural adaptations
The Provider system enables:
- Dynamic styling updates
- Theme switching
- Responsive adaptations
- Real-time feature toggles
- Performance optimizations through selective updates
Child Components
The Child Components system provides a structured way to manage props for complex components with multiple nested elements. It handles prop distribution and transformation for each child component independently.
Core Concepts
- Child Definition
Child(name: string)
.extends(parentName: string)
.props(...transformers)
.styles(...transformers)Components:
name: Unique identifier for the childprops: Prop transformers specific to this childstyles: Style transformers for this childextends: Inherit from another component's transformations, reusing transformers
- Props Distribution
const componentProps = PropertyManager.create('Component')
.styles(rootStyles)
.props(rootProps)
.child(
Child('childA').props(childAProps),
Child('childB').props(childBProps)
)How It Works
- Transformation Process
const result = componentProps.get({
color: 'primary',
children: 'Text',
Icon: 'star'
});
// Result structure:
{
// Root component props
prop: { ... },
style: { ... },
// Child components props
props: {
childA: { ... },
childB: { ... },
},
styles: {
childA: { ... },
childB: { ... },
}
}Prop Flow
- Input props are received
- Root transformers process props first
- Each child processes relevant props
- Results are organized by component hierarchy
Usage in Components
function ComplexComponent(props) {
const {
// Root props
prop: rootProps,
style: rootStyle,
// Child props
props: {
icon: iconProps,
text: textProps
}
} = componentProps.get(props);
return (
<Root {...rootProps} style={rootStyle}>
<Icon {...iconProps} />
<Text {...textProps} />
</Root>
);
}Advanced Features
- Prop Inheritance
Child('text')
.extends('Typography')
.props(
// Additional props specific to this usage
)- Inherit transformations from other components
- Override or extend inherited props
- Maintain consistency across components
- Conditional Child Props
Child('icon').props(
Prop('visible', ({hasIcon}) => ({
display: hasIcon ? 'flex' : 'none'
}))
)- Transform props based on conditions
- Dynamic child component behavior
- Responsive to parent state
- Style Organization
Child('container')
.styles(
// Layout styles
Static({ display: 'flex' }),
Prop('direction', 'flexDirection'),
// Spacing
Pattern('{size}', spacing)
.key('gap-{size}', 'gap'),
// Visual
Prop('variant', ({variant, theme}) => ({
backgroundColor: theme.colors[variant]
}))
)- Grouped style transformations
- Clear separation of concerns
- Maintainable style structure
Benefits
Organized Prop Management
- Clear hierarchy of components
- Structured prop distribution
- Isolated child component logic
Reusability
- Share transformations between components
- Consistent prop handling
- Reduced code duplication
Maintainability
- Isolated child component changes
- Clear prop flow
- Easy debugging
Type Safety
- TypeScript support
- Prop validation
- IDE autocompletion
This system is particularly useful for:
- Complex compound components
- Reusable component libraries
- Design systems
- Components with multiple variants
- Nested component structures
The Child Components system provides a powerful way to manage complex component hierarchies while maintaining clean, maintainable code.
Benefits
- Structured Prop Management: Organizes prop handling logic in a declarative way
- Component Reusability: Easily extend existing components with new behaviors
- Enhanced Testability: Test component prop transformations without rendering
- Dynamic Styling: Connect to theme providers and other dynamic data sources
- Simplified Complex Components: Manage multi-level component structures with clarity
- Pattern-Based Props: Create consistent prop interfaces using patterns
- Separation of Concerns: Clear separation between prop handling and rendering
Testing
The Property Manager provides robust testing features that make it easy to verify prop transformations and component behavior.
Core Testing Features
- Prop Transformation Testing
const componentPM = PropertyManager.create('Component')
.styles(...)
.props(...)
test('verifies prop transformations', () => {
const result = componentPM.get({
variant: 'primary',
size: 'large'
});
expect(result).toMatchObject({
style: {
// Style transformations
},
props: {
// Prop transformations
}
});
});- Child Component Testing
test('child components receive correct props', () => {
const result = componentPM.get(inputProps);
expect(result.props.icon).toMatchObject({
// Icon-specific props
});
expect(result.props.text).toMatchObject({
// Text-specific props
});
});Testing Strategies
Unit Testing Transformers
- Test individual prop transformations
- Verify style calculations
- Check conditional logic
Integration Testing
- Test multiple transformers together
- Verify provider interactions
- Check child component prop flow
Snapshot Testing
- Capture full transformation results
- Track changes over time
- Ensure consistent behavior
Benefits of Property Manager
1. Development Experience
- Clear prop transformation syntax
- Type-safe prop handling
- Predictable component behavior
- Easy debugging and testing
2. Code Organization
- Separation of concerns
- Reusable transformations
- Structured prop management
- Maintainable component logic
3. Performance
- Optimized prop calculations
- Efficient updates
- Minimal re-renders
- Scalable architecture
4. Maintainability
- Centralized prop management
- Clear transformation flow
- Easy to modify and extend
- Consistent patterns
5. Component Systems
- Design system integration
- Theme management
- Responsive design
- Dynamic styling
Best Practices
Transformer Organization
- Group related transformations
- Use meaningful names
- Keep transformations simple
- Document complex logic
Testing Strategy
- Test all transformation paths
- Verify edge cases
- Include provider testing
- Use snapshot testing
Code Structure
- Separate styling from behavior
- Use child components appropriately
- Leverage providers for dynamic data
- Keep transformations pure
Performance Considerations
- Minimize complex calculations
- Use memoization when needed
- Optimize provider updates
- Profile transformation performance
Use Cases
Component Libraries
- Consistent interfaces
- Reusable patterns
- Maintainable code
- Clear documentation
Design Systems
- Theme management
- Style consistency
- Component variants
- Dynamic updates
Complex Applications
- Organized prop handling
- Clear component hierarchy
- Testable components
- Maintainable code base
The Property Manager library provides a solid foundation for building scalable, maintainable React applications with well-organized prop management and clear testing strategies.
