### Quick Start: Render UIComponent in ViewController Source: https://github.com/lkzhao/uicomponent/blob/main/Sources/UIComponent/Documentation.docc/Installation.md Use the componentEngine to render UIComponent views directly on any UIView. This example shows how to create a simple VStack with Text elements. ```swift import UIComponent class MyViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() // Render components directly on any UIView view.componentEngine.component = VStack(spacing: 16) { Text("Welcome to UIComponent!") .font(.systemFont(ofSize: 24)) .textColor(.label) Text("A modern declarative UI framework for UIKit") .font(.systemFont(ofSize: 16)) .textColor(.secondaryLabel) .textAlignment(.center) } .inset(20) } } ``` -------------------------------- ### Example Package.swift Configuration Source: https://github.com/lkzhao/uicomponent/blob/main/Sources/UIComponent/Documentation.docc/Installation.md A complete example of a Package.swift file demonstrating how to include UIComponent as a dependency. ```swift let package = Package( name: "MyPackage", platforms: [ .iOS("15.0") ], products: [ .library( name: "MyPackage", targets: ["MyPackage"]) ], dependencies: [ .package(url: "https://github.com/lkzhao/UIComponent", from: "5.0.0"), ], targets: [ .target( name: "MyPackage", dependencies: [ "UIComponent", // Add this ]) ] ) ``` -------------------------------- ### Import UIComponent in Swift Source: https://github.com/lkzhao/uicomponent/blob/main/Sources/UIComponent/Documentation.docc/Installation.md Import the UIComponent framework at the top of your Swift file after installation. ```swift import UIComponent ``` -------------------------------- ### ZStack - Layered Stack Layout Example Source: https://context7.com/lkzhao/uicomponent/llms.txt Layer child components on top of each other with specified alignment for overlays or badges. ```swift ZStack(verticalAlignment: .end, horizontalAlignment: .end) { Image("product") .size(width: 200, height: 200) .contentMode(.scaleAspectFill) .clipsToBounds(true) // Badge overlay Text("NEW") .font(.boldSystemFont(ofSize: 10)) .textColor(.white) .inset(h: 8, v: 4) .backgroundColor(.systemRed) .with(\.layer.cornerRadius, 4) .inset(8) } ``` -------------------------------- ### SwiftUI Integration Example Source: https://github.com/lkzhao/uicomponent/blob/main/CLAUDE.md Integrate UIComponents within a SwiftUI view hierarchy. This example shows mixing UIComponent's `VStack` and `Text` with native SwiftUI elements. ```swift VStack { Text("UIComponent Text") SwiftUI.Text("SwiftUI Text").foregroundColor(.red) SwiftUIComponent { SwiftUI.VStack { /* SwiftUI content */ } }.backgroundColor(.black) } ``` -------------------------------- ### Waterfall - Masonry Grid Layout Example Source: https://context7.com/lkzhao/uicomponent/llms.txt Create a Pinterest-style masonry layout with multiple columns and varying item heights. Each item is inset and has a background color with rounded corners. ```swift Waterfall(columns: 2, spacing: 8) { for item in items { VStack(spacing: 8) { Image(item.imageName) .size(width: .fill, height: .fit) .contentMode(.scaleAspectFit) Text(item.title) .font(.systemFont(ofSize: 14)) .numberOfLines(2) } .inset(8) .backgroundColor(.secondarySystemBackground) .with(\.layer.cornerRadius, 8) } } ``` -------------------------------- ### HStack - Horizontal Stack Layout Example Source: https://context7.com/lkzhao/uicomponent/llms.txt Arrange child components horizontally with spacing and alignment. Use `.flex()` to allow a component to take available space. ```swift HStack(spacing: 8, alignItems: .center) { Image(systemName: "star.fill") .tintColor(.systemYellow) Text("4.9") .font(.boldSystemFont(ofSize: 16)) Text("(2,847 reviews)") .font(.systemFont(ofSize: 14)) .textColor(.secondaryLabel) .flex() // Takes remaining space Text("$29.99") .font(.boldSystemFont(ofSize: 18)) .textColor(.systemGreen) } .inset(h: 16, v: 12) .backgroundColor(.secondarySystemBackground) .with(\.layer.cornerRadius, 12) ``` -------------------------------- ### Install UIComponent via Swift Package Manager Source: https://context7.com/lkzhao/uicomponent/llms.txt Add UIComponent to your project's dependencies in Package.swift to integrate it into your Xcode project. ```swift // Package.swift let package = Package( name: "MyApp", platforms: [.iOS("15.0")], dependencies: [ .package(url: "https://github.com/lkzhao/UIComponent", from: "5.0.0"), ], targets: [ .target( name: "MyApp", dependencies: ["UIComponent"] ), ] ) ``` -------------------------------- ### Implement a Custom VStack Layout Component Source: https://github.com/lkzhao/uicomponent/blob/main/Sources/UIComponent/Documentation.docc/CustomComponent.md Create a custom layout component like `MyVStack` by calculating child positions and sizes within the `layout(_:)` method. This example demonstrates a simple VStack without spacing. ```swift struct MyVStack: Component { let children: [any Component] func layout(_ constraint: Constraint) -> some RenderNode { var childrenRenderNodes: [RenderNode] = [] var childrenPositions: [CGPoint] = [] var currentOffset = 0.0 var maxChildWidth = 0.0 var maxChildHeight = 0.0 for child in children { let childRenderNode = child.layout(constraint) let childPosition = CGPoint(x: 0, y: currentOffset) currentOffset += child.size.height childrenRenderNodes.append(childRenderNode) childrenPositions.append(childPosition) maxChildWidth = max(maxChildWidth, child.size.width) maxChildHeight = max(maxChildHeight, child.size.height) } let size = CGSize(width: maxChildWidth, height: currentOffset) return VerticalRenderNode(size: size, children: childrenRenderNodes, positions: childrenPositions, mainAxisMaxValue: maxChildHeight) } } ``` -------------------------------- ### VStack - Vertical Stack Layout Example Source: https://context7.com/lkzhao/uicomponent/llms.txt Arrange child components vertically with specified spacing, justification, and alignment. Supports conditional rendering. ```swift VStack(spacing: 12, justifyContent: .start, alignItems: .center) { Image("avatar") .size(width: 80, height: 80) .with(\.layer.cornerRadius, 40) .clipsToBounds(true) Text("John Doe") .font(.boldSystemFont(ofSize: 18)) Text("iOS Developer") .font(.systemFont(ofSize: 14)) .textColor(.secondaryLabel) // Conditional rendering if user.isVerified { Image(systemName: "checkmark.seal.fill") .tintColor(.systemBlue) } } ``` -------------------------------- ### Reload UI on State Changes Source: https://context7.com/lkzhao/uicomponent/llms.txt Implement manual state management by creating a `reloadComponent` method and invoking it whenever the component's state changes to ensure the UI is updated accordingly. This example demonstrates a counter with increment and decrement buttons. ```swift class CounterViewController: UIViewController { private var count = 0 { didSet { reloadComponent() } } override func viewDidLoad() { super.viewDidLoad() reloadComponent() } private func reloadComponent() { view.componentEngine.component = VStack(spacing: 16, alignItems: .center) { Text("Count: \(count)") .font(.boldSystemFont(ofSize: 32)) HStack(spacing: 12) { Text("-") .font(.boldSystemFont(ofSize: 24)) .size(width: 50, height: 50) .backgroundColor(.systemRed) .textColor(.white) .with(\.layer.cornerRadius, 25) .tappableView { [weak self] in self?.count -= 1 } Text("+") .font(.boldSystemFont(ofSize: 24)) .size(width: 50, height: 50) .backgroundColor(.systemGreen) .textColor(.white) .with(\.layer.cornerRadius, 25) .tappableView { [weak self] in self?.count += 1 } } } .centered() } } ``` -------------------------------- ### Custom Fade Animator Implementation Source: https://github.com/lkzhao/uicomponent/blob/main/Sources/UIComponent/Documentation.docc/Animation.md Implement a custom Animator by conforming to the Animator protocol. This example shows a CustomFadeAnimator that handles view deletion and insertion with fade effects, including conditions to only animate during component reloads and when views are visible. ```swift struct CustomFadeAnimator: Animator { let duration: TimeInterval init(duration: TimeInterval = 0.3) { self.duration = duration } func delete(hostingView: UIView, view: UIView, completion: @escaping () -> Void) { if // Only animate when the hostingView's component is updated, not when scrolling. hostingView.componentEngine.isReloading, // only animate if the view is deleted visibly on screen. Drop the animation if the cell is not visible. hostingView.bounds.intersects(view.frame) { UIView.animate(withDuration: duration, delay: 0, options: [.allowUserInteraction], animations: { view.alpha = 0 }, completion: { _ in completion() }) } else { completion() } } func insert(hostingView: UIView, view: UIView, frame: CGRect) { view.bounds.size = frame.bounds.size view.center = frame.center if // Only animate when the hostingView's component is updated, not when scrolling. hostingView.componentEngine.isReloading, // don't animate the first reload hostingView.componentEngine.hasReloaded, // only animate if the view is inserted visibly on screen. Drop the animation if the cell is not visible. hostingView.bounds.intersects(frame) { view.alpha = 0 UIView.animate(withDuration: duration, delay: 0, options: [.allowUserInteraction], animations: { view.alpha = 1 }) } } } ``` -------------------------------- ### Apply Size Strategies Source: https://context7.com/lkzhao/uicomponent/llms.txt Utilize `.fill` and `.fit` strategies for width and height to control component sizing relative to its container. ```swift Text("Fill Width") .size(width: .fill, height: .fit) ``` -------------------------------- ### UI Component Overview Source: https://github.com/lkzhao/uicomponent/blob/main/Sources/UIComponent/Documentation.docc/Component.md Provides an overview of the UI Component and links to related documentation. ```APIDOC ## UI Component Overview ### Description Provides an overview of the UI Component and links to related documentation. ### Topics #### Requirements - ``Component/R`` - ``Component/layout(_:)`` ### Related Links - - ``` -------------------------------- ### Displaying a Component Source: https://github.com/lkzhao/uicomponent/blob/main/Sources/UIComponent/Documentation.docc/MigrationGuides/Version4MigrationGuide.md Comparison of the legacy ComponentView approach versus the new componentEngine property available on UIView. ```swift // before version 4.0 let componentView = ComponentView() override func viewDidLoad() { super.viewDidLoad() componentView.component = VStack { Text("Hello World!") } view.addSubview(componentView) } override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() componentView.frame = view.bounds } ``` ```swift // after version 4.0 override func viewDidLoad() { super.viewDidLoad() view.componentEngine.component = VStack { Text("Hello World!") } } ``` -------------------------------- ### Apply Background with Styling Source: https://context7.com/lkzhao/uicomponent/llms.txt Set a background for a component, including styling for corner radius and shadow, using `.background()` and `.with()`. ```swift Text("Card Title") .inset(16) .background( Space().backgroundColor(.systemBackground) .with(\.layer.cornerRadius, 12) .with(\.layer.shadowOpacity, 0.1) .with(\.layer.shadowRadius, 8) ) ``` -------------------------------- ### Create a Custom Component with ComponentBuilder Source: https://github.com/lkzhao/uicomponent/blob/main/Sources/UIComponent/Documentation.docc/CustomComponent.md Use the `ComponentBuilder` protocol for a simpler way to define components. Implement `build()` to return a child component. ```swift struct ProfileComponent: ComponentBuilder { let profile: Profile func build() -> some Component { VStack { Text(profile.name) Text(profile.role) } } } ``` -------------------------------- ### List Using ViewComponent Source: https://context7.com/lkzhao/uicomponent/llms.txt Render a list of items using `ViewComponent`, which wraps custom UIViews. Set the item and size for each component in the list. ```swift VStack { for item in items { ViewComponent() .item(item) .size(width: .fill, height: 80) } } ``` -------------------------------- ### Accessing Hosting View Environment Source: https://github.com/lkzhao/uicomponent/blob/main/Sources/UIComponent/Documentation.docc/Environment.md Access the current UIView hosting the components to read trait collections or other view-specific properties. ```swift struct CustomComponent: Component { @Environment(\.hostingView) var hostingView: UIView? func layout(_ constraint: Constraint) -> some RenderNode { // Access hosting view properties let isDarkMode = hostingView?.traitCollection.userInterfaceStyle == .dark return Text("Hello") .textColor(isDarkMode ? .white : .black) .layout(constraint) } } ``` -------------------------------- ### Compose UI Components Source: https://github.com/lkzhao/uicomponent/blob/main/Sources/UIComponent/Documentation.docc/ComponentBasics.md Construct a simple UI by composing layout and view components. ```swift VStack(spacing: 8, alignItems: .center) { Image("logo") Text("Hello World!") } ``` -------------------------------- ### Custom RenderNode Implementation Source: https://github.com/lkzhao/uicomponent/blob/main/Sources/UIComponent/Documentation.docc/RenderNode.md This section outlines the process of creating a custom RenderNode by conforming to the RenderNode protocol. It also lists the key requirements and associated methods. ```APIDOC ## Custom RenderNode ### Description Implementing a custom ``RenderNode`` is a complex task. For most use cases, consider creating a custom ``Component`` or using an existing ``RenderNode``. ### Requirements To create a custom ``RenderNode``, your struct must conform to the ``RenderNode`` protocol. The key requirements include: - ``RenderNode/View`` - ``RenderNode/size`` - ``RenderNode/positions-6f59e`` - ``RenderNode/children-42h1l`` - ``RenderNode/visibleChildren(in:)-4nvhh`` - ``RenderNode/shouldRenderView(in:)-yvrd`` - ``RenderNode/makeView()-8w5z2`` - ``RenderNode/updateView(_:)-2xjz4`` - ``RenderNode/contextValue(_:)-1bc1l`` Refer to the for a deeper understanding of the underlying architecture. ``` -------------------------------- ### Define a Basic Custom Component Source: https://github.com/lkzhao/uicomponent/blob/main/Sources/UIComponent/Documentation.docc/CustomComponent.md Implement the `Component` protocol by defining the `layout(_:)` method. This method takes a `Constraint` and returns a `RenderNode`. ```swift struct MyComponent: Component { func layout(_ constraint: Constraint) -> some RenderNode { // layout code } } ``` -------------------------------- ### Render Components on UIView Source: https://github.com/lkzhao/uicomponent/blob/main/CLAUDE.md Use the `componentEngine` extension on any UIView to render UIComponents. This is the modern approach for v4.0+. ```swift view.componentEngine.component = VStack { Text("Hello World!") } ``` -------------------------------- ### Configure Context Values with LazyComponent Source: https://github.com/lkzhao/uicomponent/blob/main/Sources/UIComponent/Documentation.docc/MigrationGuides/Version5MigrationGuide.md Shows the correct order for applying context modifiers when using LazyComponent to ensure they are effective. ```swift // `id` modifier is not effective since the child is lazily initiated. MyComponent().id("myId").lazy(width: 50, height: 50) // Do this instead: MyComponent() .lazy(width: 50, height: 50) .id("myId") ``` -------------------------------- ### Dynamically Create Custom View Source: https://github.com/lkzhao/uicomponent/blob/main/Sources/UIComponent/Documentation.docc/CustomView.md Use ViewComponent for lazy initialization and memory efficiency. A size modifier is required for proper layout calculation. ```swift ViewComponent().size(width: 100, height: 100) ``` ```swift ViewComponent(generator: MyCustomView(field: field)).size(width: 100, height: 100) ``` -------------------------------- ### Apply Min/Max Size Constraints Source: https://context7.com/lkzhao/uicomponent/llms.txt Set minimum and maximum dimensions for a component using `.minSize()` and `.maxSize()` modifiers. ```swift Text("Constrained") .minSize(width: 100, height: 50) .maxSize(width: 300, height: 200) ``` -------------------------------- ### Creating Custom Environment Values Source: https://github.com/lkzhao/uicomponent/blob/main/Sources/UIComponent/Documentation.docc/Environment.md Define a custom environment key and extend EnvironmentValues to support custom data types in the environment. ```swift struct CurrentUserEnvironmentKey: EnvironmentKey { public typealias Value = User? public static let defaultValue: User? = nil } ``` ```swift extension EnvironmentValues { var currentUser: User? { get { self[CurrentUserEnvironmentKey.self] } set { self[CurrentUserEnvironmentKey.self] = newValue } } } ``` -------------------------------- ### Implement Dynamic Environment Values Source: https://github.com/lkzhao/uicomponent/blob/main/Sources/UIComponent/Documentation.docc/Environment.md Compute environment values dynamically to adapt component layouts based on external state or traits. ```swift struct ResponsiveComponent: Component { @Environment(\.hostingView) var hostingView: UIView? private var isCompact: Bool { hostingView?.traitCollection.horizontalSizeClass == .compact } func layout(_ constraint: Constraint) -> some RenderNode { if isCompact { VStack { /* Compact layout */ } } else { HStack { /* Regular layout */ } }.layout(constraint) } } ``` -------------------------------- ### SwiftUIComponent - SwiftUI Integration Source: https://context7.com/lkzhao/uicomponent/llms.txt Integrate SwiftUI views seamlessly within UIComponent hierarchies. ```APIDOC ## SwiftUIComponent - SwiftUI Integration `SwiftUIComponent` enables seamless integration of SwiftUI views within UIComponent hierarchies (v5.0+). ```swift VStack(spacing: 16) { // UIComponent Text Text("Mixed UI Example") .font(.boldSystemFont(ofSize: 20)) // SwiftUI views directly (auto-wrapped by result builder) SwiftUI.Text("Hello from SwiftUI!") .foregroundColor(.blue) // Complex SwiftUI content in wrapper SwiftUIComponent { SwiftUI.HStack { SwiftUI.Image(systemName: "star.fill") .foregroundColor(.yellow) SwiftUI.Text("Rating: 5.0") .font(.caption) } .padding() .background(Color.gray.opacity(0.1)) .cornerRadius(8) } // Custom SwiftUI View with size control SwiftUIComponent(CustomGradientView()) .size(width: .fill, height: 100) } struct CustomGradientView: View { var body: some View { LinearGradient( colors: [.blue, .purple], startPoint: .leading, endPoint: .trailing ) .overlay( Text("SwiftUI Gradient") .foregroundColor(.white) .font(.headline) ) } } ``` ``` -------------------------------- ### Apply Badge with Custom Content Source: https://context7.com/lkzhao/uicomponent/llms.txt Add a badge to a component, specifying its position and providing custom content for the badge itself. ```swift Image("avatar") .size(width: 60, height: 60) .badge( verticalAlignment: .end, horizontalAlignment: .end, offset: CGPoint(x: 4, y: 4) ) { Text("3") .font(.boldSystemFont(ofSize: 12)) .textColor(.white) .size(width: 20, height: 20) .backgroundColor(.systemRed) .roundedCorner() } ``` -------------------------------- ### Create Custom Layout Components Source: https://context7.com/lkzhao/uicomponent/llms.txt Implement the Component protocol directly for custom layouts, offering full control over element positioning. This is useful for complex or unique layout structures. ```swift struct MyVStack: Component { let spacing: CGFloat let children: [any Component] init(spacing: CGFloat = 0, @ComponentArrayBuilder _ content: () -> [any Component]) { self.spacing = spacing self.children = content() } func layout(_ constraint: Constraint) -> some RenderNode { var renderNodes: [any RenderNode] = [] var positions: [CGPoint] = [] var currentY: CGFloat = 0 var maxWidth: CGFloat = 0 var maxHeight: CGFloat = 0 for child in children { let childNode = child.layout(constraint) renderNodes.append(childNode) positions.append(CGPoint(x: 0, y: currentY)) currentY += childNode.size.height + spacing maxWidth = max(maxWidth, childNode.size.width) maxHeight = max(maxHeight, childNode.size.height) } let totalHeight = max(0, currentY - spacing) return VerticalRenderNode( size: CGSize(width: maxWidth, height: totalHeight), children: renderNodes, positions: positions, mainAxisMaxValue: maxHeight ) } } ``` -------------------------------- ### Create SwiftUIComponent with SwiftUI Views Source: https://github.com/lkzhao/uicomponent/blob/main/Sources/UIComponent/Documentation.docc/MigrationGuides/Version5MigrationGuide.md Wrap SwiftUI views using SwiftUIComponent. Supports direct instantiation, ViewBuilder syntax, custom views, and applying SwiftUI or UIComponent modifiers. ```swift SwiftUIComponent(Text("Hello World!")) ``` ```swift SwiftUIComponent { SwiftUI.Text("Hello World!") } ``` ```swift SwiftUIComponent(MyCustomView()) ``` ```swift SwiftUIComponent { SwiftUI.Text("Hello") .font(.title) .foregroundColor(.blue) } ``` ```swift SwiftUIComponent { SwiftUI.Text("Hello") }.backgroundColor(.black) ``` -------------------------------- ### Apply Overlay with Styling Source: https://context7.com/lkzhao/uicomponent/llms.txt Add an overlay to a component, such as a caption with a semi-transparent background, using `.overlay()`. ```swift Image("photo") .size(width: .fill, height: 200) .overlay { Text("Caption") .textColor(.white) .inset(8) .backgroundColor(.black.withAlphaComponent(0.5)) .size(width: .fill, height: .fit) .alignSelf(.end) } ``` -------------------------------- ### Enable Async Layout Source: https://github.com/lkzhao/uicomponent/blob/main/Sources/UIComponent/Documentation.docc/PerformanceOptimization.md Enable asynchronous layout calculation on a background thread by setting `view.componentEngine.asyncLayout = true`. This improves framerate and scroll performance but does not reduce layout latency. Ensure layout code is thread-safe and does not access UI properties during layout. ```swift view.componentEngine.asyncLayout = true ``` -------------------------------- ### State Management Pattern with ViewModel Source: https://github.com/lkzhao/uicomponent/blob/main/CLAUDE.md Implement a recommended state management pattern using a `ViewModel` and reloading the component when the state changes. Ensure the `didSet` observer triggers `reloadComponent`. ```swift class MyViewController: UIViewController { var viewModel = MyViewModel() { didSet { reloadComponent() } } func reloadComponent() { view.componentEngine.component = VStack { Text("Count: \(viewModel.count)") } } } ``` -------------------------------- ### Apply Lazy Layout Modifiers in Swift Source: https://github.com/lkzhao/uicomponent/blob/main/Sources/UIComponent/Documentation.docc/MigrationGuides/Version5MigrationGuide.md Demonstrates the transition from automatic lazy layout to explicit .lazy modifiers for fixed-sized items. ```swift // Before version 5.0 VStack { for item in items { ItemComponent(item: item).size(width: 50, height: 50) // Automatically lazy } } // After version 5.0 VStack { for item in items { ItemComponent(item: item) .lazy(width: 50, height: 50) // Explicitly mark as lazy } } ``` -------------------------------- ### Lazy Layout with Dynamic Size Provider Source: https://context7.com/lkzhao/uicomponent/llms.txt Defer layout calculation using a dynamic size provider closure that returns the required size based on constraints and item properties. ```swift VStack { for item in items { ItemCell(item: item) .lazy(sizeProvider: { constraint in CGSize(width: constraint.maxWidth, height: item.isTall ? 120 : 60) }) } } ``` -------------------------------- ### Integrate SwiftUI Views Source: https://github.com/lkzhao/uicomponent/blob/main/Sources/UIComponent/Documentation.docc/ComponentBasics.md Mix native SwiftUI views with UIComponent, using SwiftUIComponent for complex content or custom views. ```swift VStack(spacing: 16) { // UIComponent Text Text("Mixed UI Example") .font(.boldSystemFont(ofSize: 20)) .textColor(.label) // SwiftUI Text directly (automatically wrapped by result builder) SwiftUI.Text("Hello from SwiftUI!") .foregroundColor(.blue) // Complex SwiftUI content wrapped in SwiftUIComponent SwiftUIComponent { SwiftUI.HStack { SwiftUI.Image(systemName: "star.fill") .foregroundColor(.yellow) SwiftUI.Text("Rating: 5.0") .font(.caption) } .padding() .background(Color.gray.opacity(0.1)) .cornerRadius(8) } // Custom SwiftUI View SwiftUIComponent(CustomGradientView()) .size(width: .fill, height: 100) // UIComponent modifiers work on SwiftUI content SwiftUIComponent { SwiftUI.Text("Styled SwiftUI") .font(.headline) } .backgroundColor(.systemBlue) .with(\.layer.cornerRadius, 8) .inset(12) } struct CustomGradientView: View { var body: some View { LinearGradient( colors: [.blue, .purple], startPoint: .leading, endPoint: .trailing ) .overlay( Text("SwiftUI Gradient") .foregroundColor(.white) .font(.headline) ) } } ``` -------------------------------- ### Define Custom Lazy Size Provider Source: https://github.com/lkzhao/uicomponent/blob/main/Sources/UIComponent/Documentation.docc/MigrationGuides/Version5MigrationGuide.md Uses a closure to provide dynamic sizing based on layout constraints. ```swift VStack { for item in items { ItemComponent(item: item) .lazy { constraint in CGSize(width: constraint.maxWidth, height: 50 + item.isTall ? 50 : 0) } } } ``` -------------------------------- ### Configuring Text Color Environment Source: https://github.com/lkzhao/uicomponent/blob/main/Sources/UIComponent/Documentation.docc/Environment.md Set a default text color for text components using the .textColor() modifier. ```swift VStack { Text("Title") // Will use red text color Text("Subtitle") // Will use red text color Text("Body").textColor(.blue) // Overrides environment text color } .textColor(.red) ``` -------------------------------- ### Setting Environment Values via Modifiers Source: https://github.com/lkzhao/uicomponent/blob/main/Sources/UIComponent/Documentation.docc/Environment.md Use convenience modifiers for built-in values or the .environment() modifier for custom values to propagate data down the hierarchy. ```swift VStack { MyComponent() // Will use the custom font and color Text("Another text") // Will also use the custom font and color } .font(UIFont.boldSystemFont(ofSize: 20)) .textColor(.systemBlue) ``` ```swift VStack { MyComponent() Text("Another text") } .environment(\.font, value: UIFont.boldSystemFont(ofSize: 20)) .environment(\.textColor, value: UIColor.systemBlue) ``` -------------------------------- ### Decoration Modifiers Source: https://context7.com/lkzhao/uicomponent/llms.txt Add backgrounds, overlays, and badges to components. ```APIDOC ## Decoration Modifiers Add backgrounds, overlays, and badges to components. ```swift // Background Text("Card Title") .inset(16) .background( Space().backgroundColor(.systemBackground) .with(\.layer.cornerRadius, 12) .with(\.layer.shadowOpacity, 0.1) .with(\.layer.shadowRadius, 8) ) // Overlay Image("photo") .size(width: .fill, height: 200) .overlay { Text("Caption") .textColor(.white) .inset(8) .backgroundColor(.black.withAlphaComponent(0.5)) .size(width: .fill, height: .fit) .alignSelf(.end) } // Badge Image("avatar") .size(width: 60, height: 60) .badge( verticalAlignment: .end, horizontalAlignment: .end, offset: CGPoint(x: 4, y: 4) ) { Text("3") .font(.boldSystemFont(ofSize: 12)) .textColor(.white) .size(width: 20, height: 20) .backgroundColor(.systemRed) .roundedCorner() } ``` ``` -------------------------------- ### Configuring Font Environment Source: https://github.com/lkzhao/uicomponent/blob/main/Sources/UIComponent/Documentation.docc/Environment.md Set a default font for text components using the .font() modifier, which can be overridden by individual components. ```swift VStack { Text("Title") // Will use bold 24pt font Text("Subtitle") // Will use bold 24pt font Text("Body").font(.systemFont(ofSize: 16)) // Overrides environment font } .font(.boldSystemFont(ofSize: 24)) ``` -------------------------------- ### Apply Padding with UIEdgeInsets Source: https://context7.com/lkzhao/uicomponent/llms.txt Use a `UIEdgeInsets` struct to define padding values for all edges. ```swift Text("Insets").inset(UIEdgeInsets(top: 10, left: 20, bottom: 10, right: 20)) ``` -------------------------------- ### Render custom ViewComponent in a list Source: https://github.com/lkzhao/uicomponent/blob/main/Sources/UIComponent/Documentation.docc/StateManagement.md Instantiate a custom ViewComponent within a layout container to display data-driven UI elements. ```swift VStack { for profile in profiles { ViewComponent() .profile(profile) .size(width: .fill, height: 100) } } ``` -------------------------------- ### Add UIComponent to Target Dependencies in Package.swift Source: https://github.com/lkzhao/uicomponent/blob/main/Sources/UIComponent/Documentation.docc/Installation.md Specify UIComponent as a dependency for your target within the Package.swift file. ```swift .target( name: "MyPackage", dependencies: [ "UIComponent", // Add this ]), ``` -------------------------------- ### Define and Use Custom Context Keys Source: https://github.com/lkzhao/uicomponent/blob/main/Sources/UIComponent/Documentation.docc/MigrationGuides/Version5MigrationGuide.md Extends RenderNodeContextKey to support custom data types within the context system. ```swift extension RenderNodeContextKey { static let myCustomKey = RenderNodeContextKey("myCustomKey") } // Using the custom context value let value = renderNode.contextValue(.myCustomKey) as? MyType ``` -------------------------------- ### Handle Tap Gestures with TappableView Source: https://context7.com/lkzhao/uicomponent/llms.txt Wrap components with `tappableView` to add tap gesture recognition and built-in highlight animations. Advanced handling allows for double-tap and long-press gestures. ```swift Text("Tap Me") .inset(h: 24, v: 12) .backgroundColor(.systemBlue) .textColor(.white) .with(\.layer.cornerRadius, 8) .tappableView { print("Button tapped!") } ``` ```swift Text("Advanced Tap") .tappableView { tappableView.onDoubleTap = { _ in print("Double tapped!") } tappableView.onLongPress = { _ in print("Long pressed!") } } ``` ```swift VStack { Text("Button 1").tappableView { print("1") } Text("Button 2").tappableView { print("2") } } .tappableViewConfig(TappableViewConfig( highlightColor: .systemBlue.withAlphaComponent(0.2), animationDuration: 0.1 )) ``` -------------------------------- ### Usage of ComponentBuilder Source: https://github.com/lkzhao/uicomponent/blob/main/Sources/UIComponent/Documentation.docc/CustomComponent.md Assign an instance of a `ComponentBuilder` to the `componentEngine.component` property to display it. ```swift // Usage view.componentEngine.component = ProfileComponent(profile: myProfile) ``` -------------------------------- ### Observe state in UIViewController Source: https://github.com/lkzhao/uicomponent/blob/main/Sources/UIComponent/Documentation.docc/ObservableSupport.md Override updateProperties() to build a component tree that reacts to changes in an @Observable model. ```swift @available(iOS 26.0, *) final class ObservableViewController: UIViewController { @Observable private final class ViewModel { var count: Int = 0 } private let viewModel = ViewModel() override func updateProperties() { super.updateProperties() let viewModel = viewModel view.componentEngine.component = VStack(spacing: 8, justifyContent: .center, alignItems: .center) { Text("Hello world!", font: .boldSystemFont(ofSize: 22)) Text("Count: \(viewModel.count)") Text("Increase").tappableView { viewModel.count += 1 } }.fill() } } ``` -------------------------------- ### Render Components with ComponentEngine in a ViewController Source: https://context7.com/lkzhao/uicomponent/llms.txt Assign a UIComponent to the `componentEngine.component` property of any UIView to render it. The view automatically updates when the component changes. ```swift import UIComponent class MyViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() // Render components on any UIView view.componentEngine.component = VStack(spacing: 16) { Text("Welcome to UIComponent!") .font(.boldSystemFont(ofSize: 24)) .textColor(.label) Text("A modern declarative UI framework for UIKit") .font(.systemFont(ofSize: 16)) .textColor(.secondaryLabel) } .inset(20) } } ``` -------------------------------- ### Configuring TappableView Source: https://github.com/lkzhao/uicomponent/blob/main/Sources/UIComponent/Documentation.docc/Environment.md Set default configuration for tappable components using the .tappableViewConfig() modifier. ```swift VStack { Text("Button 1").tappableView { print("Tapped 1") } Text("Button 2").tappableView { print("Tapped 2") } } .tappableViewConfig(TappableViewConfig( highlightColor: .systemBlue.withAlphaComponent(0.2), animationDuration: 0.1 )) ``` -------------------------------- ### Conditional and List Rendering Source: https://github.com/lkzhao/uicomponent/blob/main/Sources/UIComponent/Documentation.docc/ComponentBasics.md Use standard Swift control flow statements within the result builder to render dynamic content. ```swift VStack { for item in items { if let image = item.image { Image(image) } switch item.type { case .fruit: Text("Fruit") case .vegetable: Text("Vegetable") } } } ``` -------------------------------- ### Use Lazy Layout for Deferred Rendering Source: https://github.com/lkzhao/uicomponent/blob/main/Sources/UIComponent/Documentation.docc/PerformanceOptimization.md Defer layout and rendering of components until they are needed by applying the `.lazy` modifier with a specified width and height. This is useful for complex layouts not immediately visible. ```swift VStack { for item in items { VStack { Image(item.image) Text(item.title) Text(item.subtitle) }.lazy(width: .fill, height: 50) // Defer layout until needed } } ``` ```swift VStack { for item in items { VStack { // Some content }.lazy(sizeProvider: { constraint in CGSize(width: constraint.maxWidth, height: 50 + item.isTall ? 50 : 0) }) } } ``` -------------------------------- ### Insert Custom View Directly Source: https://github.com/lkzhao/uicomponent/blob/main/Sources/UIComponent/Documentation.docc/CustomView.md Directly add a UIKit view instance into the component hierarchy by storing it as a property. ```swift // store this as a property somewhere let myCustomView = MyCustomView() // place it in the Component hierarchy view.componentEngine.component = VStack { Text("Working with custom view") myCustomView } ``` -------------------------------- ### Render Styled Text Components Source: https://context7.com/lkzhao/uicomponent/llms.txt The Text component supports plain strings, attributed strings, and environment-based styling. ```swift // Basic text Text("Hello World") .font(.boldSystemFont(ofSize: 24)) .textColor(.label) // Multi-line text with line limit Text("This is a long paragraph that will wrap to multiple lines...") .font(.systemFont(ofSize: 16)) .numberOfLines(3) .lineBreakMode(.byTruncatingTail) // Attributed string let attributedText = NSAttributedString( string: "Bold and Colored", attributes: [ .font: UIFont.boldSystemFont(ofSize: 18), .foregroundColor: UIColor.systemBlue ] ) Text(attributedString: attributedText) // Environment-based styling (inherits from parent) VStack { Text("Title") // Uses bold 20pt font Text("Subtitle") // Uses bold 20pt font Text("Custom").font(.systemFont(ofSize: 12)) // Overrides } .font(.boldSystemFont(ofSize: 20)) .textColor(.systemBlue) ``` -------------------------------- ### Create Reusable Components with ComponentBuilder Source: https://context7.com/lkzhao/uicomponent/llms.txt Use the ComponentBuilder protocol for creating custom components by composing other components. This is suitable for simple, reusable UI elements. ```swift struct ProfileCard: ComponentBuilder { let profile: Profile func build() -> some Component { HStack(spacing: 16, alignItems: .center) { Image(profile.avatar) .size(width: 60, height: 60) .with(\.layer.cornerRadius, 30) .clipsToBounds(true) VStack(spacing: 4) { Text(profile.name) .font(.boldSystemFont(ofSize: 17)) Text(profile.title) .font(.systemFont(ofSize: 14)) .textColor(.secondaryLabel) HStack(spacing: 4) { Image(systemName: "mappin") .tintColor(.systemGray) Text(profile.location) .font(.systemFont(ofSize: 12)) .textColor(.systemGray) } } .flex() Image(systemName: "chevron.right") .tintColor(.systemGray3) } .inset(16) .backgroundColor(.secondarySystemBackground) .with(\.layer.cornerRadius, 12) } } // Usage VStack(spacing: 12) { for profile in profiles { ProfileCard(profile: profile) .tappableView { [weak self] in self?.showProfile(profile) } } } ``` -------------------------------- ### Configure View Transition Animations with Animator Source: https://context7.com/lkzhao/uicomponent/llms.txt Use the Animator protocol to animate view insertions, deletions, and frame updates. This includes built-in animators and custom animation logic. ```swift // Built-in TransformAnimator view.componentEngine.animator = TransformAnimator( insertTransform: CATransform3DMakeScale(0.5, 0.5, 1), deleteTransform: CATransform3DMakeTranslation(0, -40, 0), insertTiming: .easeIn(duration: 0.3), updateTiming: .easeInOut(duration: 0.4), deleteTiming: .spring(duration: 0.5, damping: 0.9) ) // Per-component animator VStack { Text("Animated") .animator(TransformAnimator( transform: CATransform3DMakeTranslation(0, 100, 0), duration: 0.4 )) Text("Not animated") } // Custom one-off animations Text("Custom Animated") .animateInsert { hostingView, view, frame in view.alpha = 0 view.transform = CGAffineTransform(scaleX: 0.8, y: 0.8) UIView.animate(withDuration: 0.3) { view.alpha = 1 view.transform = .identity } } .animateDelete { hostingView, view, completion in UIView.animate(withDuration: 0.3, animations: { view.alpha = 0 view.transform = CGAffineTransform(scaleX: 0.8, y: 0.8) }) { _ in completion() } } .animateUpdate { hostingView, view, frame in UIView.animate(withDuration: 0.3) { view.frame = frame } } ``` -------------------------------- ### Apply Uniform Padding Source: https://context7.com/lkzhao/uicomponent/llms.txt Add equal padding around a component using the `.inset()` modifier with a single value. ```swift Text("Padded").inset(16) ``` -------------------------------- ### Pass Data Through Component Hierarchy with Environment Values Source: https://context7.com/lkzhao/uicomponent/llms.txt Utilize environment values to propagate data down the component tree without explicit parameter passing. This includes using built-in values like font and color, and defining custom environment keys for specific data like theming. ```swift VStack { Text("Title") // Inherits font and color Text("Subtitle") // Inherits font and color } .font(.boldSystemFont(ofSize: 18)) .textColor(.systemBlue) ``` ```swift struct ThemeEnvironmentKey: EnvironmentKey { typealias Value = Theme static let defaultValue = Theme.light } extension EnvironmentValues { var theme: Theme { get { self[ThemeEnvironmentKey.self] } set { self[ThemeEnvironmentKey.self] = newValue } } } ``` ```swift extension Component { func theme(_ theme: Theme) -> EnvironmentComponent { environment(\.theme, value: theme) } } ``` ```swift struct ThemedButton: Component { @Environment(\.theme) var theme: Theme let title: String func layout(_ constraint: Constraint) -> some RenderNode { Text(title) .font(.boldSystemFont(ofSize: 16)) .textColor(theme.buttonTextColor) .inset(h: 24, v: 12) .backgroundColor(theme.buttonBackground) .with(\.layer.cornerRadius, 8) .layout(constraint) } } ``` ```swift VStack { ThemedButton(title: "Primary Action") ThemedButton(title: "Secondary Action") } .theme(.dark) ``` -------------------------------- ### Fill Both Dimensions Source: https://context7.com/lkzhao/uicomponent/llms.txt Use the `.fill()` modifier to make a component occupy all available space in both width and height. ```swift VStack { ... } .fill() ``` -------------------------------- ### Render Component on UIView Source: https://github.com/lkzhao/uicomponent/blob/main/Sources/UIComponent/Documentation.docc/ComponentBasics.md Assign a component to the componentEngine property to trigger a view reload. ```swift // Basic rendering view.componentEngine.component = VStack(spacing: 8, alignItems: .center) { Image("logo") Text("Hello World!") } ``` -------------------------------- ### Apply Padding with One Edge Different Source: https://context7.com/lkzhao/uicomponent/llms.txt Set a distinct padding value for one edge while applying a uniform value to the rest using `.inset(top:rest:)`. ```swift Text("Top Heavy").inset(top: 24, rest: 8) ``` -------------------------------- ### One-Off View Transition Animations Source: https://github.com/lkzhao/uicomponent/blob/main/Sources/UIComponent/Documentation.docc/Animation.md Use .animateInsert, .animateDelete, and .animateUpdate modifiers for custom, one-off animations on views. These modifiers allow direct control over the animation logic for each transition type. ```swift Text("Animated Insert/Delete/Update") .animateInsert { view.alpha = 0.0 UIView.animate(withDuration: 0.3) { view.alpha = 1.0 } } .animateDelete { UIView.animate(withDuration: 0.3) { view.alpha = 0.0 } completion: { _ in completion() } } .animateUpdate { UIView.animate(withDuration: 0.3) { view.frame = frame } } ``` -------------------------------- ### Create Swipeable Pagers with HPager and VPager Source: https://context7.com/lkzhao/uicomponent/llms.txt HPager and VPager provide full-screen swipeable layouts suitable for onboarding or galleries. ```swift // Horizontal pager for onboarding HPager(alignItems: .center) { OnboardingPage(title: "Welcome", image: "onboarding1") OnboardingPage(title: "Features", image: "onboarding2") OnboardingPage(title: "Get Started", image: "onboarding3") } // Vertical pager VPager { for page in pages { PageContent(page: page) .fill() } } ``` -------------------------------- ### Lazy Layout with Known Size Source: https://context7.com/lkzhao/uicomponent/llms.txt Use the `.lazy` modifier to defer layout calculation until components become visible. Specify a fixed height for deferred rendering. ```swift VStack { for item in largeDataSet { VStack { Image(item.image) Text(item.title) Text(item.subtitle) } .lazy(width: .fill, height: 80) // Defer until visible } } ``` -------------------------------- ### Compose Components in a Custom Component Source: https://github.com/lkzhao/uicomponent/blob/main/Sources/UIComponent/Documentation.docc/CustomComponent.md Create a custom component by composing other `Component`s. Call `layout(_:)` on child components to produce `RenderNode`s. ```swift struct ProfileComponent: Component { func layout(_ constraint: Constraint) -> some RenderNode { VStack { Text("Luke Zhao") Text("iOS Developer") }.layout(constraint) } } ``` -------------------------------- ### Explicit View Reuse with .reuseKey Source: https://github.com/lkzhao/uicomponent/blob/main/Sources/UIComponent/Documentation.docc/MigrationGuides/Version5MigrationGuide.md Version 5.0 simplifies view reuse by using the .reuseKey modifier explicitly. Previously, reuse was automatic or controlled by .reuseStrategy. ```swift // Before version 5.0 VStack { for item in items { ItemComponent(item: item) // Maybe automatically reused based on type } } // After version 5.0 VStack { for item in items { ItemComponent(item: item) .reuseKey("item-cell") // Explicitly specify reuse key } } ``` -------------------------------- ### View Property Modifiers Source: https://context7.com/lkzhao/uicomponent/llms.txt Access UIView properties directly as modifiers or use `.with()` for key paths. ```APIDOC ## View Property Modifiers Use `@dynamicMemberLookup` to access any UIView property as a modifier, or use `.with()` for key paths. ```swift Text("Styled Text") .textColor(.systemBlue) .textAlignment(.center) .backgroundColor(.systemGray6) .clipsToBounds(true) .with(\.layer.cornerRadius, 8) .with(\.layer.borderWidth, 1) .with(\.layer.borderColor, UIColor.separator.cgColor) // Custom update closure Image("photo") .update { imageView in imageView.layer.shadowColor = UIColor.black.cgColor imageView.layer.shadowOffset = CGSize(width: 0, height: 2) imageView.layer.shadowOpacity = 0.2 imageView.layer.shadowRadius = 4 } ``` ``` -------------------------------- ### Custom Size Based on Constraint Source: https://context7.com/lkzhao/uicomponent/llms.txt Define a custom size for a component using a closure that receives size constraints. ```swift Text("Responsive") .size { constraint in CGSize(width: constraint.maxWidth, height: 100) } ``` -------------------------------- ### Create a Component Modifier Source: https://github.com/lkzhao/uicomponent/blob/main/Sources/UIComponent/Documentation.docc/Environment.md Define a convenience modifier to simplify setting environment values for frequently used data. ```swift extension Component { func currentUser(_ user: User?) -> EnvironmentComponent { environment(\.currentUser, value: user) } } ``` -------------------------------- ### Add UIComponent to Package.swift Dependencies Source: https://github.com/lkzhao/uicomponent/blob/main/Sources/UIComponent/Documentation.docc/Installation.md Include the UIComponent package in your project's Package.swift file under the dependencies section. ```swift .package(url: "https://github.com/lkzhao/UIComponent", from: "5.0.0"), ``` -------------------------------- ### Display Images with Aspect Ratio Preservation Source: https://context7.com/lkzhao/uicomponent/llms.txt The Image component handles assets, SF Symbols, and UIImage instances with built-in sizing and content mode modifiers. ```swift // From asset catalog Image("profilePhoto") .size(width: 100, height: 100) .contentMode(.scaleAspectFill) .clipsToBounds(true) .with(\.layer.cornerRadius, 50) // SF Symbol with configuration Image(systemName: "heart.fill", withConfiguration: UIImage.SymbolConfiguration(pointSize: 24)) .tintColor(.systemRed) // From UIImage let image = UIImage(named: "photo")! Image(image) .size(width: .fill, height: 200) .contentMode(.scaleAspectFit) ``` -------------------------------- ### Apply Padding to Individual Edges Source: https://context7.com/lkzhao/uicomponent/llms.txt Control padding on specific edges (top, left, bottom, right) using the `.inset()` modifier with named parameters. ```swift Text("Custom").inset(top: 8, left: 16, bottom: 8, right: 16) ```