Swiftpack.co - VakhoKontridze/VComponents as Swift Package

Swiftpack.co is a collection of thousands of indexed Swift packages. Search packages.
See all packages published by VakhoKontridze.
VakhoKontridze/VComponents 3.0.0
VComponents is a SwiftUI package that contains 30+ customizable UI components
⭐️ 186
🕓 7 weeks ago
iOS
.package(url: "https://github.com/VakhoKontridze/VComponents.git", from: "3.0.0")

VComponents

Table of Contents

Description

VComponents is a SwiftUI package that contains 30+ customizable UI components.

Compatibility

Versions with different majors are not compatible.

Release Date VComponents iOS SwiftUI
2022 10 02 3.0 16.0 4.0
2022 05 26 2.0 15.0 3.0
2021 02 07 1.0 14.0 2.0

Components

Buttons. VPrimaryButton, VSecondaryButton, VRoundedButton, VRoundedLabeledButton, VPlainButton

State Pickers. VToggle, VCheckBox, VRadioButton

Item Pickers. VSegmentedPicker, VWheelPicker

Value Pickers. VStepper, VSlider, VRangeSlider

Inputs. VTextField, VTextView

Containers. VSheet, VDisclosureGroup

Lists. VList

Modals. VModal, VBottomSheet, VSideBar, VAlert, VConfirmationDialog, VMenu, VContextMenu

Messages. VToast

Indicators. VSpinner, VProgressBar, VPageIndicator

Misc. VText

Brand Book

Guidelines

UI Models

Components are not meant to be customized like you would a native SwiftUI component.

Instead, UI model can be passed as parameter to initializers. This parameter has default value, and is not required every time you create a view.

UI Models are structs with default values. They break down into 5 sub-structs: Layout, Colors, Fonts, Animations, and Misc.

For instance, changing foreground color of VSecondaryButton can be done by passing an IU model.

Not Preferred:

var body: some View {
    VSecondaryButton(
        action: doSomething,
        title: "Lorem ipsum"
    )
        .foregroundColor(.black)
}

Preferred:

let uiModel: VSecondaryButtonUIModel = {
    var UIModel: VSecondaryButtonUIModel = .init()
    
    uiModel.colors.textContent = .init(
        enabled: .black,
        pressed: .gray,
        disabled: .gray
    )
    
    return uiModel
}()

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

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

extension VSecondaryButtonUIModel {
    static let someUIModel: VSecondaryButtonUIModel = {
        var uiModel: VSecondaryButtonModel = .init()
        
        uiModel.colors.textContent = .init(
            enabled: .black,
            pressed: .gray,
            disabled: .gray
        )
        
        return uiModel
    }()
}

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

Types

Some components take type as parameter. Types are represented as enums, as more can be added in the future.

For instance, VPageIndicator has three types: Finite, Infinite, and Auto. Unlike UI models, types may be required in some instances. For other enums, a default case is provided.

var body: some View {
    VStack(content: {
        VPageIndicator(type: .finite, total: 9, selectedIndex: 4)
        
        VPageIndicator(type: .infinite(), total: 99, selectedIndex: 4)
        
        VPageIndicator(type: .auto(), total: 99, selectedIndex: 4)
    })
}

Some enums can also contain additional cases, such as focused for VBaseTextField and VTextField.

Animations

VComponents approaches animations as bound to components and their UI models, and not to state. Which means, that to modify a state of component with an animation, you need to pass a custom UI model.

Not Preferred:

@State var isOn: Bool = false

var body: some View {
    VStack(content: {
        VToggle(isOn: $isOn, title: "Lorem ipsum")
        
        VSecondaryButton(
            action: { withAnimation(nil, { isOn.toggle() }) },
            title: "Toggle"
        )
    })
}

Preferred:

@State var isOn: Bool = false

let uiModel: VToggleUIModel = {
    var uiModel: VToggleUIModel = .init()
    uiModel.animations.stateChange = nil
    return uiModel
}()

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

First method is not only not preferred, but it will also not work. Despite specifying nil to change state, VToggle would still use its default animation.

Components manage state parameters internally, and animations used to change them externally do not have any effect.

Thought process behind his design choice was to centralize animations to UI model.

Components also prevent themselves from modifying external state with an animation.

Demo

Package contains demo app, that can be run to showcase all components.

Installation

Swift Package Manager

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

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

Contact

e-mail: [email protected]

GitHub

link
Stars: 186
Last commit: 3 days ago
jonrohan Something's broken? Yell at me @ptrpavlik. Praise and feedback (and money) is also welcome.

Release Notes

3.0.0
7 weeks ago

General

  • PresentationHost API is updated, and all modals now have id-based View extension methods
  • PresentationHostViewController is no longer public

VPrimaryButton

  • Corner radius is changed from 20 to 16.
  • titleMinimumScaleFactor is added in VPrimaryButtonUIModel

VSecondaryButton

  • titleMinimumScaleFactor is added in VSecondaryButtonUIModel

VSquareButton

  • VSquareButton is renamed to VRoundedButton
  • titleMinimumScaleFactor is added in VRoundedButtonUIModel

VRoundedLabeledButton

  • New button type is added

VPlainButton

  • titleMinimumScaleFactor is added in VPlainButtonUIModel

VNavigationLink

  • Component is removed, as package migrates to NavigationStack-based programatic navigation

