diff --git a/csharp/Mac/.gitignore b/csharp/Mac/.gitignore
new file mode 100644
index 00000000..1cf1debb
--- /dev/null
+++ b/csharp/Mac/.gitignore
@@ -0,0 +1,2 @@
+libyoga.dylib
+*.userprefs
diff --git a/csharp/Mac/ApiDefinition.cs b/csharp/Mac/ApiDefinition.cs
new file mode 100644
index 00000000..9fec5cd6
--- /dev/null
+++ b/csharp/Mac/ApiDefinition.cs
@@ -0,0 +1,23 @@
+/**
+ * Copyright (c) 2014-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ */
+
+using System;
+
+using AppKit;
+using Foundation;
+using ObjCRuntime;
+using CoreGraphics;
+
+namespace Facebook.Yoga.Mac
+{
+ // Xamarin.Mac binding projects allow you to include native libraries inside C# DLLs for easy consumption
+ // later. However, the binding project build files currently assume you are binding some objective-c API
+ // and that you need an ApiDefinition.cs for that. yoga is all C APIs, so just include this "blank" file so
+ // the dylib gets packaged
+}
diff --git a/csharp/Mac/CustomBuildAction.targets b/csharp/Mac/CustomBuildAction.targets
new file mode 100644
index 00000000..e20e70b8
--- /dev/null
+++ b/csharp/Mac/CustomBuildAction.targets
@@ -0,0 +1,11 @@
+
+
+
+ CopyInNativeLib;$(CompileDependsOn)
+
+
+
+
+
+
+
diff --git a/csharp/Mac/Facebook.Yoga.Mac.Test/AppDelegate.cs b/csharp/Mac/Facebook.Yoga.Mac.Test/AppDelegate.cs
new file mode 100644
index 00000000..f6a46196
--- /dev/null
+++ b/csharp/Mac/Facebook.Yoga.Mac.Test/AppDelegate.cs
@@ -0,0 +1,30 @@
+/**
+ * Copyright 2014-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the license found in the
+ * LICENSE-examples file in the root directory of this source tree.
+ */
+
+using AppKit;
+using Foundation;
+
+namespace Facebook.Yoga.Mac.Test
+{
+ [Register("AppDelegate")]
+ public class AppDelegate : NSApplicationDelegate
+ {
+ public AppDelegate()
+ {
+ }
+
+ public override void DidFinishLaunching(NSNotification notification)
+ {
+ }
+
+ public override void WillTerminate(NSNotification notification)
+ {
+ // Insert code here to tear down your application
+ }
+ }
+}
diff --git a/csharp/Mac/Facebook.Yoga.Mac.Test/Entitlements.plist b/csharp/Mac/Facebook.Yoga.Mac.Test/Entitlements.plist
new file mode 100644
index 00000000..9ae59937
--- /dev/null
+++ b/csharp/Mac/Facebook.Yoga.Mac.Test/Entitlements.plist
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/csharp/Mac/Facebook.Yoga.Mac.Test/Facebook.Yoga.Mac.Test.csproj b/csharp/Mac/Facebook.Yoga.Mac.Test/Facebook.Yoga.Mac.Test.csproj
new file mode 100644
index 00000000..70535e37
--- /dev/null
+++ b/csharp/Mac/Facebook.Yoga.Mac.Test/Facebook.Yoga.Mac.Test.csproj
@@ -0,0 +1,84 @@
+
+
+
+ Debug
+ AnyCPU
+ {64E0AB97-A904-4607-A535-EEA5A966C09E}
+ {A3F8F2AB-B479-4A4A-A458-A89E7DC349F1};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ Exe
+ Facebook.Yoga.Mac.Test
+ Facebook.Yoga.Mac.Test
+ v2.0
+ Xamarin.Mac
+ Resources
+
+
+ true
+ full
+ false
+ bin\Debug
+ DEBUG;
+ prompt
+ 4
+ false
+ Mac Developer
+ false
+ false
+ false
+ true
+ true
+ true
+ HttpClientHandler
+ Default
+ None
+ x86_64
+
+
+ pdbonly
+ true
+ bin\Release
+
+ prompt
+ 4
+ false
+ true
+ false
+ true
+ true
+ true
+ SdkOnly
+ HttpClientHandler
+ Default
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ViewController.cs
+
+
+
+
+
+
+
+ {19A1C7D7-C9CC-476A-B604-DF6A3DE1BA71}
+ Facebook.Yoga.Mac
+
+
+
+
diff --git a/csharp/Mac/Facebook.Yoga.Mac.Test/Info.plist b/csharp/Mac/Facebook.Yoga.Mac.Test/Info.plist
new file mode 100644
index 00000000..7e955671
--- /dev/null
+++ b/csharp/Mac/Facebook.Yoga.Mac.Test/Info.plist
@@ -0,0 +1,30 @@
+
+
+
+
+ CFBundleName
+ Facebook.Yoga.Mac.Test
+ CFBundleIdentifier
+ com.companyname.facebook-yoga-mac-test
+ CFBundleShortVersionString
+ 1.0
+ CFBundleVersion
+ 1
+ LSMinimumSystemVersion
+ 10.11
+ CFBundleDevelopmentRegion
+ en
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundlePackageType
+ APPL
+ CFBundleSignature
+ ????
+ NSHumanReadableCopyright
+ ${AuthorCopyright}
+ NSPrincipalClass
+ NSApplication
+ NSMainStoryboardFile
+ Main
+
+
diff --git a/csharp/Mac/Facebook.Yoga.Mac.Test/Main.cs b/csharp/Mac/Facebook.Yoga.Mac.Test/Main.cs
new file mode 100644
index 00000000..97adb4db
--- /dev/null
+++ b/csharp/Mac/Facebook.Yoga.Mac.Test/Main.cs
@@ -0,0 +1,21 @@
+/**
+ * Copyright 2014-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the license found in the
+ * LICENSE-examples file in the root directory of this source tree.
+ */
+
+using AppKit;
+
+namespace Facebook.Yoga.Mac.Test
+{
+ static class MainClass
+ {
+ static void Main(string[] args)
+ {
+ NSApplication.Init();
+ NSApplication.Main(args);
+ }
+ }
+}
diff --git a/csharp/Mac/Facebook.Yoga.Mac.Test/Main.storyboard b/csharp/Mac/Facebook.Yoga.Mac.Test/Main.storyboard
new file mode 100644
index 00000000..1d8f728d
--- /dev/null
+++ b/csharp/Mac/Facebook.Yoga.Mac.Test/Main.storyboard
@@ -0,0 +1,681 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/csharp/Mac/Facebook.Yoga.Mac.Test/ViewController.cs b/csharp/Mac/Facebook.Yoga.Mac.Test/ViewController.cs
new file mode 100644
index 00000000..e802aa4e
--- /dev/null
+++ b/csharp/Mac/Facebook.Yoga.Mac.Test/ViewController.cs
@@ -0,0 +1,137 @@
+/**
+ * Copyright 2014-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the license found in the
+ * LICENSE-examples file in the root directory of this source tree.
+ */
+
+//#define DEBUG_LAYOUT
+using System;
+
+using AppKit;
+using Foundation;
+using CoreGraphics;
+
+namespace Facebook.Yoga.Mac.Test
+{
+ public static class NSViewYogaExtensions
+ {
+ public static void ApplyYogaLayout (this NSView view, YogaNode n, bool root = true)
+ {
+#if DEBUG_LAYOUT
+ Console.WriteLine ($"ApplyYogaLayout {view.ToolTip}, {n.LayoutX}, {n.LayoutY}, {n.LayoutWidth}, {n.LayoutHeight}");
+#endif
+
+ // A bit of gross special casing
+ // This really should mostly go away if/when the UIView+Yoga.m magic gets ported to AppKit
+ if (root)
+ view.Frame = new CGRect (n.LayoutX, n.LayoutY, n.LayoutWidth, n.LayoutHeight);
+#if DEBUG_LAYOUT
+ Console.WriteLine ($"Setting {view.ToolTip} frame to {view.Frame}");
+#endif
+
+ // This assumes your YogaNode and NSView children were inserted in same order
+ for (int i = 0; i < n.Count; ++i) {
+ YogaNode childNode = n[i];
+ // Cocoa coord space is from bottom left not top left
+ view.Subviews[i].Frame = new CGRect (childNode.LayoutX, n.LayoutHeight - childNode.LayoutY - childNode.LayoutHeight, childNode.LayoutWidth, childNode.LayoutHeight);
+#if DEBUG_LAYOUT
+ Console.WriteLine ($"Setting {view.Subviews[i].ToolTip} frame to {view.Subviews[i].Frame}");
+#endif
+ if (childNode.Count > 0){
+#if DEBUG_LAYOUT
+ Console.WriteLine ($"Calling ApplyYogaLayout recursively on {view.Subviews[i].ToolTip}");
+#endif
+ ApplyYogaLayout (view.Subviews[i], childNode, false);
+ }
+ }
+ }
+ }
+
+ public partial class ViewController : NSViewController
+ {
+ public ViewController(IntPtr handle) : base(handle)
+ {
+ }
+
+ public override void ViewDidLoad()
+ {
+ base.ViewDidLoad ();
+
+ NSImage image = NSImage.ImageNamed (NSImageName.TrashFull);
+
+ NSView root = CreateViewHierarchy (image);
+ var rootNode = CalculateLayout (View.Frame, image.Size);
+
+ root.ApplyYogaLayout (rootNode);
+
+ View.AddSubview (root);
+ }
+
+ static NSView CreateViewHierarchy (NSImage image)
+ {
+ var root = new NSView () {
+ WantsLayer = true,
+ ToolTip = "Root"
+ };
+ root.Layer.BackgroundColor = NSColor.Red.CGColor;
+
+ NSView child1 = new NSView () {
+ WantsLayer = true,
+ ToolTip = "Child 1"
+ };
+ child1.Layer.BackgroundColor = NSColor.Blue.CGColor;
+
+ NSView child2 = new NSView () {
+ WantsLayer = true,
+ ToolTip = "Child 2"
+ };
+ child2.Layer.BackgroundColor = NSColor.Green.CGColor;
+
+ NSView child3 = new NSView () {
+ WantsLayer = true,
+ ToolTip = "Child 3"
+ };
+ child3.Layer.BackgroundColor = NSColor.Yellow.CGColor;
+
+ root.AddSubview (child1);
+ root.AddSubview (child2);
+ child2.AddSubview (child3);
+
+ return root;
+ }
+
+ static YogaNode CalculateLayout (CGRect rootFrame, CGSize imageSize)
+ {
+ var rootNode = new YogaNode () {
+ Width = (float)rootFrame.Width,
+ Height = (float)rootFrame.Height,
+ AlignItems = YogaAlign.Center,
+ JustifyContent = YogaJustify.Center
+ };
+
+ var child1Node = new YogaNode () {
+ Width = 100,
+ Height = 100
+ };
+
+ var child2Node = new YogaNode () {
+ Width = 200,
+ Height = 100
+ };
+
+ var child3Node = new YogaNode () {
+ Width = 100,
+ Height = 100
+ };
+
+ rootNode.Insert (0, child1Node);
+ rootNode.Insert (1, child2Node);
+ child2Node.Insert (0, child3Node);
+ rootNode.CalculateLayout ();
+
+ return rootNode;
+ }
+ }
+}
diff --git a/csharp/Mac/Facebook.Yoga.Mac.Test/ViewController.designer.cs b/csharp/Mac/Facebook.Yoga.Mac.Test/ViewController.designer.cs
new file mode 100644
index 00000000..1cf1e327
--- /dev/null
+++ b/csharp/Mac/Facebook.Yoga.Mac.Test/ViewController.designer.cs
@@ -0,0 +1,18 @@
+// WARNING
+//
+// This file has been generated automatically by Xamarin Studio to store outlets and
+// actions made in the UI designer. If it is removed, they will be lost.
+// Manual changes to this file may not be handled correctly.
+//
+using Foundation;
+
+namespace Facebook.Yoga.Mac.Test
+{
+ [Register("ViewController")]
+ partial class ViewController
+ {
+ void ReleaseDesignerOutlets()
+ {
+ }
+ }
+}
diff --git a/csharp/Mac/Facebook.Yoga.Mac.csproj b/csharp/Mac/Facebook.Yoga.Mac.csproj
new file mode 100644
index 00000000..63dcfe16
--- /dev/null
+++ b/csharp/Mac/Facebook.Yoga.Mac.csproj
@@ -0,0 +1,51 @@
+
+
+
+ Debug
+ AnyCPU
+ {19A1C7D7-C9CC-476A-B604-DF6A3DE1BA71}
+ {810C163F-4746-4721-8B8E-88A3673A62EA};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ Library
+ Facebook.Yoga.Mac
+ Facebook.Yoga.Mac
+ Resources
+
+
+ true
+ full
+ false
+ bin\Debug
+ __UNIFIED__;DEBUG;MONOMAC
+ prompt
+ 4
+ false
+
+
+ true
+ bin\Release
+ __UNIFIED__;MONOMAC
+ prompt
+ 4
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Dynamic
+ False
+
+
+
+
+
+
diff --git a/csharp/Mac/Facebook.Yoga.Mac.sln b/csharp/Mac/Facebook.Yoga.Mac.sln
new file mode 100644
index 00000000..c99766c6
--- /dev/null
+++ b/csharp/Mac/Facebook.Yoga.Mac.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2012
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Facebook.Yoga.Mac.Test", "Facebook.Yoga.Mac.Test\Facebook.Yoga.Mac.Test.csproj", "{64E0AB97-A904-4607-A535-EEA5A966C09E}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Facebook.Yoga.Mac", "Facebook.Yoga.Mac.csproj", "{19A1C7D7-C9CC-476A-B604-DF6A3DE1BA71}"
+EndProject
+Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Facebook.Yoga.Shared", "..\Facebook.Yoga\Facebook.Yoga.Shared.shproj", "{91C42D32-291D-4B72-90B4-551663D60B8B}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {64E0AB97-A904-4607-A535-EEA5A966C09E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {64E0AB97-A904-4607-A535-EEA5A966C09E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {64E0AB97-A904-4607-A535-EEA5A966C09E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {64E0AB97-A904-4607-A535-EEA5A966C09E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {19A1C7D7-C9CC-476A-B604-DF6A3DE1BA71}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {19A1C7D7-C9CC-476A-B604-DF6A3DE1BA71}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {19A1C7D7-C9CC-476A-B604-DF6A3DE1BA71}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {19A1C7D7-C9CC-476A-B604-DF6A3DE1BA71}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+EndGlobal