Skip to content

Typed Style Properties#6554

Open
Aeshus wants to merge 9 commits into
space-wizards:masterfrom
Aeshus:typed-style-properties
Open

Typed Style Properties#6554
Aeshus wants to merge 9 commits into
space-wizards:masterfrom
Aeshus:typed-style-properties

Conversation

@Aeshus
Copy link
Copy Markdown
Contributor

@Aeshus Aeshus commented May 7, 2026

About the PR

Added new StylePropertyKey<T> type to ensure style properties are correctly set to the right type, and a bunch of warnings to help enforce a better style (e.g. don't hard-code strings as StyleProperty inside of Prop)

Why

I've been doing a lot of stylesheet work recently and I've had a few times where I accidentally set a property to an invalid value, and it would just silently fail within TryGetStyleProperty<T>. Now, when writing stylesheet code, it'll give you better auto-completion for the value for a property as well as compile-time errors when you put an invalid value for a type.

Technical details

The Extract typed style properties commit is the only one with substantive changes, the rest are all either style or fixing warnings.

StylePropertyKey<T> is really just a thin wrapper around a string with a phantom type.

It is possible to bypass the type checking using StylePropertyKey<T> by constructing untyped StyleProperty values directly, as older stylesheet code did this and removing support would cause a breaking change. The string-based key compatibility stuff produces warnings but can't provide type checking.

Memory-wise, it shouldn't be an issue as it's just a struct wrapped around a single string that it implicitly transforms between.

Migration

It generally tends to be that most warnings are because a string is used as a key. Instead of hard-coding a string in the Stylesheet, define a StylePropertyKey<T> field in your Control class (or reuse another Control's) and use it. If you already had a string defined, just change the type.

Here's some examples of diffs to resolve some warnings in Content:

warning CS0618: 'MutableSelector.Prop(string, T)' is obsolete: 'Use Prop(StylePropertyKey, T) with a typed style property key.'

            E<LineEdit>()
                .Class(LineEdit.StyleClassLineEditNotEditable)
-                .Prop("font-color", new Color(192, 192, 192)),
+                .Prop(Label.StylePropertyFontColor, new Color(192, 192, 192)),
            E<LineEdit>()
                .Pseudo(LineEdit.StylePseudoClassPlaceholder)
-                .Prop("font-color", Color.Gray),
+                .Prop(Label.StylePropertyFontColor, Color.Gray),
            E<TextEdit>()
                .Pseudo(TextEdit.StylePseudoClassPlaceholder)
-                .Prop("font-color", Color.Gray),
+                .Prop(Label.StylePropertyFontColor, Color.Gray),

warning CS0618: 'Control.TryGetStyleProperty(string, out T)' is obsolete: 'Use TryGetStyleProperty(StylePropertyKey, out T) with a typed style property key.'

-        public const string StylePropertySeparation = "separation";
+        public static readonly StyleProperty<int> StylePropertySeparation = "separation";

        private const int DefaultSeparation = 0;

        private int ActualSeparation
        {
            get
            {
                if (TryGetStyleProperty(StylePropertySeparation, out int separation))
                {
                    return separation;
                }

                return SeparationOverride ?? DefaultSeparation;
            }
        }

Breaking changes

Content (space-wizards/space-station-14) builds successfully without any changes and any new errors. The build will still succeed unless a type error was already present within the style code.

Changelog

Added a new StylePropertyKey<T> class to be used to define style properties in controls. This provides type safety for styling, but can break builds if type errors are present.

Lots of new warnings for directly using strings instead of StylePropertyKey<T> as StyleProperty keys/names.

Aeshus added 4 commits May 7, 2026 14:02
Adds support for typed style properties, so that when used by .Prop or
new StyleProperty(), it verifies that the type of object that you're
passing in (e.g. Color, float, StyleBox) is the one that is going to be
extracted by the control rather than silently failing.

Create warning when using untyped StyleProperties

This should be fine to do?

Fix implicit cast from untyped -> typed

You could do like .Prop("font", 10.5f) and it would be fine as it
doesn't know what "font" matches to, but sees the 10.5f and assumes it
takes a float.

We should thus make this a warning as people should use like a typed
Label.StylePropertyFont instead of putting magic strings into their code
for properties.

Make it warn on using TryGetStyleProperty from untyped string
@Aeshus Aeshus requested review from DrSmugleaf and PJB3005 as code owners May 7, 2026 20:09
@PJB3005 PJB3005 added T: New Feature Type: New feature A: UI Things like game screens, menus, and windows. labels May 7, 2026
Comment thread Robust.Client/UserInterface/Stylesheet.cs
@PJB3005 PJB3005 added the Breaking Change Queue PRs that should be merged when we're bothering to do a major (breaking change) release label May 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A: UI Things like game screens, menus, and windows. Breaking Change Queue PRs that should be merged when we're bothering to do a major (breaking change) release T: New Feature Type: New feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants