Editor/ControlWidgetExtensions.cs
using Editor;
using Sandbox;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace ExtendedEditor;

public static class ControlWidgetExtensions // TODO: use one from new editor library
{
    extension(ControlWidget controlWidget)
    {
        public void Skip()
        {
            if(controlWidget is null)
                return;

            controlWidget.Layout ??= Layout.Row();
            controlWidget.Layout.Clear(true);
            controlWidget.Layout.Margin = 0;
            controlWidget.Layout.Spacing = 0;
            controlWidget.PaintBackground = false;

            var newControlWidget = ControlWidget.Create(controlWidget.SerializedProperty, controlWidget.GetType()!);
            if(newControlWidget is null)
                return;

            controlWidget.Layout.Add(newControlWidget);
        }
    }

    extension(ControlWidget)
    {
        public static Type GetControlWidgetType(SerializedProperty serializedProperty, params IEnumerable<Attribute> attributes)
        {
            var proxy = serializedProperty.CreateProxy(attributes);
            var widget = ControlWidget.Create(proxy);
            var type = widget.GetType();
            widget.Destroy();
            return type;
        }

        public static ControlWidget? Create(SerializedProperty serializedProperty, params IEnumerable<Type?>? skippingWidgetTypes)
        {
            var startingSerializedProperty = serializedProperty;

            if(skippingWidgetTypes is null || !skippingWidgetTypes.Any())
                return ControlWidget.Create(serializedProperty);

            ControlWidget? possibleControlWidget = null;
            Type? lastControlWidgetType = null;

            do
            {
                var newAttributes = serializedProperty.GetAttributes().ToList();

                int removeCountTotal = 0;
                foreach(var widgetType in skippingWidgetTypes)
                {
                    if(widgetType is null)
                        continue;

                    var customEditorAttributes = widgetType.GetCustomAttributes<CustomEditorAttribute>(false);
                    foreach(var customEditorAttribute in customEditorAttributes)
                    {
                        if(customEditorAttribute.Fits(serializedProperty))
                        {
                            if(customEditorAttribute.WithAllAttributes is null)
                                return null;

                            removeCountTotal += newAttributes.RemoveAll(x => customEditorAttribute.WithAllAttributes.Contains(x.GetType()));
                        }
                    }
                }

                if(removeCountTotal == 0)
                    return null;

                lastControlWidgetType = possibleControlWidget?.GetType();
                possibleControlWidget?.Destroy();
                serializedProperty = startingSerializedProperty.CreateProxy(newAttributes);
                possibleControlWidget = ControlWidget.Create(serializedProperty);

            }
            while(possibleControlWidget is not null &&
                possibleControlWidget.GetType() != lastControlWidgetType &&
                skippingWidgetTypes.Contains(possibleControlWidget.GetType()));

            if(possibleControlWidget is not null)
            {
                var type = possibleControlWidget.GetType();
                possibleControlWidget.Destroy();
                return EditorTypeLibrary.Create<ControlWidget>(type, [startingSerializedProperty]);
            }

            return possibleControlWidget;
        }
    }

    private static bool Fits(this CustomEditorAttribute attribute, SerializedProperty serializedProperty)
    {
        if(attribute.TargetType is not null)
        {
            if(!attribute.TargetType.IsAssignableFrom(serializedProperty.PropertyType))
                return false;
        }

        if(attribute.WithAllAttributes is not null)
        {
            foreach(var requiredAttributeType in attribute.WithAllAttributes)
            {
                if(requiredAttributeType is null)
                    continue;

                if(!serializedProperty.HasAttribute(requiredAttributeType))
                    return false;
            }
        }

        return true;
    }
}