{"id":20545507,"url":"https://github.com/eonist/spatial","last_synced_at":"2025-06-12T00:33:37.415Z","repository":{"id":64060161,"uuid":"149573290","full_name":"eonist/Spatial","owner":"eonist","description":"Hasle-free AutoLayout (MacOS / iOS)","archived":false,"fork":false,"pushed_at":"2023-10-22T13:07:27.000Z","size":375,"stargazers_count":16,"open_issues_count":20,"forks_count":2,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-05-16T10:42:13.038Z","etag":null,"topics":["autolayout","ios","layout","macos","nslayoutanchor","nslayoutconstraint","nslayoutguide","programmatic","swift","ui","uikit","uilayoutguide"],"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/eonist.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":"2018-09-20T08:00:13.000Z","updated_at":"2023-12-17T18:42:25.000Z","dependencies_parsed_at":"2023-02-13T00:01:24.946Z","dependency_job_id":"bfabc3f4-3205-46d0-af63-62834e741160","html_url":"https://github.com/eonist/Spatial","commit_stats":{"total_commits":49,"total_committers":1,"mean_commits":49.0,"dds":0.0,"last_synced_commit":"61d272954c05cbc41294528f1f71006226ec367b"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/eonist/Spatial","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eonist%2FSpatial","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eonist%2FSpatial/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eonist%2FSpatial/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eonist%2FSpatial/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/eonist","download_url":"https://codeload.github.com/eonist/Spatial/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eonist%2FSpatial/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259370683,"owners_count":22847383,"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","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":["autolayout","ios","layout","macos","nslayoutanchor","nslayoutconstraint","nslayoutguide","programmatic","swift","ui","uikit","uilayoutguide"],"created_at":"2024-11-16T01:52:27.012Z","updated_at":"2025-06-12T00:33:37.393Z","avatar_url":"https://github.com/eonist.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Spatial\n![mit](https://img.shields.io/badge/License-MIT-brightgreen.svg)\n![platform](https://img.shields.io/badge/Platform-iOS/macOS-blue.svg)\n![Lang](https://img.shields.io/badge/Language-Swift%205.0-orange.svg)\n[![SPM compatible](https://img.shields.io/badge/SPM-compatible-4BC51D.svg?style=flat)](https://github.com/apple/swift)\n![Tests](https://github.com/eonist/Spatial/workflows/Tests/badge.svg)\n[![codebeat badge](https://codebeat.co/badges/d73a742e-037b-4423-8a02-fb8050a1c21d)](https://codebeat.co/projects/github-com-eonist-spatial-master)\n\n\u003cimg width=\"900\" alt=\"img\" src=\"https://raw.github.com/stylekit/img/master/spatial_github.svg?sanitize=true\"\u003e\n\nDefinition: **Spatial** | ˈspeɪʃ(ə)l | adjective | **describes how objects fit together in space**\n\n\u003e :warning: **Note:** Spatial has been renamed to SpatialLib due to a conflict with a recently introduced framework by Apple also named Spatial. SPM url is the same. Just use `import SpatialLib` instead of `import Spatial`\n\n## Table of Contents\n- [What is it](#what-is-it)\n- [How does it work](#how-does-it-work)\n- [How do I get it](#how-do-i-get-it)\n- [Gotchas](#gotchas)\n- [Example](#example)\n- [Todo](#todo)\n\n### What is it\nHassle-free AutoLayout, tailored for interactivity and animation. Created for how our mental model thinks autolayout works. Not optimized for brevity.\n\n\n### How does it work\n- Spatial is just extensions and enums which enable you to write less boilerplate code\n- Spatial is interchangeable with Vanilla AutoLayout\n- Spatial comes with examples how you can animate with AutoLayout\n- Spatial uses plain and simple math under the hood.\n\n### How do I get it\n- SPM `\"https://github.com/eonist/Spatial.git\"` `branch: \"master\"`\n- Manual Open `Spatial.xcodeproj`\n\n### Gotchas:\n- SnapKit and Carthography are too clever and caters to too many facets of autolayout. This library is just a simple extension that does basic autolayout while reducing the setup time in half.\n\n### Example:\n\n```swift\n// One-liner, single\nbtn1.anchorAndSize(to: self, width: 96, height: 24)\n// Info regarding parameters and their meaning and effects\nbtn1.anchorAndSize(to: button, // to what other AutoLayout element should self anchor and size to\n\t\tsizeTo: self, // inherit size of another AutoLayout element, overrides to param\n\t\twidth: 100, // override sizeTo with constant\n\t\theight: 50, // override sizeTo with constant\n\t\talign: .topCenter, // decides where the pivot of self should be\n\t\talignTo: .bottomCenter, // decides to where self should pivot to\n\t\tmultiplier: .init(width: 1, height: 1), // multiply sizeTo, or constants\n\t\toffset: .init(x: 0, y: 20), // append constant to current position\n\t\tsizeOffset: .init(width: -20, height: 0), // append constant to current size\n\t   \tuseMargin: false) // adher to other autolayouts margin\n\n// Long-hand, single\nbtn1.activateAnchorAndSize { view in\n\tlet a = Constraint.anchor(view, to: self)\n\tlet s = Constraint.size(view, width: 96, height: 24)\n\treturn (a, s)\n}\n// or simpler:\nbtn1.activateAnchorAndSize {\n\tConstraint.anchor($0, to: self),\n\tConstraint.size($0, width: 96, height: 24)\n}\n```\n\n```swift\n// Short-hand, bulk\n[btn1, btn2, btn3].distributeAndSize(dir: .vertical, width: 96, height: 24)\n\n// Long-hand, bulk\n[btn1,btn2,btn3].activateAnchorsAndSizes { views in\n   let anchors = Constraint.distribute(vertically: views, align: .topLeft)\n   let sizes = views.map { Constraint.size($0, size: .init(width: 96, height: 42)) }\n   return (anchors, sizes)\n}\n```\n\n```swift\n// Pin something between something\n$0.activateConstraints { view in\n   let tl = Constraint.anchor(view, to: self, align: .topLeft, alignTo: .topLeft)\n   let br = Constraint.anchor(view, to: viewFinderView, align: .bottomRight, alignTo: .topRight)\n   return [tl.x, tl.y, br.x, br.y] // pins a view to the TR of the parent and BL of another sibling-view\n}\n```\n\n```swift\n// Animation\nbtn.animate(to: 100,align: left, alignTo: .left)\n```\n\n```swift\n// Distribute\n// |[--][--][--][--][--]|\n[label1, label2, label3].activateAnchorsAndSizes { views in // for anim: applyAnchorsAndSizes\n   let anchors = Constraint.distribute(vertically: views, align: .left) // there is also: horizontally\n   let sizes = views.map{ Constraint.size($0, toView: self.frame.width, height: 48)) }\n   return (anchors, sizes)\n}\n```\n\n```swift\n// SpaceAround\n// |--[]--[]--[]--[]--[]--|\nlet views: [ConstraintView] = [UIColor.purple, .orange, .red].map {\n   let view: ConstraintView = .init(frame: .zero)\n   self.addSubview(view)\n   view.backgroundColor = $0\n   return view\n}\nviews.applySizes(width: 120, height: 48)\nviews.applyAnchors(to: self, align: .top, alignTo: .top, offset: 20)\nviews.spaceAround(dir: .hor, parent: self)\n```\n\n```swift\n// Space between\n// |[]--[]--[]--[]--[]|\nviews.applySizes(width: 120, height: 48)\nviews.applyAnchors(to: self, align: .top, alignTo: .top, offset: 20)\nviews.spaceBetween(dir: .horizontal, parent: self, inset:x)\n```\n\n### Todo:\n- Complete the spaceAround and spaceBetween methods ✅\n- Add macOS support ✅\n- Document every param in every declaration (Since the API is more stable now) ✅\n- Make examples with AutoLayout margins not\n- Add methods for applyAnchor for horizontal and vertical types\n- Consider renaming anchor and size to pin and fit\n- Write problem / solution statment in readme?\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feonist%2Fspatial","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feonist%2Fspatial","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feonist%2Fspatial/lists"}