Code Monkey home page Code Monkey logo

swiftuikit's Introduction

SwiftUIKit Logo

Version Swift 5.9 Swift UI MIT License Twitter: @danielsaidi Mastodon: @danielsaidi@mastodon.social

About SwiftUIKit

SwiftUIKit is a Swift SDK that adds extra functionality to SwiftUI and Swift. It contains additional components, a lot of extensions to native types, and much more.

SwiftUIKit can kickstart your development and solves many tricky problems.

Installation

SwiftUIKit can be installed with the Swift Package Manager:

https://github.com/danielsaidi/SwiftUIKit.git

Getting Started

SwiftUIKit started as a small project, but has grown pretty huge over the years.

Due to its complexity, I have decided to remove the demo. Instead, have a look at the various namespaces and use the live previews to explore the components in the SDK.

I will therefore extract parts of this SDK into separate libraries, to be able to provide better documentation & help.

For more Swift & SwiftUI SDKs that I have created, please have a look at my open-source listing page.

Documentation

The online documentation has more information, code examples, etc.

Support my work

You can sponsor me on GitHub Sponsors or reach out for paid support, to help support my open-source projects.

Your support makes it possible for me to put more work into these projects and make them the best they can be.

Contact

Feel free to reach out if you have questions or want to contribute in any way:

License

SwiftUIKit is available under the MIT license. See the LICENSE file for more info.

swiftuikit's People

Contributors

alfredcc avatar daniel-arden avatar danielsaidi avatar itsliamdowd avatar woxtu avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

swiftuikit's Issues

Undimmed detents no longer work when passing a 'selection'.

Hey, love your code thanks for your help! 😁

I'm facing an issue all of a sudden with your PresentationDetents code and was wondering if you could help me resolve it.

Suddenly (I believe after I updated to XCode 15) the sheet is no longer keeping the undimmed state of its background after dragging it. For example when the sheet opens up everything is fine, but when I try dragging it slightly it dims my background again not respecting the largestUndimmed I set. I noticed that this only happens when setting a selection, like so:

.presentationDetents(
  [
    .fraction(0.1),
    .fraction(0.5),
    .fraction(1)
  ],
  largestUndimmed: .fraction(0.5),
  selection: $currentSheetPosition
)

However, I really need the selection parameter there as it lets me control the state of the sheet. Can you help me resolve this please?

Make the library less complicated

This library was always about adding reusable, simple utilities and views to extend SwiftUI.

However, over time, I have added more complex component types and concepts to the library, which is a bad fit, since this concepts may require more specific demos, documentation etc. than fits this project.

As such, from SwiftUI 3, I will move many complex types into their own libraries. I will therefore list such components in the list below and deprecate them once they are their own libraries. I will then bump to 3.0 once they have all been converted.

  • ColorPickerBar
  • LinkText
  • List items -> ListItemKit?
  • PageIndicator
  • Pickers -> PickerKit
  • Presentation -> PresentationKit
  • Printing -> PrintingKit
  • ProgressBar
  • SystemFontPicker
  • WebView -> WebViewKit

For each new kit, I should have:

  • A readme
  • Release notes
  • Automation with Fastlane
  • Documentation
  • Web documentation
  • Demo app

More may come as I start this work.

OnTapGesutre on CollectionView prevents scrolling

Whenever I add a .OnTapGesture to a view contained in a CollectionView row, the gesture works just fine, but the collection view no longer responds to scrolling.

Is this a bug, or am I just missing something?

Alert is deprecated in current version

https://developer.apple.com/documentation/swiftui/alert

I just wanted to give you a heads up that the Alert component used in your package is deprecated in the latest version of SwiftUI. I've created a custom alert as a temporary solution, but it would be awesome if you could update the package to support the current SwiftUI version.

Thanks for creating this package - it's been super helpful for my app, and I really appreciate your work. Looking forward to seeing the update!

Cheers!

// CustomAlert.swift
import SwiftUI

public class CustomAlert: ObservableObject {
    let title: Text
    let message: AnyView
    let content: AnyView

