feat(cpp): expose enum name in getProperties for cpp and js (#13032) ced1506e5b
* feat(viewmodel): expose enum name in PropertyData

* feat(viewmodel): expose enumName in getProperties

* add test in for getting enumName

* clang check

Co-authored-by: Miklós Fazekas <mfazekas@szemafor.com>
Co-authored-by: Zachary Plata <zach@rive.app>
diff --git a/.rive_head b/.rive_head
index 50fe441..da6eb28 100644
--- a/.rive_head
+++ b/.rive_head
@@ -1 +1 @@
-37997d7366fa70e190725e00f399a9dacd4c8a38
+ced1506e5bddd30e8d3939578f024e7d9c8b8409
diff --git a/include/rive/viewmodel/runtime/viewmodel_runtime.hpp b/include/rive/viewmodel/runtime/viewmodel_runtime.hpp
index 77f6f0e..a0435bf 100644
--- a/include/rive/viewmodel/runtime/viewmodel_runtime.hpp
+++ b/include/rive/viewmodel/runtime/viewmodel_runtime.hpp
@@ -16,6 +16,7 @@
 {
     DataType type;
     std::string name;
+    std::string enumName;
 };
 
 class ViewModelRuntime : public RefCnt<ViewModelRuntime>
diff --git a/src/viewmodel/runtime/viewmodel_runtime.cpp b/src/viewmodel/runtime/viewmodel_runtime.cpp
index f625b8c..d92500f 100644
--- a/src/viewmodel/runtime/viewmodel_runtime.cpp
+++ b/src/viewmodel/runtime/viewmodel_runtime.cpp
@@ -46,6 +46,7 @@
     for (auto property : properties)
     {
         DataType type = DataType::none;
+        std::string enumName;
         switch (property->coreType())
         {
             case ViewModelPropertyString::typeKey:
@@ -66,8 +67,16 @@
             case ViewModelPropertyEnum::typeKey:
             case ViewModelPropertyEnumCustomBase::typeKey:
             case ViewModelPropertyEnumSystemBase::typeKey:
+            {
                 type = DataType::enumType;
+                auto* dataEnum =
+                    static_cast<ViewModelPropertyEnum*>(property)->dataEnum();
+                if (dataEnum != nullptr)
+                {
+                    enumName = dataEnum->enumName();
+                }
                 break;
+            }
             case ViewModelPropertyTrigger::typeKey:
                 type = DataType::trigger;
                 break;
@@ -86,7 +95,7 @@
             default:
                 break;
         }
-        props.push_back({type, property->name()});
+        props.push_back({type, property->name(), enumName});
     }
     return props;
 }
diff --git a/tests/unit_tests/runtime/data_binding_test.cpp b/tests/unit_tests/runtime/data_binding_test.cpp
index b4deb63..9fa10c0 100644
--- a/tests/unit_tests/runtime/data_binding_test.cpp
+++ b/tests/unit_tests/runtime/data_binding_test.cpp
@@ -1,5 +1,6 @@
 #include <rive/file.hpp>
 #include <rive/node.hpp>
+#include <algorithm>
 #include <rive/shapes/rectangle.hpp>
 #include <rive/shapes/shape.hpp>
 #include <utils/no_op_renderer.hpp>
@@ -1476,6 +1477,26 @@
     auto numChi = instance->propertyNumber("chi/chi-num");
     REQUIRE(numChi != nullptr);
     REQUIRE(numChi->dataType() == rive::DataType::number);
+
+    // Enum properties expose the backing enum's name while non-enum properties
+    // leave enumName empty.
+    auto properties = instance->properties();
+    auto findProperty = [&properties](const std::string& name) {
+        return std::find_if(properties.begin(),
+                            properties.end(),
+                            [&name](const rive::PropertyData& data) {
+                                return data.name == name;
+                            });
+    };
+    auto enuData = findProperty("enu");
+    REQUIRE(enuData != properties.end());
+    REQUIRE(enuData->type == rive::DataType::enumType);
+    REQUIRE(enuData->enumName == "Horizontal Align");
+
+    auto numData = findProperty("num");
+    REQUIRE(numData != properties.end());
+    REQUIRE(numData->type == rive::DataType::number);
+    REQUIRE(numData->enumName.empty());
 }
 
 TEST_CASE("Trigger fires single change on listener", "[data binding]")