VLink

  • Component is removed, to support more UI customization with simple UIApplication.shared.open(:)

VToggle

  • titleLineLimit is replaced with titleLineType in VToggleUIModel
  • titleMinimumScaleFactor is added in VToggleUIModel

VCheckBox

  • titleLineLimit is replaced with titleLineType in VCheckBoxUIModel
  • titleMinimumScaleFactor is added in VCheckBoxUIModel

VRadioButton

  • titleLineLimit is replaced with titleLineType in VRadioButtonUIModel
  • titleMinimumScaleFactor is added in VRadioButtonUIModel

VSegmentedPicker

  • headerLineLimit is replaced with headerTitleLineType is VSegmentedPickerUIModel
  • footerLineLimit is replaced with footerTitleLineType is VSegmentedPickerUIModel
  • titleMinimumScaleFactor is added in VSegmentedPickerUIModel
  • Header and footer color mismatched when disabled is fixed

VWheelPicker

  • headerLineLimit is replaced with headerTitleLineType is VWheelPickerUIModel
  • footerLineLimit is replaced with footerTitleLineType is VWheelPickerUIModel
  • titleMinimumScaleFactor is added in VWheelPickerUIModel
  • Header and footer color mismatched when disabled is fixed

VMenuPicker

  • MenuPicker is deprecated. Use VMenu with VMenuPickerSection.

VTextField

  • TextField Height is changed from 45 to 50
  • placeholder color is added to VTextFieldUIModel
  • headerLineLimit is replaced with headerTitleLineType is VTextFieldUIModel
  • footerLineLimit is replaced with footerTitleLineType is VTextFieldUIModel
  • Header and footer color mismatched when disabled is fixed

VTextView

  • TextView component is added

VDisclosureGroup

  • Chevron icon direction is now right for collapsed state, and down for expanded
  • contentMargins are changed from 15s to zero in VDisclosureGroupUIModel. This configuration supports list with already-padded rows. But in case of non-list content, additional padding must be used.
  • VDisclosureGroupUIModel.insettedContent is added
  • Issue with corner radius messing layout when content margin is zero is fixed

VLazyScrollView

  • List is removed for more versatile VListRow-based API

VList

  • List is removed for more versatile VListRow-based API

VStaticList

  • List is removed for more versatile VListRow-based API

VModal

  • Modal header title now can be changed via vModalHeaderTitle(_:) and vModalHeaderLabel(_:)
  • contentMargins are changed from 15s to zero in VModalUIModel. This configuration supports list with already-padded rows. But in case of non-list content, additional padding must be used.
  • VModalUIModel.insettedContent is added
  • VModalUIModel.noHeaderLabel is added
  • headerSafeAreaEdges is added to VModalUIModel that can be used for full-sized modal

VBottomSheet

  • BottomSheet header title now can be changed via vBottomSheetHeaderTitle(_:) and vBottomSheetHeaderLabel(_:)
  • contentMargins are changed from 15s to zero in VBottomSheetUIModel. This configuration supports list with already-padded rows. But in case of non-list content, additional padding must be used.
  • VBottomSheetUIModel.insettedContent is added
  • VBottomSheetUIModel.scrollableContent is added
  • VBottomSheetUIModel.noHeaderLabel is added
  • VBottomSheetUIModel.scrollableContentNoHeaderLabel is added
  • VBottomSheetUIModel.fullSizedContent is added
  • headerSafeAreaEdges is added to VBottomSheetUIModel that can be used for full-sized modal
  • Issue with content clipping outside container with big corner radius is fixed
  • Issue with content not stretching to full height when grabber, header, and divider are all hidden if fixed
  • isContentDraggable is renamed to contentIsDraggable in VBottomSheetUIModel

VSideBar

  • contentMargins are changed from 15s to zero in VSideBarUIModel. This configuration supports list with already-padded rows. But in case of non-list content, additional padding must be used.
  • VSideBarUIModel.insettedContent is added

VAlert

  • Alert now builds actions using resultBuilder
  • VAlertPresentable is added in style of AlertPresentable from VCore

VConfirmationDialog

  • ConfirmationDialog now builds actions using resultBuilder
  • ConfirmationDialog API is updated to match VAlert
  • VConfirmationDialogPresentable is added in style of ConfirmationDialogPresentable from VCore

VMenu

  • Menu now support multiple section
  • Menu now builds sections and rows using resultBuilder
  • Menu now supports picker section, transferred from VMenuPicker

VContextMenu

  • ContextMenu now support multiple section
  • ContextMenu now builds sections and rows using resultBuilder
  • ContextMenu now supports picker section, transferred from VMenuPicker

VToast

  • VToastType is renamed to VToastTextLineType

VSpinner

  • VSpinnerPresentable is added in style of ProgressViewPresentable from VCore

VText

  • VTextType is renamed to TextLineType

Other

  • PickableEnumeration is renamed to HashableEnumeration
  • PickableTitledEnumeration is renamed to StringRepresentableHashableEnumeration
  • HashableEnumeration and CustomStringConvertibleHashableEnumeration are moved to VCore
  • GenericStates and GenericStateModelss are moved to VCore
  • BasicAnimation is moved to VCore
  • pressed and disabled Colors in ColorBook are updated, to be 0.3 opacity of original reference Colors

Swiftpack is being maintained by Petr Pavlik | @ptrpavlik | @swiftpackco | API | Analytics