First off, thank you for considering contributing to FlexUI! It's people like you that make FlexUI such a great tool.
- Code of Conduct
- Getting Started
- How Can I Contribute?
- Development Workflow
- Coding Standards
- Community
This project and everyone participating in it is governed by our Code of Conduct. By participating, you are expected to uphold this code. Please report unacceptable behavior to nv3212@gmail.com.
See CODE_OF_CONDUCT.md for details.
-
Fork the repository
# Click the "Fork" button on GitHub -
Clone your fork
git clone https://github.com/YOUR_USERNAME/flex-ui.git cd flex-ui -
Set up the development environment
# Bootstrap the project make bootstrap -
Create a feature branch
git checkout -b feature/your-feature-name
-
Open the project in Xcode
open Package.swift
Before creating a bug report, please check the existing issues to avoid duplicates.
When creating a bug report, include:
- Clear title - Describe the issue concisely
- Reproduction steps - Detailed steps to reproduce the bug
- Expected behavior - What you expected to happen
- Actual behavior - What actually happened
- Environment - iOS version, Xcode version, Swift version
- Code samples - Minimal reproducible example
- Error messages - Complete error output if applicable
Example:
**Title:** Chainable configuration breaks with custom UIView subclass
**Steps to reproduce:**
1. Create custom UIView subclass
2. Add .flex configuration chain
3. Attempt to set backgroundColor
**Expected:** Background color should be set correctly
**Actual:** Compiler error about missing return type
**Environment:**
- iOS 16.0
- Xcode 16.0
- Swift 6.0
**Code:**
\`\`\`swift
class CustomView: UIView { }
let view = CustomView()
.flex
.backgroundColor(.red) // Error here
\`\`\`We love feature suggestions! When proposing a new feature, include:
- Problem statement - What problem does this solve?
- Proposed solution - How should it work?
- Alternatives - What alternatives did you consider?
- Use cases - Real-world scenarios
- API design - Example code showing usage
- Breaking changes - Will this break existing code?
Example:
**Feature:** Add animation helper methods to FlexUI
**Problem:** Configuring view animations requires breaking the chain and using UIView.animate separately.
**Solution:** Add chainable animation methods to FlexUI protocol.
**API:**
\`\`\`swift
let view = UIView()
.flex
.backgroundColor(.blue)
.animate(duration: 0.3) { view in
view.flex
.alpha(0.5)
.transform(CGAffineTransform(scaleX: 1.2, y: 1.2))
}
\`\`\`
**Use case:** Creating animated UI without breaking the fluent configuration chain.Documentation improvements are always welcome:
- Code comments - Add/improve inline documentation
- DocC documentation - Enhance documentation articles
- README - Fix typos, add examples
- Guides - Write tutorials or how-to guides
- API documentation - Document public APIs
- Check existing work - Look for related issues or PRs
- Discuss major changes - Open an issue for large features
- Follow coding standards - See Coding Standards
- Write tests - All code changes require tests
- Update documentation - Keep docs in sync with code
- Create a pull request - Use clear description
We use a simplified branching model:
main- Main development branch (all PRs target this)feature/*- New featuresfix/*- Bug fixesdocs/*- Documentation updatesrefactor/*- Code refactoringtest/*- Test improvements
Branch naming examples:
feature/animation-helpers
fix/chaining-with-custom-views
docs/update-extension-guide
refactor/simplify-flex-protocol
test/add-uitableview-testsWe use Conventional Commits for clear, structured commit history.
Format:
<type>(<scope>): <subject>
<body>
<footer>
Types:
feat- New featurefix- Bug fixdocs- Documentation changesstyle- Code style (formatting, no logic changes)refactor- Code refactoringtest- Adding or updating testschore- Maintenance tasksperf- Performance improvements
Scopes:
core- Core FlexUI protocolextensions- UIKit component extensionsui- UI components (UILabel, UIButton, etc.)utilities- Helper utilitiesdeps- Dependencies
Examples:
feat(extensions): add UIStackView configuration methods
Implement chainable configuration methods for UIStackView including
axis, alignment, distribution, and spacing properties.
Closes #23
---
fix(core): correct return type inference for custom views
Fixed issue where custom UIView subclasses lost type information
in chaining. Now properly preserves the concrete type through
the entire chain.
Fixes #45
---
docs(readme): add custom extension examples
Add practical examples showing how to create custom FlexUI
extensions for project-specific styling needs.
---
test(extensions): add UITextField configuration tests
Add comprehensive tests for UITextField extensions including:
- Text and placeholder configuration
- Keyboard and input settings
- Border and styling propertiesCommit message rules:
- Use imperative mood ("add" not "added")
- Don't capitalize first letter
- No period at the end
- Keep subject line under 72 characters
- Separate subject from body with blank line
- Reference issues in footer
-
Update your branch
git checkout main git pull upstream main git checkout feature/your-feature git rebase main
-
Run tests and checks
# Run all tests swift test # Check test coverage swift test --enable-code-coverage
-
Push to your fork
git push origin feature/your-feature
-
Create pull request
- Target the
mainbranch - Provide clear description
- Link related issues
- Include examples if applicable
- Request review from maintainers
- Target the
-
Review process
- Address review comments
- Keep PR up to date with main
- Squash commits if requested
- Wait for CI to pass
-
After merge
# Clean up local branch git checkout main git pull upstream main git branch -d feature/your-feature # Clean up remote branch git push origin --delete feature/your-feature
We follow the Swift API Design Guidelines and Ray Wenderlich Swift Style Guide.
Key points:
-
Naming
// ✅ Good func backgroundColor(_ color: UIColor) -> Self let cornerRadius: CGFloat // ❌ Bad func setBG(_ c: UIColor) -> Self let rad: CGFloat
-
Protocols
// ✅ Good - Use descriptive protocol names public protocol FlexUIConfigurable { associatedtype Component var component: Component { get } } // ❌ Bad protocol Config { }
-
Access Control
// ✅ Good - Explicit access control public struct FlexUI<Component> { public let component: Component public init(component: Component) { self.component = component } @discardableResult @MainActor public func backgroundColor(_ color: UIColor) -> Self where Component: UIView { component.backgroundColor = color return self } }
-
Documentation
/// Sets the background color of the view. /// /// This method allows chainable configuration of the view's background color /// while maintaining type safety. /// /// - Parameter color: The color to set as background /// - Returns: Self for method chaining /// /// - Example: /// ```swift /// let view = UIView() /// .flex /// .backgroundColor(.systemBlue) /// .cornerRadius(8) /// ``` @discardableResult @MainActor public func backgroundColor(_ color: UIColor) -> Self where Component: UIView { component.backgroundColor = color return self }
- No force unwrapping - Use optional binding or guards
- No force casting - Use conditional casting
- No magic numbers - Use named constants
- Single responsibility - One class, one purpose
- DRY principle - Don't repeat yourself
- Type safety - Leverage Swift's type system
Example:
// ✅ Good
private enum ViewConstants {
static let defaultCornerRadius: CGFloat = 8.0
static let defaultAlpha: CGFloat = 1.0
}
@discardableResult
@MainActor
public func cornerRadius(_ radius: CGFloat = ViewConstants.defaultCornerRadius) -> Self where Component: UIView {
component.layer.cornerRadius = radius
return self
}
// ❌ Bad
func setRadius(_ r: CGFloat) -> Self {
component.layer.cornerRadius = r == 0 ? 8 : r // Magic number
return self
}All code changes must include tests:
- Unit tests - Test individual components
- Integration tests - Test component interactions
- Edge cases - Test boundary conditions
- Type safety - Test generic constraints
- Chaining - Test method chaining behavior
Coverage requirements:
- New code: minimum 80% coverage
- Modified code: maintain or improve existing coverage
- Critical paths: 100% coverage
Test structure:
import XCTest
@testable import FlexUI
final class FlexUIUIViewTests: XCTestCase {
var sut: UIView!
override func setUp() {
super.setUp()
sut = UIView()
}
override func tearDown() {
sut = nil
super.tearDown()
}
// MARK: - Configuration Tests
func testBackgroundColor_SetsColorCorrectly() {
// Given
let expectedColor = UIColor.red
// When
let result = sut.flex.backgroundColor(expectedColor)
// Then
XCTAssertEqual(sut.backgroundColor, expectedColor)
XCTAssertTrue(result.component === sut)
}
// MARK: - Chaining Tests
func testChaining_MultipleConfigurations_AppliesAllChanges() {
// Given
let expectedColor = UIColor.blue
let expectedAlpha: CGFloat = 0.5
let expectedRadius: CGFloat = 10
// When
sut.flex
.backgroundColor(expectedColor)
.alpha(expectedAlpha)
.cornerRadius(expectedRadius)
// Then
XCTAssertEqual(sut.backgroundColor, expectedColor)
XCTAssertEqual(sut.alpha, expectedAlpha)
XCTAssertEqual(sut.layer.cornerRadius, expectedRadius)
}
// MARK: - Type Safety Tests
func testTypeSafety_PreservesConcreteType() {
// Given
let button = UIButton()
// When
let result = button.flex.backgroundColor(.red)
// Then
XCTAssertTrue(result.component is UIButton)
}
}- Discussions - Join GitHub Discussions
- Issues - Track open issues
- Pull Requests - Review open PRs
Contributors are recognized in:
- GitHub contributors page
- Release notes
- Project README (for significant contributions)
- Check existing issues
- Search discussions
- Ask in Q&A discussions
- Email the maintainer: nv3212@gmail.com
Thank you for contributing to FlexUI! 🎉
Your efforts help make this project better for everyone.