    public init(title: Text, message: some View, content: some View) {
        self.title = title
        self.message = AnyView(message)
        self.content = AnyView(content)
    }

    public init(title: Text, message: some View) {
        self.title = title
        self.message = AnyView(message)
        self.content = AnyView(Button("OK") {})
    }
}
// CustomAlertContext.swift
import SwiftUI

public class CustomAlertContext: ObservableObject {

    public init() {}

    @Published public var isActive = false

    @Published public internal(set) var alertObject: CustomAlert? {
        didSet { isActive = alertObject != nil }
    }

    public var isActiveBinding: Binding<Bool> {
        .init(get: { self.isActive },
                set: { self.isActive = $0 }
        )
    }

    public func dismiss() {
        isActive = false
    }

    public func present(_ alert: CustomAlert) {
        self.alertObject = alert
    }
}
// View+CustomAlert.swift
import SwiftUI

public extension View {

    /**
     Present an alert from a certain context. The alert will
     be presented when the context is active.
     */
    func customAlert(context: CustomAlertContext) -> some View {
        alert(context.alertObject?.title ?? Text(""), isPresented: context.isActiveBinding) {
            context.alertObject?.content
        } message: {
            context.alertObject?.message ?? AnyView(Text(""))
        }
    }
}

GIF/Images of the Demo

Hi Daniel! I just saw this from your Twitter and it looks pretty awesome and resourceful.
It would be amazing to see a GIF of the demo, or just images so people can instantly see if the kit has stuff that would be useful for them, without having to clone the repo!

Undimmed Sheet Detents - Dim reappears after sheet height changes.

Hello, thanks for the undimmed sheet detents, I find it surprising this isn't included in SwiftUI by default, but great work figuring out how to implement it!

I've spotted that the dim reappears if the sheet height is changed programmatically. Here's a quick sample:

import SwiftUI
import SwiftUIKit

struct ContentView: View {
  @State var sheetHeight: CGFloat = 100
  @State var sheetIsPresented = false

  var body: some View {
    VStack {
      Button(
        action: {
          sheetIsPresented.toggle()
          sheetHeight = 100
        },
        label: {
          Text("Show Sheet")
        }
      )
    }
    .sheet(
      isPresented: $sheetIsPresented
    ) {
        VStack {
          Text("\(sheetHeight)")
          Button(
            action: {
              sheetHeight += 10
            },
            label: {
              Text("Increase Sheet Size")
            }
          )
        }
      .presentationDetents(
        undimmed: [ UndimmedPresentationDetent.height(sheetHeight)]
      )
    }
  }
}

Before tapping "increase sheet size", and after:
IMG_0007
IMG_0008

Documenation Zip File is missing

Hello,
I just wanted to download the documentation, but it turns out the link https://github.com/danielsaidi/SwiftUIKit/raw/master/Docs/SwiftUIKit.doccarchive.zip in the readme is returning a 404, and the file does not seem to exist within th repository.

Would love to be able to download and read it! :)

Best, Matthias

Convert WebView to a separate library

This component is much more fitting as a micro library.

Once SwiftUI adds this to the standard libraries, we can then deprecate the library.

Once this new library is live, deprecate the WebView view in SwiftUIKit.

Demo images / Sample snippets

Please show demo images or include sample snippets for different elements in README. Helps in understanding what the repo has to offer.

ScrollViewGestureButton remains pressed on fast swipe outside the ScrollView

Hello,
when using the ScrollViewGestureButton preview, a combination of touch and swipe can make the button permanently pressed, even if no button should ever remain pressed without an active touch.
No presses on other views will release the button apart from a press on the button itself.
Even if the button gets eventually released, the repeating action continues to fire.
Only a long press on the button prevents the repeating action from firing.

See video attached: https://github.com/danielsaidi/SwiftUIKit/assets/8497370/2b0655e8-f2f4-41bf-b305-2b4622f16816.

Can Build on Xcode 14

