{"id":27808253,"url":"https://github.com/fabernovel/compositionallayoutdsl","last_synced_at":"2025-09-13T00:43:56.366Z","repository":{"id":43491924,"uuid":"355188342","full_name":"faberNovel/CompositionalLayoutDSL","owner":"faberNovel","description":"CompositionalLayoutDSL, library to simplify the creation of UICollectionViewCompositionalLayout. It wraps the UIKit API and makes the code shorter and easier to read.","archived":false,"fork":false,"pushed_at":"2023-10-02T16:26:48.000Z","size":4470,"stargazers_count":80,"open_issues_count":1,"forks_count":7,"subscribers_count":21,"default_branch":"main","last_synced_at":"2025-04-27T14:02:43.450Z","etag":null,"topics":["appkit","dsl","ios","macos","swift","tvos","uikit"],"latest_commit_sha":null,"homepage":"https://fabernovel.github.io/2021-05-18/simplify-collection-view-compositional-layout-with-a-dsl","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/faberNovel.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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":"2021-04-06T12:55:11.000Z","updated_at":"2025-02-06T12:09:43.000Z","dependencies_parsed_at":"2022-08-21T03:20:55.677Z","dependency_job_id":"b00c3e85-0b19-42f8-9918-323d3d6e1118","html_url":"https://github.com/faberNovel/CompositionalLayoutDSL","commit_stats":{"total_commits":108,"total_committers":2,"mean_commits":54.0,"dds":0.01851851851851849,"last_synced_commit":"4c1cb10c39ff5a4f3cfb2dfdbca431956ccf172f"},"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/faberNovel%2FCompositionalLayoutDSL","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/faberNovel%2FCompositionalLayoutDSL/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/faberNovel%2FCompositionalLayoutDSL/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/faberNovel%2FCompositionalLayoutDSL/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/faberNovel","download_url":"https://codeload.github.com/faberNovel/CompositionalLayoutDSL/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251858550,"owners_count":21655406,"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":["appkit","dsl","ios","macos","swift","tvos","uikit"],"created_at":"2025-05-01T10:25:38.103Z","updated_at":"2025-05-01T10:25:41.018Z","avatar_url":"https://github.com/faberNovel.png","language":"Swift","readme":"[![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2FfaberNovel%2FCompositionalLayoutDSL%2Fbadge%3Ftype%3Dswift-versions)](https://swiftpackageindex.com/faberNovel/CompositionalLayoutDSL)\n[![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2FfaberNovel%2FCompositionalLayoutDSL%2Fbadge%3Ftype%3Dplatforms)](https://swiftpackageindex.com/faberNovel/CompositionalLayoutDSL)\n\n# CompositionalLayoutDSL\n\nCompositionalLayoutDSL is a Swift library. It makes easier to create compositional layout for collection view.\n\n---\n\n- [Requirements](#requirements)\n- [Documentation](#documentation)\n- [Getting started](#getting-started)\n- [Installation](#installation)\n    - [CocoaPods](#cocoapods)\n    - [Swift Package Manager](#swift-package-manager)\n    - [Credits](#credits)\n- [Behind the scene](#behind-the-scene)\n    - [Core structs](#core-structs)\n    - [Modifiers](#modifiers)\n    - [DSL to UIKit Conversion](#dsl-to-uikit-conversion)\n- [License](#license)\n\n## Requirements\n\n`CompositionalLayoutDSL` is written in Swift 5. Compatible with iOS 13.0+, tvOS 13.0+ and macOS 10.15+.\n\n## Documentation\n\nAn online documentation can be found [here](https://fabernovel.github.io/CompositionalLayoutDSL/documentation/compositionallayoutdsl/).\n\nThe documentation can be build locally and seen with this command:\n```bash\nswift package --disable-sandbox preview-documentation --target CompositionalLayoutDSL\n```\n\n## Getting started\n\nTo see some usage of this library you can look to:\n- An [example project](./Example/) is available and contains an iOS and a macOS application.\n- The [testing target](./CompositionalLayoutDSLTests) which contains snapshot tests. The tests verify that the DSL behave the same way of using UIKit directly, the snapshot can be found [here](./CompositionalLayoutDSLTests/LayoutTests/__Snapshots__/).\n\nHere some layout examples:\n\n\u003ctable\u003e\n\u003ctr\u003e\n\u003ctd\u003eScreenshot\u0026nbsp;for\u0026nbsp;the\u0026nbsp;layout\u0026nbsp;code\u003c/td\u003e\u003ctd\u003eLayout code\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003cimg src=\"./CompositionalLayoutDSLTests/LayoutTests/__Snapshots__/GroupDSLTests/testInnerGroups.2.png\" /\u003e\u003c/td\u003e\n\u003ctd\u003e\n\nHere an example from the test target: [GroupDSLTests.swift (contains the same layout without the DSL)](./CompositionalLayoutDSLTests/LayoutTests/GroupDSLTests.swift)\n```swift\nlet layout = CompositionalLayout { section, environment in\n    Section {\n        HGroup {\n            Item(width: .fractionalWidth(1 / 3))\n                .contentInsets(trailing: 4)\n            VGroup(count: 2) { Item() }\n                .width(.fractionalWidth(1 / 3))\n                .interItemSpacing(.fixed(8))\n                .contentInsets(horizontal: 4)\n            VGroup(count: 3) { Item() }\n                .width(.fractionalWidth(1 / 3))\n                .interItemSpacing(.fixed(8))\n                .contentInsets(leading: 4)\n        }\n        .height(.absolute(100))\n        .contentInsets(horizontal: 16)\n    }\n    .interGroupSpacing(8)\n}\n.interSectionSpacing(8)\n\n// Apply to a collection view\ncollectionView.setCollectionViewLayout(layout, animated: false)\n// or\ncollectionView.collectionViewLayout = LayoutBuilder { layout }\n```\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003cimg src=\"./images/GettingStartedExample.jpg\"/\u003e\u003c/td\u003e\n\u003ctd\u003e\n\nHere is an example from the Example project: [GettingStartedCompositionalLayout.swift](./Example/CompositionalLayoutDSL_Example_iOS/App/ShowcaseViewController/CompositionalLayout/GettingStartedCompositionalLayout.swift)\n\n```swift\ncollectionView.collectionViewLayout = LayoutBuilder {\n    Section {\n        VGroup(count: 1) { Item() }\n            .height(.fractionalWidth(0.3))\n            .width(.fractionalWidth(0.3))\n            .interItemSpacing(.fixed(8))\n    }\n    .interGroupSpacing(8)\n    .contentInsets(horizontal: 16, vertical: 8)\n    .orthogonalScrollingBehavior(.continuous)\n    .supplementariesFollowContentInsets(false)\n    .boundarySupplementaryItems {\n        BoundarySupplementaryItem(elementKind: UICollectionView.elementKindSectionHeader)\n            .height(.absolute(30))\n            .alignment(.top)\n            .pinToVisibleBounds(true)\n    }\n}\n```\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e\n\n## Installation\n\n### Cocoapods\n\nTo integrate `CompositionalLayoutDSL` into your Xcode project using CocoaPods, specify it in your Podfile:\n```\npod 'CompositionalLayoutDSL', '~\u003e 0.2.0'\n```\n\n### Swift Package Manager\n\n`CompositionalLayoutDSL` can be installed as a Swift Package with Xcode 11 or higher. To install it, add a package using Xcode or a dependency to your Package.swift file:\n\n```swift\n.package(url: \"https://github.com/faberNovel/CompositionalLayoutDSL\", from: \"0.2.0\")\n```\n\n## Behind the scene\n\nHere some explanation of how this library work, it can be divided in 3 parts: the role of the core blocks,\nhow does the modifiers works, and how the conversion to the UIKit world is handled\n\n### Core structs\n\nThis library contains all the core structs for creating a compositional layout, here the exhaustive list:\n- `Configuration`\n- `Section`\n- `HGroup`\n- `VGroup`\n- `CustomGroup`\n- `Item`\n- `DecorationItem`\n- `SupplementaryItem`\n- `BoundarySupplementaryItem`\n\nEach of those building blocks conforms to their respective public protocol and handle the immutable properties\nof their associated UIKit object.\n\nFor example `SupplementaryItem` conforms to `LayoutSupplementaryItem` and handles the immutable\nproperties of `NSCollectionLayoutSupplementaryItem`, which are:\n`layoutSize`, `elementKind`, `containerAnchor` and `itemAnchor`.\n\nThose immutable properties can only be changed on those core structs, and are not available globally\non `LayoutSupplementaryItem`. This is the same for all core structs.\n\n### Modifiers\n\nMutable properties of the UIKit objects are handled by the extension of the `Layout...` protocols.\nHere some example: `contentInset(_:)`, `edgeSpacing(_:)`, `zIndex(_:)`, `interItemSpacing(_:)`, `scrollDirection(_:)`.\nChanging those mutable values are done with [modifiers](./Sources/CompositionalLayoutDSL/Internal/ModifiedLayout),\nwhich are internal struct (e.g. [`ValueModifiedLayoutItem`](./Sources/CompositionalLayoutDSL/Internal/ModifiedLayout/ModifiedLayoutItem.swift)).\nAs those methods provided through extension of the `Layout...` protocol, their are available for custom\nelements outside the library.\n\nSomething to note is once you applied a modifier for mutable properties you no longer have an `Item`,\nbut you have a `LayoutItem`, so changing immutable values will not be possible afterward.\n\n### DSL to UIKit Conversion\n\nFinally once we have combined the core structs and the modifiers, the last step is the conversion of the `Layout...` to the UIKit world.\nThis is done with [builders](./Sources/CompositionalLayoutDSL/Internal/Builders), they all work in a similar way.\nAs an example here how `ItemBuilder` works:\n- It tries to find a layoutItem conforming to the internal protocol `BuildableItem` by calling repeatedly `.layoutItem` .\n- Then it calls `makeItem()` on the candidate and returns it\n\n**⚠️ Warning ⚠️**\n\nThis means that only internal struct can be converted to a UIKit object, if you try to define a custom `LayoutItem`\nand write `var layoutItem: LayoutItem { self }` like it is done internally, it will cause an infinite loop inside the ItemBuilder.\n\nUser of the library **needs** to base their custom layout on core structs provided by this library.\n\n\n## Credits\n\nCompositionalLayoutDSL is owned and maintained by [Fabernovel](https://www.fabernovel.com/). You can follow us on Twitter at [@Fabernovel](https://twitter.com/FabernovelTech).\n\n## License\n\n`CompositionalLayoutDSL` is available under the MIT license. See the LICENSE file for more info.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffabernovel%2Fcompositionallayoutdsl","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffabernovel%2Fcompositionallayoutdsl","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffabernovel%2Fcompositionallayoutdsl/lists"}