├── .github
└── workflows
│ ├── CocoaPodsRelease.yml
│ └── swift.yml
├── .gitignore
├── Demo_MondrianLayout
├── AppDelegate.swift
├── Assets.xcassets
│ ├── AccentColor.colorset
│ │ └── Contents.json
│ ├── AppIcon.appiconset
│ │ └── Contents.json
│ └── Contents.json
├── Base.lproj
│ └── LaunchScreen.storyboard
├── Book.Background.swift
├── Book.Classic.swift
├── Book.HStackBlock.swift
├── Book.LayoutContainer.swift
├── Book.Manager.swift
├── Book.Mondrian.swift
├── Book.Overlay.swift
├── Book.RelativeBlock.swift
├── Book.SafeArea.swift
├── Book.Sizing.swift
├── Book.VGridBlock.swift
├── Book.VStackBlock.swift
├── Book.ViewController.swift
├── Book.ZStackBlock.swift
├── Book.swift
├── CGSize+.swift
├── ExampleView.swift
├── Extensions.swift
├── Info.plist
├── InstagramPostView.swift
├── RootContainerViewController.swift
├── SwiftUIComparison.swift
└── UIColor+Mondrian.swift
├── Gemfile
├── Gemfile.lock
├── LICENSE
├── MondrianLayout.podspec
├── MondrianLayout.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ ├── IDEWorkspaceChecks.plist
│ │ └── swiftpm
│ │ └── Package.resolved
└── xcshareddata
│ └── xcschemes
│ ├── Demo_MondrianLayout.xcscheme
│ ├── MondrianLayout.xcscheme
│ ├── Tests-Record.xcscheme
│ └── Tests.xcscheme
├── MondrianLayout
├── Classic
│ ├── LayoutDescriptor.swift
│ └── MondrianArrayBuilder.swift
├── Descriptors
│ ├── DimensionDescriptor.swift
│ ├── Edge.swift
│ ├── LayoutBuilderContext.swift
│ ├── Optimization.swift
│ ├── VHStackContentBuilder.swift
│ ├── _LayoutBlockNode.swift
│ └── _LayoutBlockType.swift
├── EntryPoint.swift
├── Extensions
│ ├── NSLayoutConstraint+.swift
│ ├── UILayoutGuide+Mondrian.swift
│ └── UIView+Mondrian.swift
├── Internal
│ ├── Utils.swift
│ └── _LayoutElement.swift
├── LayoutBlocks
│ ├── BackgroundBlock.swift
│ ├── HStackBlock.swift
│ ├── LayoutContainer.swift
│ ├── LayoutGuideBlock.swift
│ ├── OverlayBlock.swift
│ ├── RelativeBlock.swift
│ ├── StackingSpacer.swift
│ ├── VGridBlock.swift
│ ├── VStackBlock.swift
│ ├── ViewBlock.swift
│ └── ZStackBlock.swift
├── Manager
│ └── LayoutManager.swift
└── MondrianNamespace.swift
├── Package.swift
├── README.md
├── RevealServer.xcframework
├── Info.plist
├── Scripts
│ └── integrate_revealserver.sh
├── _CodeSignature
│ ├── CodeDirectory
│ ├── CodeRequirements
│ ├── CodeRequirements-1
│ ├── CodeResources
│ └── CodeSignature
├── ios-arm64_armv7
│ └── RevealServer.framework
│ │ ├── Headers
│ │ └── RevealServer.h
│ │ ├── Info.plist
│ │ ├── Modules
│ │ └── module.modulemap
│ │ ├── RevealServer
│ │ ├── Scripts
│ │ └── integrate_revealserver.sh
│ │ └── _CodeSignature
│ │ └── CodeResources
├── ios-arm64_i386_x86_64-simulator
│ └── RevealServer.framework
│ │ ├── Headers
│ │ └── RevealServer.h
│ │ ├── Info.plist
│ │ ├── Modules
│ │ └── module.modulemap
│ │ ├── RevealServer
│ │ ├── Scripts
│ │ └── integrate_revealserver.sh
│ │ └── _CodeSignature
│ │ └── CodeResources
├── ios-arm64_x86_64-maccatalyst
│ └── RevealServer.framework
│ │ ├── Headers
│ │ ├── Modules
│ │ ├── Resources
│ │ ├── RevealServer
│ │ └── Versions
│ │ ├── A
│ │ ├── Headers
│ │ │ └── RevealServer.h
│ │ ├── Modules
│ │ │ └── module.modulemap
│ │ ├── Resources
│ │ │ ├── Info.plist
│ │ │ └── Scripts
│ │ │ │ └── integrate_revealserver.sh
│ │ ├── RevealServer
│ │ └── _CodeSignature
│ │ │ └── CodeResources
│ │ └── Current
├── ios-x86_64-maccatalyst
│ └── RevealServer.framework
│ │ ├── Headers
│ │ ├── Modules
│ │ ├── Resources
│ │ ├── RevealServer
│ │ └── Versions
│ │ ├── A
│ │ ├── Headers
│ │ │ └── RevealServer.h
│ │ ├── Modules
│ │ │ └── module.modulemap
│ │ ├── Resources
│ │ │ ├── Info.plist
│ │ │ └── Scripts
│ │ │ │ └── integrate_revealserver.sh
│ │ ├── RevealServer
│ │ └── _CodeSignature
│ │ │ └── CodeResources
│ │ └── Current
├── tvos-arm64
│ └── RevealServer.framework
│ │ ├── Headers
│ │ └── RevealServer.h
│ │ ├── Info.plist
│ │ ├── Modules
│ │ └── module.modulemap
│ │ ├── RevealServer
│ │ ├── Scripts
│ │ └── integrate_revealserver.sh
│ │ └── _CodeSignature
│ │ └── CodeResources
└── tvos-arm64_x86_64-simulator
│ └── RevealServer.framework
│ ├── Headers
│ └── RevealServer.h
│ ├── Info.plist
│ ├── Modules
│ └── module.modulemap
│ ├── RevealServer
│ ├── Scripts
│ └── integrate_revealserver.sh
│ └── _CodeSignature
│ └── CodeResources
├── Tests
├── ClassicTests.swift
├── HStackTests.swift
├── Info.plist
├── LayoutDescriptorTests.swift
├── OverlayTests.swift
├── RelativeTests.swift
├── SizingTests.swift
├── SyntaxTests.swift
├── Tests.swift
├── VGridTests.swift
├── VStackTests.swift
├── ZStackTests.swift
└── __Snapshots__
│ ├── ClassicTests
│ └── test_multiplier_constraints.1.png
│ ├── HStackTests
│ ├── test_additional_spacing.1.png
│ └── test_mixing_spacer.1.png
│ ├── LayoutDescriptorTests
│ ├── test_layout_0.1.png
│ ├── test_layout_center.1.png
│ └── test_layout_edge.1.png
│ ├── OverlayTests
│ ├── test_1.1.png
│ └── test_2.1.png
│ ├── RelativeTests
│ ├── test_accumulate_padding.1.png
│ ├── test_accumulate_relative.1.png
│ └── test_centering_in_ambiguous.1.png
│ ├── SizingTests
│ └── test_sizing.1.png
│ ├── SyntaxTests
│ ├── test_hStack.1.png
│ └── test_vStack.1.png
│ ├── Tests
│ ├── test_1.1.png
│ └── test_mondrian.1.png
│ ├── VGridTests
│ └── test_basic.1.png
│ ├── VStackTests
│ ├── test_additional_spacing.1.png
│ ├── test_enter.1.png
│ ├── test_including_layoutGuide.1.png
│ ├── test_label_alignment.1.png
│ ├── test_leading.1.png
│ ├── test_mixing_spacer.1.png
│ └── test_trailing.1.png
│ └── ZStackTests
│ ├── test_alignSelf.1.png
│ ├── test_expandsElementIfCanBeExpanding.1.png
│ ├── test_expandsElementWithRelative.1.png
│ └── test_minimum_padding.1.png
└── fastlane
├── Appfile
├── Fastfile
└── README.md
/.github/workflows/CocoaPodsRelease.yml:
--------------------------------------------------------------------------------
1 | name: Release
2 |
3 | on:
4 | push:
5 | tags:
6 | - "*"
7 |
8 | jobs:
9 | pod-trunk-push:
10 | runs-on: macOS-11
11 | steps:
12 | - uses: maxim-lobanov/setup-xcode@v1.1
13 | with:
14 | xcode-version: "12.5"
15 | - uses: actions/checkout@v2
16 | - name: Deploy
17 | env:
18 | COCOAPODS_TRUNK_TOKEN: ${{ secrets.COCOAPODS_TRUNK_TOKEN }}
19 | run: pod trunk push --allow-warnings
20 |
--------------------------------------------------------------------------------
/.github/workflows/swift.yml:
--------------------------------------------------------------------------------
1 | name: Swift
2 |
3 | on:
4 | push:
5 | branches: "*"
6 | pull_request:
7 | branches: "*"
8 |
9 | jobs:
10 | test:
11 | runs-on: macos-11
12 |
13 | steps:
14 | - uses: maxim-lobanov/setup-xcode@v1.1
15 | with:
16 | xcode-version: "12.5"
17 | - uses: actions/checkout@v2
18 | - name: Run test
19 | run: fastlane test_project
20 | pod-lint:
21 | runs-on: macos-11
22 |
23 | steps:
24 | - uses: maxim-lobanov/setup-xcode@v1.1
25 | with:
26 | xcode-version: "12.5"
27 | - uses: actions/checkout@v2
28 | - name: Run lint
29 | run: pod lib lint --allow-warnings
30 | swift-pm:
31 | runs-on: macos-11
32 |
33 | steps:
34 | - uses: maxim-lobanov/setup-xcode@v1.1
35 | with:
36 | xcode-version: "12.5"
37 | - uses: actions/checkout@v2
38 | - name: Build
39 | run: swift build -Xswiftc "-sdk" -Xswiftc "`xcrun --sdk iphoneos --show-sdk-path`" -Xswiftc "-target" -Xswiftc "arm64-apple-ios14.0"
40 |
41 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # Created by https://www.toptal.com/developers/gitignore/api/swift
3 | # Edit at https://www.toptal.com/developers/gitignore?templates=swift
4 |
5 | ### Swift ###
6 | # Xcode
7 | #
8 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
9 |
10 | ## User settings
11 | xcuserdata/
12 |
13 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)
14 | *.xcscmblueprint
15 | *.xccheckout
16 |
17 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)
18 | build/
19 | DerivedData/
20 | *.moved-aside
21 | *.pbxuser
22 | !default.pbxuser
23 | *.mode1v3
24 | !default.mode1v3
25 | *.mode2v3
26 | !default.mode2v3
27 | *.perspectivev3
28 | !default.perspectivev3
29 |
30 | ## Obj-C/Swift specific
31 | *.hmap
32 |
33 | ## App packaging
34 | *.ipa
35 | *.dSYM.zip
36 | *.dSYM
37 |
38 | ## Playgrounds
39 | timeline.xctimeline
40 | playground.xcworkspace
41 |
42 | # Swift Package Manager
43 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
44 | # Packages/
45 | # Package.pins
46 | # Package.resolved
47 | # *.xcodeproj
48 | # Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata
49 | # hence it is not needed unless you have added a package configuration file to your project
50 | # .swiftpm
51 |
52 | .build/
53 |
54 | # CocoaPods
55 | # We recommend against adding the Pods directory to your .gitignore. However
56 | # you should judge for yourself, the pros and cons are mentioned at:
57 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
58 | Pods/
59 | # Add this line if you want to avoid checking in source code from the Xcode workspace
60 | # *.xcworkspace
61 |
62 | # Carthage
63 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
64 | # Carthage/Checkouts
65 |
66 | Carthage/Build/
67 |
68 | # Add this lines if you are using Accio dependency management (Deprecated since Xcode 12)
69 | # Dependencies/
70 | # .accio/
71 |
72 | # fastlane
73 | # It is recommended to not store the screenshots in the git repo.
74 | # Instead, use fastlane to re-generate the screenshots whenever they are needed.
75 | # For more information about the recommended setup visit:
76 | # https://docs.fastlane.tools/best-practices/source-control/#source-control
77 |
78 | fastlane/report.xml
79 | fastlane/Preview.html
80 | fastlane/screenshots/**/*.png
81 | fastlane/test_output
82 |
83 | # Code Injection
84 | # After new code Injection tools there's a generated folder /iOSInjectionProject
85 | # https://github.com/johnno1962/injectionforxcode
86 |
87 | iOSInjectionProject/
88 |
89 | .swiftpm
90 |
91 | .DS_Store
92 | # End of https://www.toptal.com/developers/gitignore/api/swift
93 |
--------------------------------------------------------------------------------
/Demo_MondrianLayout/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | @UIApplicationMain
4 | class AppDelegate: UIResponder, UIApplicationDelegate {
5 |
6 | var window: UIWindow?
7 |
8 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
9 |
10 | let newWindow = UIWindow()
11 | newWindow.rootViewController = RootContainerViewController()
12 | newWindow.makeKeyAndVisible()
13 | self.window = newWindow
14 | return true
15 | }
16 |
17 | }
18 |
19 |
--------------------------------------------------------------------------------
/Demo_MondrianLayout/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Demo_MondrianLayout/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "scale" : "2x",
6 | "size" : "20x20"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "scale" : "3x",
11 | "size" : "20x20"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "scale" : "2x",
16 | "size" : "29x29"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "scale" : "3x",
21 | "size" : "29x29"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "scale" : "2x",
26 | "size" : "40x40"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "scale" : "3x",
31 | "size" : "40x40"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "scale" : "2x",
36 | "size" : "60x60"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "scale" : "3x",
41 | "size" : "60x60"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "scale" : "1x",
46 | "size" : "20x20"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "scale" : "2x",
51 | "size" : "20x20"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "scale" : "1x",
56 | "size" : "29x29"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "scale" : "2x",
61 | "size" : "29x29"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "scale" : "1x",
66 | "size" : "40x40"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "scale" : "2x",
71 | "size" : "40x40"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "scale" : "1x",
76 | "size" : "76x76"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "scale" : "2x",
81 | "size" : "76x76"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "scale" : "2x",
86 | "size" : "83.5x83.5"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "scale" : "1x",
91 | "size" : "1024x1024"
92 | }
93 | ],
94 | "info" : {
95 | "author" : "xcode",
96 | "version" : 1
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/Demo_MondrianLayout/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Demo_MondrianLayout/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/Demo_MondrianLayout/Book.Background.swift:
--------------------------------------------------------------------------------
1 | import StorybookKit
2 | import UIKit
3 |
4 | import MondrianLayout
5 |
6 | var _book_background: BookView {
7 | BookNavigationLink(title: "Background") {
8 | BookPreview {
9 | ExampleView(width: nil, height: nil) { (view: UIView) in
10 |
11 | Mondrian.buildSubviews(on: view) {
12 | VStackBlock {
13 | UIView.mock(
14 | backgroundColor: .mondrianYellow,
15 | preferredSize: .smallSquare
16 | )
17 | UIView.mock(
18 | backgroundColor: .mondrianYellow,
19 | preferredSize: .smallSquare
20 | )
21 | UIView.mock(
22 | backgroundColor: .mondrianYellow,
23 | preferredSize: .smallSquare
24 | )
25 | }
26 | .padding(10)
27 | .background(UIView.mock(backgroundColor: .mondrianGray))
28 | }
29 |
30 | }
31 | }
32 |
33 | BookPreview {
34 | ExampleView(width: nil, height: nil) { (view: UIView) in
35 | Mondrian.buildSubviews(on: view) {
36 | VStackBlock(spacing: 2) {
37 | UIView.mock(
38 | backgroundColor: .mondrianYellow,
39 | preferredSize: .smallSquare
40 | )
41 | UIView.mock(
42 | backgroundColor: .mondrianYellow,
43 | preferredSize: .smallSquare
44 | )
45 | UIView.mock(
46 | backgroundColor: .mondrianYellow,
47 | preferredSize: .smallSquare
48 | )
49 |
50 | HStackBlock(spacing: 2) {
51 | UIView.mock(
52 | backgroundColor: .mondrianBlue,
53 | preferredSize: .smallSquare
54 | )
55 | UIView.mock(
56 | backgroundColor: .mondrianBlue,
57 | preferredSize: .smallSquare
58 | )
59 | UIView.mock(
60 | backgroundColor: .mondrianBlue,
61 | preferredSize: .smallSquare
62 | )
63 | }
64 |
65 | }
66 | .padding(10)
67 | .background(UIView.mock(backgroundColor: .mondrianGray))
68 | }
69 | }
70 | }
71 |
72 | BookPreview {
73 | ExampleView(width: nil, height: nil) { (view: UIView) in
74 | Mondrian.buildSubviews(on: view) {
75 | VStackBlock {
76 | UIView.mock(
77 | backgroundColor: .mondrianYellow,
78 | preferredSize: .smallSquare
79 | )
80 | UIView.mock(
81 | backgroundColor: .mondrianYellow,
82 | preferredSize: .smallSquare
83 | )
84 | UIView.mock(
85 | backgroundColor: .mondrianYellow,
86 | preferredSize: .smallSquare
87 | )
88 | .viewBlock
89 | .padding(10)
90 | .background(UIView.mock(backgroundColor: .mondrianGray))
91 | }
92 | .padding(10)
93 | .background(UIView.mock(backgroundColor: .mondrianGray))
94 | }
95 | }
96 | }
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/Demo_MondrianLayout/Book.LayoutContainer.swift:
--------------------------------------------------------------------------------
1 | import MondrianLayout
2 | import StorybookKit
3 | import UIKit
4 |
5 | var _book_layoutContainer: BookView {
6 |
7 | BookNavigationLink(title: "LayoutContainer") {
8 |
9 | BookPreview {
10 |
11 | let view = UIView.mock()
12 | Mondrian.buildSubviews(on: view) {
13 | LayoutContainer(attachedSafeAreaEdges: .all) {
14 | VStackBlock {
15 |
16 | }
17 | }
18 | }
19 | return view
20 |
21 | }
22 |
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/Demo_MondrianLayout/Book.Manager.swift:
--------------------------------------------------------------------------------
1 | import MondrianLayout
2 | import StorybookKit
3 | import UIKit
4 |
5 | var _book_layoutManager: BookView {
6 | BookNavigationLink(title: "LayoutManager") {
7 |
8 | let manager = LayoutManager()
9 | var counter = 0
10 |
11 | BookPreview {
12 | ExampleView(width: 200, height: 200) { view in
13 |
14 | let box1 = UIView.mock(backgroundColor: .neon(.cyan))
15 | let box2 = UIView.mock(backgroundColor: .neon(.cyan))
16 | let box3 = UIView.mock(backgroundColor: .neon(.cyan))
17 |
18 | manager.setup(on: view) {
19 |
20 | if counter % 2 == 0 {
21 |
22 | VStackBlock {
23 | box1
24 | .viewBlock
25 | .size(.smallSquare)
26 |
27 | box2
28 | .viewBlock
29 | .size(.smallSquare)
30 |
31 | box3
32 | .viewBlock
33 | .size(.smallSquare)
34 |
35 | StackingSpacer(minLength: 0)
36 | }
37 | } else {
38 |
39 | HStackBlock {
40 | box1
41 | .viewBlock
42 | .size(.largeSquare)
43 |
44 | box2
45 | .viewBlock
46 | .size(.largeSquare)
47 |
48 | box3
49 | .viewBlock
50 | .size(.largeSquare)
51 |
52 | StackingSpacer(minLength: 0)
53 | }
54 | }
55 |
56 | }
57 |
58 | }
59 | }
60 | .addButton(
61 | "Update",
62 | handler: { view in
63 | counter += 1
64 | manager.reloadLayout()
65 | }
66 | )
67 | .addButton(
68 | "Update Animated",
69 | handler: { view in
70 | counter += 1
71 | UIViewPropertyAnimator(duration: 1.2, dampingRatio: 0.9) {
72 | manager.reloadLayout()
73 | view.layoutIfNeeded()
74 | }
75 | .startAnimation()
76 | }
77 | )
78 | .title("LayoutManager")
79 |
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/Demo_MondrianLayout/Book.Overlay.swift:
--------------------------------------------------------------------------------
1 | import MondrianLayout
2 | import StorybookKit
3 | import UIKit
4 |
5 | var _book_overlay: BookView {
6 | BookNavigationLink(title: "Overlay") {
7 |
8 | BookPreview {
9 | ExampleView(width: nil, height: nil) { (view: UIView) in
10 |
11 | Mondrian.buildSubviews(on: view) {
12 | UIView.mock(
13 | backgroundColor: .mondrianYellow,
14 | preferredSize: .init(width: 100, height: 100)
15 | )
16 | .viewBlock
17 | .overlay(
18 | UIView.mock(backgroundColor: .layeringColor)
19 | .viewBlock
20 | .overlay(
21 | UIView.mock(backgroundColor: .layeringColor)
22 | .viewBlock
23 | .padding(10)
24 | )
25 | .padding(10)
26 | )
27 | }
28 | }
29 | }
30 |
31 |
32 | BookPreview {
33 | ExampleView(width: nil, height: nil) { (view: UIView) in
34 | Mondrian.buildSubviews(on: view) {
35 | UIView.mock(
36 | backgroundColor: .mondrianYellow,
37 | preferredSize: .init(width: 100, height: 100)
38 | )
39 | .viewBlock
40 | .overlay(
41 | UIView.mock(backgroundColor: .layeringColor)
42 | .viewBlock
43 | .overlay(
44 | UIView.mock(backgroundColor: .layeringColor)
45 | .viewBlock
46 | .padding(10)
47 | )
48 | .padding(10)
49 | )
50 | }
51 | }
52 | }
53 |
54 | BookPreview {
55 | ExampleView(width: nil, height: nil) { (view: UIView) in
56 | Mondrian.buildSubviews(on: view) {
57 | VStackBlock {
58 | UIView.mock(
59 | backgroundColor: .mondrianYellow,
60 | preferredSize: .smallSquare
61 | )
62 | UIView.mock(
63 | backgroundColor: .mondrianYellow,
64 | preferredSize: .smallSquare
65 | )
66 | UIView.mock(
67 | backgroundColor: .mondrianYellow,
68 | preferredSize: .smallSquare
69 | )
70 | }
71 | .padding(10)
72 | .overlay(UIView.mock(backgroundColor: .layeringColor))
73 | }
74 | }
75 | }
76 |
77 | BookPreview {
78 | ExampleView(width: nil, height: nil) { (view: UIView) in
79 | Mondrian.buildSubviews(on: view) {
80 | VStackBlock(spacing: 2) {
81 | UIView.mock(
82 | backgroundColor: .mondrianYellow,
83 | preferredSize: .smallSquare
84 | )
85 | UIView.mock(
86 | backgroundColor: .mondrianYellow,
87 | preferredSize: .smallSquare
88 | )
89 | UIView.mock(
90 | backgroundColor: .mondrianYellow,
91 | preferredSize: .smallSquare
92 | )
93 |
94 | HStackBlock(spacing: 2) {
95 | UIView.mock(
96 | backgroundColor: .mondrianBlue,
97 | preferredSize: .smallSquare
98 | )
99 | UIView.mock(
100 | backgroundColor: .mondrianBlue,
101 | preferredSize: .smallSquare
102 | )
103 | UIView.mock(
104 | backgroundColor: .mondrianBlue,
105 | preferredSize: .smallSquare
106 | )
107 | }
108 |
109 | }
110 | .padding(10)
111 | .overlay(UIView.mock(backgroundColor: .layeringColor))
112 | }
113 | }
114 | }
115 |
116 | BookPreview {
117 | ExampleView(width: nil, height: nil) { (view: UIView) in
118 | Mondrian.buildSubviews(on: view) {
119 | VStackBlock {
120 | UIView.mock(
121 | backgroundColor: .mondrianYellow,
122 | preferredSize: .smallSquare
123 | )
124 | UIView.mock(
125 | backgroundColor: .mondrianYellow,
126 | preferredSize: .smallSquare
127 | )
128 | UIView.mock(
129 | backgroundColor: .mondrianYellow,
130 | preferredSize: .smallSquare
131 | )
132 | .viewBlock
133 | .padding(10)
134 | .overlay(UIView.mock(backgroundColor: .layeringColor))
135 | }
136 | .padding(10)
137 | .overlay(UIView.mock(backgroundColor: .layeringColor))
138 | }
139 | }
140 | }
141 | }
142 | }
143 |
--------------------------------------------------------------------------------
/Demo_MondrianLayout/Book.RelativeBlock.swift:
--------------------------------------------------------------------------------
1 | import MondrianLayout
2 | import StorybookKit
3 | import UIKit
4 |
5 | extension FixedWidthInteger {
6 |
7 | public var bk: CGFloat {
8 | return 4 * CGFloat(self)
9 | }
10 | }
11 |
12 | var _book_RelativeBlock: BookView {
13 | BookNavigationLink(title: "RelativeBlock") {
14 |
15 | BookPreview {
16 | ExampleView(width: 100, height: 100) { view in
17 | Mondrian.buildSubviews(on: view) {
18 | LayoutContainer(attachedSafeAreaEdges: .all) {
19 | ZStackBlock {
20 |
21 | UIView.mock(backgroundColor: .layeringColor)
22 | .viewBlock.alignSelf(.attach(.all))
23 |
24 | UIView.mock(backgroundColor: .layeringColor, preferredSize: .smallSquare)
25 | .viewBlock
26 | .relative(.bottom, 20)
27 | .relative(.trailing, 20)
28 | }
29 | }
30 | }
31 | }
32 | }
33 |
34 | BookPreview {
35 | ExampleView(width: 100, height: 100) { view in
36 | Mondrian.buildSubviews(on: view) {
37 | ZStackBlock {
38 | UILabel.mockSingleline(text: "A")
39 | .viewBlock
40 | .background(UIView.mock())
41 | .relative(.all, .min(20))
42 | }
43 | .background(UIView.mock())
44 | }
45 | }
46 | }
47 |
48 | BookPreview {
49 | ExampleView(width: 100, height: 100) { view in
50 | Mondrian.buildSubviews(on: view) {
51 | ZStackBlock {
52 | ZStackBlock {
53 | UILabel.mockSingleline(text: "Hello Hello Hello")
54 | .viewBlock
55 | .background(UIView.mock())
56 | }
57 | .padding(20)
58 | }
59 | .background(UIView.mock())
60 | }
61 | }
62 | }
63 |
64 | BookPreview {
65 | ExampleView(width: 100, height: 100) { view in
66 | Mondrian.buildSubviews(on: view) {
67 | ZStackBlock {
68 | ZStackBlock {
69 | UILabel.mockSingleline(text: "Hello Hello Hello")
70 | .viewBlock
71 | }
72 | .relative(.horizontal, 20)
73 | }
74 | }
75 | }
76 | }
77 |
78 | BookPreview {
79 | ExampleView(width: nil, height: nil) { (view: UIView) in
80 | Mondrian.buildSubviews(on: view) {
81 | VStackBlock {
82 | ZStackBlock {
83 | UIView.mock(
84 | backgroundColor: .mondrianYellow,
85 | preferredSize: .init(width: 100, height: 100)
86 | )
87 |
88 | UIView.mock(
89 | backgroundColor: .systemBlue,
90 | preferredSize: .init(width: 10, height: 10)
91 | )
92 | .viewBlock
93 | .relative(.top, 2.bk)
94 | .relative([.trailing], 10)
95 | .padding(20)
96 |
97 | }
98 | }
99 | }
100 | }
101 | }
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/Demo_MondrianLayout/Book.SafeArea.swift:
--------------------------------------------------------------------------------
1 | import MondrianLayout
2 | import StorybookKit
3 | import UIKit
4 |
5 | var _book_SafeArea: BookView {
6 | BookNavigationLink(title: "SafeArea") {
7 |
8 | BookPush(title: "Push") {
9 | AnyViewController { view in
10 | Mondrian.buildSubviews(on: view) {
11 | LayoutContainer(attachedSafeAreaEdges: .vertical) {
12 | VStackBlock {
13 | UIView.mock(
14 | backgroundColor: .layeringColor,
15 | preferredSize: .init(width: 100, height: 100)
16 | )
17 | UIView.mock(
18 | backgroundColor: .layeringColor,
19 | preferredSize: .init(width: 100, height: 100)
20 | )
21 | UIView.mock(
22 | backgroundColor: .layeringColor,
23 | preferredSize: .init(width: 100, height: 100)
24 | )
25 | }
26 | }
27 |
28 | }
29 | }
30 | }
31 |
32 | BookPush(title: "Push custom") {
33 | AnyViewController { view in
34 |
35 | Mondrian.buildSubviews(on: view) {
36 | LayoutContainer(top: .view(.top), leading: .view(.leading), bottom: .safeArea(.top), trailing: .view(.trailing)) {
37 | UIView.mock(
38 | backgroundColor: .layeringColor,
39 | preferredSize: .init(width: 100, height: 100)
40 | )
41 | .viewBlock
42 | }
43 |
44 | }
45 |
46 | Mondrian.buildSubviews(on: view) {
47 | LayoutContainer(attachedSafeAreaEdges: .vertical) {
48 | UIView.mock(
49 | backgroundColor: .layeringColor,
50 | preferredSize: .init(width: 100, height: 100)
51 | )
52 | .viewBlock
53 | }
54 |
55 | }
56 | }
57 | }
58 |
59 | BookPush(title: "Push") {
60 | AnyViewController { view in
61 | Mondrian.buildSubviews(on: view) {
62 | LayoutContainer(attachedSafeAreaEdges: .vertical) {
63 | ZStackBlock {
64 | UIView.mock(
65 | backgroundColor: .layeringColor
66 | )
67 |
68 | UIView.mock(
69 | backgroundColor: .mondrianBlue,
70 | preferredSize: .smallSquare
71 | )
72 | }
73 | }
74 | }
75 | }
76 | }
77 |
78 | BookPush(title: "Bottom Buttons") {
79 | AnyViewController { view in
80 | Mondrian.buildSubviews(on: view) {
81 | LayoutContainer(attachedSafeAreaEdges: .vertical) {
82 | ZStackBlock {
83 |
84 | VStackBlock(alignment: .center) {
85 | HStackBlock {
86 | UIView.mock(
87 | backgroundColor: .mondrianBlue,
88 | preferredSize: .init(width: 20, height: 30)
89 | )
90 | UIView.mock(
91 | backgroundColor: .mondrianBlue,
92 | preferredSize: .init(width: 20, height: 10)
93 | )
94 | UIView.mock(
95 | backgroundColor: .mondrianBlue,
96 | preferredSize: .init(width: 20, height: 20)
97 | )
98 | }
99 | }
100 | .padding(20)
101 | .background(
102 | UIView.mock(
103 | backgroundColor: .layeringColor
104 | )
105 | )
106 | .relative([.horizontal, .bottom], 0)
107 |
108 | }
109 | }
110 | }
111 | }
112 | }
113 |
114 | }
115 | }
116 |
117 | final class AnyViewController: UIViewController {
118 |
119 | private let onViewDidLoad: (UIView) -> Void
120 |
121 | init(
122 | onViewDidLoad: @escaping (UIView) -> Void
123 | ) {
124 | self.onViewDidLoad = onViewDidLoad
125 |
126 | super.init(nibName: nil, bundle: nil)
127 |
128 | if #available(iOS 13.0, *) {
129 | view.backgroundColor = .systemBackground
130 | } else {
131 | view.backgroundColor = .white
132 | }
133 |
134 | additionalSafeAreaInsets = .init(top: 60, left: 60, bottom: 60, right: 60)
135 | }
136 |
137 | required init?(
138 | coder: NSCoder
139 | ) {
140 | fatalError()
141 | }
142 |
143 | override func viewDidLoad() {
144 | super.viewDidLoad()
145 |
146 | onViewDidLoad(view)
147 | }
148 |
149 | }
150 |
--------------------------------------------------------------------------------
/Demo_MondrianLayout/Book.Sizing.swift:
--------------------------------------------------------------------------------
1 | import MondrianLayout
2 | import StorybookKit
3 | import UIKit
4 |
5 | var _book_sizing: BookView {
6 |
7 | BookNavigationLink(title: "Sizing") {
8 |
9 | BookPreview {
10 | ExampleView(width: 200, height: 200) { (view: UIView) in
11 | Mondrian.buildSubviews(on: view) {
12 | ZStackBlock {
13 |
14 | HStackBlock {
15 | VStackBlock(alignment: .leading) {
16 | UIView.mock(
17 | backgroundColor: .layeringColor,
18 | preferredSize: .init(width: 36, height: 36)
19 | )
20 | .viewBlock
21 | .alignSelf(.fill)
22 |
23 | UIView.mock(
24 | backgroundColor: .layeringColor,
25 | preferredSize: .init(width: 36, height: 36)
26 | )
27 | .viewBlock
28 | .alignSelf(.fill)
29 | }
30 | .width(20)
31 |
32 | VStackBlock(alignment: .leading) {
33 | UIView.mock(
34 | backgroundColor: .layeringColor,
35 | preferredSize: .init(width: 36, height: 36)
36 | )
37 | .viewBlock
38 | .alignSelf(.fill)
39 |
40 | UIView.mock(
41 | backgroundColor: .layeringColor,
42 | preferredSize: .init(width: 36, height: 36)
43 | )
44 | .viewBlock
45 | .alignSelf(.fill)
46 | }
47 | .width(40)
48 |
49 | UIView.mock(
50 | backgroundColor: .layeringColor,
51 | preferredSize: .init(width: 36, height: 36)
52 | )
53 | .viewBlock
54 | .padding(10)
55 | .width(.max(30))
56 |
57 | }
58 | .height(50)
59 |
60 | }
61 | }
62 | }
63 | }
64 |
65 | }
66 |
67 | }
68 |
--------------------------------------------------------------------------------
/Demo_MondrianLayout/Book.VGridBlock.swift:
--------------------------------------------------------------------------------
1 | import MondrianLayout
2 | import StorybookKit
3 | import UIKit
4 |
5 | var _book_VGridConstraint: BookView {
6 |
7 | BookNavigationLink(title: "VGridBlock") {
8 |
9 | BookPreview {
10 | ExampleView(width: 100, height: nil) { view in
11 | Mondrian.buildSubviews(on: view) {
12 | VGridBlock(
13 | columns: [
14 | .init(.flexible(), spacing: 16),
15 | .init(.flexible(), spacing: 16),
16 | ],
17 | spacing: 4
18 | ) {
19 |
20 | UILabel.mockMultiline(text: "Helloooo")
21 | .viewBlock
22 | .overlay(UIView.mock(backgroundColor: .layeringColor, preferredSize: .smallSquare))
23 |
24 | UIView.mock(backgroundColor: .neon(.cyan), preferredSize: .smallSquare)
25 | UIView.mock(backgroundColor: .neon(.cyan), preferredSize: .smallSquare)
26 | UIView.mock(backgroundColor: .neon(.cyan), preferredSize: .smallSquare)
27 |
28 | UIView.mock(backgroundColor: .neon(.cyan), preferredSize: .smallSquare)
29 | UIView.mock(backgroundColor: .neon(.cyan), preferredSize: .smallSquare)
30 | UIView.mock(backgroundColor: .neon(.cyan), preferredSize: .smallSquare)
31 | UIView.mock(backgroundColor: .neon(.cyan), preferredSize: .smallSquare)
32 |
33 | UIView.mock(backgroundColor: .neon(.cyan), preferredSize: .smallSquare)
34 | UIView.mock(backgroundColor: .neon(.cyan), preferredSize: .smallSquare)
35 | }
36 | }
37 | }
38 | }
39 | .title("Grid")
40 |
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/Demo_MondrianLayout/Book.VStackBlock.swift:
--------------------------------------------------------------------------------
1 | import MondrianLayout
2 | import StorybookKit
3 | import UIKit
4 |
5 | var _book_VStackBlock: BookView {
6 |
7 | BookNavigationLink(title: "VStackBlock") {
8 |
9 | BookPreview {
10 | ExampleView(width: 200, height: 200) { (view: UIView) in
11 | Mondrian.buildSubviews(on: view) {
12 | VStackBlock(alignment: .leading) {
13 | UILabel.mockMultiline(text: BookGenerator.loremIpsum(length: 10))
14 | .viewBlock
15 | .padding(.horizontal, 10)
16 | UIView.mock(backgroundColor: .layeringColor)
17 | .viewBlock
18 | .alignSelf(.fill)
19 | }
20 | .background(UIView.mock(backgroundColor: .layeringColor))
21 | }
22 | }
23 | }
24 | .title("Spacing")
25 |
26 | BookPreview {
27 | ExampleView(width: nil, height: 180) { (view: UIView) in
28 | Mondrian.buildSubviews(on: view) {
29 | VStackBlock(spacing: 4) {
30 | UIView.mock(
31 | backgroundColor: .mondrianYellow,
32 | preferredSize: .smallSquare
33 | )
34 |
35 | StackingSpacer(minLength: 20)
36 |
37 | UIView.mock(
38 | backgroundColor: .mondrianYellow,
39 | preferredSize: .smallSquare
40 | )
41 |
42 | UIView.mock(
43 | backgroundColor: .mondrianYellow,
44 | preferredSize: .smallSquare
45 | )
46 |
47 | StackingSpacer(minLength: 20, expands: false)
48 | }
49 | .background(UIView.mock(backgroundColor: .layeringColor))
50 | }
51 | }
52 | }
53 | .title("Spacing")
54 |
55 | BookForEach(data: [.center, .leading, .trailing, .fill] as [VStackBlock.XAxisAlignment]) { alignment in
56 | BookPreview {
57 | ExampleView(width: nil, height: nil) { (view: UIView) in
58 | Mondrian.buildSubviews(on: view) {
59 | VStackBlock(spacing: 4, alignment: alignment) {
60 | UILabel.mockMultiline(text: "Hello", textColor: .white)
61 | .viewBlock
62 | .padding(8)
63 | .background(UIView.mock(backgroundColor: .mondrianYellow))
64 | UILabel.mockMultiline(text: "Mondrian", textColor: .white)
65 | .viewBlock
66 | .padding(8)
67 | .background(UIView.mock(backgroundColor: .mondrianRed))
68 | UILabel.mockMultiline(text: "Layout!", textColor: .white)
69 | .viewBlock
70 | .padding(8)
71 | .background(UIView.mock(backgroundColor: .mondrianBlue))
72 | }
73 | }
74 | }
75 | }
76 | .title("Labels - align: \(alignment)")
77 | }
78 |
79 | BookPreview {
80 | ExampleView(width: nil, height: nil) { (view: UIView) in
81 | Mondrian.buildSubviews(on: view) {
82 | VStackBlock(spacing: 4) {
83 | UIView.mock(
84 | backgroundColor: .mondrianYellow,
85 | preferredSize: .smallSquare
86 | )
87 |
88 | UIView.mock(
89 | backgroundColor: .mondrianYellow,
90 | preferredSize: .smallSquare
91 | )
92 |
93 | UIView.mock(
94 | backgroundColor: .mondrianYellow,
95 | preferredSize: .smallSquare
96 | )
97 | }
98 | }
99 | }
100 | }
101 | .title("Spacing")
102 |
103 | BookPreview {
104 | ExampleView(width: nil, height: nil) { (view: UIView) in
105 | Mondrian.buildSubviews(on: view) {
106 | VStackBlock(spacing: 4) {
107 | UIView.mock(
108 | backgroundColor: .mondrianYellow,
109 | preferredSize: .smallSquare
110 | )
111 |
112 | StackingSpacer(minLength: 4)
113 |
114 | UIView.mock(
115 | backgroundColor: .mondrianYellow,
116 | preferredSize: .smallSquare
117 | )
118 |
119 | UIView.mock(
120 | backgroundColor: .mondrianYellow,
121 | preferredSize: .smallSquare
122 | )
123 | }
124 | }
125 | }
126 | }
127 | .title("Spacing with additional spacer")
128 |
129 | BookPreview {
130 | ExampleView(width: 200, height: 200) { (view: UIView) in
131 |
132 | let boxes = (0..<3).map { _ in UIView.mock(backgroundColor: .layeringColor) }
133 | let guides = (0..<2).map { _ in UILayoutGuide() }
134 |
135 | Mondrian.buildSubviews(on: view) {
136 | VStackBlock(alignment: .leading) {
137 |
138 | boxes[0]
139 |
140 | guides[0]
141 |
142 | boxes[1]
143 |
144 | guides[1]
145 |
146 | boxes[2]
147 |
148 | StackingSpacer(minLength: 0)
149 |
150 | }
151 | .background(UIView.mock(backgroundColor: .layeringColor))
152 | }
153 |
154 | mondrianBatchLayout {
155 |
156 | boxes.map { $0.mondrian.layout.height(20) }
157 |
158 | guides[0].mondrian.layout.height(.to(boxes[0]))
159 | guides[1].mondrian.layout.height(.to(boxes[2]), multiplier: 2)
160 | }
161 | }
162 | }
163 | .title("Including LayoutGuide")
164 |
165 | }
166 | }
167 |
--------------------------------------------------------------------------------
/Demo_MondrianLayout/Book.ViewController.swift:
--------------------------------------------------------------------------------
1 | import MondrianLayout
2 | import StorybookKit
3 | import UIKit
4 |
5 | var _book_ViewController: BookView {
6 |
7 | BookNavigationLink(title: "ViewController") {
8 |
9 | BookPush(title: "Push") {
10 |
11 | let body = ExampleView(width: nil, height: nil) { view in
12 | Mondrian.buildSubviews(on: view) {
13 | HStackBlock {
14 | UIView.mock(
15 | backgroundColor: .layeringColor,
16 | preferredSize: .smallSquare
17 | )
18 | UIView.mock(
19 | backgroundColor: .layeringColor,
20 | preferredSize: .smallSquare
21 | )
22 | UIView.mock(
23 | backgroundColor: .layeringColor,
24 | preferredSize: .smallSquare
25 | )
26 | }
27 | }
28 | }
29 |
30 | let container = ExampleView(width: nil, height: nil) { view in
31 | Mondrian.buildSubviews(on: view) {
32 | ZStackBlock {
33 | body.viewBlock.padding(10)
34 | }
35 | }
36 | }
37 |
38 | return AnyViewController { view in
39 | Mondrian.buildSubviews(on: view) {
40 | LayoutContainer(attachedSafeAreaEdges: .all) {
41 | ZStackBlock {
42 | container
43 | .viewBlock
44 | .padding(20)
45 | .background(UIView.mock(backgroundColor: .layeringColor))
46 | .relative([.bottom, .horizontal], 0)
47 | }
48 | }
49 | }
50 | }
51 | }
52 |
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/Demo_MondrianLayout/Book.swift:
--------------------------------------------------------------------------------
1 | import MondrianLayout
2 | import StorybookKit
3 | import UIKit
4 |
5 | let book = Book(title: "MondrianLayout") {
6 |
7 | _book_neonGrid
8 |
9 | _book_mondrian
10 |
11 | _book_sizing
12 |
13 | _book_background
14 |
15 | _book_overlay
16 |
17 | _book_VStackBlock
18 |
19 | _book_HStackBlock
20 |
21 | _book_ZStackConstraint
22 |
23 | _book_VGridConstraint
24 |
25 | _book_RelativeBlock
26 |
27 | _book_SafeArea
28 |
29 | _book_ViewController
30 |
31 | _book_classic
32 |
33 | _book_layoutManager
34 |
35 | BookNavigationLink(title: "Instagram Post") {
36 | BookPreview {
37 | InstagramPostView()
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/Demo_MondrianLayout/CGSize+.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CGSize+.swift
3 | // Demo_MondrianLayout
4 | //
5 | // Created by Muukii on 2021/06/17.
6 | //
7 |
8 | import UIKit
9 |
10 | extension CGSize {
11 |
12 | static var smallSquare: Self {
13 | .init(width: 20, height: 20)
14 | }
15 |
16 | static var largeSquare: Self {
17 | .init(width: 60, height: 60)
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Demo_MondrianLayout/ExampleView.swift:
--------------------------------------------------------------------------------
1 |
2 | import UIKit
3 | import MondrianLayout
4 |
5 | final class ExampleView: UIView {
6 |
7 | init(
8 | width: CGFloat?,
9 | height: CGFloat?,
10 | build: (UIView) -> Void
11 | ) {
12 |
13 | super.init(frame: .zero)
14 | build(self)
15 |
16 | translatesAutoresizingMaskIntoConstraints = false
17 |
18 | mondrian.layout
19 | .width(width.map { .exact($0) } ?? .exact(0, .fittingSizeLevel))
20 | .height(height.map { .exact($0) } ?? .exact(0, .fittingSizeLevel))
21 | .activate()
22 |
23 | layoutIfNeeded()
24 |
25 | }
26 |
27 | required init?(
28 | coder: NSCoder
29 | ) {
30 | fatalError("init(coder:) has not been implemented")
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/Demo_MondrianLayout/Extensions.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Extensions.swift
3 | // Demo_BoxLayout2
4 | //
5 | // Created by Muukii on 2021/06/13.
6 | //
7 |
8 | import UIKit
9 |
10 | extension UIView {
11 |
12 | static func mock(backgroundColor: UIColor = .layeringColor) -> UIView {
13 | let view = UIView()
14 | view.backgroundColor = backgroundColor
15 | view.layer.borderWidth = 3
16 | view.layer.borderColor = UIColor(white: 0, alpha: 0.2).cgColor
17 | return view
18 | }
19 |
20 | static func mock(backgroundColor: UIColor = .layeringColor, preferredSize: CGSize) -> UIView {
21 | let view = IntrinsicSizeView(preferredSize: preferredSize)
22 | view.backgroundColor = backgroundColor
23 | view.layer.borderWidth = 3
24 | view.layer.borderColor = UIColor(white: 0, alpha: 0.2).cgColor
25 | return view
26 | }
27 | }
28 |
29 | extension UIImageView {
30 |
31 | static func mock(image: UIImage) -> UIView {
32 | let view = UIImageView(image: image)
33 | return view
34 |
35 | }
36 | }
37 |
38 | final class IntrinsicSizeView: UIView {
39 |
40 | private let preferredSize: CGSize
41 |
42 | init(
43 | preferredSize: CGSize
44 | ) {
45 | self.preferredSize = preferredSize
46 | super.init(frame: .zero)
47 | }
48 |
49 | required init?(
50 | coder: NSCoder
51 | ) {
52 | fatalError("init(coder:) has not been implemented")
53 | }
54 |
55 | override var intrinsicContentSize: CGSize {
56 | preferredSize
57 | }
58 |
59 | }
60 |
61 | extension UILabel {
62 |
63 | static func mockSingleline(text: String, textColor: UIColor = .black) -> UILabel {
64 | let label = UILabel()
65 | label.font = .preferredFont(forTextStyle: .headline)
66 | label.textColor = textColor
67 | label.numberOfLines = 1
68 | label.text = text
69 | return label
70 | }
71 |
72 | static func mockMultiline(text: String, textColor: UIColor = .black) -> UILabel {
73 | let label = UILabel()
74 | label.font = .preferredFont(forTextStyle: .headline)
75 | label.textColor = textColor
76 | label.numberOfLines = 0
77 | label.text = text
78 | return label
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/Demo_MondrianLayout/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UIApplicationSupportsIndirectInputEvents
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 | UISupportedInterfaceOrientations~ipad
38 |
39 | UIInterfaceOrientationPortrait
40 | UIInterfaceOrientationPortraitUpsideDown
41 | UIInterfaceOrientationLandscapeLeft
42 | UIInterfaceOrientationLandscapeRight
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/Demo_MondrianLayout/InstagramPostView.swift:
--------------------------------------------------------------------------------
1 | import MondrianLayout
2 | import StorybookKit
3 | import UIKit
4 |
5 | final class InstagramPostView: UIView {
6 |
7 | private let profileImageView = UIView.mock(
8 | backgroundColor: .mondrianBlue,
9 | preferredSize: .init(width: 32, height: 32)
10 | )
11 |
12 | private let nicknameLabel = UILabel.mockMultiline(text: "Muukii")
13 |
14 | private let imageView = UIView.mock(backgroundColor: .mondrianYellow)
15 |
16 | private let likeButton = UIView.mock(
17 | backgroundColor: .mondrianRed,
18 | preferredSize: .init(width: 32, height: 32)
19 | )
20 |
21 | private let commentButton = UIView.mock(
22 | backgroundColor: .mondrianRed,
23 | preferredSize: .init(width: 32, height: 32)
24 | )
25 |
26 | private let messageButton = UIView.mock(
27 | backgroundColor: .mondrianRed,
28 | preferredSize: .init(width: 32, height: 32)
29 | )
30 |
31 | private let saveButton = UIView.mock(
32 | backgroundColor: .mondrianCyan,
33 | preferredSize: .init(width: 32, height: 32)
34 | )
35 |
36 | private let captionBackground = UIView.mock(backgroundColor: .layeringColor)
37 | private let captionLabel = UILabel.mockMultiline(text: "Caption", textColor: .white)
38 |
39 | init() {
40 |
41 | super.init(frame: .zero)
42 |
43 | self.mondrian.buildSelfSizing {
44 | $0.width(200)
45 | }
46 |
47 | Mondrian.buildSubviews(on: self) {
48 | VStackBlock(alignment: .fill) {
49 |
50 | HStackBlock {
51 | ViewBlock(profileImageView)
52 | .huggingPriority(.horizontal, .required)
53 | .spacingAfter(4)
54 | nicknameLabel
55 | }
56 | .spacingAfter(10)
57 |
58 | ViewBlock(imageView)
59 | .aspectRatio(1)
60 | .overlay(
61 | captionLabel.viewBlock
62 | .padding(10)
63 | .background(captionBackground)
64 | .relative([.bottom, .trailing], 8)
65 | )
66 | .spacingAfter(10)
67 |
68 | HStackBlock {
69 | HStackBlock(spacing: 2) {
70 | likeButton
71 | commentButton
72 | messageButton
73 | }
74 | StackingSpacer(minLength: 8)
75 | saveButton
76 | }
77 | .spacingAfter(10)
78 |
79 | }
80 | }
81 |
82 | }
83 |
84 | required init?(
85 | coder: NSCoder
86 | ) {
87 | fatalError("init(coder:) has not been implemented")
88 | }
89 |
90 | }
91 |
--------------------------------------------------------------------------------
/Demo_MondrianLayout/RootContainerViewController.swift:
--------------------------------------------------------------------------------
1 | import StorybookKit
2 | import StorybookUI
3 | import UIKit
4 |
5 | final class RootContainerViewController: UIViewController {
6 |
7 | init() {
8 | super.init(nibName: nil, bundle: nil)
9 |
10 | let child = StorybookViewController(
11 | book: book,
12 | dismissHandler: nil
13 | )
14 |
15 | addChild(child)
16 | view.addSubview(child.view)
17 | child.view.frame = view.bounds
18 | child.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
19 |
20 | }
21 |
22 | required init?(coder: NSCoder) {
23 | fatalError("init(coder:) has not been implemented")
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Demo_MondrianLayout/SwiftUIComparison.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 |
3 | @available(iOS 13, *)
4 | enum Padding {
5 |
6 | struct ContentView: View {
7 |
8 | var body: some View {
9 | BorderedRect()
10 | .frame(maxWidth: 100, maxHeight: 100)
11 | .foregroundColor(.init(white: 0, opacity: 0.2))
12 | .overlay(
13 | BorderedRect()
14 | .foregroundColor(.init(white: 0, opacity: 0.2))
15 | .overlay(
16 | BorderedRect()
17 | .foregroundColor(.init(white: 0, opacity: 0.2))
18 | .padding(10)
19 | )
20 | .padding(10)
21 | )
22 |
23 | }
24 | }
25 |
26 | struct BorderedRect: View {
27 |
28 | var body: some View {
29 | Rectangle()
30 | .border(Color(white: 0, opacity: 0.2), width: 3)
31 | .foregroundColor(.init(white: 0, opacity: 0.2))
32 | }
33 | }
34 |
35 | enum Preview: PreviewProvider {
36 |
37 | static var previews: some View {
38 |
39 | Group {
40 |
41 | Group {
42 | VStack {
43 | Text("Financial Results")
44 | .font(.title)
45 | .background(BorderedRect())
46 |
47 | HStack(alignment: .center) {
48 | Text("Q1 Sales")
49 | .font(.headline)
50 | .frame(maxHeight: .infinity)
51 | .background(BorderedRect())
52 |
53 |
54 | VStack {
55 | Text("January")
56 | Text("February")
57 | Text("March")
58 | }
59 | .background(BorderedRect())
60 |
61 | VStack {
62 | Text("$1000")
63 | Text("$200")
64 | Text("$3000")
65 | }
66 | .background(BorderedRect())
67 | }
68 | }
69 | }
70 |
71 | ContentView()
72 |
73 | }
74 | }
75 |
76 | }
77 |
78 | }
79 |
--------------------------------------------------------------------------------
/Demo_MondrianLayout/UIColor+Mondrian.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | extension UIColor {
4 |
5 | static var mondrianRed: UIColor = #colorLiteral(red: 1, green: 0.5661777854, blue: 0.3006193042, alpha: 1)
6 | static var mondrianBlue: UIColor = #colorLiteral(red: 0.09076789767, green: 0.3224385977, blue: 0.9202803969, alpha: 1)
7 | static var mondrianCyan: UIColor = #colorLiteral(red: 0, green: 0.856479466, blue: 1, alpha: 1)
8 | static var mondrianYellow: UIColor = #colorLiteral(red: 1, green: 0.4053340554, blue: 0, alpha: 1)
9 | static var mondrianGray: UIColor = #colorLiteral(red: 0.6430723071, green: 0.6431827545, blue: 0.6430577636, alpha: 1)
10 | static var layeringColor: UIColor {
11 | return .init(white: 0, alpha: 0.2)
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source "https://rubygems.org"
2 |
3 | gem "fastlane"
4 |
--------------------------------------------------------------------------------
/Gemfile.lock:
--------------------------------------------------------------------------------
1 | GEM
2 | remote: https://rubygems.org/
3 | specs:
4 | CFPropertyList (3.0.3)
5 | addressable (2.7.0)
6 | public_suffix (>= 2.0.2, < 5.0)
7 | artifactory (3.0.15)
8 | atomos (0.1.3)
9 | aws-eventstream (1.1.1)
10 | aws-partitions (1.467.0)
11 | aws-sdk-core (3.114.2)
12 | aws-eventstream (~> 1, >= 1.0.2)
13 | aws-partitions (~> 1, >= 1.239.0)
14 | aws-sigv4 (~> 1.1)
15 | jmespath (~> 1.0)
16 | aws-sdk-kms (1.43.0)
17 | aws-sdk-core (~> 3, >= 3.112.0)
18 | aws-sigv4 (~> 1.1)
19 | aws-sdk-s3 (1.96.1)
20 | aws-sdk-core (~> 3, >= 3.112.0)
21 | aws-sdk-kms (~> 1)
22 | aws-sigv4 (~> 1.1)
23 | aws-sigv4 (1.2.3)
24 | aws-eventstream (~> 1, >= 1.0.2)
25 | babosa (1.0.4)
26 | claide (1.0.3)
27 | colored (1.2)
28 | colored2 (3.1.2)
29 | commander (4.6.0)
30 | highline (~> 2.0.0)
31 | declarative (0.0.20)
32 | digest-crc (0.6.3)
33 | rake (>= 12.0.0, < 14.0.0)
34 | domain_name (0.5.20190701)
35 | unf (>= 0.0.5, < 1.0.0)
36 | dotenv (2.7.6)
37 | emoji_regex (3.2.2)
38 | excon (0.82.0)
39 | faraday (1.4.2)
40 | faraday-em_http (~> 1.0)
41 | faraday-em_synchrony (~> 1.0)
42 | faraday-excon (~> 1.1)
43 | faraday-net_http (~> 1.0)
44 | faraday-net_http_persistent (~> 1.1)
45 | multipart-post (>= 1.2, < 3)
46 | ruby2_keywords (>= 0.0.4)
47 | faraday-cookie_jar (0.0.7)
48 | faraday (>= 0.8.0)
49 | http-cookie (~> 1.0.0)
50 | faraday-em_http (1.0.0)
51 | faraday-em_synchrony (1.0.0)
52 | faraday-excon (1.1.0)
53 | faraday-net_http (1.0.1)
54 | faraday-net_http_persistent (1.1.0)
55 | faraday_middleware (1.0.0)
56 | faraday (~> 1.0)
57 | fastimage (2.2.4)
58 | fastlane (2.185.1)
59 | CFPropertyList (>= 2.3, < 4.0.0)
60 | addressable (>= 2.3, < 3.0.0)
61 | artifactory (~> 3.0)
62 | aws-sdk-s3 (~> 1.0)
63 | babosa (>= 1.0.3, < 2.0.0)
64 | bundler (>= 1.12.0, < 3.0.0)
65 | colored
66 | commander (~> 4.6)
67 | dotenv (>= 2.1.1, < 3.0.0)
68 | emoji_regex (>= 0.1, < 4.0)
69 | excon (>= 0.71.0, < 1.0.0)
70 | faraday (~> 1.0)
71 | faraday-cookie_jar (~> 0.0.6)
72 | faraday_middleware (~> 1.0)
73 | fastimage (>= 2.1.0, < 3.0.0)
74 | gh_inspector (>= 1.1.2, < 2.0.0)
75 | google-apis-androidpublisher_v3 (~> 0.1)
76 | google-apis-playcustomapp_v1 (~> 0.1)
77 | google-cloud-storage (~> 1.31)
78 | highline (~> 2.0)
79 | json (< 3.0.0)
80 | jwt (>= 2.1.0, < 3)
81 | mini_magick (>= 4.9.4, < 5.0.0)
82 | multipart-post (~> 2.0.0)
83 | naturally (~> 2.2)
84 | plist (>= 3.1.0, < 4.0.0)
85 | rubyzip (>= 2.0.0, < 3.0.0)
86 | security (= 0.1.3)
87 | simctl (~> 1.6.3)
88 | terminal-notifier (>= 2.0.0, < 3.0.0)
89 | terminal-table (>= 1.4.5, < 2.0.0)
90 | tty-screen (>= 0.6.3, < 1.0.0)
91 | tty-spinner (>= 0.8.0, < 1.0.0)
92 | word_wrap (~> 1.0.0)
93 | xcodeproj (>= 1.13.0, < 2.0.0)
94 | xcpretty (~> 0.3.0)
95 | xcpretty-travis-formatter (>= 0.0.3)
96 | gh_inspector (1.1.3)
97 | google-apis-androidpublisher_v3 (0.6.0)
98 | google-apis-core (~> 0.1)
99 | google-apis-core (0.3.0)
100 | addressable (~> 2.5, >= 2.5.1)
101 | googleauth (~> 0.14)
102 | httpclient (>= 2.8.1, < 3.0)
103 | mini_mime (~> 1.0)
104 | representable (~> 3.0)
105 | retriable (>= 2.0, < 4.0)
106 | rexml
107 | signet (~> 0.14)
108 | webrick
109 | google-apis-iamcredentials_v1 (0.4.0)
110 | google-apis-core (~> 0.1)
111 | google-apis-playcustomapp_v1 (0.3.0)
112 | google-apis-core (~> 0.1)
113 | google-apis-storage_v1 (0.4.0)
114 | google-apis-core (~> 0.1)
115 | google-cloud-core (1.6.0)
116 | google-cloud-env (~> 1.0)
117 | google-cloud-errors (~> 1.0)
118 | google-cloud-env (1.5.0)
119 | faraday (>= 0.17.3, < 2.0)
120 | google-cloud-errors (1.1.0)
121 | google-cloud-storage (1.31.1)
122 | addressable (~> 2.5)
123 | digest-crc (~> 0.4)
124 | google-apis-iamcredentials_v1 (~> 0.1)
125 | google-apis-storage_v1 (~> 0.1)
126 | google-cloud-core (~> 1.2)
127 | googleauth (~> 0.9)
128 | mini_mime (~> 1.0)
129 | googleauth (0.16.2)
130 | faraday (>= 0.17.3, < 2.0)
131 | jwt (>= 1.4, < 3.0)
132 | memoist (~> 0.16)
133 | multi_json (~> 1.11)
134 | os (>= 0.9, < 2.0)
135 | signet (~> 0.14)
136 | highline (2.0.3)
137 | http-cookie (1.0.4)
138 | domain_name (~> 0.5)
139 | httpclient (2.8.3)
140 | jmespath (1.4.0)
141 | json (2.5.1)
142 | jwt (2.2.3)
143 | memoist (0.16.2)
144 | mini_magick (4.11.0)
145 | mini_mime (1.1.0)
146 | multi_json (1.15.0)
147 | multipart-post (2.0.0)
148 | nanaimo (0.3.0)
149 | naturally (2.2.1)
150 | os (1.1.1)
151 | plist (3.6.0)
152 | public_suffix (4.0.6)
153 | rake (13.0.3)
154 | representable (3.1.1)
155 | declarative (< 0.1.0)
156 | trailblazer-option (>= 0.1.1, < 0.2.0)
157 | uber (< 0.2.0)
158 | retriable (3.1.2)
159 | rexml (3.2.5)
160 | rouge (2.0.7)
161 | ruby2_keywords (0.0.4)
162 | rubyzip (2.3.0)
163 | security (0.1.3)
164 | signet (0.15.0)
165 | addressable (~> 2.3)
166 | faraday (>= 0.17.3, < 2.0)
167 | jwt (>= 1.5, < 3.0)
168 | multi_json (~> 1.10)
169 | simctl (1.6.8)
170 | CFPropertyList
171 | naturally
172 | terminal-notifier (2.0.0)
173 | terminal-table (1.8.0)
174 | unicode-display_width (~> 1.1, >= 1.1.1)
175 | trailblazer-option (0.1.1)
176 | tty-cursor (0.7.1)
177 | tty-screen (0.8.1)
178 | tty-spinner (0.9.3)
179 | tty-cursor (~> 0.7)
180 | uber (0.1.0)
181 | unf (0.1.4)
182 | unf_ext
183 | unf_ext (0.0.7.7)
184 | unicode-display_width (1.7.0)
185 | webrick (1.7.0)
186 | word_wrap (1.0.0)
187 | xcodeproj (1.19.0)
188 | CFPropertyList (>= 2.3.3, < 4.0)
189 | atomos (~> 0.1.3)
190 | claide (>= 1.0.2, < 2.0)
191 | colored2 (~> 3.1)
192 | nanaimo (~> 0.3.0)
193 | xcpretty (0.3.0)
194 | rouge (~> 2.0.7)
195 | xcpretty-travis-formatter (1.0.1)
196 | xcpretty (~> 0.2, >= 0.0.7)
197 |
198 | PLATFORMS
199 | ruby
200 |
201 | DEPENDENCIES
202 | fastlane
203 |
204 | BUNDLED WITH
205 | 2.1.4
206 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 muukii
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/MondrianLayout.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |spec|
2 | spec.name = "MondrianLayout"
3 | spec.version = "0.10.0"
4 | spec.summary = "A DSL based layout builder for AutoLayout"
5 | spec.description = <<-DESC
6 | This library is a layout builder by DSL described for AutoLayout.
7 | DESC
8 |
9 | spec.homepage = "https://github.com/muukii/MondrianLayout"
10 | spec.license = "MIT"
11 | spec.author = { "Muukii" => "muukii.app@gmail.com" }
12 | spec.social_media_url = "https://twitter.com/muukii_app"
13 |
14 | spec.ios.deployment_target = "12.0"
15 | # spec.osx.deployment_target = "10.7"
16 | # spec.watchos.deployment_target = "2.0"
17 | # spec.tvos.deployment_target = "9.0"
18 |
19 | spec.source = { :git => "https://github.com/muukii/MondrianLayout.git", :tag => "#{spec.version}" }
20 | spec.source_files = "MondrianLayout/**/*.swift"
21 | spec.framework = "UIKit"
22 | spec.requires_arc = true
23 | spec.swift_versions = ["5.3", "5.4", "5.5"]
24 | end
25 |
--------------------------------------------------------------------------------
/MondrianLayout.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/MondrianLayout.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/MondrianLayout.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved:
--------------------------------------------------------------------------------
1 | {
2 | "object": {
3 | "pins": [
4 | {
5 | "package": "Ne",
6 | "repositoryURL": "https://github.com/muukii/Ne.git",
7 | "state": {
8 | "branch": null,
9 | "revision": "6555f94596b634c14bd0818265ef8c86bb3005f3",
10 | "version": "1.0.1"
11 | }
12 | },
13 | {
14 | "package": "Storybook",
15 | "repositoryURL": "https://github.com/eure/Storybook-ios.git",
16 | "state": {
17 | "branch": null,
18 | "revision": "cd9238e7800ead2a120e81291bbbf5c0012131c8",
19 | "version": "1.8.0"
20 | }
21 | },
22 | {
23 | "package": "SnapshotTesting",
24 | "repositoryURL": "https://github.com/pointfreeco/swift-snapshot-testing.git",
25 | "state": {
26 | "branch": null,
27 | "revision": "f8a9c997c3c1dab4e216a8ec9014e23144cbab37",
28 | "version": "1.9.0"
29 | }
30 | }
31 | ]
32 | },
33 | "version": 1
34 | }
35 |
--------------------------------------------------------------------------------
/MondrianLayout.xcodeproj/xcshareddata/xcschemes/Demo_MondrianLayout.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
29 |
35 |
36 |
37 |
38 |
39 |
44 |
45 |
47 |
53 |
54 |
55 |
56 |
57 |
67 |
69 |
75 |
76 |
77 |
78 |
84 |
86 |
92 |
93 |
94 |
95 |
97 |
98 |
101 |
102 |
103 |
--------------------------------------------------------------------------------
/MondrianLayout.xcodeproj/xcshareddata/xcschemes/MondrianLayout.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
29 |
35 |
36 |
37 |
38 |
39 |
44 |
45 |
47 |
53 |
54 |
55 |
56 |
57 |
67 |
68 |
74 |
75 |
81 |
82 |
83 |
84 |
86 |
87 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/MondrianLayout.xcodeproj/xcshareddata/xcschemes/Tests-Record.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
35 |
36 |
37 |
38 |
40 |
46 |
47 |
48 |
49 |
50 |
60 |
61 |
67 |
68 |
74 |
75 |
76 |
77 |
79 |
80 |
83 |
84 |
85 |
--------------------------------------------------------------------------------
/MondrianLayout.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
42 |
43 |
53 |
54 |
60 |
61 |
67 |
68 |
69 |
70 |
72 |
73 |
76 |
77 |
78 |
--------------------------------------------------------------------------------
/MondrianLayout/Classic/MondrianArrayBuilder.swift:
--------------------------------------------------------------------------------
1 |
2 | func buildArray(type: T.Type, @MondrianArrayBuilder _ build: () -> [T]) -> [T] {
3 | build()
4 | }
5 |
6 | @resultBuilder
7 | public struct MondrianArrayBuilder {
8 |
9 | public static func buildBlock() -> [Element] {
10 | []
11 | }
12 |
13 | public static func buildBlock(_ contents: C...) -> [Element] where C.Element == Element {
14 | return contents.flatMap { $0 }
15 | }
16 |
17 | public static func buildOptional(_ component: [Element]?) -> [Element] {
18 | return component ?? []
19 | }
20 |
21 | public static func buildEither(first component: [Element]) -> [Element] {
22 | return component
23 | }
24 |
25 | public static func buildEither(second component: [Element]) -> [Element] {
26 | return component
27 | }
28 |
29 | public static func buildArray(_ components: [[Element]]) -> [Element] {
30 | components.flatMap { $0 }
31 | }
32 |
33 | public static func buildExpression(_ element: Element?) -> [Element] {
34 | return element.map { [$0] } ?? []
35 | }
36 |
37 | public static func buildExpression(_ element: Element) -> [Element] {
38 | return [element]
39 | }
40 |
41 | public static func buildExpression(_ elements: C) -> [Element] where C.Element == Element {
42 | Array(elements)
43 | }
44 |
45 | public static func buildExpression(_ elements: C) -> [Element] where C.Element == Optional {
46 | elements.compactMap { $0 }
47 | }
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/MondrianLayout/Descriptors/Edge.swift:
--------------------------------------------------------------------------------
1 |
2 | public enum Edge: Int8, CaseIterable {
3 |
4 | case top = 0
5 | case leading = 1
6 | case bottom = 2
7 | case trailing = 3
8 |
9 | public struct Set: OptionSet {
10 |
11 | public var rawValue: Int8
12 | public var isEmpty: Bool {
13 | rawValue == 0
14 | }
15 |
16 | public init(rawValue: Int8) {
17 | self.rawValue = rawValue
18 | }
19 |
20 | public static let top: Set = .init(rawValue: 1 << 1)
21 |
22 | /// In LTR - meaning `left`
23 | public static let leading: Set = .init(rawValue: 1 << 2)
24 |
25 | public static let bottom: Set = .init(rawValue: 1 << 3)
26 |
27 | /// In LTR - meaning `right`
28 | public static let trailing: Set = .init(rawValue: 1 << 4)
29 |
30 | public static var horizontal: Set {
31 | [.leading, .trailing]
32 | }
33 |
34 | public static var vertical: Set {
35 | [.top, .bottom]
36 | }
37 |
38 | public static var all: Set {
39 | [.top, .bottom, .trailing, leading]
40 | }
41 |
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/MondrianLayout/Descriptors/LayoutBuilderContext.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | /**
4 | A building layout enviroment
5 | - constraints
6 | - layout guides
7 | - tasks apply to view (setting content hugging and compression resistance)
8 | */
9 | public final class LayoutBuilderContext {
10 |
11 | public weak var targetView: UIView?
12 | public let name: String?
13 | public private(set) var isActive = false
14 |
15 | public init(
16 | name: String? = nil,
17 | targetView: UIView
18 | ) {
19 | self.name = name
20 | self.targetView = targetView
21 | }
22 |
23 | public private(set) var managedLayoutGuides: [UILayoutGuide] = []
24 | public private(set) var constraints: [NSLayoutConstraint] = []
25 | public private(set) var viewBlocks: [ViewBlock] = []
26 | public private(set) var unmanagedLayoutGuides: [LayoutGuideBlock] = []
27 | public private(set) var viewAppliers: [() -> Void] = []
28 |
29 | func add(constraints: [NSLayoutConstraint]) {
30 | self.constraints.append(contentsOf: constraints)
31 | }
32 |
33 | func makeLayoutGuide(identifier: String) -> UILayoutGuide {
34 |
35 | let guide = UILayoutGuide()
36 | if let name = name {
37 | guide.identifier = "\(identifier):\(name)"
38 | } else {
39 | guide.identifier = identifier
40 | }
41 |
42 | managedLayoutGuides.append(guide)
43 | return guide
44 | }
45 |
46 | func register(viewBlock: ViewBlock) {
47 | assert(viewBlocks.contains(where: { $0.view == viewBlock.view }) == false)
48 |
49 | viewBlocks.append(viewBlock)
50 | constraints.append(contentsOf: viewBlock.makeConstraints())
51 | viewAppliers.append(viewBlock.makeApplier())
52 | }
53 |
54 | func register(layoutGuideBlock: LayoutGuideBlock) {
55 | unmanagedLayoutGuides.append(layoutGuideBlock)
56 | constraints.append(contentsOf: layoutGuideBlock.makeConstraints())
57 | }
58 |
59 | /// Add including views to the target view.
60 | public func prepareViewHierarchy() {
61 |
62 | guard let targetView = targetView else {
63 | return
64 | }
65 |
66 | viewBlocks.forEach {
67 | $0.view.translatesAutoresizingMaskIntoConstraints = false
68 | targetView.addSubview($0.view)
69 | }
70 | }
71 |
72 | /**
73 | Activate constraints and layout guides.
74 | */
75 | public func activate() {
76 |
77 | assert(Thread.isMainThread)
78 |
79 | guard let targetView = targetView else {
80 | return
81 | }
82 |
83 | guard isActive == false else {
84 | return
85 | }
86 |
87 | isActive = true
88 |
89 | viewAppliers.forEach { $0() }
90 |
91 | managedLayoutGuides.forEach {
92 | targetView.addLayoutGuide($0)
93 | }
94 |
95 | unmanagedLayoutGuides.forEach {
96 | targetView.addLayoutGuide($0.layoutGuide)
97 | }
98 |
99 | NSLayoutConstraint.activate(constraints)
100 |
101 | }
102 |
103 | /**
104 | Deactivate constraints and layout guides.
105 | */
106 | public func deactivate() {
107 |
108 | guard let targetView = targetView else {
109 | return
110 | }
111 |
112 | guard isActive == true else {
113 | return
114 | }
115 |
116 | isActive = false
117 |
118 | managedLayoutGuides.forEach {
119 | targetView.removeLayoutGuide($0)
120 | }
121 |
122 | unmanagedLayoutGuides.forEach {
123 | targetView.removeLayoutGuide($0.layoutGuide)
124 | }
125 |
126 | NSLayoutConstraint.deactivate(constraints)
127 | }
128 |
129 | }
130 |
131 |
--------------------------------------------------------------------------------
/MondrianLayout/Descriptors/Optimization.swift:
--------------------------------------------------------------------------------
1 | import CoreGraphics
2 |
3 | extension Array where Element : _StackElementNodeType {
4 |
5 | /// merging continuous spacing into one
6 | func optimizedSpacing() -> [Element] {
7 |
8 | var spacing: CGFloat = 0
9 | var expands: Bool = false
10 |
11 | /**
12 |
13 | __X_ _X___X__
14 |
15 | _X_X_X
16 |
17 | */
18 |
19 | var array: [Element] = []
20 |
21 | for element in self {
22 |
23 | if let spacer = element._spacer {
24 |
25 | spacing += spacer.minLength
26 | expands = spacer.expands ? true : expands
27 |
28 | continue
29 | }
30 |
31 | if let content = element._content {
32 |
33 | spacing += content.spacingBefore ?? 0
34 |
35 | if spacing > 0 || expands {
36 | array.append(.spacer(.init(minLength: spacing, expands: expands)))
37 | }
38 | array.append(element)
39 |
40 | spacing = content.spacingAfter ?? 0
41 | expands = false
42 |
43 | continue
44 | }
45 |
46 | preconditionFailure()
47 |
48 | }
49 |
50 | if spacing > 0 || expands {
51 | array.append(.spacer(.init(minLength: spacing, expands: expands)))
52 | }
53 |
54 | return array
55 |
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/MondrianLayout/Descriptors/_LayoutBlockNode.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | public protocol _LayoutBlockNodeConvertible: _VStackItemConvertible, _HStackItemConvertible, _ZStackItemConvertible {
4 | var _layoutBlockNode: _LayoutBlockNode { get }
5 | }
6 |
7 | extension _LayoutBlockNodeConvertible {
8 | public var _vStackItem: _VStackItem {
9 | return .init(node: _layoutBlockNode)
10 | }
11 |
12 | public var _hStackItem: _HStackItem {
13 | return .init(node: _layoutBlockNode)
14 | }
15 |
16 | public var _zStackItem: _ZStackItem {
17 | return .init(node: _layoutBlockNode)
18 | }
19 | }
20 |
21 | public indirect enum _LayoutBlockNode: _LayoutBlockNodeConvertible {
22 |
23 | case view(ViewBlock)
24 | case layoutGuide(LayoutGuideBlock)
25 | case vStack(VStackBlock)
26 | case hStack(HStackBlock)
27 | case zStack(ZStackBlock)
28 | case relative(RelativeBlock)
29 | case overlay(OverlayBlock)
30 | case background(BackgroundBlock)
31 | case vGrid(VGridBlock)
32 |
33 | public var _layoutBlockNode: _LayoutBlockNode { self }
34 | }
35 |
36 | extension _LayoutBlockNodeConvertible {
37 |
38 | public func background(_ view: UIView) -> BackgroundBlock {
39 | return .init(content: _layoutBlockNode, backgroundContent: .view(view.viewBlock))
40 | }
41 |
42 | public func background(_ block: Block) -> BackgroundBlock {
43 | return .init(content: _layoutBlockNode, backgroundContent: block._layoutBlockNode)
44 | }
45 |
46 | public func overlay(_ view: UIView) -> OverlayBlock {
47 | return .init(content: _layoutBlockNode, overlayContent: .view(view.viewBlock))
48 | }
49 |
50 | public func overlay(_ block: Block) -> OverlayBlock {
51 | return .init(content: _layoutBlockNode, overlayContent: block._layoutBlockNode)
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/MondrianLayout/Descriptors/_LayoutBlockType.swift:
--------------------------------------------------------------------------------
1 |
2 | public protocol _LayoutBlockType: _LayoutBlockNodeConvertible {
3 |
4 | var name: String { get }
5 | func setupConstraints(parent: _LayoutElement, in context: LayoutBuilderContext)
6 | }
7 |
--------------------------------------------------------------------------------
/MondrianLayout/EntryPoint.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | public enum Mondrian {
4 |
5 | @discardableResult
6 | public static func layout(
7 | @MondrianArrayBuilder _ closure: () -> [LayoutDescriptor]
8 | ) -> ConstraintGroup {
9 |
10 | let descriptors = closure()
11 |
12 | let group = ConstraintGroup(constraints: [])
13 |
14 | descriptors.forEach {
15 | let g = $0.activate()
16 | group.append(g)
17 | }
18 |
19 | return group
20 |
21 | }
22 |
23 | /**
24 | Builds subviews of this view.
25 | - activating layout-constraints
26 | - adding layout-guides
27 | - applying content-hugging, content-compression-resistance
28 |
29 | You can start to describe like followings:
30 |
31 | ```swift
32 | Mondrian.buildSubviews(on: view) {
33 | ZStackBlock {
34 | ...
35 | }
36 | }
37 | ```
38 |
39 | ```swift
40 | Mondrian.buildSubviews(on: view) {
41 | LayoutContainer(attachedSafeAreaEdges: .vertical) {
42 | ...
43 | }
44 | }
45 | ```
46 |
47 |
48 | ```swift
49 | Mondrian.buildSubviews(on: view) {
50 | LayoutContainer(attachedSafeAreaEdges: .vertical) {
51 | ...
52 | }
53 | ZStackBlock {
54 | ...
55 | }
56 | }
57 | ```
58 | */
59 | @discardableResult
60 | public static func buildSubviews(
61 | on view: UIView,
62 | @EntrypointBuilder _ build: () -> [EntrypointBuilder.Either]
63 | ) -> LayoutBuilderContext {
64 |
65 | let entrypoints = build()
66 |
67 | let context = LayoutBuilderContext(targetView: view)
68 |
69 | for entrypoint in entrypoints {
70 | switch entrypoint {
71 | case .block(let block):
72 | block.setupConstraints(parent: .init(view: view), in: context)
73 | case .container(let container):
74 | container.setupConstraints(parent: view, in: context)
75 | }
76 | }
77 |
78 | context.prepareViewHierarchy()
79 | context.activate()
80 |
81 | return context
82 | }
83 |
84 | }
85 |
--------------------------------------------------------------------------------
/MondrianLayout/Extensions/NSLayoutConstraint+.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | extension NSLayoutConstraint {
4 |
5 | @discardableResult
6 | func setInternalIdentifier(_ string: String) -> NSLayoutConstraint {
7 | self.identifier = "BoxLayout." + string
8 | return self
9 | }
10 |
11 | @discardableResult
12 | func setIdentifier(_ string: String) -> NSLayoutConstraint {
13 | self.identifier = string
14 | return self
15 | }
16 |
17 | @discardableResult
18 | func setPriority(_ priority: UILayoutPriority) -> NSLayoutConstraint {
19 | self.priority = priority
20 | return self
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/MondrianLayout/Extensions/UILayoutGuide+Mondrian.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | extension UILayoutGuide {
4 |
5 | public var mondrian: MondrianNamespace {
6 | return .init(base: self)
7 | }
8 |
9 | public var layoutGuideBlock: LayoutGuideBlock {
10 | .init(self)
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/MondrianLayout/Extensions/UIView+Mondrian.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | @resultBuilder
4 | public enum EntrypointBuilder {
5 |
6 | public enum Either {
7 | case block(_LayoutBlockType)
8 | case container(LayoutContainer)
9 | }
10 |
11 | public static func buildBlock() -> [EntrypointBuilder.Either] {
12 | return []
13 | }
14 |
15 | public static func buildBlock(_ components: [Either]...) -> [Either] {
16 | return components.flatMap { $0 }
17 | }
18 |
19 | public static func buildExpression(_ components: Block...) -> [Either] {
20 | return components.map { .block($0) }
21 | }
22 |
23 | public static func buildExpression(_ components: LayoutContainer...) -> [EntrypointBuilder.Either] {
24 | return components.map { .container($0) }
25 | }
26 |
27 | public static func buildEither(first component: [EntrypointBuilder.Either]) -> [EntrypointBuilder.Either] {
28 | return component
29 | }
30 |
31 | public static func buildEither(second component: [EntrypointBuilder.Either]) -> [EntrypointBuilder.Either] {
32 | return component
33 | }
34 |
35 | }
36 |
37 | extension MondrianNamespace where Base : UIView {
38 |
39 | @available(*, deprecated, message: "Use Mondrian.buildSubviews")
40 | @discardableResult
41 | public func buildSubviews(@EntrypointBuilder _ build: () -> [EntrypointBuilder.Either]) -> LayoutBuilderContext {
42 | Mondrian.buildSubviews(on: base, build)
43 | }
44 |
45 | @available(*, deprecated, message: "Use classic layout")
46 | /// Applies the layout of the dimension in itself.
47 | public func buildSelfSizing(build: (ViewBlock) -> ViewBlock) {
48 |
49 | let constraint = ViewBlock(base)
50 | let modifiedConstraint = build(constraint)
51 |
52 | modifiedConstraint.makeApplier()()
53 | NSLayoutConstraint.activate(
54 | modifiedConstraint.makeConstraints()
55 | )
56 |
57 | }
58 |
59 | }
60 |
61 | extension UIView {
62 |
63 | public var mondrian: MondrianNamespace {
64 | return .init(base: self)
65 | }
66 |
67 | }
68 |
69 |
70 |
71 | extension UIView {
72 |
73 | /// Returns an instance of ViewBlock to describe layout.
74 | public var viewBlock: ViewBlock {
75 | .init(self)
76 | }
77 |
78 | public var hasAmbiguousLayoutRecursively: Bool {
79 |
80 | var hasAmbiguous: Bool = false
81 |
82 | func traverse(_ view: UIView) {
83 |
84 | if view.hasAmbiguousLayout {
85 | hasAmbiguous = true
86 | }
87 |
88 | for subview in view.subviews {
89 | traverse(subview)
90 | }
91 |
92 | }
93 |
94 | traverse(self)
95 |
96 | return hasAmbiguous
97 | }
98 |
99 | }
100 |
--------------------------------------------------------------------------------
/MondrianLayout/Internal/Utils.swift:
--------------------------------------------------------------------------------
1 |
2 | func modify(_ value: inout Value, _ modifier: (inout Value) throws -> Void) rethrows {
3 | try modifier(&value)
4 | }
5 |
6 | func modified(_ value: Value, _ modifier: (inout Value) throws -> Void) rethrows -> Value {
7 | var new = value
8 | try modifier(&new)
9 | return new
10 | }
11 |
--------------------------------------------------------------------------------
/MondrianLayout/Internal/_LayoutElement.swift:
--------------------------------------------------------------------------------
1 |
2 | import UIKit
3 |
4 | /// MondrianLayout internal protocol
5 | public protocol __LayoutElementConvertible {
6 | var _layoutElement: _LayoutElement { get }
7 | }
8 |
9 | extension UIView: __LayoutElementConvertible {
10 | /// MondrianLayout internal property
11 | public var _layoutElement: _LayoutElement {
12 | return .init(view: self)
13 | }
14 | }
15 |
16 | extension UILayoutGuide: __LayoutElementConvertible {
17 | /// MondrianLayout internal property
18 | public var _layoutElement: _LayoutElement {
19 | return .init(layoutGuide: self)
20 | }
21 | }
22 |
23 | /**
24 | Abstraction of element that can be laied out by layout anchors.
25 | */
26 | public struct _LayoutElement: __LayoutElementConvertible {
27 |
28 | public enum XAxisAnchor: Equatable {
29 | case right
30 | case left
31 | case leading
32 | case trailing
33 | case centerX
34 | }
35 |
36 | public enum DimensionAnchor: Equatable {
37 | case width
38 | case height
39 | }
40 |
41 | public enum YAxisAnchor: Equatable {
42 | case top
43 | case bottom
44 | case centerY
45 | }
46 |
47 | public var _layoutElement: _LayoutElement {
48 | self
49 | }
50 |
51 | let leadingAnchor: NSLayoutXAxisAnchor
52 | let trailingAnchor: NSLayoutXAxisAnchor
53 | let leftAnchor: NSLayoutXAxisAnchor
54 | let rightAnchor: NSLayoutXAxisAnchor
55 | let topAnchor: NSLayoutYAxisAnchor
56 | let bottomAnchor: NSLayoutYAxisAnchor
57 | let widthAnchor: NSLayoutDimension
58 | let heightAnchor: NSLayoutDimension
59 | let centerXAnchor: NSLayoutXAxisAnchor
60 | let centerYAnchor: NSLayoutYAxisAnchor
61 |
62 | var owningView: UIView? {
63 | return view?.superview ?? layoutGuide?.owningView
64 | }
65 |
66 | let view: UIView?
67 | let layoutGuide: UILayoutGuide?
68 |
69 | public init(view: UIView) {
70 |
71 | self.view = view
72 | self.layoutGuide = nil
73 |
74 | leadingAnchor = view.leadingAnchor
75 | trailingAnchor = view.trailingAnchor
76 | leftAnchor = view.leftAnchor
77 | rightAnchor = view.rightAnchor
78 | topAnchor = view.topAnchor
79 | bottomAnchor = view.bottomAnchor
80 | widthAnchor = view.widthAnchor
81 | heightAnchor = view.heightAnchor
82 | centerXAnchor = view.centerXAnchor
83 | centerYAnchor = view.centerYAnchor
84 | }
85 |
86 | public init(layoutGuide: UILayoutGuide) {
87 |
88 | self.view = nil
89 | self.layoutGuide = layoutGuide
90 |
91 | leadingAnchor = layoutGuide.leadingAnchor
92 | trailingAnchor = layoutGuide.trailingAnchor
93 | leftAnchor = layoutGuide.leftAnchor
94 | rightAnchor = layoutGuide.rightAnchor
95 | topAnchor = layoutGuide.topAnchor
96 | bottomAnchor = layoutGuide.bottomAnchor
97 | widthAnchor = layoutGuide.widthAnchor
98 | heightAnchor = layoutGuide.heightAnchor
99 | centerXAnchor = layoutGuide.centerXAnchor
100 | centerYAnchor = layoutGuide.centerYAnchor
101 |
102 | }
103 |
104 | func anchor(_ type: XAxisAnchor) -> NSLayoutXAxisAnchor {
105 | switch type {
106 | case .right:
107 | return rightAnchor
108 | case .left:
109 | return leftAnchor
110 | case .leading:
111 | return leadingAnchor
112 | case .trailing:
113 | return trailingAnchor
114 | case .centerX:
115 | return centerXAnchor
116 | }
117 | }
118 |
119 | func anchor(_ type: YAxisAnchor) -> NSLayoutYAxisAnchor {
120 | switch type {
121 | case .top:
122 | return topAnchor
123 | case .bottom:
124 | return bottomAnchor
125 | case .centerY:
126 | return centerYAnchor
127 | }
128 | }
129 |
130 | func anchor(_ type: DimensionAnchor) -> NSLayoutDimension {
131 | switch type {
132 | case .width:
133 | return widthAnchor
134 | case .height:
135 | return heightAnchor
136 | }
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/MondrianLayout/LayoutBlocks/BackgroundBlock.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | /// [MondrianLayout]
4 | /// A descriptor that lays out the content and background content in the parent layout element.
5 | public struct BackgroundBlock:
6 | _LayoutBlockType
7 | {
8 |
9 | // MARK: - Properties
10 |
11 | public var name: String = "Background"
12 |
13 | public var _layoutBlockNode: _LayoutBlockNode {
14 | .background(self)
15 | }
16 |
17 | let content: _LayoutBlockNode
18 | let backgroundContent: _LayoutBlockNode
19 |
20 | // MARK: - Initializers
21 |
22 | init(
23 | content: _LayoutBlockNode,
24 | backgroundContent: _LayoutBlockNode
25 | ) {
26 |
27 | self.content = content
28 | self.backgroundContent = backgroundContent
29 | }
30 |
31 | // MARK: - Functions
32 |
33 | public func setupConstraints(parent: _LayoutElement, in context: LayoutBuilderContext) {
34 |
35 | setupBackground: do {
36 |
37 | switch backgroundContent {
38 | case .layoutGuide(let block):
39 |
40 | context.register(layoutGuideBlock: block)
41 | context.add(
42 | constraints: block.makeConstraintsToEdge(parent)
43 | )
44 |
45 | case .view(let c):
46 |
47 | context.register(viewBlock: c)
48 | context.add(
49 | constraints: c.makeConstraintsToEdge(parent)
50 | )
51 |
52 | case .relative(let c as _LayoutBlockType),
53 | .vStack(let c as _LayoutBlockType),
54 | .hStack(let c as _LayoutBlockType),
55 | .zStack(let c as _LayoutBlockType),
56 | .overlay(let c as _LayoutBlockType),
57 | .background(let c as _LayoutBlockType),
58 | .vGrid(let c as _LayoutBlockType):
59 |
60 | let backgroundLayoutGuide = context.makeLayoutGuide(identifier: "Background")
61 |
62 | context.add(
63 | constraints:
64 | backgroundLayoutGuide.mondrian.layout.edges(.to(parent)).makeConstraints()
65 | )
66 |
67 | c.setupConstraints(
68 | parent: .init(layoutGuide: backgroundLayoutGuide),
69 | in: context
70 | )
71 | }
72 |
73 | }
74 |
75 | setupContent: do {
76 |
77 | switch content {
78 | case .layoutGuide(let block):
79 |
80 | context.register(layoutGuideBlock: block)
81 | context.add(
82 | constraints: block.makeConstraintsToEdge(parent)
83 | )
84 |
85 | case .view(let c):
86 | context.register(viewBlock: c)
87 | context.add(
88 | constraints: c.makeConstraintsToEdge(parent)
89 | )
90 | case .relative(let c as _LayoutBlockType),
91 | .vStack(let c as _LayoutBlockType),
92 | .hStack(let c as _LayoutBlockType),
93 | .zStack(let c as _LayoutBlockType),
94 | .overlay(let c as _LayoutBlockType),
95 | .background(let c as _LayoutBlockType),
96 | .vGrid(let c as _LayoutBlockType):
97 | c.setupConstraints(parent: parent, in: context)
98 | }
99 | }
100 |
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/MondrianLayout/LayoutBlocks/LayoutGuideBlock.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | public struct LayoutGuideBlock:
4 | _LayoutBlockNodeConvertible,
5 | _DimensionConstraintType,
6 | Equatable
7 | {
8 |
9 | public var _layoutBlockNode: _LayoutBlockNode {
10 | return .layoutGuide(self)
11 | }
12 |
13 | public let layoutGuide: UILayoutGuide
14 |
15 | public var dimensionConstraints: DimensionDescriptor = .init()
16 |
17 | public init(
18 | _ layoutGuide: UILayoutGuide
19 | ) {
20 | self.layoutGuide = layoutGuide
21 | }
22 |
23 | func makeConstraintsToEdge(_ element: _LayoutElement) -> [NSLayoutConstraint] {
24 | return layoutGuide.mondrian.layout.edges(.to(element)).makeConstraints()
25 | }
26 |
27 | func makeConstraints() -> [NSLayoutConstraint] {
28 | dimensionConstraints.makeConstraints(for: layoutGuide)
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/MondrianLayout/LayoutBlocks/OverlayBlock.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | /// [MondrianLayout]
4 | /// A descriptor that lays out the content and overlay content in the parent layout element.
5 | public struct OverlayBlock:
6 | _LayoutBlockType
7 | {
8 |
9 | // MARK: - Properties
10 |
11 | public var name: String = "Overlay"
12 |
13 | public var _layoutBlockNode: _LayoutBlockNode {
14 | .overlay(self)
15 | }
16 |
17 | public let content: _LayoutBlockNode
18 | public let overlayContent: _LayoutBlockNode
19 |
20 | // MARK: - Initializers
21 |
22 | init(
23 | content: _LayoutBlockNode,
24 | overlayContent: _LayoutBlockNode
25 | ) {
26 |
27 | self.content = content
28 | self.overlayContent = overlayContent
29 |
30 | }
31 |
32 | // MARK: - Functions
33 |
34 | public func setupConstraints(parent: _LayoutElement, in context: LayoutBuilderContext) {
35 |
36 | setupContent: do {
37 |
38 | switch content {
39 | case .layoutGuide(let block):
40 | context.register(layoutGuideBlock: block)
41 | context.add(
42 | constraints: block.makeConstraintsToEdge(parent)
43 | )
44 | case .view(let block):
45 | context.register(viewBlock: block)
46 | context.add(
47 | constraints: block.makeConstraintsToEdge(parent)
48 | )
49 | case .relative(let c as _LayoutBlockType),
50 | .vStack(let c as _LayoutBlockType),
51 | .hStack(let c as _LayoutBlockType),
52 | .zStack(let c as _LayoutBlockType),
53 | .overlay(let c as _LayoutBlockType),
54 | .background(let c as _LayoutBlockType),
55 | .vGrid(let c as _LayoutBlockType):
56 | c.setupConstraints(parent: parent, in: context)
57 | }
58 | }
59 |
60 | setupOverlay: do {
61 |
62 | switch overlayContent {
63 | case .layoutGuide(let block):
64 | context.register(layoutGuideBlock: block)
65 | context.add(
66 | constraints: block.makeConstraintsToEdge(parent)
67 | )
68 | case .view(let block):
69 |
70 | context.register(viewBlock: block)
71 |
72 | context.add(
73 | constraints: block.makeConstraintsToEdge(parent)
74 | )
75 |
76 | case .relative(let c as _LayoutBlockType),
77 | .vStack(let c as _LayoutBlockType),
78 | .hStack(let c as _LayoutBlockType),
79 | .zStack(let c as _LayoutBlockType),
80 | .overlay(let c as _LayoutBlockType),
81 | .background(let c as _LayoutBlockType),
82 | .vGrid(let c as _LayoutBlockType):
83 |
84 | let overlayLayoutGuide = context.makeLayoutGuide(identifier: "Overlay")
85 |
86 | context.add(
87 | constraints:
88 | overlayLayoutGuide.mondrian.layout.edges(.to(parent)).makeConstraints()
89 | )
90 |
91 | c.setupConstraints(
92 | parent: .init(layoutGuide: overlayLayoutGuide),
93 | in: context
94 | )
95 |
96 | }
97 |
98 | }
99 |
100 | }
101 |
102 | }
103 |
--------------------------------------------------------------------------------
/MondrianLayout/LayoutBlocks/StackingSpacer.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | /// A flexible space that expands along the major axis of its containing stack layout, or on both axes if not contained in a stack.
4 | /// Currently it does work only inside stacking.
5 | public struct StackingSpacer {
6 |
7 | public let minLength: CGFloat
8 | public let expands: Bool
9 |
10 | public init(
11 | minLength: CGFloat,
12 | expands: Bool = true
13 | ) {
14 | self.minLength = minLength
15 | self.expands = expands
16 | }
17 | }
18 |
19 |
--------------------------------------------------------------------------------
/MondrianLayout/LayoutBlocks/ViewBlock.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | public struct AxisMask: OptionSet {
4 |
5 | public var rawValue: Int8
6 | public var isEmpty: Bool {
7 | rawValue == 0
8 | }
9 |
10 | public init(rawValue: Int8) {
11 | self.rawValue = rawValue
12 | }
13 |
14 | public static let vertical: Self = .init(rawValue: 1 << 1)
15 | public static let horizontal: Self = .init(rawValue: 1 << 2)
16 | }
17 |
18 | public struct ViewBlock: _LayoutBlockNodeConvertible, _DimensionConstraintType,
19 | Equatable
20 | {
21 |
22 | public var _layoutBlockNode: _LayoutBlockNode {
23 | return .view(self)
24 | }
25 |
26 | public let view: UIView
27 |
28 | public var dimensionConstraints: DimensionDescriptor = .init()
29 |
30 | var verticalHuggingPriority: UILayoutPriority?
31 | var horizontalHuggingPriority: UILayoutPriority?
32 |
33 | var verticalCompressionResistancePriority: UILayoutPriority?
34 | var horizontalCompressionResistancePriority: UILayoutPriority?
35 |
36 | public init(
37 | _ view: UIView
38 | ) {
39 | self.view = view
40 | }
41 |
42 | private func _modify(_ modifier: (inout Self) -> Void) -> Self {
43 | var new = self
44 | modifier(&new)
45 | return new
46 | }
47 |
48 | public func huggingPriority(
49 | _ axisMask: AxisMask,
50 | _ priority: UILayoutPriority = .required
51 | ) -> Self {
52 | _modify {
53 | if axisMask.contains(.horizontal) {
54 | $0.horizontalHuggingPriority = priority
55 | }
56 | if axisMask.contains(.vertical) {
57 | $0.verticalHuggingPriority = priority
58 | }
59 | }
60 | }
61 |
62 | public func compressionResistancePriority(
63 | _ axisMask: AxisMask,
64 | _ priority: UILayoutPriority = .required
65 | ) -> Self {
66 | _modify {
67 | if axisMask.contains(.horizontal) {
68 | $0.horizontalCompressionResistancePriority = priority
69 | }
70 | if axisMask.contains(.vertical) {
71 | $0.verticalCompressionResistancePriority = priority
72 | }
73 | }
74 | }
75 |
76 | func makeConstraintsToEdge(_ element: _LayoutElement) -> [NSLayoutConstraint] {
77 | return
78 | [
79 | view.topAnchor.constraint(equalTo: element.topAnchor),
80 | view.leadingAnchor.constraint(equalTo: element.leadingAnchor),
81 | view.bottomAnchor.constraint(equalTo: element.bottomAnchor),
82 | view.trailingAnchor.constraint(equalTo: element.trailingAnchor),
83 | ]
84 |
85 | }
86 |
87 | func makeApplier() -> () -> Void {
88 |
89 | return { [weak view] in
90 |
91 | guard let view = view else { return }
92 |
93 | if let priority = verticalHuggingPriority {
94 | view.setContentHuggingPriority(priority, for: .vertical)
95 | }
96 | if let priority = horizontalHuggingPriority {
97 | view.setContentHuggingPriority(priority, for: .horizontal)
98 | }
99 | if let priority = verticalCompressionResistancePriority {
100 | view.setContentCompressionResistancePriority(priority, for: .vertical)
101 | }
102 | if let priority = horizontalCompressionResistancePriority {
103 | view.setContentCompressionResistancePriority(priority, for: .horizontal)
104 | }
105 | }
106 | }
107 |
108 | func makeConstraints() -> [NSLayoutConstraint] {
109 | dimensionConstraints.makeConstraints(for: view)
110 | }
111 |
112 | }
113 |
--------------------------------------------------------------------------------
/MondrianLayout/Manager/LayoutManager.swift:
--------------------------------------------------------------------------------
1 |
2 | import UIKit
3 |
4 | /**
5 | An object that manages layout.
6 | It supports updating the layout.
7 | In the case of defining distinct layouts under some conditions, this helps.
8 |
9 | ```swift
10 | /// Defines a instance
11 | /// It needs to be retained somewhere such as inside view controller or view.
12 | let manager = LayoutManager()
13 |
14 | /// Sets up the layout in the escaping closure
15 | manager.setup(on: view) {
16 | VStackBlock {
17 | ...
18 | }
19 | }
20 |
21 | /// Calls when you need to get a new layout.
22 | /// It calls the closure set in `setup` to build subviews again.
23 | manager.reloadLayout()
24 | ```
25 |
26 | */
27 | public final class LayoutManager {
28 |
29 | private var _layoutBuilder: (() -> [EntrypointBuilder.Either])?
30 | private var currentContext: LayoutBuilderContext?
31 | private weak var targetView: UIView?
32 |
33 | public init() {
34 | }
35 |
36 | /**
37 | Setting up the layout of subviews on the view.
38 | the layout closure is called each calling `reloadLayout` and after `setup`.
39 |
40 | Please avoid creating view and layout-guide instances in the closure. Performance decreases by creating a new instance and destroying the previous one.
41 | */
42 | public func setup(
43 | on view: UIView,
44 | @EntrypointBuilder layout: @escaping () -> [EntrypointBuilder.Either]
45 | ) {
46 | targetView = view
47 | _layoutBuilder = layout
48 | reloadLayout()
49 | }
50 |
51 | /**
52 | Re lays out the subviews with deactivating the current layout.
53 | */
54 | public func reloadLayout() {
55 | guard let _layoutBuilder = _layoutBuilder else {
56 | return
57 | }
58 |
59 | guard let targetView = targetView else {
60 | return
61 | }
62 |
63 | let previousContext = currentContext
64 |
65 | previousContext?.deactivate()
66 | let newContext = targetView.mondrian.buildSubviews(_layoutBuilder)
67 | currentContext = newContext
68 |
69 | }
70 |
71 | }
72 |
--------------------------------------------------------------------------------
/MondrianLayout/MondrianNamespace.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | public struct MondrianNamespace {
4 |
5 | public let base: Base
6 |
7 | init(base: Base) {
8 | self.base = base
9 | }
10 | }
11 |
12 | extension MondrianNamespace where Base: UIView {
13 |
14 | /**
15 | Entry point to describe layout constraints
16 | Activates by calling `activate()` or using `mondrianBatchLayout`
17 |
18 | ```swift
19 | view.mondrian.layout
20 | .top(.toSuperview)
21 | .left(.toSuperview)
22 | .right(.to(box2).left)
23 | .bottom(.to(box2).bottom)
24 | .activate()
25 | ```
26 | */
27 | public var layout: LayoutDescriptor {
28 | .init(view: base)
29 | }
30 | //
31 | // public var block: ViewBlock {
32 | // .init(base)
33 | // }
34 |
35 | }
36 |
37 | extension MondrianNamespace where Base: UILayoutGuide {
38 |
39 | /**
40 | Entry point to describe layout constraints
41 | Activates by calling `activate()` or using `mondrianBatchLayout`
42 |
43 | ```swift
44 | view.mondrian.layout
45 | .top(.toSuperview)
46 | .left(.toSuperview)
47 | .right(.to(box2).left)
48 | .bottom(.to(box2).bottom)
49 | .activate()
50 | ```
51 | */
52 | public var layout: LayoutDescriptor {
53 | .init(layoutGuide: base)
54 | }
55 | //
56 | // public var block: LayoutGuideBlock {
57 | // .init(base)
58 | // }
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.3
2 | import PackageDescription
3 |
4 | let package = Package(
5 | name: "MondrianLayout",
6 | platforms: [.iOS(.v12)],
7 | products: [
8 | .library(name: "MondrianLayout", type: .static, targets: ["MondrianLayout"]),
9 | .library(name: "MondrianLayoutDynamic", type: .dynamic, targets: ["MondrianLayout"])
10 | ],
11 | dependencies: [],
12 | targets: [
13 | .target(
14 | name: "MondrianLayout",
15 | dependencies: [],
16 | path: "MondrianLayout"
17 | )
18 | ]
19 | )
20 |
--------------------------------------------------------------------------------
/RevealServer.xcframework/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | AvailableLibraries
6 |
7 |
8 | DebugSymbolsPath
9 | dSYMs
10 | LibraryIdentifier
11 | ios-arm64_x86_64-maccatalyst
12 | LibraryPath
13 | RevealServer.framework
14 | SupportedArchitectures
15 |
16 | arm64
17 | x86_64
18 |
19 | SupportedPlatform
20 | ios
21 | SupportedPlatformVariant
22 | maccatalyst
23 |
24 |
25 | DebugSymbolsPath
26 | dSYMs
27 | LibraryIdentifier
28 | ios-arm64_armv7
29 | LibraryPath
30 | RevealServer.framework
31 | SupportedArchitectures
32 |
33 | arm64
34 | armv7
35 |
36 | SupportedPlatform
37 | ios
38 |
39 |
40 | DebugSymbolsPath
41 | dSYMs
42 | LibraryIdentifier
43 | ios-arm64_i386_x86_64-simulator
44 | LibraryPath
45 | RevealServer.framework
46 | SupportedArchitectures
47 |
48 | arm64
49 | i386
50 | x86_64
51 |
52 | SupportedPlatform
53 | ios
54 | SupportedPlatformVariant
55 | simulator
56 |
57 |
58 | DebugSymbolsPath
59 | dSYMs
60 | LibraryIdentifier
61 | tvos-arm64_x86_64-simulator
62 | LibraryPath
63 | RevealServer.framework
64 | SupportedArchitectures
65 |
66 | arm64
67 | x86_64
68 |
69 | SupportedPlatform
70 | tvos
71 | SupportedPlatformVariant
72 | simulator
73 |
74 |
75 | DebugSymbolsPath
76 | dSYMs
77 | LibraryIdentifier
78 | tvos-arm64
79 | LibraryPath
80 | RevealServer.framework
81 | SupportedArchitectures
82 |
83 | arm64
84 |
85 | SupportedPlatform
86 | tvos
87 |
88 |
89 | CFBundlePackageType
90 | XFWK
91 | XCFrameworkFormatVersion
92 | 1.0
93 |
94 |
95 |
--------------------------------------------------------------------------------
/RevealServer.xcframework/Scripts/integrate_revealserver.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -o errexit
3 | set -o nounset
4 |
5 | # This script takes care of integrating Reveal Server into your iOS application target when you have already manually linked the XCFramework into your app.
6 |
7 | # If the current build configuration as defined by the environment variable CONFIGURATION does not match the name provided by REVEAL_LOAD_FOR_CONFIGURATION (this defaults to "Debug"), then any copies of RevealServer that Xcode has copied into your application will be removed.
8 |
9 | # NOTE: This script is intended to be run from within an Xcode run script build phase, and won't work without the environment variables provided therein.
10 |
11 | # If you want to inspect your app using Reveal in build configurations that are not the default "Debug" configuration, override the REVEAL_LOAD_FOR_CONFIGURATION environment variable with the full name of your desired configuration.
12 | load_trigger=${REVEAL_LOAD_FOR_CONFIGURATION:-Debug}
13 |
14 | if [ "${PLATFORM_NAME}" == *simulator ]; then
15 | echo "Reveal Server not integrated into ${TARGET_NAME}: Targeted platform is simulated, and does not require it."
16 | exit 0
17 | fi
18 |
19 | if [ "${CONFIGURATION}" != "${load_trigger}" ]; then
20 | # If we are not running in the expected configuration, remove the RevealServer framework (which needs to have been weakly linked).
21 | bundled_reveal_server="${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RevealServer.framework"
22 |
23 | if [ -e "${bundled_reveal_server}" ]; then
24 | rm -r "${bundled_reveal_server}"
25 | fi
26 |
27 | echo "Reveal Server has been removed from ${TARGET_NAME}: Current build configuration is not '${load_trigger}'."
28 | exit 0
29 | fi
30 |
31 | # Otherwise, we need to insert the NSBonjourServices array into the app's Info.plist. It's OK if this fails due to the key already existing.
32 | plutil -insert NSBonjourServices -xml '' "${CONFIGURATION_BUILD_DIR}/${INFOPLIST_PATH}" || true
33 |
34 | # Insert Reveal's Bonjour details into the NSBonjourServices array.
35 | plutil -insert NSBonjourServices.0 -string "_reveal._tcp" "${CONFIGURATION_BUILD_DIR}/${INFOPLIST_PATH}"
36 |
37 | echo "An NSBonjourServices entry for Reveal (_reveal._tcp) has been added to ${INFOPLIST_PATH}"
38 |
39 | echo "Reveal Server has been successfully integrated into ${TARGET_NAME}."
40 |
--------------------------------------------------------------------------------
/RevealServer.xcframework/_CodeSignature/CodeDirectory:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluidGroup/MondrianLayout/b26edaa5a469bc5fd58f9afe37d257ca1b3771e0/RevealServer.xcframework/_CodeSignature/CodeDirectory
--------------------------------------------------------------------------------
/RevealServer.xcframework/_CodeSignature/CodeRequirements:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluidGroup/MondrianLayout/b26edaa5a469bc5fd58f9afe37d257ca1b3771e0/RevealServer.xcframework/_CodeSignature/CodeRequirements
--------------------------------------------------------------------------------
/RevealServer.xcframework/_CodeSignature/CodeRequirements-1:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluidGroup/MondrianLayout/b26edaa5a469bc5fd58f9afe37d257ca1b3771e0/RevealServer.xcframework/_CodeSignature/CodeRequirements-1
--------------------------------------------------------------------------------
/RevealServer.xcframework/_CodeSignature/CodeSignature:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluidGroup/MondrianLayout/b26edaa5a469bc5fd58f9afe37d257ca1b3771e0/RevealServer.xcframework/_CodeSignature/CodeSignature
--------------------------------------------------------------------------------
/RevealServer.xcframework/ios-arm64_armv7/RevealServer.framework/Headers/RevealServer.h:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright © 2015 Itty Bitty Apps, Pty Ltd. All rights reserved.
3 |
4 | #import
5 |
6 | //! Project version number for RevealServer.
7 | FOUNDATION_EXPORT double RevealServerVersionNumber;
8 |
9 | //! Project version string for RevealServer.
10 | FOUNDATION_EXPORT const unsigned char RevealServerVersionString[];
11 |
12 |
--------------------------------------------------------------------------------
/RevealServer.xcframework/ios-arm64_armv7/RevealServer.framework/Info.plist:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluidGroup/MondrianLayout/b26edaa5a469bc5fd58f9afe37d257ca1b3771e0/RevealServer.xcframework/ios-arm64_armv7/RevealServer.framework/Info.plist
--------------------------------------------------------------------------------
/RevealServer.xcframework/ios-arm64_armv7/RevealServer.framework/Modules/module.modulemap:
--------------------------------------------------------------------------------
1 | framework module RevealServer {
2 | umbrella header "RevealServer.h"
3 |
4 | export *
5 | module * { export * }
6 | }
7 |
--------------------------------------------------------------------------------
/RevealServer.xcframework/ios-arm64_armv7/RevealServer.framework/RevealServer:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluidGroup/MondrianLayout/b26edaa5a469bc5fd58f9afe37d257ca1b3771e0/RevealServer.xcframework/ios-arm64_armv7/RevealServer.framework/RevealServer
--------------------------------------------------------------------------------
/RevealServer.xcframework/ios-arm64_armv7/RevealServer.framework/Scripts/integrate_revealserver.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -o errexit
3 | set -o nounset
4 |
5 | # This script takes care of integrating Reveal Server into your iOS application target when you have already manually linked the XCFramework into your app.
6 |
7 | # If the current build configuration as defined by the environment variable CONFIGURATION does not match the name provided by REVEAL_LOAD_FOR_CONFIGURATION (this defaults to "Debug"), then any copies of RevealServer that Xcode has copied into your application will be removed.
8 |
9 | # NOTE: This script is intended to be run from within an Xcode run script build phase, and won't work without the environment variables provided therein.
10 |
11 | # If you want to inspect your app using Reveal in build configurations that are not the default "Debug" configuration, override the REVEAL_LOAD_FOR_CONFIGURATION environment variable with the full name of your desired configuration.
12 | load_trigger=${REVEAL_LOAD_FOR_CONFIGURATION:-Debug}
13 |
14 | if [ "${PLATFORM_NAME}" == *simulator ]; then
15 | echo "Reveal Server not integrated into ${TARGET_NAME}: Targeted platform is simulated, and does not require it."
16 | exit 0
17 | fi
18 |
19 | if [ "${CONFIGURATION}" != "${load_trigger}" ]; then
20 | # If we are not running in the expected configuration, remove the RevealServer framework (which needs to have been weakly linked).
21 | bundled_reveal_server="${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RevealServer.framework"
22 |
23 | if [ -e "${bundled_reveal_server}" ]; then
24 | rm -r "${bundled_reveal_server}"
25 | fi
26 |
27 | echo "Reveal Server has been removed from ${TARGET_NAME}: Current build configuration is not '${load_trigger}'."
28 | exit 0
29 | fi
30 |
31 | # Otherwise, we need to insert the NSBonjourServices array into the app's Info.plist. It's OK if this fails due to the key already existing.
32 | plutil -insert NSBonjourServices -xml '' "${CONFIGURATION_BUILD_DIR}/${INFOPLIST_PATH}" || true
33 |
34 | # Insert Reveal's Bonjour details into the NSBonjourServices array.
35 | plutil -insert NSBonjourServices.0 -string "_reveal._tcp" "${CONFIGURATION_BUILD_DIR}/${INFOPLIST_PATH}"
36 |
37 | echo "An NSBonjourServices entry for Reveal (_reveal._tcp) has been added to ${INFOPLIST_PATH}"
38 |
39 | echo "Reveal Server has been successfully integrated into ${TARGET_NAME}."
40 |
--------------------------------------------------------------------------------
/RevealServer.xcframework/ios-arm64_armv7/RevealServer.framework/_CodeSignature/CodeResources:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | files
6 |
7 | Headers/RevealServer.h
8 |
9 | JavE2LI6bNGfH9W90/bDxwIxVlg=
10 |
11 | Info.plist
12 |
13 | Oo7PlxKe5fz4rMQ1m3/8Z6QxBVo=
14 |
15 | Modules/module.modulemap
16 |
17 | EuDEeG1dcC1sd+hIW2SkUAImUg8=
18 |
19 | Scripts/integrate_revealserver.sh
20 |
21 | pDjnAHC1xiLNLJDDIIrTACRCcFA=
22 |
23 |
24 | files2
25 |
26 | Headers/RevealServer.h
27 |
28 | hash
29 |
30 | JavE2LI6bNGfH9W90/bDxwIxVlg=
31 |
32 | hash2
33 |
34 | weLK/65HyV1EiL9dd4xoAqQhf0/0r/Oy6os2nXCA+Ew=
35 |
36 |
37 | Modules/module.modulemap
38 |
39 | hash
40 |
41 | EuDEeG1dcC1sd+hIW2SkUAImUg8=
42 |
43 | hash2
44 |
45 | tstqiJpIPr4iEd3MDHClLuTB/ciSC/zNlke1AjfSVuU=
46 |
47 |
48 | Scripts/integrate_revealserver.sh
49 |
50 | hash
51 |
52 | pDjnAHC1xiLNLJDDIIrTACRCcFA=
53 |
54 | hash2
55 |
56 | XOjBVOZRN/oNePfbAbXae72e3s7W6HqdKnPKJdHque8=
57 |
58 |
59 |
60 | rules
61 |
62 | ^.*
63 |
64 | ^.*\.lproj/
65 |
66 | optional
67 |
68 | weight
69 | 1000
70 |
71 | ^.*\.lproj/locversion.plist$
72 |
73 | omit
74 |
75 | weight
76 | 1100
77 |
78 | ^Base\.lproj/
79 |
80 | weight
81 | 1010
82 |
83 | ^version.plist$
84 |
85 |
86 | rules2
87 |
88 | .*\.dSYM($|/)
89 |
90 | weight
91 | 11
92 |
93 | ^(.*/)?\.DS_Store$
94 |
95 | omit
96 |
97 | weight
98 | 2000
99 |
100 | ^.*
101 |
102 | ^.*\.lproj/
103 |
104 | optional
105 |
106 | weight
107 | 1000
108 |
109 | ^.*\.lproj/locversion.plist$
110 |
111 | omit
112 |
113 | weight
114 | 1100
115 |
116 | ^Base\.lproj/
117 |
118 | weight
119 | 1010
120 |
121 | ^Info\.plist$
122 |
123 | omit
124 |
125 | weight
126 | 20
127 |
128 | ^PkgInfo$
129 |
130 | omit
131 |
132 | weight
133 | 20
134 |
135 | ^embedded\.provisionprofile$
136 |
137 | weight
138 | 20
139 |
140 | ^version\.plist$
141 |
142 | weight
143 | 20
144 |
145 |
146 |
147 |
148 |
--------------------------------------------------------------------------------
/RevealServer.xcframework/ios-arm64_i386_x86_64-simulator/RevealServer.framework/Headers/RevealServer.h:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright © 2015 Itty Bitty Apps, Pty Ltd. All rights reserved.
3 |
4 | #import
5 |
6 | //! Project version number for RevealServer.
7 | FOUNDATION_EXPORT double RevealServerVersionNumber;
8 |
9 | //! Project version string for RevealServer.
10 | FOUNDATION_EXPORT const unsigned char RevealServerVersionString[];
11 |
12 |
--------------------------------------------------------------------------------
/RevealServer.xcframework/ios-arm64_i386_x86_64-simulator/RevealServer.framework/Info.plist:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluidGroup/MondrianLayout/b26edaa5a469bc5fd58f9afe37d257ca1b3771e0/RevealServer.xcframework/ios-arm64_i386_x86_64-simulator/RevealServer.framework/Info.plist
--------------------------------------------------------------------------------
/RevealServer.xcframework/ios-arm64_i386_x86_64-simulator/RevealServer.framework/Modules/module.modulemap:
--------------------------------------------------------------------------------
1 | framework module RevealServer {
2 | umbrella header "RevealServer.h"
3 |
4 | export *
5 | module * { export * }
6 | }
7 |
--------------------------------------------------------------------------------
/RevealServer.xcframework/ios-arm64_i386_x86_64-simulator/RevealServer.framework/RevealServer:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluidGroup/MondrianLayout/b26edaa5a469bc5fd58f9afe37d257ca1b3771e0/RevealServer.xcframework/ios-arm64_i386_x86_64-simulator/RevealServer.framework/RevealServer
--------------------------------------------------------------------------------
/RevealServer.xcframework/ios-arm64_i386_x86_64-simulator/RevealServer.framework/Scripts/integrate_revealserver.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -o errexit
3 | set -o nounset
4 |
5 | # This script takes care of integrating Reveal Server into your iOS application target when you have already manually linked the XCFramework into your app.
6 |
7 | # If the current build configuration as defined by the environment variable CONFIGURATION does not match the name provided by REVEAL_LOAD_FOR_CONFIGURATION (this defaults to "Debug"), then any copies of RevealServer that Xcode has copied into your application will be removed.
8 |
9 | # NOTE: This script is intended to be run from within an Xcode run script build phase, and won't work without the environment variables provided therein.
10 |
11 | # If you want to inspect your app using Reveal in build configurations that are not the default "Debug" configuration, override the REVEAL_LOAD_FOR_CONFIGURATION environment variable with the full name of your desired configuration.
12 | load_trigger=${REVEAL_LOAD_FOR_CONFIGURATION:-Debug}
13 |
14 | if [ "${PLATFORM_NAME}" == *simulator ]; then
15 | echo "Reveal Server not integrated into ${TARGET_NAME}: Targeted platform is simulated, and does not require it."
16 | exit 0
17 | fi
18 |
19 | if [ "${CONFIGURATION}" != "${load_trigger}" ]; then
20 | # If we are not running in the expected configuration, remove the RevealServer framework (which needs to have been weakly linked).
21 | bundled_reveal_server="${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RevealServer.framework"
22 |
23 | if [ -e "${bundled_reveal_server}" ]; then
24 | rm -r "${bundled_reveal_server}"
25 | fi
26 |
27 | echo "Reveal Server has been removed from ${TARGET_NAME}: Current build configuration is not '${load_trigger}'."
28 | exit 0
29 | fi
30 |
31 | # Otherwise, we need to insert the NSBonjourServices array into the app's Info.plist. It's OK if this fails due to the key already existing.
32 | plutil -insert NSBonjourServices -xml '' "${CONFIGURATION_BUILD_DIR}/${INFOPLIST_PATH}" || true
33 |
34 | # Insert Reveal's Bonjour details into the NSBonjourServices array.
35 | plutil -insert NSBonjourServices.0 -string "_reveal._tcp" "${CONFIGURATION_BUILD_DIR}/${INFOPLIST_PATH}"
36 |
37 | echo "An NSBonjourServices entry for Reveal (_reveal._tcp) has been added to ${INFOPLIST_PATH}"
38 |
39 | echo "Reveal Server has been successfully integrated into ${TARGET_NAME}."
40 |
--------------------------------------------------------------------------------
/RevealServer.xcframework/ios-arm64_i386_x86_64-simulator/RevealServer.framework/_CodeSignature/CodeResources:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | files
6 |
7 | Headers/RevealServer.h
8 |
9 | JavE2LI6bNGfH9W90/bDxwIxVlg=
10 |
11 | Info.plist
12 |
13 | hpLxIgCYsaLsKpf7FYEcsZa3Fmw=
14 |
15 | Modules/module.modulemap
16 |
17 | EuDEeG1dcC1sd+hIW2SkUAImUg8=
18 |
19 | Scripts/integrate_revealserver.sh
20 |
21 | pDjnAHC1xiLNLJDDIIrTACRCcFA=
22 |
23 |
24 | files2
25 |
26 | Headers/RevealServer.h
27 |
28 | hash
29 |
30 | JavE2LI6bNGfH9W90/bDxwIxVlg=
31 |
32 | hash2
33 |
34 | weLK/65HyV1EiL9dd4xoAqQhf0/0r/Oy6os2nXCA+Ew=
35 |
36 |
37 | Modules/module.modulemap
38 |
39 | hash
40 |
41 | EuDEeG1dcC1sd+hIW2SkUAImUg8=
42 |
43 | hash2
44 |
45 | tstqiJpIPr4iEd3MDHClLuTB/ciSC/zNlke1AjfSVuU=
46 |
47 |
48 | Scripts/integrate_revealserver.sh
49 |
50 | hash
51 |
52 | pDjnAHC1xiLNLJDDIIrTACRCcFA=
53 |
54 | hash2
55 |
56 | XOjBVOZRN/oNePfbAbXae72e3s7W6HqdKnPKJdHque8=
57 |
58 |
59 |
60 | rules
61 |
62 | ^.*
63 |
64 | ^.*\.lproj/
65 |
66 | optional
67 |
68 | weight
69 | 1000
70 |
71 | ^.*\.lproj/locversion.plist$
72 |
73 | omit
74 |
75 | weight
76 | 1100
77 |
78 | ^Base\.lproj/
79 |
80 | weight
81 | 1010
82 |
83 | ^version.plist$
84 |
85 |
86 | rules2
87 |
88 | .*\.dSYM($|/)
89 |
90 | weight
91 | 11
92 |
93 | ^(.*/)?\.DS_Store$
94 |
95 | omit
96 |
97 | weight
98 | 2000
99 |
100 | ^.*
101 |
102 | ^.*\.lproj/
103 |
104 | optional
105 |
106 | weight
107 | 1000
108 |
109 | ^.*\.lproj/locversion.plist$
110 |
111 | omit
112 |
113 | weight
114 | 1100
115 |
116 | ^Base\.lproj/
117 |
118 | weight
119 | 1010
120 |
121 | ^Info\.plist$
122 |
123 | omit
124 |
125 | weight
126 | 20
127 |
128 | ^PkgInfo$
129 |
130 | omit
131 |
132 | weight
133 | 20
134 |
135 | ^embedded\.provisionprofile$
136 |
137 | weight
138 | 20
139 |
140 | ^version\.plist$
141 |
142 | weight
143 | 20
144 |
145 |
146 |
147 |
148 |
--------------------------------------------------------------------------------
/RevealServer.xcframework/ios-arm64_x86_64-maccatalyst/RevealServer.framework/Headers:
--------------------------------------------------------------------------------
1 | Versions/Current/Headers
--------------------------------------------------------------------------------
/RevealServer.xcframework/ios-arm64_x86_64-maccatalyst/RevealServer.framework/Modules:
--------------------------------------------------------------------------------
1 | Versions/Current/Modules
--------------------------------------------------------------------------------
/RevealServer.xcframework/ios-arm64_x86_64-maccatalyst/RevealServer.framework/Resources:
--------------------------------------------------------------------------------
1 | Versions/Current/Resources
--------------------------------------------------------------------------------
/RevealServer.xcframework/ios-arm64_x86_64-maccatalyst/RevealServer.framework/RevealServer:
--------------------------------------------------------------------------------
1 | Versions/Current/RevealServer
--------------------------------------------------------------------------------
/RevealServer.xcframework/ios-arm64_x86_64-maccatalyst/RevealServer.framework/Versions/A/Headers/RevealServer.h:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright © 2015 Itty Bitty Apps, Pty Ltd. All rights reserved.
3 |
4 | #import
5 |
6 | //! Project version number for RevealServer.
7 | FOUNDATION_EXPORT double RevealServerVersionNumber;
8 |
9 | //! Project version string for RevealServer.
10 | FOUNDATION_EXPORT const unsigned char RevealServerVersionString[];
11 |
12 |
--------------------------------------------------------------------------------
/RevealServer.xcframework/ios-arm64_x86_64-maccatalyst/RevealServer.framework/Versions/A/Modules/module.modulemap:
--------------------------------------------------------------------------------
1 | framework module RevealServer {
2 | umbrella header "RevealServer.h"
3 |
4 | export *
5 | module * { export * }
6 | }
7 |
--------------------------------------------------------------------------------
/RevealServer.xcframework/ios-arm64_x86_64-maccatalyst/RevealServer.framework/Versions/A/Resources/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | BuildMachineOSBuild
6 | 21A559
7 | CFBundleDevelopmentRegion
8 | en
9 | CFBundleExecutable
10 | RevealServer
11 | CFBundleIdentifier
12 | com.ittybittyapps.RevealServer
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | RevealServer
17 | CFBundlePackageType
18 | FMWK
19 | CFBundleShortVersionString
20 | 2.0
21 | CFBundleSupportedPlatforms
22 |
23 | MacOSX
24 |
25 | CFBundleVersion
26 | 2.0.0
27 | DTCompiler
28 | com.apple.compilers.llvm.clang.1_0
29 | DTPlatformBuild
30 | 13C90
31 | DTPlatformName
32 | macosx
33 | DTPlatformVersion
34 | 12.1
35 | DTSDKBuild
36 | 21C46
37 | DTSDKName
38 | macosx12.1
39 | DTXcode
40 | 1320
41 | DTXcodeBuild
42 | 13C90
43 | LSMinimumSystemVersion
44 | 10.15
45 | UIDeviceFamily
46 |
47 | 2
48 | 6
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/RevealServer.xcframework/ios-arm64_x86_64-maccatalyst/RevealServer.framework/Versions/A/Resources/Scripts/integrate_revealserver.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -o errexit
3 | set -o nounset
4 |
5 | # This script takes care of integrating Reveal Server into your iOS application target when you have already manually linked the XCFramework into your app.
6 |
7 | # If the current build configuration as defined by the environment variable CONFIGURATION does not match the name provided by REVEAL_LOAD_FOR_CONFIGURATION (this defaults to "Debug"), then any copies of RevealServer that Xcode has copied into your application will be removed.
8 |
9 | # NOTE: This script is intended to be run from within an Xcode run script build phase, and won't work without the environment variables provided therein.
10 |
11 | # If you want to inspect your app using Reveal in build configurations that are not the default "Debug" configuration, override the REVEAL_LOAD_FOR_CONFIGURATION environment variable with the full name of your desired configuration.
12 | load_trigger=${REVEAL_LOAD_FOR_CONFIGURATION:-Debug}
13 |
14 | if [ "${PLATFORM_NAME}" == *simulator ]; then
15 | echo "Reveal Server not integrated into ${TARGET_NAME}: Targeted platform is simulated, and does not require it."
16 | exit 0
17 | fi
18 |
19 | if [ "${CONFIGURATION}" != "${load_trigger}" ]; then
20 | # If we are not running in the expected configuration, remove the RevealServer framework (which needs to have been weakly linked).
21 | bundled_reveal_server="${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RevealServer.framework"
22 |
23 | if [ -e "${bundled_reveal_server}" ]; then
24 | rm -r "${bundled_reveal_server}"
25 | fi
26 |
27 | echo "Reveal Server has been removed from ${TARGET_NAME}: Current build configuration is not '${load_trigger}'."
28 | exit 0
29 | fi
30 |
31 | # Otherwise, we need to insert the NSBonjourServices array into the app's Info.plist. It's OK if this fails due to the key already existing.
32 | plutil -insert NSBonjourServices -xml '' "${CONFIGURATION_BUILD_DIR}/${INFOPLIST_PATH}" || true
33 |
34 | # Insert Reveal's Bonjour details into the NSBonjourServices array.
35 | plutil -insert NSBonjourServices.0 -string "_reveal._tcp" "${CONFIGURATION_BUILD_DIR}/${INFOPLIST_PATH}"
36 |
37 | echo "An NSBonjourServices entry for Reveal (_reveal._tcp) has been added to ${INFOPLIST_PATH}"
38 |
39 | echo "Reveal Server has been successfully integrated into ${TARGET_NAME}."
40 |
--------------------------------------------------------------------------------
/RevealServer.xcframework/ios-arm64_x86_64-maccatalyst/RevealServer.framework/Versions/A/RevealServer:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluidGroup/MondrianLayout/b26edaa5a469bc5fd58f9afe37d257ca1b3771e0/RevealServer.xcframework/ios-arm64_x86_64-maccatalyst/RevealServer.framework/Versions/A/RevealServer
--------------------------------------------------------------------------------
/RevealServer.xcframework/ios-arm64_x86_64-maccatalyst/RevealServer.framework/Versions/A/_CodeSignature/CodeResources:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | files
6 |
7 | Resources/Info.plist
8 |
9 | et//D8sEtGeZE028IqHQT2le8nA=
10 |
11 | Resources/Scripts/integrate_revealserver.sh
12 |
13 | pDjnAHC1xiLNLJDDIIrTACRCcFA=
14 |
15 |
16 | files2
17 |
18 | Headers/RevealServer.h
19 |
20 | hash2
21 |
22 | weLK/65HyV1EiL9dd4xoAqQhf0/0r/Oy6os2nXCA+Ew=
23 |
24 |
25 | Modules/module.modulemap
26 |
27 | hash2
28 |
29 | tstqiJpIPr4iEd3MDHClLuTB/ciSC/zNlke1AjfSVuU=
30 |
31 |
32 | Resources/Info.plist
33 |
34 | hash2
35 |
36 | 7hhQs89td/Za58K/uMm6HB7+XekoilqLk0CBY1wHHyM=
37 |
38 |
39 | Resources/Scripts/integrate_revealserver.sh
40 |
41 | hash2
42 |
43 | XOjBVOZRN/oNePfbAbXae72e3s7W6HqdKnPKJdHque8=
44 |
45 |
46 |
47 | rules
48 |
49 | ^Resources/
50 |
51 | ^Resources/.*\.lproj/
52 |
53 | optional
54 |
55 | weight
56 | 1000
57 |
58 | ^Resources/.*\.lproj/locversion.plist$
59 |
60 | omit
61 |
62 | weight
63 | 1100
64 |
65 | ^Resources/Base\.lproj/
66 |
67 | weight
68 | 1010
69 |
70 | ^version.plist$
71 |
72 |
73 | rules2
74 |
75 | .*\.dSYM($|/)
76 |
77 | weight
78 | 11
79 |
80 | ^(.*/)?\.DS_Store$
81 |
82 | omit
83 |
84 | weight
85 | 2000
86 |
87 | ^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/
88 |
89 | nested
90 |
91 | weight
92 | 10
93 |
94 | ^.*
95 |
96 | ^Info\.plist$
97 |
98 | omit
99 |
100 | weight
101 | 20
102 |
103 | ^PkgInfo$
104 |
105 | omit
106 |
107 | weight
108 | 20
109 |
110 | ^Resources/
111 |
112 | weight
113 | 20
114 |
115 | ^Resources/.*\.lproj/
116 |
117 | optional
118 |
119 | weight
120 | 1000
121 |
122 | ^Resources/.*\.lproj/locversion.plist$
123 |
124 | omit
125 |
126 | weight
127 | 1100
128 |
129 | ^Resources/Base\.lproj/
130 |
131 | weight
132 | 1010
133 |
134 | ^[^/]+$
135 |
136 | nested
137 |
138 | weight
139 | 10
140 |
141 | ^embedded\.provisionprofile$
142 |
143 | weight
144 | 20
145 |
146 | ^version\.plist$
147 |
148 | weight
149 | 20
150 |
151 |
152 |
153 |
154 |
--------------------------------------------------------------------------------
/RevealServer.xcframework/ios-arm64_x86_64-maccatalyst/RevealServer.framework/Versions/Current:
--------------------------------------------------------------------------------
1 | A
--------------------------------------------------------------------------------
/RevealServer.xcframework/ios-x86_64-maccatalyst/RevealServer.framework/Headers:
--------------------------------------------------------------------------------
1 | Versions/Current/Headers
--------------------------------------------------------------------------------
/RevealServer.xcframework/ios-x86_64-maccatalyst/RevealServer.framework/Modules:
--------------------------------------------------------------------------------
1 | Versions/Current/Modules
--------------------------------------------------------------------------------
/RevealServer.xcframework/ios-x86_64-maccatalyst/RevealServer.framework/Resources:
--------------------------------------------------------------------------------
1 | Versions/Current/Resources
--------------------------------------------------------------------------------
/RevealServer.xcframework/ios-x86_64-maccatalyst/RevealServer.framework/RevealServer:
--------------------------------------------------------------------------------
1 | Versions/Current/RevealServer
--------------------------------------------------------------------------------
/RevealServer.xcframework/ios-x86_64-maccatalyst/RevealServer.framework/Versions/A/Headers/RevealServer.h:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright © 2015 Itty Bitty Apps, Pty Ltd. All rights reserved.
3 |
4 | #import
5 |
6 | //! Project version number for RevealServer.
7 | FOUNDATION_EXPORT double RevealServerVersionNumber;
8 |
9 | //! Project version string for RevealServer.
10 | FOUNDATION_EXPORT const unsigned char RevealServerVersionString[];
11 |
12 |
--------------------------------------------------------------------------------
/RevealServer.xcframework/ios-x86_64-maccatalyst/RevealServer.framework/Versions/A/Modules/module.modulemap:
--------------------------------------------------------------------------------
1 | framework module RevealServer {
2 | umbrella header "RevealServer.h"
3 |
4 | export *
5 | module * { export * }
6 | }
7 |
--------------------------------------------------------------------------------
/RevealServer.xcframework/ios-x86_64-maccatalyst/RevealServer.framework/Versions/A/Resources/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | BuildMachineOSBuild
6 | 19H2
7 | CFBundleDevelopmentRegion
8 | en
9 | CFBundleExecutable
10 | RevealServer
11 | CFBundleIdentifier
12 | com.ittybittyapps.RevealServer
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | RevealServer
17 | CFBundlePackageType
18 | FMWK
19 | CFBundleShortVersionString
20 | 2.0
21 | CFBundleSupportedPlatforms
22 |
23 | MacOSX
24 |
25 | CFBundleVersion
26 | 2.0.0
27 | DTCompiler
28 | com.apple.compilers.llvm.clang.1_0
29 | DTPlatformBuild
30 | 12A7300
31 | DTPlatformName
32 | macosx
33 | DTPlatformVersion
34 | 10.15.6
35 | DTSDKBuild
36 | 19G68
37 | DTSDKName
38 | macosx10.15
39 | DTXcode
40 | 1201
41 | DTXcodeBuild
42 | 12A7300
43 | LSMinimumSystemVersion
44 | 10.15
45 | UIDeviceFamily
46 |
47 | 2
48 | 6
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/RevealServer.xcframework/ios-x86_64-maccatalyst/RevealServer.framework/Versions/A/Resources/Scripts/integrate_revealserver.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -o errexit
3 | set -o nounset
4 |
5 | # This script takes care of integrating Reveal Server into your iOS application target when you have already manually linked the XCFramework into your app.
6 |
7 | # If the current build configuration as defined by the environment variable CONFIGURATION does not match the name provided by REVEAL_LOAD_FOR_CONFIGURATION (this defaults to "Debug"), then any copies of RevealServer that Xcode has copied into your application will be removed.
8 |
9 | # NOTE: This script is intended to be run from within an Xcode run script build phase, and won't work without the environment variables provided therein.
10 |
11 | # If you want to inspect your app using Reveal in build configurations that are not the default "Debug" configuration, override the REVEAL_LOAD_FOR_CONFIGURATION environment variable with the full name of your desired configuration.
12 | load_trigger=${REVEAL_LOAD_FOR_CONFIGURATION:=Debug}
13 |
14 | if [ "${PLATFORM_NAME}" == *simulator ]; then
15 | echo "Reveal Server not integrated into ${TARGET_NAME}: Targeted platform is simulated, and does not require it."
16 | exit 0
17 | fi
18 |
19 | if [ "${CONFIGURATION}" != "${load_trigger}" ]; then
20 | # If we are not running in the expected configuration, remove the RevealServer framework (which needs to have been weakly linked).
21 | bundled_reveal_server="${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RevealServer.framework"
22 |
23 | if [ -e "${bundled_reveal_server}" ]; then
24 | rm -r "${bundled_reveal_server}"
25 | fi
26 |
27 | echo "Reveal Server has been removed from ${TARGET_NAME}: Current build configuration is not '${load_trigger}'."
28 | exit 0
29 | fi
30 |
31 | # Otherwise, we need to insert the NSBonjourServices array into the app's Info.plist. It's OK if this fails due to the key already existing.
32 | plutil -insert NSBonjourServices -xml '' "${CONFIGURATION_BUILD_DIR}/${INFOPLIST_PATH}" || true
33 |
34 | # Insert Reveal's Bonjour details into the NSBonjourServices array.
35 | plutil -insert NSBonjourServices.0 -string "_reveal._tcp" "${CONFIGURATION_BUILD_DIR}/${INFOPLIST_PATH}"
36 |
37 | echo "An NSBonjourServices entry for Reveal (_reveal._tcp) has been added to ${INFOPLIST_PATH}"
38 |
39 | echo "Reveal Server has been successfully integrated into ${TARGET_NAME}."
40 |
--------------------------------------------------------------------------------
/RevealServer.xcframework/ios-x86_64-maccatalyst/RevealServer.framework/Versions/A/RevealServer:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluidGroup/MondrianLayout/b26edaa5a469bc5fd58f9afe37d257ca1b3771e0/RevealServer.xcframework/ios-x86_64-maccatalyst/RevealServer.framework/Versions/A/RevealServer
--------------------------------------------------------------------------------
/RevealServer.xcframework/ios-x86_64-maccatalyst/RevealServer.framework/Versions/A/_CodeSignature/CodeResources:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | files
6 |
7 | Resources/Info.plist
8 |
9 | bqlFKmmTGdMgqxUofdTTciy8v18=
10 |
11 | Resources/Scripts/integrate_revealserver.sh
12 |
13 | a3jybJGZUpf0alfGOc1ePZz/ZKo=
14 |
15 |
16 | files2
17 |
18 | Headers/RevealServer.h
19 |
20 | hash2
21 |
22 | weLK/65HyV1EiL9dd4xoAqQhf0/0r/Oy6os2nXCA+Ew=
23 |
24 |
25 | Modules/module.modulemap
26 |
27 | hash2
28 |
29 | tstqiJpIPr4iEd3MDHClLuTB/ciSC/zNlke1AjfSVuU=
30 |
31 |
32 | Resources/Info.plist
33 |
34 | hash2
35 |
36 | PA4Mey+/2kWidWGMf4PjFncRyKBdU1qFZsfUlTJniho=
37 |
38 |
39 | Resources/Scripts/integrate_revealserver.sh
40 |
41 | hash2
42 |
43 | 7XROfzVgRqq/iFxwUMYYXR9BlPfvd905/+vDF/eKsZs=
44 |
45 |
46 |
47 | rules
48 |
49 | ^Resources/
50 |
51 | ^Resources/.*\.lproj/
52 |
53 | optional
54 |
55 | weight
56 | 1000
57 |
58 | ^Resources/.*\.lproj/locversion.plist$
59 |
60 | omit
61 |
62 | weight
63 | 1100
64 |
65 | ^Resources/Base\.lproj/
66 |
67 | weight
68 | 1010
69 |
70 | ^version.plist$
71 |
72 |
73 | rules2
74 |
75 | .*\.dSYM($|/)
76 |
77 | weight
78 | 11
79 |
80 | ^(.*/)?\.DS_Store$
81 |
82 | omit
83 |
84 | weight
85 | 2000
86 |
87 | ^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/
88 |
89 | nested
90 |
91 | weight
92 | 10
93 |
94 | ^.*
95 |
96 | ^Info\.plist$
97 |
98 | omit
99 |
100 | weight
101 | 20
102 |
103 | ^PkgInfo$
104 |
105 | omit
106 |
107 | weight
108 | 20
109 |
110 | ^Resources/
111 |
112 | weight
113 | 20
114 |
115 | ^Resources/.*\.lproj/
116 |
117 | optional
118 |
119 | weight
120 | 1000
121 |
122 | ^Resources/.*\.lproj/locversion.plist$
123 |
124 | omit
125 |
126 | weight
127 | 1100
128 |
129 | ^Resources/Base\.lproj/
130 |
131 | weight
132 | 1010
133 |
134 | ^[^/]+$
135 |
136 | nested
137 |
138 | weight
139 | 10
140 |
141 | ^embedded\.provisionprofile$
142 |
143 | weight
144 | 20
145 |
146 | ^version\.plist$
147 |
148 | weight
149 | 20
150 |
151 |
152 |
153 |
154 |
--------------------------------------------------------------------------------
/RevealServer.xcframework/ios-x86_64-maccatalyst/RevealServer.framework/Versions/Current:
--------------------------------------------------------------------------------
1 | A
--------------------------------------------------------------------------------
/RevealServer.xcframework/tvos-arm64/RevealServer.framework/Headers/RevealServer.h:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright © 2015 Itty Bitty Apps, Pty Ltd. All rights reserved.
3 |
4 | #import
5 |
6 | //! Project version number for RevealServer.
7 | FOUNDATION_EXPORT double RevealServerVersionNumber;
8 |
9 | //! Project version string for RevealServer.
10 | FOUNDATION_EXPORT const unsigned char RevealServerVersionString[];
11 |
12 |
--------------------------------------------------------------------------------
/RevealServer.xcframework/tvos-arm64/RevealServer.framework/Info.plist:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluidGroup/MondrianLayout/b26edaa5a469bc5fd58f9afe37d257ca1b3771e0/RevealServer.xcframework/tvos-arm64/RevealServer.framework/Info.plist
--------------------------------------------------------------------------------
/RevealServer.xcframework/tvos-arm64/RevealServer.framework/Modules/module.modulemap:
--------------------------------------------------------------------------------
1 | framework module RevealServer {
2 | umbrella header "RevealServer.h"
3 |
4 | export *
5 | module * { export * }
6 | }
7 |
--------------------------------------------------------------------------------
/RevealServer.xcframework/tvos-arm64/RevealServer.framework/RevealServer:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluidGroup/MondrianLayout/b26edaa5a469bc5fd58f9afe37d257ca1b3771e0/RevealServer.xcframework/tvos-arm64/RevealServer.framework/RevealServer
--------------------------------------------------------------------------------
/RevealServer.xcframework/tvos-arm64/RevealServer.framework/Scripts/integrate_revealserver.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -o errexit
3 | set -o nounset
4 |
5 | # This script takes care of integrating Reveal Server into your iOS application target when you have already manually linked the XCFramework into your app.
6 |
7 | # If the current build configuration as defined by the environment variable CONFIGURATION does not match the name provided by REVEAL_LOAD_FOR_CONFIGURATION (this defaults to "Debug"), then any copies of RevealServer that Xcode has copied into your application will be removed.
8 |
9 | # NOTE: This script is intended to be run from within an Xcode run script build phase, and won't work without the environment variables provided therein.
10 |
11 | # If you want to inspect your app using Reveal in build configurations that are not the default "Debug" configuration, override the REVEAL_LOAD_FOR_CONFIGURATION environment variable with the full name of your desired configuration.
12 | load_trigger=${REVEAL_LOAD_FOR_CONFIGURATION:-Debug}
13 |
14 | if [ "${PLATFORM_NAME}" == *simulator ]; then
15 | echo "Reveal Server not integrated into ${TARGET_NAME}: Targeted platform is simulated, and does not require it."
16 | exit 0
17 | fi
18 |
19 | if [ "${CONFIGURATION}" != "${load_trigger}" ]; then
20 | # If we are not running in the expected configuration, remove the RevealServer framework (which needs to have been weakly linked).
21 | bundled_reveal_server="${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RevealServer.framework"
22 |
23 | if [ -e "${bundled_reveal_server}" ]; then
24 | rm -r "${bundled_reveal_server}"
25 | fi
26 |
27 | echo "Reveal Server has been removed from ${TARGET_NAME}: Current build configuration is not '${load_trigger}'."
28 | exit 0
29 | fi
30 |
31 | # Otherwise, we need to insert the NSBonjourServices array into the app's Info.plist. It's OK if this fails due to the key already existing.
32 | plutil -insert NSBonjourServices -xml '' "${CONFIGURATION_BUILD_DIR}/${INFOPLIST_PATH}" || true
33 |
34 | # Insert Reveal's Bonjour details into the NSBonjourServices array.
35 | plutil -insert NSBonjourServices.0 -string "_reveal._tcp" "${CONFIGURATION_BUILD_DIR}/${INFOPLIST_PATH}"
36 |
37 | echo "An NSBonjourServices entry for Reveal (_reveal._tcp) has been added to ${INFOPLIST_PATH}"
38 |
39 | echo "Reveal Server has been successfully integrated into ${TARGET_NAME}."
40 |
--------------------------------------------------------------------------------
/RevealServer.xcframework/tvos-arm64/RevealServer.framework/_CodeSignature/CodeResources:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | files
6 |
7 | Headers/RevealServer.h
8 |
9 | JavE2LI6bNGfH9W90/bDxwIxVlg=
10 |
11 | Info.plist
12 |
13 | uGUpa+zfZp7ETHQS3+BBbJBXfgc=
14 |
15 | Modules/module.modulemap
16 |
17 | EuDEeG1dcC1sd+hIW2SkUAImUg8=
18 |
19 | Scripts/integrate_revealserver.sh
20 |
21 | pDjnAHC1xiLNLJDDIIrTACRCcFA=
22 |
23 |
24 | files2
25 |
26 | Headers/RevealServer.h
27 |
28 | hash
29 |
30 | JavE2LI6bNGfH9W90/bDxwIxVlg=
31 |
32 | hash2
33 |
34 | weLK/65HyV1EiL9dd4xoAqQhf0/0r/Oy6os2nXCA+Ew=
35 |
36 |
37 | Modules/module.modulemap
38 |
39 | hash
40 |
41 | EuDEeG1dcC1sd+hIW2SkUAImUg8=
42 |
43 | hash2
44 |
45 | tstqiJpIPr4iEd3MDHClLuTB/ciSC/zNlke1AjfSVuU=
46 |
47 |
48 | Scripts/integrate_revealserver.sh
49 |
50 | hash
51 |
52 | pDjnAHC1xiLNLJDDIIrTACRCcFA=
53 |
54 | hash2
55 |
56 | XOjBVOZRN/oNePfbAbXae72e3s7W6HqdKnPKJdHque8=
57 |
58 |
59 |
60 | rules
61 |
62 | ^.*
63 |
64 | ^.*\.lproj/
65 |
66 | optional
67 |
68 | weight
69 | 1000
70 |
71 | ^.*\.lproj/locversion.plist$
72 |
73 | omit
74 |
75 | weight
76 | 1100
77 |
78 | ^Base\.lproj/
79 |
80 | weight
81 | 1010
82 |
83 | ^version.plist$
84 |
85 |
86 | rules2
87 |
88 | .*\.dSYM($|/)
89 |
90 | weight
91 | 11
92 |
93 | ^(.*/)?\.DS_Store$
94 |
95 | omit
96 |
97 | weight
98 | 2000
99 |
100 | ^.*
101 |
102 | ^.*\.lproj/
103 |
104 | optional
105 |
106 | weight
107 | 1000
108 |
109 | ^.*\.lproj/locversion.plist$
110 |
111 | omit
112 |
113 | weight
114 | 1100
115 |
116 | ^Base\.lproj/
117 |
118 | weight
119 | 1010
120 |
121 | ^Info\.plist$
122 |
123 | omit
124 |
125 | weight
126 | 20
127 |
128 | ^PkgInfo$
129 |
130 | omit
131 |
132 | weight
133 | 20
134 |
135 | ^embedded\.provisionprofile$
136 |
137 | weight
138 | 20
139 |
140 | ^version\.plist$
141 |
142 | weight
143 | 20
144 |
145 |
146 |
147 |
148 |
--------------------------------------------------------------------------------
/RevealServer.xcframework/tvos-arm64_x86_64-simulator/RevealServer.framework/Headers/RevealServer.h:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright © 2015 Itty Bitty Apps, Pty Ltd. All rights reserved.
3 |
4 | #import
5 |
6 | //! Project version number for RevealServer.
7 | FOUNDATION_EXPORT double RevealServerVersionNumber;
8 |
9 | //! Project version string for RevealServer.
10 | FOUNDATION_EXPORT const unsigned char RevealServerVersionString[];
11 |
12 |
--------------------------------------------------------------------------------
/RevealServer.xcframework/tvos-arm64_x86_64-simulator/RevealServer.framework/Info.plist:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluidGroup/MondrianLayout/b26edaa5a469bc5fd58f9afe37d257ca1b3771e0/RevealServer.xcframework/tvos-arm64_x86_64-simulator/RevealServer.framework/Info.plist
--------------------------------------------------------------------------------
/RevealServer.xcframework/tvos-arm64_x86_64-simulator/RevealServer.framework/Modules/module.modulemap:
--------------------------------------------------------------------------------
1 | framework module RevealServer {
2 | umbrella header "RevealServer.h"
3 |
4 | export *
5 | module * { export * }
6 | }
7 |
--------------------------------------------------------------------------------
/RevealServer.xcframework/tvos-arm64_x86_64-simulator/RevealServer.framework/RevealServer:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluidGroup/MondrianLayout/b26edaa5a469bc5fd58f9afe37d257ca1b3771e0/RevealServer.xcframework/tvos-arm64_x86_64-simulator/RevealServer.framework/RevealServer
--------------------------------------------------------------------------------
/RevealServer.xcframework/tvos-arm64_x86_64-simulator/RevealServer.framework/Scripts/integrate_revealserver.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -o errexit
3 | set -o nounset
4 |
5 | # This script takes care of integrating Reveal Server into your iOS application target when you have already manually linked the XCFramework into your app.
6 |
7 | # If the current build configuration as defined by the environment variable CONFIGURATION does not match the name provided by REVEAL_LOAD_FOR_CONFIGURATION (this defaults to "Debug"), then any copies of RevealServer that Xcode has copied into your application will be removed.
8 |
9 | # NOTE: This script is intended to be run from within an Xcode run script build phase, and won't work without the environment variables provided therein.
10 |
11 | # If you want to inspect your app using Reveal in build configurations that are not the default "Debug" configuration, override the REVEAL_LOAD_FOR_CONFIGURATION environment variable with the full name of your desired configuration.
12 | load_trigger=${REVEAL_LOAD_FOR_CONFIGURATION:-Debug}
13 |
14 | if [ "${PLATFORM_NAME}" == *simulator ]; then
15 | echo "Reveal Server not integrated into ${TARGET_NAME}: Targeted platform is simulated, and does not require it."
16 | exit 0
17 | fi
18 |
19 | if [ "${CONFIGURATION}" != "${load_trigger}" ]; then
20 | # If we are not running in the expected configuration, remove the RevealServer framework (which needs to have been weakly linked).
21 | bundled_reveal_server="${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RevealServer.framework"
22 |
23 | if [ -e "${bundled_reveal_server}" ]; then
24 | rm -r "${bundled_reveal_server}"
25 | fi
26 |
27 | echo "Reveal Server has been removed from ${TARGET_NAME}: Current build configuration is not '${load_trigger}'."
28 | exit 0
29 | fi
30 |
31 | # Otherwise, we need to insert the NSBonjourServices array into the app's Info.plist. It's OK if this fails due to the key already existing.
32 | plutil -insert NSBonjourServices -xml '' "${CONFIGURATION_BUILD_DIR}/${INFOPLIST_PATH}" || true
33 |
34 | # Insert Reveal's Bonjour details into the NSBonjourServices array.
35 | plutil -insert NSBonjourServices.0 -string "_reveal._tcp" "${CONFIGURATION_BUILD_DIR}/${INFOPLIST_PATH}"
36 |
37 | echo "An NSBonjourServices entry for Reveal (_reveal._tcp) has been added to ${INFOPLIST_PATH}"
38 |
39 | echo "Reveal Server has been successfully integrated into ${TARGET_NAME}."
40 |
--------------------------------------------------------------------------------
/RevealServer.xcframework/tvos-arm64_x86_64-simulator/RevealServer.framework/_CodeSignature/CodeResources:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | files
6 |
7 | Headers/RevealServer.h
8 |
9 | JavE2LI6bNGfH9W90/bDxwIxVlg=
10 |
11 | Info.plist
12 |
13 | Ozik2ierbamqUMW8Y5/SytPiqOg=
14 |
15 | Modules/module.modulemap
16 |
17 | EuDEeG1dcC1sd+hIW2SkUAImUg8=
18 |
19 | Scripts/integrate_revealserver.sh
20 |
21 | pDjnAHC1xiLNLJDDIIrTACRCcFA=
22 |
23 |
24 | files2
25 |
26 | Headers/RevealServer.h
27 |
28 | hash
29 |
30 | JavE2LI6bNGfH9W90/bDxwIxVlg=
31 |
32 | hash2
33 |
34 | weLK/65HyV1EiL9dd4xoAqQhf0/0r/Oy6os2nXCA+Ew=
35 |
36 |
37 | Modules/module.modulemap
38 |
39 | hash
40 |
41 | EuDEeG1dcC1sd+hIW2SkUAImUg8=
42 |
43 | hash2
44 |
45 | tstqiJpIPr4iEd3MDHClLuTB/ciSC/zNlke1AjfSVuU=
46 |
47 |
48 | Scripts/integrate_revealserver.sh
49 |
50 | hash
51 |
52 | pDjnAHC1xiLNLJDDIIrTACRCcFA=
53 |
54 | hash2
55 |
56 | XOjBVOZRN/oNePfbAbXae72e3s7W6HqdKnPKJdHque8=
57 |
58 |
59 |
60 | rules
61 |
62 | ^.*
63 |
64 | ^.*\.lproj/
65 |
66 | optional
67 |
68 | weight
69 | 1000
70 |
71 | ^.*\.lproj/locversion.plist$
72 |
73 | omit
74 |
75 | weight
76 | 1100
77 |
78 | ^Base\.lproj/
79 |
80 | weight
81 | 1010
82 |
83 | ^version.plist$
84 |
85 |
86 | rules2
87 |
88 | .*\.dSYM($|/)
89 |
90 | weight
91 | 11
92 |
93 | ^(.*/)?\.DS_Store$
94 |
95 | omit
96 |
97 | weight
98 | 2000
99 |
100 | ^.*
101 |
102 | ^.*\.lproj/
103 |
104 | optional
105 |
106 | weight
107 | 1000
108 |
109 | ^.*\.lproj/locversion.plist$
110 |
111 | omit
112 |
113 | weight
114 | 1100
115 |
116 | ^Base\.lproj/
117 |
118 | weight
119 | 1010
120 |
121 | ^Info\.plist$
122 |
123 | omit
124 |
125 | weight
126 | 20
127 |
128 | ^PkgInfo$
129 |
130 | omit
131 |
132 | weight
133 | 20
134 |
135 | ^embedded\.provisionprofile$
136 |
137 | weight
138 | 20
139 |
140 | ^version\.plist$
141 |
142 | weight
143 | 20
144 |
145 |
146 |
147 |
148 |
--------------------------------------------------------------------------------
/Tests/ClassicTests.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 | import MondrianLayout
3 | import SnapshotTesting
4 | import XCTest
5 |
6 | final class ClassicTests: XCTestCase {
7 |
8 | func test_resultBuilder() {
9 |
10 | func syntax() {
11 |
12 | do {
13 | let views: [UIView] = []
14 |
15 | mondrianBatchLayout {
16 | views.map {
17 | $0.mondrian.layout.height(.min(10))
18 | }
19 | }
20 | }
21 |
22 | do {
23 | let views: [UIView] = []
24 |
25 | mondrianBatchLayout {
26 |
27 | views.map {
28 | $0.mondrian.layout.height(.min(10))
29 | }
30 |
31 | views.map {
32 | $0.mondrian.layout.height(.min(10))
33 | }
34 | }
35 | }
36 |
37 | do {
38 | let view: UIView? = nil
39 | let views: [UIView] = []
40 |
41 | mondrianBatchLayout {
42 |
43 | view?.mondrian.layout.height(.min(10))
44 |
45 | views.map {
46 | $0.mondrian.layout.height(.min(10))
47 | }
48 |
49 | views.map {
50 | $0.mondrian.layout.height(.min(10))
51 | }
52 | }
53 | }
54 |
55 | do {
56 | let view: UIView? = nil
57 | let views: [UIView?] = []
58 |
59 | mondrianBatchLayout {
60 |
61 | view?.mondrian.layout.height(.min(10))
62 |
63 | views.map {
64 | $0?.mondrian.layout.height(.min(10))
65 | }
66 |
67 | views.map {
68 | $0?.mondrian.layout.height(.min(10))
69 | }
70 | }
71 | }
72 |
73 | do {
74 | let view: UIView? = nil
75 | mondrianBatchLayout {
76 | view?.mondrian.layout.height(.min(10))
77 | }
78 | }
79 |
80 | do {
81 | let view: UIView = UIView()
82 | mondrianBatchLayout {
83 | view.mondrian.layout.height(.min(10))
84 | }
85 | }
86 |
87 | do {
88 | let view: UIView = UIView()
89 | mondrianBatchLayout {
90 | if true {
91 | view.mondrian.layout.height(.min(10))
92 | }
93 | }
94 | }
95 |
96 | do {
97 | let flag = true
98 | let view: UIView = UIView()
99 | mondrianBatchLayout {
100 | if flag {
101 | view.mondrian.layout.height(.min(10))
102 | } else {
103 | view.mondrian.layout.height(.min(10))
104 | }
105 | }
106 | }
107 | }
108 |
109 | }
110 |
111 | func test_multiplier_constraints() {
112 |
113 | let view = ExampleView(width: nil, height: nil) { view in
114 |
115 | let box1 = UIView.mock(
116 | backgroundColor: .layeringColor,
117 | preferredSize: .init(width: 30, height: 30)
118 | )
119 |
120 | let box2 = UIView.mock(
121 | backgroundColor: .layeringColor,
122 | preferredSize: .init(width: 30, height: 30)
123 | )
124 |
125 | view.addSubview(box1)
126 | view.addSubview(box2)
127 |
128 | mondrianBatchLayout {
129 |
130 | box1.mondrian.layout
131 | .top(.toSuperview, .min(0))
132 | .left(.toSuperview)
133 | .right(.to(box2).left)
134 | .bottom(.to(box2).bottom)
135 |
136 | box2.mondrian.layout
137 | .top(.toSuperview.top)
138 | .height(.to(box1).height, multiplier: 2)
139 | .right(.toSuperview)
140 | .bottom(.toSuperview)
141 |
142 | }
143 | }
144 |
145 | assertSnapshot(matching: view, as: .image, record: _record)
146 |
147 | }
148 | }
149 |
--------------------------------------------------------------------------------
/Tests/HStackTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // HStackTests.swift
3 | // Tests
4 | //
5 | // Created by Muukii on 2021/06/17.
6 | //
7 |
8 | import Foundation
9 | import MondrianLayout
10 | import SnapshotTesting
11 | import XCTest
12 |
13 | final class HStackTests: XCTestCase {
14 |
15 | func test_mixing_spacer() {
16 |
17 | let view = ExampleView(width: 180, height: nil) { (view: UIView) in
18 | Mondrian.buildSubviews(on: view) {
19 | HStackBlock(spacing: 4) {
20 | UIView.mock(
21 | backgroundColor: .layeringColor,
22 | preferredSize: .smallSquare
23 | ) as UIView?
24 |
25 | StackingSpacer(minLength: 20)
26 |
27 | UIView.mock(
28 | backgroundColor: .layeringColor,
29 | preferredSize: .smallSquare
30 | )
31 |
32 | UIView.mock(
33 | backgroundColor: .layeringColor,
34 | preferredSize: .smallSquare
35 | )
36 |
37 | StackingSpacer(minLength: 20, expands: false)
38 | }
39 | .background(UIView.mock(backgroundColor: .layeringColor))
40 | }
41 | }
42 |
43 | assertSnapshot(matching: view, as: .image, record: _record)
44 |
45 | }
46 |
47 | func test_additional_spacing() {
48 |
49 | let view = ExampleView(width: nil, height: nil) { (view: UIView) in
50 | Mondrian.buildSubviews(on: view) {
51 | HStackBlock(spacing: 4) {
52 | UIView.mock(
53 | preferredSize: .smallSquare
54 | )
55 |
56 | StackingSpacer(minLength: 4)
57 |
58 | UIView.mock(
59 | preferredSize: .smallSquare
60 | )
61 |
62 | UIView.mock(
63 | preferredSize: .smallSquare
64 | )
65 | }
66 | }
67 | }
68 |
69 | assertSnapshot(matching: view, as: .image, record: _record)
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/Tests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/Tests/LayoutDescriptorTests.swift:
--------------------------------------------------------------------------------
1 |
2 | import Foundation
3 | import MondrianLayout
4 | import SnapshotTesting
5 | import XCTest
6 |
7 | final class LayoutDescriptorTests: XCTestCase {
8 |
9 | func testSyntax() {
10 |
11 | let container = UIView()
12 | let view = UIView()
13 |
14 | container.addSubview(view)
15 |
16 | let g = view.mondrian.layout
17 | .width(10)
18 | .top(.toSuperview)
19 | .right(.toSuperview)
20 | .leading(.toSuperview)
21 | .activate()
22 |
23 | XCTAssertEqual(g.constraints.count, 4)
24 | }
25 |
26 | func testSyntax_batch() {
27 |
28 | let container = UIView()
29 |
30 | let parent = UIView()
31 | let view = UIView()
32 |
33 | container.addSubview(parent)
34 | container.addSubview(view)
35 |
36 | let group = mondrianBatchLayout {
37 | view.mondrian.layout.width(10)
38 | view.mondrian.layout.top(.to(parent))
39 | }
40 |
41 | XCTAssertEqual(group.constraints.count, 2)
42 | }
43 |
44 | func test_layout_0() {
45 |
46 | let view = ExampleView(width: nil, height: nil) { view in
47 |
48 | let box1 = UIView.mock(backgroundColor: .layeringColor, preferredSize: .smallSquare)
49 | let box2 = UIView.mock(backgroundColor: .layeringColor, preferredSize: .smallSquare)
50 |
51 | view.addSubview(box1)
52 | view.addSubview(box2)
53 |
54 | mondrianBatchLayout {
55 |
56 | box1.mondrian.layout
57 | .top(.toSuperview)
58 | .left(.toSuperview)
59 | .right(.to(box2).left)
60 | .bottom(.to(box2).bottom)
61 |
62 | box2.mondrian.layout
63 | .top(.toSuperview.top, .exact(10))
64 | .right(.toSuperview)
65 | .bottom(.toSuperview)
66 |
67 | }
68 | }
69 |
70 | assertSnapshot(matching: view, as: .image, record: _record)
71 |
72 | }
73 |
74 | func test_layout_center() {
75 |
76 | let view = ExampleView(width: nil, height: nil) { view in
77 |
78 | let containerCenterDemo = UIView.mock(backgroundColor: .layeringColor, preferredSize: .largeSquare)
79 | let containeeCenterDemo = UIView.mock(backgroundColor: .layeringColor, preferredSize: .smallSquare)
80 |
81 | view.addSubview(containerCenterDemo)
82 |
83 | containerCenterDemo.addSubview(containeeCenterDemo)
84 |
85 | mondrianBatchLayout {
86 |
87 | containerCenterDemo.mondrian.layout
88 | .edges(.toSuperview)
89 |
90 | containeeCenterDemo.mondrian.layout
91 | .center(.toSuperview)
92 |
93 | }
94 | }
95 |
96 | assertSnapshot(matching: view, as: .image, record: _record)
97 |
98 | }
99 |
100 | func test_layout_edge() {
101 |
102 | let view = ExampleView(width: nil, height: nil) { view in
103 |
104 | let containerEdgesDemo = UIView.mock(backgroundColor: .layeringColor, preferredSize: .largeSquare)
105 | let containeeEdgesDemo = UIView.mock(backgroundColor: .layeringColor)
106 |
107 | view.addSubview(containerEdgesDemo)
108 |
109 | containerEdgesDemo.addSubview(containeeEdgesDemo)
110 |
111 | mondrianBatchLayout {
112 |
113 | containerEdgesDemo.mondrian.layout
114 | .edges(.toSuperview)
115 |
116 | containeeEdgesDemo.mondrian.layout
117 | .edges(.toSuperview, .exact(8))
118 | }
119 | }
120 |
121 | assertSnapshot(matching: view, as: .image, record: _record)
122 |
123 | }
124 | }
125 |
--------------------------------------------------------------------------------
/Tests/OverlayTests.swift:
--------------------------------------------------------------------------------
1 |
2 | import Foundation
3 | import MondrianLayout
4 | import SnapshotTesting
5 | import XCTest
6 |
7 | final class OverlayTests: XCTestCase {
8 |
9 | func test_1() {
10 |
11 | let view = ExampleView(width: nil, height: nil) { (view: UIView) in
12 | Mondrian.buildSubviews(on: view) {
13 | UIView.mock(
14 | backgroundColor: .layeringColor,
15 | preferredSize: .init(width: 100, height: 100)
16 | )
17 | .viewBlock
18 | .overlay(
19 | UIView.mock(backgroundColor: .layeringColor)
20 | .viewBlock
21 | .overlay(
22 | UIView.mock(backgroundColor: .layeringColor)
23 | .viewBlock
24 | .padding(10)
25 | )
26 | .padding(10)
27 | )
28 | }
29 | }
30 |
31 | assertSnapshot(matching: view, as: .image, record: _record)
32 |
33 | }
34 |
35 | func test_2() {
36 |
37 | let view = ExampleView(width: nil, height: nil) { (view: UIView) in
38 | Mondrian.buildSubviews(on: view) {
39 | VStackBlock {
40 | UIView.mock(
41 | preferredSize: .smallSquare
42 | )
43 | UIView.mock(
44 | preferredSize: .smallSquare
45 | )
46 | UIView.mock(
47 | preferredSize: .smallSquare
48 | )
49 | }
50 | .padding(10)
51 | .overlay(UIView.mock(backgroundColor: .layeringColor))
52 | }
53 | }
54 |
55 | XCTAssertFalse(view.hasAmbiguousLayoutRecursively)
56 | assertSnapshot(matching: view, as: .image, record: _record)
57 |
58 | }
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/Tests/RelativeTests.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 | import MondrianLayout
3 | import SnapshotTesting
4 | import XCTest
5 |
6 | final class RelateiveTests: XCTestCase {
7 |
8 | func test_centering_in_ambiguous() {
9 | let view = ExampleView(width: 100, height: 100) { view in
10 | Mondrian.buildSubviews(on: view) {
11 | ZStackBlock {
12 | UILabel.mockSingleline(text: "A")
13 | .viewBlock
14 | .background(UIView.mock())
15 | .relative(.all, .min(20))
16 | }
17 | .background(UIView.mock())
18 | }
19 | }
20 | assertSnapshot(matching: view, as: .image, record: _record)
21 | }
22 |
23 | func test_accumulate_relative() {
24 | let view = ExampleView(width: 100, height: 100) { view in
25 | Mondrian.buildSubviews(on: view) {
26 | LayoutContainer(attachedSafeAreaEdges: .all) {
27 | ZStackBlock {
28 |
29 | UIView.mock(backgroundColor: .layeringColor)
30 | .viewBlock.alignSelf(.attach(.all))
31 |
32 | UIView.mock(backgroundColor: .layeringColor, preferredSize: .smallSquare)
33 | .viewBlock
34 | .relative(.bottom, 20)
35 | .relative(.trailing, 20)
36 | }
37 | }
38 | }
39 | }
40 |
41 | assertSnapshot(matching: view, as: .image, record: _record)
42 | }
43 |
44 | func test_accumulate_padding() {
45 |
46 | let view = ExampleView(width: 100, height: 100) { view in
47 | Mondrian.buildSubviews(on: view) {
48 | LayoutContainer(attachedSafeAreaEdges: .vertical) {
49 | VStackBlock {
50 | UIView.mock(
51 | backgroundColor: .layeringColor,
52 | preferredSize: .smallSquare
53 | )
54 | .viewBlock
55 | .padding(.bottom, 10)
56 | .padding(.bottom, 10)
57 | .padding(.bottom, 10)
58 | }
59 | .background(
60 | UIView.mock(
61 | backgroundColor: .layeringColor,
62 | preferredSize: .smallSquare
63 | )
64 | )
65 | }
66 | }
67 | }
68 |
69 | assertSnapshot(matching: view, as: .image, record: _record)
70 |
71 | }
72 |
73 | func test_accumulation_0() {
74 |
75 | var base = RelativeBlock.ConstrainedValue()
76 |
77 | XCTAssert(base.min == nil)
78 | XCTAssert(base.exact == nil)
79 | XCTAssert(base.max == nil)
80 |
81 | let other = RelativeBlock.ConstrainedValue(min: 0, exact: nil, max: nil)
82 |
83 | base.accumulate(other)
84 |
85 | XCTAssertEqual(base.min, 0)
86 | XCTAssertEqual(base.exact, nil)
87 | XCTAssertEqual(base.max, nil)
88 |
89 | }
90 |
91 | func test_accumulation_1() {
92 |
93 | var base = RelativeBlock.ConstrainedValue(min: 1, exact: nil, max: nil)
94 |
95 | XCTAssertEqual(base.min, 1)
96 | XCTAssertEqual(base.exact, nil)
97 | XCTAssertEqual(base.max, nil)
98 |
99 | let other = RelativeBlock.ConstrainedValue(min: nil, exact: nil, max: nil)
100 |
101 | base.accumulate(other)
102 |
103 | XCTAssertEqual(base.min, 1)
104 | XCTAssertEqual(base.exact, nil)
105 | XCTAssertEqual(base.max, nil)
106 |
107 | }
108 |
109 | func test_accumulation_2() {
110 |
111 | var base = RelativeBlock.ConstrainedValue(min: 1, exact: nil, max: nil)
112 |
113 | XCTAssertEqual(base.min, 1)
114 | XCTAssertEqual(base.exact, nil)
115 | XCTAssertEqual(base.max, nil)
116 |
117 | let other = RelativeBlock.ConstrainedValue(min: 1, exact: nil, max: nil)
118 |
119 | base.accumulate(other)
120 |
121 | XCTAssertEqual(base.min, 2)
122 | XCTAssertEqual(base.exact, nil)
123 | XCTAssertEqual(base.max, nil)
124 |
125 | }
126 | }
127 |
--------------------------------------------------------------------------------
/Tests/SizingTests.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 | import MondrianLayout
3 | import SnapshotTesting
4 | import XCTest
5 |
6 | final class SizingTests: XCTestCase {
7 |
8 | func test_sizing() {
9 | let view = ExampleView(width: 200, height: 200) { (view: UIView) in
10 | Mondrian.buildSubviews(on: view) {
11 | ZStackBlock {
12 |
13 | HStackBlock {
14 | VStackBlock(alignment: .leading) {
15 | UIView.mock(
16 | backgroundColor: .layeringColor,
17 | preferredSize: .init(width: 36, height: 36)
18 | )
19 | .viewBlock
20 | .alignSelf(.fill)
21 |
22 | UIView.mock(
23 | backgroundColor: .layeringColor,
24 | preferredSize: .init(width: 36, height: 36)
25 | )
26 | .viewBlock
27 | .alignSelf(.fill)
28 | }
29 | .width(20)
30 |
31 | VStackBlock(alignment: .leading) {
32 | UIView.mock(
33 | backgroundColor: .layeringColor,
34 | preferredSize: .init(width: 36, height: 36)
35 | )
36 | .viewBlock
37 | .alignSelf(.fill)
38 |
39 | UIView.mock(
40 | backgroundColor: .layeringColor,
41 | preferredSize: .init(width: 36, height: 36)
42 | )
43 | .viewBlock
44 | .alignSelf(.fill)
45 | }
46 | .width(40)
47 |
48 | UIView.mock(
49 | backgroundColor: .layeringColor,
50 | preferredSize: .init(width: 36, height: 36)
51 | )
52 | .viewBlock
53 | .padding(10)
54 | .width(.max(30))
55 |
56 | }
57 | .height(50)
58 |
59 | }
60 | }
61 | }
62 | assertSnapshot(matching: view, as: .image, record: _record)
63 | }
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/Tests/SyntaxTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ZStackTests.swift
3 | // Tests
4 | //
5 | // Created by Muukii on 2021/06/18.
6 | //
7 |
8 | import Foundation
9 | import MondrianLayout
10 | import SnapshotTesting
11 | import XCTest
12 |
13 | final class SyntaxTests: XCTestCase {
14 |
15 | func test_vStack() {
16 |
17 | let view = ExampleView(width: 20, height: nil) { view in
18 | Mondrian.buildSubviews(on: view) {
19 | LayoutContainer(attachedSafeAreaEdges: .vertical) {
20 | VStackBlock {
21 |
22 | UIView.mock(backgroundColor: .layeringColor)
23 | .viewBlock
24 | .height(10)
25 | .spacingBefore(10)
26 |
27 | UIView.mock(backgroundColor: .layeringColor)
28 | .viewBlock
29 | .height(10)
30 | .spacingAfter(10)
31 |
32 | UIView.mock(backgroundColor: .layeringColor)
33 | .viewBlock
34 | .height(10)
35 | .spacingAfter(10)
36 | .spacingAfter(10)
37 | .spacingBefore(10)
38 | .spacingBefore(10)
39 |
40 | }
41 | .background(UIView.mock(backgroundColor: .layeringColor))
42 | }
43 | }
44 | }
45 |
46 | XCTAssertEqual(view.frame.height, 90)
47 | assertSnapshot(matching: view, as: .image, record: _record)
48 |
49 | }
50 |
51 | func test_hStack() {
52 |
53 | let view = ExampleView(width: nil, height: 20) { view in
54 | Mondrian.buildSubviews(on: view) {
55 | LayoutContainer(attachedSafeAreaEdges: .vertical) {
56 | HStackBlock {
57 |
58 | UIView.mock(backgroundColor: .layeringColor)
59 | .viewBlock
60 | .width(10)
61 | .spacingBefore(10)
62 |
63 | UIView.mock(backgroundColor: .layeringColor)
64 | .viewBlock
65 | .width(10)
66 | .spacingAfter(10)
67 |
68 | UIView.mock(backgroundColor: .layeringColor)
69 | .viewBlock
70 | .width(10)
71 | .spacingAfter(10)
72 | .spacingAfter(10)
73 | .spacingBefore(10)
74 | .spacingBefore(10)
75 |
76 | }
77 | .background(UIView.mock(backgroundColor: .layeringColor))
78 | }
79 | }
80 | }
81 |
82 | XCTAssertEqual(view.frame.width, 90)
83 | assertSnapshot(matching: view, as: .image, record: _record)
84 |
85 | }
86 |
87 | }
88 |
--------------------------------------------------------------------------------
/Tests/Tests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Tests.swift
3 | // Tests
4 | //
5 | // Created by Muukii on 2021/06/13.
6 | //
7 |
8 | import XCTest
9 | import MondrianLayout
10 | import SnapshotTesting
11 |
12 | let _record = ProcessInfo().environment["RECORD"] != nil
13 |
14 | final class LayoutSnapshotTests: XCTestCase {
15 |
16 | func test_1() {
17 |
18 | let view = ExampleView(width: 100, height: 100) { view in
19 | Mondrian.buildSubviews(on: view) {
20 | VStackBlock {
21 | ZStackBlock {
22 | UIView.mock(
23 | backgroundColor: .layeringColor,
24 | preferredSize: .init(width: 100, height: 100)
25 | )
26 |
27 | UIView.mock(
28 | backgroundColor: .layeringColor,
29 | preferredSize: .init(width: 10, height: 10)
30 | )
31 | .viewBlock
32 | .relative([.top, .trailing], 10)
33 |
34 | }
35 | }
36 | }
37 | }
38 |
39 | assertSnapshot(matching: view, as: .image, record: _record)
40 |
41 | }
42 |
43 | func test_mondrian() {
44 |
45 | let view = ExampleView(width: 200, height: 200) { (view: UIView) in
46 | Mondrian.buildSubviews(on: view) {
47 |
48 | HStackBlock(spacing: 2, alignment: .fill) {
49 | VStackBlock(spacing: 2, alignment: .fill) {
50 | UIView.mock(
51 | backgroundColor: .layeringColor,
52 | preferredSize: .smallSquare
53 | )
54 |
55 | UIView.mock(
56 | backgroundColor: .layeringColor,
57 | preferredSize: .init(width: 28, height: 50)
58 | )
59 |
60 | UIView.mock(
61 | backgroundColor: .layeringColor,
62 | preferredSize: .smallSquare
63 | )
64 |
65 | UIView.mock(
66 | backgroundColor: .layeringColor,
67 | preferredSize: .smallSquare
68 | )
69 |
70 | HStackBlock(spacing: 2, alignment: .fill) {
71 | UIView.mock(
72 | backgroundColor: .layeringColor,
73 | preferredSize: .smallSquare
74 | )
75 | UIView.mock(
76 | backgroundColor: .layeringColor,
77 | preferredSize: .smallSquare
78 | )
79 | }
80 | }
81 |
82 | VStackBlock(spacing: 2, alignment: .fill) {
83 | HStackBlock(spacing: 2, alignment: .fill) {
84 | UIView.mock(
85 | backgroundColor: .layeringColor,
86 | preferredSize: .smallSquare
87 | )
88 | VStackBlock(spacing: 2, alignment: .fill) {
89 | HStackBlock(spacing: 2, alignment: .fill) {
90 | UIView.mock(
91 | backgroundColor: .layeringColor,
92 | preferredSize: .smallSquare
93 | )
94 | UIView.mock(
95 | backgroundColor: .layeringColor,
96 | preferredSize: .smallSquare
97 | )
98 | }
99 | UIView.mock(
100 | backgroundColor: .layeringColor,
101 | preferredSize: .smallSquare
102 | )
103 | }
104 | }
105 |
106 | HStackBlock(spacing: 2, alignment: .fill) {
107 | VStackBlock(spacing: 2, alignment: .fill) {
108 | UIView.mock(
109 | backgroundColor: .layeringColor,
110 | preferredSize: .smallSquare
111 | )
112 | UIView.mock(
113 | backgroundColor: .layeringColor,
114 | preferredSize: .smallSquare
115 | )
116 | }
117 |
118 | UIView.mock(
119 | backgroundColor: .layeringColor,
120 | preferredSize: .smallSquare
121 | )
122 |
123 | VStackBlock(spacing: 2, alignment: .fill) {
124 | UIView.mock(
125 | backgroundColor: .layeringColor,
126 | preferredSize: .smallSquare
127 | )
128 | UIView.mock(
129 | backgroundColor: .layeringColor,
130 | preferredSize: .smallSquare
131 | )
132 | }
133 | }
134 |
135 | HStackBlock(spacing: 2, alignment: .fill) {
136 | UIView.mock(
137 | backgroundColor: .layeringColor,
138 | preferredSize: .smallSquare
139 | )
140 | VStackBlock(spacing: 2, alignment: .fill) {
141 | UIView.mock(
142 | backgroundColor: .layeringColor,
143 | preferredSize: .smallSquare
144 | )
145 | UIView.mock(
146 | backgroundColor: .layeringColor,
147 | preferredSize: .smallSquare
148 | )
149 | }
150 | }
151 |
152 | }
153 |
154 | }
155 | .overlay(
156 | UILabel.mockMultiline(text: "Mondrian Layout", textColor: .white)
157 | .viewBlock
158 | .padding(4)
159 | .background(
160 | UIView.mock(
161 | backgroundColor: .layeringColor
162 | )
163 | .viewBlock
164 | )
165 | .relative([.bottom, .trailing], 10)
166 | )
167 |
168 | }
169 | }
170 |
171 | assertSnapshot(matching: view, as: .image, record: _record)
172 | }
173 |
174 | }
175 |
176 | /*
177 | @discardableResult
178 | func layout(
179 | @LayoutConstraintBuilder _ c: () -> Content
180 | ) -> Content {
181 | c()
182 | }
183 |
184 | class Tests: XCTestCase {
185 |
186 | func test_pattern_stack() {
187 |
188 | _ = layout {
189 | HStackBlock {
190 | UIView()
191 | }
192 | }
193 |
194 | _ = layout {
195 | HStackBlock {
196 | UIView()
197 | StackSpacer(minLength: 0)
198 | }
199 | }
200 |
201 | }
202 |
203 | func test_pattern1() {
204 |
205 | _ = layout {
206 | HStackBlock {
207 | // VStackBlock {
208 | // UIView()
209 | // }
210 | }
211 | }
212 |
213 | }
214 |
215 | func test_pattern2() {
216 |
217 | _ = layout {
218 | HStackBlock {
219 | UIView()
220 | // VStackBlock {}
221 | }
222 | }
223 |
224 | }
225 |
226 | func test_pattern3() {
227 |
228 | _ = layout {
229 | HStackBlock {
230 | UIView()
231 | UIView()
232 | }
233 | }
234 |
235 | }
236 | }
237 | */
238 |
--------------------------------------------------------------------------------
/Tests/VGridTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // VGridTests.swift
3 | // Tests
4 | //
5 | // Created by Muukii on 2021/12/15.
6 | //
7 |
8 | import Foundation
9 | import MondrianLayout
10 | import SnapshotTesting
11 | import XCTest
12 |
13 | final class VGridTests: XCTestCase {
14 |
15 | func test_basic() {
16 |
17 | let view = ExampleView(width: 100, height: nil) { view in
18 | Mondrian.buildSubviews(on: view) {
19 | VGridBlock(
20 | columns: [
21 | .init(.flexible(), spacing: 16),
22 | .init(.flexible(), spacing: 16),
23 | ],
24 | spacing: 4
25 | ) {
26 |
27 | UILabel.mockMultiline(text: "Helloooo")
28 | .viewBlock
29 | .overlay(UIView.mock(backgroundColor: .layeringColor, preferredSize: .smallSquare))
30 |
31 | UIView.mock(backgroundColor: .layeringColor, preferredSize: .smallSquare)
32 | UIView.mock(backgroundColor: .layeringColor, preferredSize: .smallSquare)
33 | UIView.mock(backgroundColor: .layeringColor, preferredSize: .smallSquare)
34 |
35 | UIView.mock(backgroundColor: .layeringColor, preferredSize: .smallSquare)
36 | UIView.mock(backgroundColor: .layeringColor, preferredSize: .smallSquare)
37 | UIView.mock(backgroundColor: .layeringColor, preferredSize: .smallSquare)
38 | UIView.mock(backgroundColor: .layeringColor, preferredSize: .smallSquare)
39 |
40 | UIView.mock(backgroundColor: .layeringColor, preferredSize: .smallSquare)
41 | UIView.mock(backgroundColor: .layeringColor, preferredSize: .smallSquare)
42 | }
43 | }
44 | }
45 |
46 | assertSnapshot(matching: view, as: .image, record: _record)
47 |
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/Tests/VStackTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // OverlayTests.swift
3 | // Tests
4 | //
5 | // Created by Muukii on 2021/06/16.
6 | //
7 |
8 | import Foundation
9 | import MondrianLayout
10 | import SnapshotTesting
11 | import XCTest
12 |
13 | final class VStackTests: XCTestCase {
14 |
15 | func test_mixing_spacer() {
16 | let view = ExampleView(width: nil, height: 180) { (view: UIView) in
17 | Mondrian.buildSubviews(on: view) {
18 | VStackBlock(spacing: 4) {
19 | UIView.mock(
20 | backgroundColor: .layeringColor,
21 | preferredSize: .smallSquare
22 | )
23 |
24 | StackingSpacer(minLength: 20)
25 |
26 | UIView.mock(
27 | backgroundColor: .layeringColor,
28 | preferredSize: .smallSquare
29 | )
30 |
31 | UIView.mock(
32 | backgroundColor: .layeringColor,
33 | preferredSize: .smallSquare
34 | )
35 |
36 | StackingSpacer(minLength: 20, expands: false)
37 | }
38 | .background(UIView.mock(backgroundColor: .layeringColor))
39 | }
40 | }
41 |
42 | assertSnapshot(matching: view, as: .image, record: _record)
43 | }
44 |
45 | func test_enter() {
46 |
47 | let view = ExampleView(width: nil, height: nil) { (view: UIView) in
48 | Mondrian.buildSubviews(on: view) {
49 | VStackBlock(spacing: 4, alignment: .center) {
50 | UILabel.mockMultiline(text: "Hello", textColor: .white)
51 | .viewBlock
52 | .padding(8)
53 | .background(UIView.mock(backgroundColor: .layeringColor))
54 | UILabel.mockMultiline(text: "Mondrian", textColor: .white)
55 | .viewBlock
56 | .padding(8)
57 | .background(UIView.mock(backgroundColor: .layeringColor))
58 | UILabel.mockMultiline(text: "Layout!", textColor: .white)
59 | .viewBlock
60 | .padding(8)
61 | .background(UIView.mock(backgroundColor: .layeringColor))
62 | }
63 | }
64 | }
65 |
66 | assertSnapshot(matching: view, as: .image, record: _record)
67 |
68 | }
69 |
70 | func test_leading() {
71 |
72 | let view = ExampleView(width: nil, height: nil) { (view: UIView) in
73 | Mondrian.buildSubviews(on: view) {
74 | VStackBlock(spacing: 4, alignment: .leading) {
75 | UILabel.mockMultiline(text: "Hello", textColor: .white)
76 | .viewBlock
77 | .padding(8)
78 | .background(UIView.mock(backgroundColor: .layeringColor))
79 | UILabel.mockMultiline(text: "Mondrian", textColor: .white)
80 | .viewBlock
81 | .padding(8)
82 | .background(UIView.mock(backgroundColor: .layeringColor))
83 | UILabel.mockMultiline(text: "Layout!", textColor: .white)
84 | .viewBlock
85 | .padding(8)
86 | .background(UIView.mock(backgroundColor: .layeringColor))
87 | }
88 | }
89 | }
90 |
91 | assertSnapshot(matching: view, as: .image, record: _record)
92 |
93 | }
94 |
95 | func test_trailing() {
96 |
97 | let view = ExampleView(width: nil, height: nil) { (view: UIView) in
98 | Mondrian.buildSubviews(on: view) {
99 | VStackBlock(spacing: 4, alignment: .trailing) {
100 | UILabel.mockMultiline(text: "Hello", textColor: .white)
101 | .viewBlock
102 | .padding(8)
103 | .background(UIView.mock(backgroundColor: .layeringColor))
104 | UILabel.mockMultiline(text: "Mondrian", textColor: .white)
105 | .viewBlock
106 | .padding(8)
107 | .background(UIView.mock(backgroundColor: .layeringColor))
108 | UILabel.mockMultiline(text: "Layout!", textColor: .white)
109 | .viewBlock
110 | .padding(8)
111 | .background(UIView.mock(backgroundColor: .layeringColor))
112 | }
113 | }
114 | }
115 |
116 | assertSnapshot(matching: view, as: .image, record: _record)
117 |
118 | }
119 |
120 | func test_additional_spacing() {
121 |
122 | let view = ExampleView(width: nil, height: nil) { (view: UIView) in
123 | Mondrian.buildSubviews(on: view) {
124 | VStackBlock(spacing: 4) {
125 | UIView.mock(
126 | preferredSize: .smallSquare
127 | )
128 |
129 | StackingSpacer(minLength: 4)
130 |
131 | UIView.mock(
132 | preferredSize: .smallSquare
133 | )
134 |
135 | UIView.mock(
136 | preferredSize: .smallSquare
137 | )
138 | }
139 | }
140 | }
141 |
142 | assertSnapshot(matching: view, as: .image, record: _record)
143 | }
144 |
145 | func test_label_alignment() {
146 |
147 | let view = ExampleView(width: 200, height: 200) { (view: UIView) in
148 | Mondrian.buildSubviews(on: view) {
149 | VStackBlock(alignment: .leading) {
150 | UILabel.mockMultiline(text: "Hello")
151 | .viewBlock
152 | .padding(.horizontal, 10)
153 | UIView.mock(backgroundColor: .layeringColor)
154 | .viewBlock
155 | .alignSelf(.fill)
156 | }
157 | .background(UIView.mock(backgroundColor: .layeringColor))
158 | }
159 | }
160 |
161 | assertSnapshot(matching: view, as: .image, record: _record)
162 |
163 | }
164 |
165 | func test_including_layoutGuide() {
166 |
167 | let view = ExampleView(width: 200, height: 200) { (view: UIView) in
168 |
169 | let boxes = (0..<3).map { _ in UIView.mock(backgroundColor: .layeringColor) }
170 | let guides = (0..<2).map { _ in UILayoutGuide() }
171 |
172 | Mondrian.buildSubviews(on: view) {
173 | VStackBlock(alignment: .leading) {
174 |
175 | boxes[0]
176 |
177 | guides[0]
178 |
179 | boxes[1]
180 |
181 | guides[1]
182 |
183 | boxes[2]
184 |
185 | StackingSpacer(minLength: 0)
186 |
187 | }
188 | .background(UIView.mock(backgroundColor: .layeringColor))
189 | }
190 |
191 | mondrianBatchLayout {
192 |
193 | boxes.map { $0.mondrian.layout.height(20) }
194 |
195 | guides[0].mondrian.layout.height(.to(boxes[0]))
196 | guides[1].mondrian.layout.height(.to(boxes[2]), multiplier: 2)
197 | }
198 | }
199 |
200 | assertSnapshot(matching: view, as: .image, record: _record)
201 | }
202 |
203 | }
204 |
--------------------------------------------------------------------------------
/Tests/ZStackTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ZStackTests.swift
3 | // Tests
4 | //
5 | // Created by Muukii on 2021/06/18.
6 | //
7 |
8 | import Foundation
9 | import MondrianLayout
10 | import SnapshotTesting
11 | import XCTest
12 |
13 | final class ZStackTests: XCTestCase {
14 |
15 | func test_minimum_padding() {
16 |
17 | let view = ExampleView(width: 100, height: 100) { view in
18 | Mondrian.buildSubviews(on: view) {
19 | ZStackBlock {
20 | ZStackBlock {
21 | UILabel.mockSingleline(text: "Hello Hello Hello")
22 | .viewBlock
23 | .background(UIView.mock())
24 | }
25 | .padding(20) /// a minimum padding for the label in the container
26 | }
27 | .background(UIView.mock())
28 | }
29 | }
30 |
31 | assertSnapshot(matching: view, as: .image, record: _record)
32 |
33 | }
34 |
35 | func test_expandsElementIfCanBeExpanding() {
36 |
37 | let view = ExampleView(width: 100, height: 100) { view in
38 | Mondrian.buildSubviews(on: view) {
39 | LayoutContainer(attachedSafeAreaEdges: .vertical) {
40 | ZStackBlock {
41 |
42 | /// this view must be expanded to parent view
43 | UIView.mock(
44 | backgroundColor: .layeringColor
45 | )
46 |
47 | /// this view must be sized with intrinsic content size.
48 | UIView.mock(
49 | backgroundColor: .layeringColor,
50 | preferredSize: .smallSquare
51 | )
52 | }
53 | }
54 | }
55 | }
56 |
57 | assertSnapshot(matching: view, as: .image, record: _record)
58 |
59 | }
60 |
61 | func test_expandsElementWithRelative() {
62 |
63 | let view = ExampleView(width: 100, height: 100) { view in
64 | Mondrian.buildSubviews(on: view) {
65 | LayoutContainer(attachedSafeAreaEdges: .vertical) {
66 | ZStackBlock {
67 | UIView.mock(
68 | backgroundColor: .layeringColor,
69 | preferredSize: .smallSquare
70 | )
71 | .viewBlock
72 | .relative(0)
73 | }
74 | }
75 | }
76 | }
77 |
78 | assertSnapshot(matching: view, as: .image, record: _record)
79 | }
80 |
81 | func test_alignSelf() {
82 |
83 | let view = ExampleView(width: 100, height: 100) { view in
84 | Mondrian.buildSubviews(on: view) {
85 | LayoutContainer(attachedSafeAreaEdges: .vertical) {
86 | ZStackBlock {
87 |
88 | UIView.mock(
89 | backgroundColor: .layeringColor,
90 | preferredSize: .smallSquare
91 | )
92 | .viewBlock
93 | .alignSelf(.attach(.all))
94 |
95 | UIView.mock(
96 | backgroundColor: .layeringColor,
97 | preferredSize: .smallSquare
98 | )
99 | .viewBlock
100 | .alignSelf(.attach(.top))
101 |
102 | UIView.mock(
103 | backgroundColor: .layeringColor,
104 | preferredSize: .smallSquare
105 | )
106 | .viewBlock
107 | .alignSelf(.attach(.bottom))
108 |
109 | UIView.mock(
110 | backgroundColor: .layeringColor,
111 | preferredSize: .smallSquare
112 | )
113 | .viewBlock
114 | .alignSelf(.attach(.leading))
115 |
116 | UIView.mock(
117 | backgroundColor: .layeringColor,
118 | preferredSize: .smallSquare
119 | )
120 | .viewBlock
121 | .alignSelf(.attach(.trailing))
122 |
123 | UIView.mock(
124 | backgroundColor: .layeringColor,
125 | preferredSize: .smallSquare
126 | )
127 | .viewBlock
128 | .alignSelf(.attach([.top, .leading]))
129 |
130 | UIView.mock(
131 | backgroundColor: .layeringColor,
132 | preferredSize: .smallSquare
133 | )
134 | .viewBlock
135 | .alignSelf(.attach([.top, .trailing]))
136 |
137 | UIView.mock(
138 | backgroundColor: .layeringColor,
139 | preferredSize: .smallSquare
140 | )
141 | .viewBlock
142 | .alignSelf(.attach([.bottom, .leading]))
143 |
144 | UIView.mock(
145 | backgroundColor: .layeringColor,
146 | preferredSize: .smallSquare
147 | )
148 | .viewBlock
149 | .alignSelf(.attach([.bottom, .trailing]))
150 |
151 |
152 | UIView.mock(
153 | backgroundColor: .layeringColor,
154 | preferredSize: .smallSquare
155 | )
156 | .viewBlock
157 | .alignSelf(.attach([.top, .bottom]))
158 |
159 | UIView.mock(
160 | backgroundColor: .layeringColor,
161 | preferredSize: .smallSquare
162 | )
163 | .viewBlock
164 | .alignSelf(.attach([.leading, .trailing]))
165 |
166 | UIView.mock(
167 | backgroundColor: .layeringColor,
168 | preferredSize: .smallSquare
169 | )
170 | .viewBlock
171 | .alignSelf(.attach([.top, .leading, .trailing]))
172 |
173 | UIView.mock(
174 | backgroundColor: .layeringColor,
175 | preferredSize: .smallSquare
176 | )
177 | .viewBlock
178 | .alignSelf(.attach([.bottom, .leading, .trailing]))
179 |
180 | UIView.mock(
181 | backgroundColor: .layeringColor,
182 | preferredSize: .smallSquare
183 | )
184 | .viewBlock
185 | .alignSelf(.attach([.top, .bottom, .leading]))
186 |
187 | UIView.mock(
188 | backgroundColor: .layeringColor,
189 | preferredSize: .smallSquare
190 | )
191 | .viewBlock
192 | .alignSelf(.attach([.top, .bottom, .trailing]))
193 |
194 | UIView.mock(
195 | backgroundColor: .layeringColor,
196 | preferredSize: .smallSquare
197 | )
198 | .viewBlock
199 | .alignSelf(.attach([]))
200 |
201 | UIView.mock(
202 | backgroundColor: .layeringColor,
203 | preferredSize: .smallSquare
204 | )
205 | .viewBlock
206 | .alignSelf(.center)
207 |
208 | }
209 | }
210 | }
211 | }
212 |
213 | assertSnapshot(matching: view, as: .image, record: _record)
214 |
215 | }
216 | }
217 |
--------------------------------------------------------------------------------
/Tests/__Snapshots__/ClassicTests/test_multiplier_constraints.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluidGroup/MondrianLayout/b26edaa5a469bc5fd58f9afe37d257ca1b3771e0/Tests/__Snapshots__/ClassicTests/test_multiplier_constraints.1.png
--------------------------------------------------------------------------------
/Tests/__Snapshots__/HStackTests/test_additional_spacing.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluidGroup/MondrianLayout/b26edaa5a469bc5fd58f9afe37d257ca1b3771e0/Tests/__Snapshots__/HStackTests/test_additional_spacing.1.png
--------------------------------------------------------------------------------
/Tests/__Snapshots__/HStackTests/test_mixing_spacer.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluidGroup/MondrianLayout/b26edaa5a469bc5fd58f9afe37d257ca1b3771e0/Tests/__Snapshots__/HStackTests/test_mixing_spacer.1.png
--------------------------------------------------------------------------------
/Tests/__Snapshots__/LayoutDescriptorTests/test_layout_0.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluidGroup/MondrianLayout/b26edaa5a469bc5fd58f9afe37d257ca1b3771e0/Tests/__Snapshots__/LayoutDescriptorTests/test_layout_0.1.png
--------------------------------------------------------------------------------
/Tests/__Snapshots__/LayoutDescriptorTests/test_layout_center.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluidGroup/MondrianLayout/b26edaa5a469bc5fd58f9afe37d257ca1b3771e0/Tests/__Snapshots__/LayoutDescriptorTests/test_layout_center.1.png
--------------------------------------------------------------------------------
/Tests/__Snapshots__/LayoutDescriptorTests/test_layout_edge.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluidGroup/MondrianLayout/b26edaa5a469bc5fd58f9afe37d257ca1b3771e0/Tests/__Snapshots__/LayoutDescriptorTests/test_layout_edge.1.png
--------------------------------------------------------------------------------
/Tests/__Snapshots__/OverlayTests/test_1.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluidGroup/MondrianLayout/b26edaa5a469bc5fd58f9afe37d257ca1b3771e0/Tests/__Snapshots__/OverlayTests/test_1.1.png
--------------------------------------------------------------------------------
/Tests/__Snapshots__/OverlayTests/test_2.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluidGroup/MondrianLayout/b26edaa5a469bc5fd58f9afe37d257ca1b3771e0/Tests/__Snapshots__/OverlayTests/test_2.1.png
--------------------------------------------------------------------------------
/Tests/__Snapshots__/RelativeTests/test_accumulate_padding.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluidGroup/MondrianLayout/b26edaa5a469bc5fd58f9afe37d257ca1b3771e0/Tests/__Snapshots__/RelativeTests/test_accumulate_padding.1.png
--------------------------------------------------------------------------------
/Tests/__Snapshots__/RelativeTests/test_accumulate_relative.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluidGroup/MondrianLayout/b26edaa5a469bc5fd58f9afe37d257ca1b3771e0/Tests/__Snapshots__/RelativeTests/test_accumulate_relative.1.png
--------------------------------------------------------------------------------
/Tests/__Snapshots__/RelativeTests/test_centering_in_ambiguous.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluidGroup/MondrianLayout/b26edaa5a469bc5fd58f9afe37d257ca1b3771e0/Tests/__Snapshots__/RelativeTests/test_centering_in_ambiguous.1.png
--------------------------------------------------------------------------------
/Tests/__Snapshots__/SizingTests/test_sizing.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluidGroup/MondrianLayout/b26edaa5a469bc5fd58f9afe37d257ca1b3771e0/Tests/__Snapshots__/SizingTests/test_sizing.1.png
--------------------------------------------------------------------------------
/Tests/__Snapshots__/SyntaxTests/test_hStack.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluidGroup/MondrianLayout/b26edaa5a469bc5fd58f9afe37d257ca1b3771e0/Tests/__Snapshots__/SyntaxTests/test_hStack.1.png
--------------------------------------------------------------------------------
/Tests/__Snapshots__/SyntaxTests/test_vStack.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluidGroup/MondrianLayout/b26edaa5a469bc5fd58f9afe37d257ca1b3771e0/Tests/__Snapshots__/SyntaxTests/test_vStack.1.png
--------------------------------------------------------------------------------
/Tests/__Snapshots__/Tests/test_1.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluidGroup/MondrianLayout/b26edaa5a469bc5fd58f9afe37d257ca1b3771e0/Tests/__Snapshots__/Tests/test_1.1.png
--------------------------------------------------------------------------------
/Tests/__Snapshots__/Tests/test_mondrian.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluidGroup/MondrianLayout/b26edaa5a469bc5fd58f9afe37d257ca1b3771e0/Tests/__Snapshots__/Tests/test_mondrian.1.png
--------------------------------------------------------------------------------
/Tests/__Snapshots__/VGridTests/test_basic.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluidGroup/MondrianLayout/b26edaa5a469bc5fd58f9afe37d257ca1b3771e0/Tests/__Snapshots__/VGridTests/test_basic.1.png
--------------------------------------------------------------------------------
/Tests/__Snapshots__/VStackTests/test_additional_spacing.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluidGroup/MondrianLayout/b26edaa5a469bc5fd58f9afe37d257ca1b3771e0/Tests/__Snapshots__/VStackTests/test_additional_spacing.1.png
--------------------------------------------------------------------------------
/Tests/__Snapshots__/VStackTests/test_enter.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluidGroup/MondrianLayout/b26edaa5a469bc5fd58f9afe37d257ca1b3771e0/Tests/__Snapshots__/VStackTests/test_enter.1.png
--------------------------------------------------------------------------------
/Tests/__Snapshots__/VStackTests/test_including_layoutGuide.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluidGroup/MondrianLayout/b26edaa5a469bc5fd58f9afe37d257ca1b3771e0/Tests/__Snapshots__/VStackTests/test_including_layoutGuide.1.png
--------------------------------------------------------------------------------
/Tests/__Snapshots__/VStackTests/test_label_alignment.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluidGroup/MondrianLayout/b26edaa5a469bc5fd58f9afe37d257ca1b3771e0/Tests/__Snapshots__/VStackTests/test_label_alignment.1.png
--------------------------------------------------------------------------------
/Tests/__Snapshots__/VStackTests/test_leading.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluidGroup/MondrianLayout/b26edaa5a469bc5fd58f9afe37d257ca1b3771e0/Tests/__Snapshots__/VStackTests/test_leading.1.png
--------------------------------------------------------------------------------
/Tests/__Snapshots__/VStackTests/test_mixing_spacer.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluidGroup/MondrianLayout/b26edaa5a469bc5fd58f9afe37d257ca1b3771e0/Tests/__Snapshots__/VStackTests/test_mixing_spacer.1.png
--------------------------------------------------------------------------------
/Tests/__Snapshots__/VStackTests/test_trailing.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluidGroup/MondrianLayout/b26edaa5a469bc5fd58f9afe37d257ca1b3771e0/Tests/__Snapshots__/VStackTests/test_trailing.1.png
--------------------------------------------------------------------------------
/Tests/__Snapshots__/ZStackTests/test_alignSelf.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluidGroup/MondrianLayout/b26edaa5a469bc5fd58f9afe37d257ca1b3771e0/Tests/__Snapshots__/ZStackTests/test_alignSelf.1.png
--------------------------------------------------------------------------------
/Tests/__Snapshots__/ZStackTests/test_expandsElementIfCanBeExpanding.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluidGroup/MondrianLayout/b26edaa5a469bc5fd58f9afe37d257ca1b3771e0/Tests/__Snapshots__/ZStackTests/test_expandsElementIfCanBeExpanding.1.png
--------------------------------------------------------------------------------
/Tests/__Snapshots__/ZStackTests/test_expandsElementWithRelative.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluidGroup/MondrianLayout/b26edaa5a469bc5fd58f9afe37d257ca1b3771e0/Tests/__Snapshots__/ZStackTests/test_expandsElementWithRelative.1.png
--------------------------------------------------------------------------------
/Tests/__Snapshots__/ZStackTests/test_minimum_padding.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FluidGroup/MondrianLayout/b26edaa5a469bc5fd58f9afe37d257ca1b3771e0/Tests/__Snapshots__/ZStackTests/test_minimum_padding.1.png
--------------------------------------------------------------------------------
/fastlane/Appfile:
--------------------------------------------------------------------------------
1 | # app_identifier("[[APP_IDENTIFIER]]") # The bundle identifier of your app
2 | # apple_id("[[APPLE_ID]]") # Your Apple email address
3 |
4 |
5 | # For more information about the Appfile, see:
6 | # https://docs.fastlane.tools/advanced/#appfile
7 |
--------------------------------------------------------------------------------
/fastlane/Fastfile:
--------------------------------------------------------------------------------
1 | # This file contains the fastlane.tools configuration
2 | # You can find the documentation at https://docs.fastlane.tools
3 | #
4 | # For a list of all available actions, check out
5 | #
6 | # https://docs.fastlane.tools/actions
7 | #
8 | # For a list of all available plugins, check out
9 | #
10 | # https://docs.fastlane.tools/plugins/available-plugins
11 | #
12 |
13 | # Uncomment the line if you want fastlane to automatically update itself
14 | # update_fastlane
15 |
16 | default_platform(:ios)
17 |
18 | platform :ios do
19 | desc "Description of what the lane does"
20 | lane :custom_lane do
21 | # add actions here: https://docs.fastlane.tools/actions
22 | end
23 |
24 | lane :test_project do
25 | scan(scheme: "Tests")
26 | end
27 | end
28 |
--------------------------------------------------------------------------------
/fastlane/README.md:
--------------------------------------------------------------------------------
1 | fastlane documentation
2 | ================
3 | # Installation
4 |
5 | Make sure you have the latest version of the Xcode command line tools installed:
6 |
7 | ```
8 | xcode-select --install
9 | ```
10 |
11 | Install _fastlane_ using
12 | ```
13 | [sudo] gem install fastlane -NV
14 | ```
15 | or alternatively using `brew install fastlane`
16 |
17 | # Available Actions
18 | ## iOS
19 | ### ios custom_lane
20 | ```
21 | fastlane ios custom_lane
22 | ```
23 | Description of what the lane does
24 | ### ios test_project
25 | ```
26 | fastlane ios test_project
27 | ```
28 |
29 |
30 | ----
31 |
32 | This README.md is auto-generated and will be re-generated every time [fastlane](https://fastlane.tools) is run.
33 | More information about fastlane can be found on [fastlane.tools](https://fastlane.tools).
34 | The documentation of fastlane can be found on [docs.fastlane.tools](https://docs.fastlane.tools).
35 |
--------------------------------------------------------------------------------