{"id":20878899,"url":"https://github.com/codeandtheory/ysnackbar-ios","last_synced_at":"2025-12-11T22:51:57.702Z","repository":{"id":95962092,"uuid":"606725679","full_name":"codeandtheory/ysnackbar-ios","owner":"codeandtheory","description":"An easy-to-use UI component to display brief, transient messages to the user.","archived":false,"fork":false,"pushed_at":"2023-08-07T11:33:18.000Z","size":232,"stargazers_count":4,"open_issues_count":0,"forks_count":1,"subscribers_count":6,"default_branch":"main","last_synced_at":"2025-11-18T09:25:29.606Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/codeandtheory.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2023-02-26T11:34:36.000Z","updated_at":"2023-10-01T10:52:58.000Z","dependencies_parsed_at":"2023-10-15T04:50:31.176Z","dependency_job_id":null,"html_url":"https://github.com/codeandtheory/ysnackbar-ios","commit_stats":null,"previous_names":["yml-org/ysnackbar-ios"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/codeandtheory/ysnackbar-ios","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codeandtheory%2Fysnackbar-ios","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codeandtheory%2Fysnackbar-ios/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codeandtheory%2Fysnackbar-ios/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codeandtheory%2Fysnackbar-ios/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/codeandtheory","download_url":"https://codeload.github.com/codeandtheory/ysnackbar-ios/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codeandtheory%2Fysnackbar-ios/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":27570384,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-12-07T02:00:07.896Z","response_time":53,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-18T07:14:33.503Z","updated_at":"2025-12-11T22:51:57.685Z","avatar_url":"https://github.com/codeandtheory.png","language":"Swift","readme":"![Y—Snackbar](https://user-images.githubusercontent.com/1037520/221581980-3961ac0e-2804-4a91-a129-918788dd3353.jpeg)\n[![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fyml-org%2Fysnackbar-ios%2Fbadge%3Ftype%3Dswift-versions)](https://swiftpackageindex.com/yml-org/ysnackbar-ios) [![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fyml-org%2Fysnackbar-ios%2Fbadge%3Ftype%3Dplatforms)](https://swiftpackageindex.com/yml-org/ysnackbar-ios)  \n_An easy-to-use UI component to display brief, transient messages to the user._\n\nThis framework allows you to add transient in-app messaging to your application. Multiple messages will stack using fluid animations. Messages can be fully themed and set to either expire after a specified time interval or to remain on-screen until dismissed.\n\n![Snackbar demo animation](https://user-images.githubusercontent.com/1037520/221582361-e040414c-973b-4b14-9de8-645a11757471.gif)\n\nLicensing\n----------\nY—Snackbar is licensed under the [Apache 2.0 license](LICENSE).\n\nDocumentation\n----------\n\nDocumentation is automatically generated from source code comments and rendered as a static website hosted via GitHub Pages at: https://yml-org.github.io/ysnackbar-ios/\n\nUsage\n----------\n\n### Snack\n\nA `Snack` is a model that represents a floating ephemeral alert or message to be presented to the user. It consists of the following:\n\n- `alignment`: Alignment for the snack view. Default is `SnackbarManager.defaultAlignment`.\n- `title`: Title for the snack view. This is an optional string and the default is nil.\n- `message`: Message to be displayed by `SnackView`. This is of type `String`.\n- `reuseIdentifier`: A string for identifying a snack. This is of type `String?` and the default is nil.\n- `icon`: A small image to be displayed as part of the snack view. This is of type `UIImage?` and the default is nil.\n- `duration`: The total duration for which the snack will be displayed. The default is 4 seconds.\n- `appearance`: Sets the appearance of the `SnackView`. The default is `.default`.\n- `voRequiresInteraction`: voice over interaction require. The default is 'false'\n\nTwo snacks are said to be equal if either the `reuseIdentifier` of both snacks are equal or the `title` and `message` of both snacks are equal. This is made possible by the snack’s conformance to both `Equatable` and `Hashable`.\n\n💡 If the snack `duration` is `.nan` or `.zero` then the snack lives forever (until you swipe to dismiss it)\n\n### SnackView\n\nA `SnackView` is a view that will be presented to the user through the `SnackbarManager`. The content of the view is populated using a `Snack` model object. It has one initializer:\n\n- `init(snack: Snack)`\n    - Initializes a `SnackView` using the `snack` data model.\n\nClients can modify or set the appearance of the `SnackView` while creating a `Snack` by setting the `appearance`. This will allow the client to modify the following properties:\n\n- `title`:\n    - A tuple consisting of `textColor` and `typography` for the title label.\n    - Default is `(.label, .systemLabel.bold)` .\n- `message`:\n    - A tuple consisting of `textColor` and `typography` for the message label.\n    - Default is `(.label, .systemLabel)` .\n- `backgroundColor`:\n    - Background color. The default is `systemBackground`.\n- `borderColor`:\n    - Border color. The default is `.label`.\n- `borderWidth`:\n    - Border width. The default is `0`.\n- `elevation`:\n    - Elevation (also known as box shadow). Default is `Appearance.elevation`.\n- `layout`:\n    - Layout properties such as spacing between views, corner radius. Default is `Layout()`.\n\n**How to get `SnackView` from a `Snack`?**\n\n```swift\nfunc getSnackAssociatedView() -\u003e SnackUpdatable\n```\n\n### SnackUpdatable\n\n- Any object that can be updated with a new `Snack` model object.\n- `SnackView` uses this to update an existing view with new information.\n\n### SnackbarManager\n\nAll snacks are managed by the `SnackbarManager`.\n\n#### State\n\n- `defaultAlignment`\n    - It is a global mutable shared state.\n    - Describes the default alignment of the snack view.\n    - Default is `.top`\n    \n#### Operations\n\n- `class func add(snack: Snack)`\n    - Creates a snack view using the snack passed as an argument to display a snack. \n    \n    - Depending on the alignment, duplicate snacks will be updated and pushed to the bottom or top.\n\n- `class func remove(snack: Snack)`\n    - Removes a snack view using the snack passed as an argument. The `SnackContainerView` will be dismissed after the last snack is removed. \n    - There are 3 ways by which you can remove a snack. They are as follows:  \n        - By calling `class func remove(snack: Snack)` operation.\n        - When the snack has completed its `duration`\n        - Swiping it up or down to dismiss.\n    \nClients can control or modify the animation duration, spacing, etc of the `SnackbarManager` by setting the `appearance` property which is of type `SnackbarManager.Appearance`. This will allow the client to modify the following properties:\n\n- `addAnimation`:\n    - The animation to use when adding a snack.\n    - The default is a spring animation with duration of 0.4\n- `rearrangeAnimation`:\n    - The animation to use when rearranging two or more snacks.\n    - The default is an ease in, ease out animation with duration of 0.3\n- `removeAnimation`:\n    - The animation to use when removing a snack.\n    - The default is an ease out animation with duration of 0.3\n- `snackSpacing`:\n    - Spacing between the snacks\n    - The default is **16.0**\n- `contentInset`:\n    - The distance the content is inset from the superview.\n    - The default is **16.0**\n- `maxSnackWidth`:\n    - Maximum width of a snack view. \n    - Helps to keep a fixed width for a snack view on an iPad screen.\n    - The default is **428.0**\n    \n#### Default Features\n\nEvery snack added has the following default features:  \n\n* corner radius based on appearance\n* shadow based on appearance\n* swipe enabled to dismiss snack view \n\n### Usage\n\n1. **Importing the framework**\n    \n    ```swift\n    import YSnackbar\n    ```\n\n2. **Create a snack**\n    \n    ```swift\n    func makeSnack() -\u003e Snack {\n        Snack(\n            alignment: .bottom,\n            title: \"Network Reachable\",\n            message: \"You are currently online.\",\n            reuseIdentifier: \"yml.co\",\n            icon: UIImage(named: \"wifi\"),\n            duration: 8.0\n          )\n    }\n    ```\n\n3. **Add a snack**\n    \n    ```swift\n    // Creates a snack using `SnackbarManager.defaultAlignment = .top` \n    let snack = Snack(message: \"No network\")\n\n    // Adds to the top of the screen\n    SnackbarManager.add(snack: snack) \n    ```\n    \n    ```swift\n    // Creates a snack with bottom alignment\n    let snack = Snack(alignment: .bottom, message: \"Copied to clipboard\")\n\n    // Adds to the bottom of the screen\n    SnackbarManager.add(snack: snack) \n    ```\n    \n    ```swift\n    // Set `SnackbarManager.defaultAlignment` to bottom\n    SnackbarManager.defaultAlignment = .bottom\n\n    // Creates a snack using defaultAlignment.\n    let snack = Snack(message: \"Copied to clipboard\")\n\n    // Adds to the bottom of the screen\n    SnackbarManager.add(snack: snack) \n    ```\n\n4. **Remove a snack**\n    \n    ```swift\n    let snack = Snack() \n    SnackbarManager.remove(snack)\n    ```\n\n5. **Create a custom Snack**\n    \n    ```swift\n    final class ImageSnack: Snack {\n        convenience init(named: String) {\n            self.init(message: named, reuseIdentifier: \"co.yml.page\")\n        }\n    \n        override func getSnackAssociatedView() -\u003e SnackUpdatable {\n            SnackImageView(snack: self)\n        }\n    }\n    \n    final class SnackImageView: UIImageView {\n        private(set) var snack: Snack\n    \n        required init(snack: Snack) {\n            self.snack = snack\n            super.init(image: UIImage(named: snack.message))\n            setUp()\n        }\n    \n        required init?(coder: NSCoder) { nil }\n    \n        private func setUp() {\n            self.contentMode = .scaleAspectFit\n        }\n    }\n    \n    extension SnackImageView: SnackUpdatable {\n        func update(_ snack: Snack) {\n            self.image = UIImage(named: snack.message)\n            self.snack = snack\n        }\n    }\n    ```\n\nDependencies\n----------\n\nY—Snackbar depends upon our [Y—CoreUI](https://github.com/yml-org/ycoreui) and [Y—MatterType](https://github.com/yml-org/ymattertype) frameworks (both also open source and Apache 2.0 licensed).\n\nInstallation\n----------\n\nYou can add Y—Snackbar to an Xcode project by adding it as a package dependency.\n\n1. From the **File** menu, select **Add Packages...**\n2. Enter \"[https://github.com/yml-org/ysnackbar-ios](https://github.com/yml-org/ysnackbar-ios)\" into the package repository URL text field\n3. Click **Add Package**\n\nContributing to Y—Snackbar\n----------\n\n### Requirements\n\n#### SwiftLint (linter)\n```\nbrew install swiftlint\n```\n\n#### Jazzy (documentation)\n```\nsudo gem install jazzy\n```\n\n### Setup\n\nClone the repo and open `Package.swift` in Xcode.\n\n### Versioning strategy\n\nWe utilize [semantic versioning](https://semver.org).\n\n```\n{major}.{minor}.{patch}\n```\n\ne.g.\n\n```\n1.0.5\n```\n\n### Branching strategy\n\nWe utilize a simplified branching strategy for our frameworks.\n\n* main (and development) branch is `main`\n* both feature (and bugfix) branches branch off of `main`\n* feature (and bugfix) branches are merged back into `main` as they are completed and approved.\n* `main` gets tagged with an updated version # for each release\n \n### Branch naming conventions:\n\n```\nfeature/{ticket-number}-{short-description}\nbugfix/{ticket-number}-{short-description}\n```\ne.g.\n```\nfeature/CM-44-button\nbugfix/CM-236-textview-color\n```\n\n### Pull Requests\n\nPrior to submitting a pull request you should:\n\n1. Compile and ensure there are no warnings and no errors.\n2. Run all unit tests and confirm that everything passes.\n3. Check unit test coverage and confirm that all new / modified code is fully covered.\n4. Run `swiftlint` from the command line and confirm that there are no violations.\n5. Run `jazzy` from the command line and confirm that you have 100% documentation coverage.\n6. Consider using `git rebase -i HEAD~{commit-count}` to squash your last {commit-count} commits together into functional chunks.\n7. If HEAD of the parent branch (typically `main`) has been updated since you created your branch, use `git rebase main` to rebase your branch.\n    * _Never_ merge the parent branch into your branch.\n    * _Always_ rebase your branch off of the parent branch.\n\nWhen submitting a pull request:\n\n* Use the [provided pull request template](.github/pull_request_template.md) and populate the Introduction, Purpose, and Scope fields at a minimum.\n* If you're submitting before and after screenshots, movies, or GIF's, enter them in a two-column table so that they can be viewed side-by-side.\n\nWhen merging a pull request:\n\n* Make sure the branch is rebased (not merged) off of the latest HEAD from the parent branch. This keeps our git history easy to read and understand.\n* Make sure the branch is deleted upon merge (should be automatic).\n\n### Releasing new versions\n* Tag the corresponding commit with the new version (e.g. `1.0.5`)\n* Push the local tag to remote\n\nGenerating Documentation (via Jazzy)\n----------\n\nYou can generate your own local set of documentation directly from the source code using the following command from Terminal:\n```\njazzy\n```\nThis generates a set of documentation under `/docs`. The default configuration is set in the default config file `.jazzy.yaml` file.\n\nTo view additional documentation options type:\n```\njazzy --help\n```\nA GitHub Action automatically runs each time a commit is pushed to `main` that runs Jazzy to generate the documentation for our GitHub page at: https://yml-org.github.io/ysnackbar-ios/\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcodeandtheory%2Fysnackbar-ios","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcodeandtheory%2Fysnackbar-ios","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcodeandtheory%2Fysnackbar-ios/lists"}