Hi
Im getting this error on recent update Xcode 14 and IOS 16
SwiftUIKit/views/ContactPicker.swift:73:24: error build: Inheritance from non-protocol, non-class type 'ContactPicker.Coordinator' (aka 'any Coordinator')
Screen Shot 2022-09-14 at 10 13 58 p m

Ability for GestureButton to gracefully prioritise handling between a tap and long press action

I have a GestureButton that I have events for when the user taps as well as long presses (with a minimum delay).

I can’t depend on plain SwiftUI gesture modifiers for this because when the two are chained together, the long press minimum duration set appears to be ignored.

With GestureButton, I am trying to use releaseInsideAction combined with longPressAction with a longPressDelay of 0.1.

When I tap on the button, the releaseInsideAction is called correctly.

When I long press on the button, the longPressAction after the correct delay is called correctly. However, it also then proceeds to call the releaseInsideAction too, which isn’t what I want or expected.

To workaround this, I have added a new @State variable:

private var isLongPressed: Bool = false

Inside tryTriggerLongPressAfterDelay(), after its action() call, I flag it to be true:

        DispatchQueue.main.asyncAfter(deadline: .now() + delay) {
            guard self.longPressDate == date else { return }
            action()
            isLongPressed = true
        }

Finally, in tryHandleRelease(), I check whether isLongPressed is true to determine whether to proceed with its associated action:

        if !isLongPressed {
            if geo.contains(value.location) {
                releaseInsideAction?()
            } else {
                releaseOutsideAction?()
            }
        }
        else {
            isLongPressed = false
        }
        endAction?()

In my tests, this seems to work really well without any issues. Can’t see where it could possibly trip up! Thank you so much for implementing such a versatile button that helps workaround SwiftUI limitations.

Setting subsequent Toasts to a context doesn't reset their timing

Hello,

Lovely collection here.

Title says it all. Because of lingering asyncAfter calls, timing gets all gunked up if you present multiple toasts in sequence.

I'd be happy to contribute a fix on this myself if you had any suggestions on how to approach it within your existing design.

Thanks so much for the code, very helpful stuff.

Demo run failure

I've got a weird issue that code run failure. I just download the code and run.
WX20221128-230503
WX20221128-230523
WX20221128-230603
WX20221128-231050@2x

Unreliable UndimmedPresentationDetentsViewModifier behavior

Firstly, thanks for this great library. There's a lot of great stuff in here.

We have been experimenting with using SwiftUIKit for our bottom sheets so that we can allow background interactions while sheets are presented. This works in basic use cases but I find that ~30% of the time when my sheet is presented there is still a dimmed view covering the background. It seems to happen the most on the first appearance although I don't have any data to back that up.

Here's our ideal workflow:

  1. A PostDetailView sheet is presented with:
    .presentationDetents(undimmed: [.fraction(0.6)], largestUndimmed: .fraction(0.6))

  2. If a user taps the edit button, a separate PostEditorView sheet is presented with: .presentationDetents(undimmed: [.fraction(0.6)], largestUndimmed: .fraction(0.6))

(Note: Even up until this point before we start changing the selected detent the behavior seems to be a bit hit or miss)

  1. There are multiple controls in the PostEditorView that each have their own heights. For example, we would love to be able to switch the selected state between .fraction(0.2) and .fraction(0.6) using the selection property:
            .presentationDetents(undimmed: viewStore.isUsingTools ? [.fraction(0.2)] : [.fraction(0.2), .fraction(0.6)],
                                 largestUndimmed: .fraction(0.6),
                                 selection: .constant(viewStore.isUsingTools ? .fraction(0.2) : .fraction(0.6)))

Unfortunately, whenever we change the selection programmatically to .fraction(0.2) it seems to add the dimmed view back which does not goes away if we set the selection back to .fraction(0.6).

Universal Demo App currently doesn't run on macOS

The new demo app is a universal one that should run on both iOS and macOS. However, I have focused on a great iOS experience first, and the macOS demo doesn't currently build.

The demo app should disable parts that aren't supported by macOS, but I will wait with this until I have an M1.

