{"id":20630452,"url":"https://github.com/mkj-is/elementary","last_synced_at":"2025-08-04T10:33:56.398Z","repository":{"id":63918586,"uuid":"194846567","full_name":"mkj-is/Elementary","owner":"mkj-is","description":"Experimental, uni-directional and purely functional architecture in Swift.","archived":false,"fork":false,"pushed_at":"2020-06-14T18:23:07.000Z","size":38,"stargazers_count":14,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-08-02T20:11:47.534Z","etag":null,"topics":["effects","elm-architecture","functional-programming","redux","state","swift","swift-package","unidirectional-data-flow"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mkj-is.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-07-02T11:02:14.000Z","updated_at":"2025-04-29T09:10:47.000Z","dependencies_parsed_at":"2023-01-14T14:00:51.999Z","dependency_job_id":null,"html_url":"https://github.com/mkj-is/Elementary","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/mkj-is/Elementary","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mkj-is%2FElementary","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mkj-is%2FElementary/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mkj-is%2FElementary/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mkj-is%2FElementary/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mkj-is","download_url":"https://codeload.github.com/mkj-is/Elementary/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mkj-is%2FElementary/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":268682653,"owners_count":24289677,"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-08-04T02:00:09.867Z","response_time":79,"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":["effects","elm-architecture","functional-programming","redux","state","swift","swift-package","unidirectional-data-flow"],"created_at":"2024-11-16T14:07:54.179Z","updated_at":"2025-08-04T10:33:56.349Z","avatar_url":"https://github.com/mkj-is.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Elementary\n\n**Elementary** is experimental, uni-directional and purely functional architecture in Swift.\nIt is inspired by ELM and Redux. Main motivation behind this was the introduction of SwiftUI,\nbut this core package does not depend on Combine or SwiftUI.\n\n## Installation\n\nWhen using Swift package manager install using Xcode 11+ or add following line to your dependencies:\n\n```swift\n.package(url: \"https://github.com/mkj-is/Elementary.git\", from: \"0.1.0\")\n```\n\n### Extensions\n\nBase extension for making SwiftUI apps is [ElementaryCombine](https://github.com/mkj-is/ElementaryCombine).\nDon't hesitate with using this one if you are supporting only newest Apple operating systems.\n\nAnother truly experimantal extension is [ElementaryEffectBuilder](https://github.com/mkj-is/ElementaryEffectBuilder).\nThis one is for combining side-effects using the new Swift function builders.\n\n## Usage\n\nEverything is bound together by initializing `Store` with these components:\n\n- *State* (model from which the whole user interface can be built.)\n- *Actions* (anything that can happen in your code, both user actions and actions that are dispatched by your side-effects.)\n- *Update function* (which takes state and action and creates new state.)\n- *Effects* (functions which are called after the update and can dispatch back actions asynchronously.)\n\n## Examples\n\nLet's take a first example: Simple implementation of a counter, where user can increment, decrement and reset it.\n\nFirstly, we need to define all the actions. In this case, some enum should be sufficient:\n\n```swift\nenum CounterAction {\n    case increment, decrement, reset\n}\n```\n\nThen we implement the function taking state and action and updates the state.\nThe only thing which should be happening here is changing the state.\n\n```swift\nfunc updateCounter(state: inout Int, action: CounterAction) {\n    switch action {\n    case .increment:\n        state += 1\n    case .decrement:\n        state = max(0, state - 1)\n    case .reset:\n        state = 0\n    }\n}\n```\nThe last thing we need to do is initialize the store. This code does exactly that\nand simulates sample run through the app. Testability is one of the key features\nof this decomposition, you can see for yourself\nin the example [test cases](Tests/Elementarytests/CounterTests.swift).\n\n```swift\nlet store = Store(state: 0, update: updateCounter)\nstore.dispatch(.increment)\nstore.dispatch(.increment)\nstore.dispatch(.decrement)\nstore.dispatch(.increment)\nstore.dispatch(.reset)\nstore.state\n```\n\n### Effects\n\nMost client apps need to execute some asynchronous work.\nLet's take simple stopwatch, which increments the state every second.\n\n```swift\nenum StopwatchAction {\n    case start, stop, increment, reset\n}\n\n\nfunc updateStopwatch(state: inout Int, action: StopwatchAction) {\n    switch action {\n    case .reset:\n        state = 0\n    case .increment:\n        state += 1\n    case .start, .stop:\n        break\n    }\n}\n```\n\nNow we have all the actions and update function defined.\nNext step is writing function which returns new side-effect\nwith captured-value of the timer. The effect will only react\non two actions, start and stop. When these actions are dispatched\nthe timer is either started or stopped. `DispatchSourceTimer`\nis used to make this code multiplatform and backward-compatible.\n\n```swift\nfunc createStopwatchEffect() -\u003e Effect\u003cInt, StopwatchAction\u003e {\n    var timer: DispatchSourceTimer?\n    return { _, action, dispatch in\n        switch action {\n        case .start:\n            timer = DispatchSource.makeTimerSource()\n            timer?.schedule(deadline: .now() + 1, repeating: 1)\n            timer?.setEventHandler {\n                dispatch(.increment)\n            }\n            timer?.resume()\n        case .stop, .reset:\n            timer = nil\n        case .increment:\n            break\n        }\n    }\n}\n```\n\n## Contributing\n\nAll contributions are welcome.\n\nProject was created by [Matěj Kašpar Jirásek](https://github.com/mkj-is).\n\nProject is licensed under [MIT license](LICENSE.txt).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmkj-is%2Felementary","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmkj-is%2Felementary","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmkj-is%2Felementary/lists"}