Wrappers for the Nested Properties and Collections

For the nested properties like Selectable.colors.normalColor or properties in collections wrappers should be create manually.

Widget with Nested Field

public class WidgetWithNestedField : MonoBehaviour
{
        [Serializable]
        public class Data
        {
                public string Name;

                // nested property cannot be automatically accessed
                public Sprite Icon;
        }

        public Data WidgetData = new Data();

        public void UpdateData()
        {
                // update game objects which display WidgetData
        }
}

Wrapper for the Widget with Nested Field

public class WidgetWithNestedFieldWrapper : Wrapper<Sprite, WidgetWithNestedField>
{
        public WidgetWithNestedFieldWrapper()
        {
                Name = string.Format("{0}.{1}", nameof(WidgetWithNestedField.WidgetData), nameof(WidgetWithNestedField.Data.Icon));
        }

        protected override Sprite Get(WidgetWithNestedField widget) => widget.WidgetData?.Icon;

        protected override void Set(WidgetWithNestedField widget, Sprite value)
        {
                widget.WidgetData.Icon = value;
                widget.UpdateData();
        }

        protected override bool ShouldAttachValue(WidgetWithNestedField widget) => Get(widget) != null;

        [PropertiesRegistry, Preserve]
        public static void AddWrappers()
        {
                PropertyWrappers<Sprite>.Add(new WidgetWithNestedFieldWrapper());
        }
}

Widget with Collections

public class WidgetWithList : MonoBehaviour
{
        [Serializable]
        public class Data
        {
                public string Name;

                public Sprite Icon;
        }

        // properties in collections cannot be automatically accessed
        public List<Data> WidgetData = new List<Data>();

        public void UpdateData(int index)
        {
                // update game objects that display WidgetData[index]
        }
}

Wrapper for the Widget with Collections

public class WidgetWithListWrapper : Wrapper<Sprite, WidgetWithList>
{
        readonly int index;

        public WidgetWithListWrapper(int index)
        {
                this.index = index;
                Name = string.Format("{0}[{1}].{2}", nameof(WidgetWithList.WidgetData), index, nameof(WidgetWithList.Data.Icon));
        }

        protected override Sprite Get(WidgetWithList widget) => Active(widget) ? widget.WidgetData[index].Icon : null;

        protected override void Set(WidgetWithList widget, Sprite value)
        {
                if (Active(widget))
                {
                        widget.WidgetData[index].Icon = value;
                        widget.UpdateData(index);
                }
        }

        protected override bool Active(WidgetWithList widget) => index < widget.WidgetData.Count;

        protected override bool ShouldAttachValue(WidgetWithList widget) => Get(widget) != null;

        [PropertiesRegistry, Preserve]
        public static void AddWrappers()
        {
                // 20 is the maximum supported size of the WidgetData array and can be changed
                for (var i = 0; i < 20; i++)
                {
                        PropertyWrappers<Sprite>.Add(new WidgetWithListWrapper(i));
                }
        }
}