ReorderableForEach -> Pass through index of element

Heya,

Have been playing around with ReorderableForEach - it's awesome! Cheers for the method.

One thing I need is the index of the element, was using the SwiftUI ForEach and passing the index through to the view, doesn't appear there's a way to do this with the method? I attempted to add it myself but got a little lost

Is there any chance of getting it added when you have a spare moment? Cheers!

Demo doesn’t build

Tried for iOS, cloned master. This fixes it:

diff --git a/Demo/Demo.xcodeproj/project.pbxproj b/Demo/Demo.xcodeproj/project.pbxproj
index 63775cc..c50d62e 100644
--- a/Demo/Demo.xcodeproj/project.pbxproj
+++ b/Demo/Demo.xcodeproj/project.pbxproj
@@ -7,6 +7,8 @@
 	objects = {
 
 /* Begin PBXBuildFile section */
+		63C55D8E25E2E3EF000D9CE6 /* ShadowStyle+Toast.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63C55D8D25E2E3EF000D9CE6 /* ShadowStyle+Toast.swift */; };
+		63C55D8F25E2E3EF000D9CE6 /* ShadowStyle+Toast.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63C55D8D25E2E3EF000D9CE6 /* ShadowStyle+Toast.swift */; };
 		A901F033256F8C9A00F1C285 /* BlursScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = A901F032256F8C9A00F1C285 /* BlursScreen.swift */; };
 		A901F034256F8C9A00F1C285 /* BlursScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = A901F032256F8C9A00F1C285 /* BlursScreen.swift */; };
 		A901F03A256F8CA600F1C285 /* DataScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = A901F039256F8CA600F1C285 /* DataScreen.swift */; };
@@ -238,8 +240,6 @@
 		A98279CC257ED06F0006D64F /* View+FullScreenCover.swift in Sources */ = {isa = PBXBuildFile; fileRef = A982793F257ED06F0006D64F /* View+FullScreenCover.swift */; };
 		A98279CD257ED06F0006D64F /* View+Alert.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9827940257ED06F0006D64F /* View+Alert.swift */; };
 		A98279CE257ED06F0006D64F /* View+Alert.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9827940257ED06F0006D64F /* View+Alert.swift */; };
-		A98279CF257ED06F0006D64F /* Toast+Shadow.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9827941257ED06F0006D64F /* Toast+Shadow.swift */; };
-		A98279D0257ED06F0006D64F /* Toast+Shadow.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9827941257ED06F0006D64F /* Toast+Shadow.swift */; };
 		A98279D1257ED06F0006D64F /* View+Sheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9827942257ED06F0006D64F /* View+Sheet.swift */; };
 		A98279D2257ED06F0006D64F /* View+Sheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9827942257ED06F0006D64F /* View+Sheet.swift */; };
 		A98279D3257ED06F0006D64F /* ToastStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9827943257ED06F0006D64F /* ToastStyle.swift */; };
@@ -293,6 +293,7 @@
 /* End PBXBuildFile section */
 
 /* Begin PBXFileReference section */
