{"id":31144281,"url":"https://github.com/zeezide/uxkit","last_synced_at":"2025-09-18T14:38:45.466Z","repository":{"id":29084602,"uuid":"110698788","full_name":"ZeeZide/UXKit","owner":"ZeeZide","description":"Write code that works on both, UIKit and AppKit.","archived":false,"fork":false,"pushed_at":"2025-01-03T14:02:36.000Z","size":161,"stargazers_count":55,"open_issues_count":1,"forks_count":7,"subscribers_count":5,"default_branch":"develop","last_synced_at":"2025-01-03T15:19:51.342Z","etag":null,"topics":["appkit","cross-platform","swift","uikit"],"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/ZeeZide.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-11-14T14:12:29.000Z","updated_at":"2025-01-03T14:02:39.000Z","dependencies_parsed_at":"2024-04-18T13:58:49.378Z","dependency_job_id":"86436290-847b-4ec5-95a0-41cae6d91740","html_url":"https://github.com/ZeeZide/UXKit","commit_stats":null,"previous_names":[],"tags_count":26,"template":false,"template_full_name":null,"purl":"pkg:github/ZeeZide/UXKit","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ZeeZide%2FUXKit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ZeeZide%2FUXKit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ZeeZide%2FUXKit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ZeeZide%2FUXKit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ZeeZide","download_url":"https://codeload.github.com/ZeeZide/UXKit/tar.gz/refs/heads/develop","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ZeeZide%2FUXKit/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":275782046,"owners_count":25527509,"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-09-18T02:00:09.552Z","response_time":77,"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":["appkit","cross-platform","swift","uikit"],"created_at":"2025-09-18T14:38:44.445Z","updated_at":"2025-09-18T14:38:45.457Z","avatar_url":"https://github.com/ZeeZide.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ch2\u003eUXKit\n\u003cimg src=\"http://zeezide.com/img/UXKitIcon1024.png\"\n  align=\"right\" width=\"128\" height=\"128\" /\u003e\n\u003c/h2\u003e\n\n![Swift3](https://img.shields.io/badge/swift-3-blue.svg)\n![Swift4](https://img.shields.io/badge/swift-4-blue.svg)\n![Swift5](https://img.shields.io/badge/swift-5-blue.svg)\n![macOS](https://img.shields.io/badge/os-macOS-green.svg?style=flat)\n![iOS](https://img.shields.io/badge/os-iOS-green.svg?style=flat)\n![Travis](https://travis-ci.org/ZeeZide/UXKit.svg?branch=develop)\n\nThere is a rumor that something called *UXKit* exists as part of the Apple\nPhotos application, enabling the same codebase to run on macOS and iOS.\nThough the\n[article](https://medium.com/@guilhermerambo/why-uikit-for-macos-is-important-ff4e74a82cf0)\nis probably incorrect in that this is an UIKit implementation for macOS:\n\n\u003e UIKit for macOS already exists, and it is called UXKit\n\u003e I heard about UXKit when Apple first introduced the new Photos app for macOS.\n\nAt [ZeeZide](http://www.zeezide.de/) we are using something along the lines to\nbuild all applications for both, macOS and iOS.\nOne demo of that are the\n[CodeCows](http://zeezide.com/en/products/codecows/index.html)\nand\n[ASCII Cows](http://zeezide.com/en/products/asciicows/index.html)\napplications, which share about 90% of the code, while offering unique system\nfeatures on both platforms (e.g. Stickers on iOS and System Services on macOS).\n\nThis is not only useful for actual deployment to macOS, but also during\ndevelopment, as it saves you a lot of the simulator or device testing hassle if\nyou develop for macOS first. (e.g. you can do CoreBluetooth development on\nmacOS)\n\n## ZeeZide UXKit\n\nThe Apple acquired UXKit is not an official API, and there are good reasons for\nthis.\nUXKit is more of a hack to get stuff running in both environments,\nand not a beautiful framework wrapping UIKit and/or AppKit.\n\nThis codebase while not small, has very little 'actual' code.\nMost stuff is just typealiases, constant aliases, etc.\n\nThe idea of this is NOT to provide a full cross platform abstraction.\nIt is expected that a lot of apps will still carry `#if os(macOS)` like code to\nenable/disable specific features.\n\nWORK IN PROGRESS: Still cleaning up the stuff.\n\n## How to do write Cross-Platform Code using UXKit\n\n### View Aliases\n\nGenerally instead of using `UIView` or `NSView`, you are using `UXView` in\nUXKit. UXKit provides a lot of such aliases to streamline the available classes.\n\nSometimes different aliases point to the same class in one or the other\nframework. For example UIKit has `UILabel` and `UITextField` as distinct\nclasses, while AppKit uses `NSTextField` for both, readonly and editable\ntextfields.\nIn UXKit you should then use the more specific UXKit variant. E.g. on AppKit,\nuse `UXLabel` for readonly texts and `UXTextField` for editable lines, even\nthough both alias to `NSTextField`. This way the code will work right on\nboth platforms.\n\nNote: The far majority of those are really just typealiases and not subclasses.\n\nTODO\n\n### View Identifiers\n\nTODO:\n- all views have `identifiers`\n  - uses accessibilityIdentifier on UIKit (is that OK?)\n- special type in Swift 4\n\n### Target/Action\n\nIn UIKit one can attach multiple handlers to a single control action,\nand quite often there are multiple options on when the action fires\n(e.g. `touchUpInside` etc).\nThis isn't usually available in AppKit. In AppKit a control usually has\na single target, and usually one action (sometimes a second for double clicks).\n\nWhen doing a UXKit application, the code needs to constraint itself to using\na single, 'semantic', action.\nFor example this UIKit code:\n\n```swift\nbutton.addTarget(self, action: #selector(doIt(:_)), for: .touchUpInside)\n```\n\nBecomes:\n\n```swift\nbutton.onClick(self, #selector(doIt(:_)))\n```\n\nAnd works on both, UIKit and AppKit.\n\nTODO\n- gestures (below)\n\n### Table Views\n\n`UITableView` is incorrectly labeled 'table view' - it really is a\n'list view' with support for sections.\nThe AppKit `NSTableView` is an actual tableview with support for columns\n(and also sections).\n\nThere are other differences. For example UIKit has a `UITableViewCell` which\nis a full implementation of a cell which can be used as-is in the table view.\nOn AppKit, the corresponding `NSTableCellView` is just a shallow wrapper object\nmaintaining just outlets to associated labels and such.\nTo streamline the porting, UXKit adds a `NSTableViewCell` which matches the\n`UITableViewCell`.\nAll of those are properly aliases to the corresponding UX names (i.e.\n`UXTableViewCell`).\n\nAnother example is that UIKit *requires* the datasource to return an instance\nof `UITableViewCell` or a subclass of it.\nIn AppKit you can return arbitrary views. So avoid doing that when you write\nportable code.\n\nRow editing is also different on UIKit and AppKit. For example reordering is\ndone using drag\u0026drop on AppKit, while UIKit has special builtin support for\nthat.\n\nTODO\n- sectioned list view vs table view vs outline view\n- source lists\n- integrate the `UXTableViewController` into UXKit\n- row indexing is different, it includes sections on AppKit, but not on iOS\n  - this also affects things like selectedRow!\n\n\n### Collection Views\n\nTODO\n- VC vs View factory\n- items are VCs on AppKit and Views on UIKit\n- layouts can be shared\n\n### Layer based views\n\nTODO\n- explain the tricky parts\n- e.g. how layers transforms are reset in unexpected ways on AppKit\n\n### View Controllers\n\nTODO\n- representedObject for UIKit\n\n### Control Values\n\nTODO\n- formatters attached to controls\n- `objectValue` vs `intValue` etc\n\n### Gestures\n\nTODO\n\n### Alerts\n\nTODO\n- on AppKit buttons are selected by index\n- on UIKit actions are triggered by individual closures\n\n### Who\n\n**UXKit** is brought to you by\n[ZeeZide](http://zeezide.de).\nWe like feedback, GitHub stars, cool contract work,\npresumably any form of praise you can think of.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzeezide%2Fuxkit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzeezide%2Fuxkit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzeezide%2Fuxkit/lists"}