Skip to content

VComponents is a SwiftUI collection that contains reusable UI components

License

Notifications You must be signed in to change notification settings

VakhoKontridze/VComponents

Repository files navigation

VComponents

Table of Contents

Description

VComponents is a SwiftUI collection that contains reusable UI components.

Components

Buttons

State Pickers

Value Pickers

Inputs

Containers

Modals

Notifications

Indicators (Definite)

Indicators (Indefinite)

Misc

Guidelines: Customization

Components from VComponents are not meant to be customized the same way you would customize atomic SwiftUI components.

Rather than directly modifying them using ViewModifierss, you are supposed to pass an UI model as a parameter to the initializers. All components have default UI models and passing them to initializers is not required. Furthermore, all properties within the UI models have their own default values.

For instance, you can change the foreground color of a VPlainButton by changing the values.

Not Preferred:

var body: some View {
    VPlainButton(
        action: doSomething,
        title: "Lorem Ipsum"
    )
    .foregroundStyle(.primary)
}

Preferred:

let uiModel: VPlainButtonUIModel = {
    var uiModel: VPlainButtonUIModel = .init()
    
    uiModel.titleTextColors = VPlainButtonUIModel.StateColors(
        enabled: Color.primary,
        pressed: Color.secondary,
        disabled: Color.secondary
    )
    
    return uiModel
}()

var body: some View {
    VPlainButton(
        uiModel: uiModel,
        action: doSomething,
        title: "Lorem Ipsum"
    )
}

Alternately, you can create static instances of UI models for reusability.

extension VPlainButtonUIModel {
    static let someUIModel: Self = {
        var uiModel: Self = .init()
        
        uiModel.titleTextColors = StateColors(
            enabled: Color.primary,
            pressed: Color.secondary,
            disabled: Color.secondary
        )
        
        return uiModel
    }()
}

var body: some View {
    VPlainButton(
        uiModel: .someUIModel,
        action: doSomething,
        title: "Lorem Ipsum"
    )
}

Frequently, you will discover pre-configured static factory-initialized UI models associated with each component. It's recommended to investigate UI model files before defining them yourself.

var body: some View {
    VWrappingMarquee(
        uiModel: .insettedGradientMask,
        content: {
            HStack(content: {
                Image(systemName: "swift")
                Text("Lorem ipsum dolor sit amet, consectetur adipiscing elit.")
            })
            .drawingGroup() // For `Image`
        }
    )
}

Guidelines: Animations

VComponents associates animations directly with the components and their UI models, rather than with the external state.

@State private var isOn: Bool = false

var body: some View {
    VStack(content: {
        VToggle(isOn: $isOn)
        
        VPlainButton(
            action: { isOn.toggle() },
            title: "Toggle"
        )
    })
}

By default, the VToggle uses an easeIn animation with a duration of 0.1 to handle state changes. This applies uniformly to both touch interactions, as well as any external modifications of the state. So, to modify state with a different animation, you'll need to provide a custom UI model.

@State private var isOn: Bool = false

var body: some View {
    VStack(content: {
        VToggle(
            uiModel: {
                var uiModel: VToggleUIModel = .init()
                uiModel.stateChangeAnimation = .easeIn(duration: 1)
                return uiModel
            }(),
            isOn: $isOn
        )
        
        VPlainButton(
            action: { isOn.toggle() },
            title: "Toggle"
        )
    })
}

There are two available options for completely cancelling animations.

The first is to set stateChangeAnimation to nil. While this does not completely remove animation, it essentially applies a nil animation.

@State private var isOn: Bool = false

var body: some View {
    VStack(content: {
        VToggle(
            uiModel: {
                var uiModel: VToggleUIModel = .init()
                uiModel.stateChangeAnimation = nil
                return uiModel
            }(),
            isOn: $isOn
        )
        
        VPlainButton(
            action: { isOn.toggle() },
            title: "Toggle"
        )
    })
}

The second is to set appliesStateChangeAnimation to false. This option ensures that the stateChangeAnimation is not applied at all, thus effectively removing any animation tied to state changes, even nil.

@State private var isOn: Bool = false

var body: some View {
    VStack(content: {
        VToggle(
            uiModel: {
                var uiModel: VToggleUIModel = .init()
                uiModel.appliesStateChangeAnimation = false
                return uiModel
            }(),
            isOn: $isOn
        )
        
        VPlainButton(
            action: { isOn.toggle() },
            title: "Toggle"
        )
    })
}

In certain scenarios, the distinction between these two can be substantial. For example, we could set the appliesStateChangeAnimation flag to false and subsequently mutate the state with an external animation.

@State private var isOn: Bool = false

var body: some View {
    VStack(content: {
        VToggle(
            uiModel: {
                var uiModel: VToggleUIModel = .init()
                uiModel.appliesStateChangeAnimation = false
                return uiModel
            }(),
            isOn: $isOn
        )
        
        VPlainButton(
            action: { 
                withAnimation(.easeInOut(duration: 1), {
                    isOn.toggle()
                })
            },
            title: "Toggle"
        )
    })
}

Installation

Swift Package Manager

Add https://github.com/VakhoKontridze/VComponents as a Swift Package in Xcode and follow the instructions.

Compatibility

Platform and Version Support

Package provides limited macOS, tvOS, watchOS, and visionOS support.

Versions with different majors are not directly compatible. When a new major is released, deprecated symbols are removed.

Versioning

Major. Major changes, such as big overhauls

Minor. Minor changes, such as new component, types, or properties in UI models

Patch. Bug fixes and improvements

History

Ver Release Date Swift SDK VCore Comment
7.0 2024 09 20 6.0 iOS 16.0
macOS 13.0
tvOS 16.0
watchOS 9.0
visionOS 1.0
7.0.0 - 7.x.x New SDK.
API changes.
6.0 2024 02 18 5.10
(6.0.1 - 6.x.x)
5.9
(6.0.0)
iOS 15.0
macOS 12.0
tvOS 15.0
watchOS 8.0
visionOS 1.0
6.0.0 - 6.x.x API changes.
visionOS support.
5.0 2023 10 08 5.9 iOS 15.0
macOS 12.0
tvOS 15.0
watchOS 8.0
5.0.0 - 5.x.x New SDK.
API changes.
4.0 2023 04 09 5.8 iOS 13.0
macOS 10.15
tvOS 13.0
watchOS 6.0
4.7.0 - 4.x.x iOS 13.0 support.
Multiplatform support.
RTL language support.
3.0 2022 10 02 5.7 iOS 16.0 4.1.0 - 4.x.x New SDK.
API changes.
2.0 2022 05 26 5.6 iOS 15.0 3.2.0 - 3.x.x New SDK.
API changes.
SPM support.
1.0 2021 02 07 5.3 iOS 14.0 - -

For additional info, refer to the CHANGELOG.

Contact

e-mail: vakhtang.kontridze@gmail.com