+		63C55D8D25E2E3EF000D9CE6 /* ShadowStyle+Toast.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ShadowStyle+Toast.swift"; sourceTree = "<group>"; };
 		A901F032256F8C9A00F1C285 /* BlursScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlursScreen.swift; sourceTree = "<group>"; };
 		A901F039256F8CA600F1C285 /* DataScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataScreen.swift; sourceTree = "<group>"; };
 		A901F03E256F8CB100F1C285 /* ExtensionsScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtensionsScreen.swift; sourceTree = "<group>"; };
@@ -424,7 +425,6 @@
 		A982793E257ED06F0006D64F /* PresentationContext.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PresentationContext.swift; sourceTree = "<group>"; };
 		A982793F257ED06F0006D64F /* View+FullScreenCover.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "View+FullScreenCover.swift"; sourceTree = "<group>"; };
 		A9827940257ED06F0006D64F /* View+Alert.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "View+Alert.swift"; sourceTree = "<group>"; };
-		A9827941257ED06F0006D64F /* Toast+Shadow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Toast+Shadow.swift"; sourceTree = "<group>"; };
 		A9827942257ED06F0006D64F /* View+Sheet.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "View+Sheet.swift"; sourceTree = "<group>"; };
 		A9827943257ED06F0006D64F /* ToastStyle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ToastStyle.swift; sourceTree = "<group>"; };
 		A9827944257ED06F0006D64F /* View+Toast.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "View+Toast.swift"; sourceTree = "<group>"; };
@@ -953,8 +953,8 @@
 		A9D34660259092B700A2C8B9 /* Toast */ = {
 			isa = PBXGroup;
 			children = (
-				A9827941257ED06F0006D64F /* Toast+Shadow.swift */,
 				A9827946257ED06F0006D64F /* ToastContext.swift */,
+				63C55D8D25E2E3EF000D9CE6 /* ShadowStyle+Toast.swift */,
 				A982793B257ED06F0006D64F /* ToastProvider.swift */,
 				A9827943257ED06F0006D64F /* ToastStyle.swift */,
 				A9827944257ED06F0006D64F /* View+Toast.swift */,
@@ -1118,7 +1118,6 @@
 				A98279BF257ED06F0006D64F /* OptionalView.swift in Sources */,
 				A989133725DE8452007F4DFE /* TextFieldClearButton.swift in Sources */,
 				A9355045256F7E3D00BBE9CE /* ContentView.swift in Sources */,
-				A98279CF257ED06F0006D64F /* Toast+Shadow.swift in Sources */,
 				A98279E1257ED06F0006D64F /* UIBlurEffectStyle+Name.swift in Sources */,
 				A98279DF257ED06F0006D64F /* FullScreenCoverProvider.swift in Sources */,
 				A989134925DE8470007F4DFE /* MenuListLink.swift in Sources */,
@@ -1189,6 +1188,7 @@
 				A9827993257ED06F0006D64F /* QrCodeGenerator.swift in Sources */,
 				A982799B257ED06F0006D64F /* CircularProgressBar.swift in Sources */,
 				A901F04E256F8CFE00F1C285 /* StylesScreen.swift in Sources */,
+				63C55D8E25E2E3EF000D9CE6 /* ShadowStyle+Toast.swift in Sources */,
 				A982796B257ED06F0006D64F /* FontStyle.swift in Sources */,
 				A9827961257ED06F0006D64F /* View+Enabled.swift in Sources */,
 				A982796D257ED06F0006D64F /* ShadowStyle.swift in Sources */,
@@ -1261,7 +1261,6 @@
 				A98279C0257ED06F0006D64F /* OptionalView.swift in Sources */,
 				A9355046256F7E3D00BBE9CE /* ContentView.swift in Sources */,
 				A989133825DE8452007F4DFE /* TextFieldClearButton.swift in Sources */,
-				A98279D0257ED06F0006D64F /* Toast+Shadow.swift in Sources */,
 				A98279E2257ED06F0006D64F /* UIBlurEffectStyle+Name.swift in Sources */,
 				A98279E0257ED06F0006D64F /* FullScreenCoverProvider.swift in Sources */,
 				A901F1382570771600F1C285 /* CircularProgressBarScreen.swift in Sources */,
@@ -1334,6 +1333,7 @@
 				A982796C257ED06F0006D64F /* FontStyle.swift in Sources */,
 				A9827962257ED06F0006D64F /* View+Enabled.swift in Sources */,
 				A989132825DE81E2007F4DFE /* MenuListStyle.swift in Sources */,
+				63C55D8F25E2E3EF000D9CE6 /* ShadowStyle+Toast.swift in Sources */,
 				A982796E257ED06F0006D64F /* ShadowStyle.swift in Sources */,
 				A989132B25DE81E2007F4DFE /* Image+MenuList.swift in Sources */,
 				A9827976257ED06F0006D64F /* FontIdentifier.swift in Sources */,

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.