From 2862e6d407a11df60ef266e1b2c27a540e2bbae6 Mon Sep 17 00:00:00 2001 From: Khaleel Al-Adhami Date: Wed, 12 Feb 2025 11:52:08 -0800 Subject: [PATCH 1/3] treat hyphen as underscore in keys of styles --- reflex/style.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reflex/style.py b/reflex/style.py index 192835ca3f0..d4aa54177c7 100644 --- a/reflex/style.py +++ b/reflex/style.py @@ -237,7 +237,7 @@ def format_style_key(key: str) -> Tuple[str, ...]: Returns: Tuple of css style names corresponding to the key provided. """ - key = format.to_camel_case(key, allow_hyphens=True) + key = format.to_camel_case(key) return STYLE_PROP_SHORTHAND_MAPPING.get(key, (key,)) From a826281d2aaf930aa5b0c4fddc104192e3820955 Mon Sep 17 00:00:00 2001 From: Khaleel Al-Adhami Date: Wed, 12 Feb 2025 12:42:20 -0800 Subject: [PATCH 2/3] fix tests --- tests/units/components/markdown/test_markdown.py | 2 +- tests/units/components/test_component.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/units/components/markdown/test_markdown.py b/tests/units/components/markdown/test_markdown.py index c6d395eb1d8..15d662ef64b 100644 --- a/tests/units/components/markdown/test_markdown.py +++ b/tests/units/components/markdown/test_markdown.py @@ -157,7 +157,7 @@ def test_create_map_fn_var_subclass(cls, fn_body, fn_args, explicit_return, expe value, **props ) }, - r"""(({node, inline, className, children, ...props}) => { const match = (className || '').match(/language-(?.*)/); let _language = match ? match[1] : ''; ; return inline ? ( {children} ) : ( ); })""", + r"""(({node, inline, className, children, ...props}) => { const match = (className || '').match(/language-(?.*)/); let _language = match ? match[1] : ''; ; return inline ? ( {children} ) : ( ); })""", ), ( "h1", diff --git a/tests/units/components/test_component.py b/tests/units/components/test_component.py index 8cffa6e0eea..36ff17b6ec3 100644 --- a/tests/units/components/test_component.py +++ b/tests/units/components/test_component.py @@ -651,7 +651,7 @@ def test_create_filters_none_props(test_component): # Assert that the style prop is present in the component's props assert str(component.style["color"]) == '"white"' - assert str(component.style["text-align"]) == '"center"' + assert str(component.style["textAlign"]) == '"center"' @pytest.mark.parametrize( From 70bedabddb28669c45708d8bce98f1b80367393d Mon Sep 17 00:00:00 2001 From: Khaleel Al-Adhami Date: Wed, 12 Feb 2025 13:29:45 -0800 Subject: [PATCH 3/3] more nuanced conversions --- reflex/components/tags/tag.py | 2 +- reflex/style.py | 5 ++++- reflex/utils/format.py | 11 +++++------ tests/units/utils/test_format.py | 10 +++++----- 4 files changed, 15 insertions(+), 13 deletions(-) diff --git a/reflex/components/tags/tag.py b/reflex/components/tags/tag.py index 515d9e05f59..7f7a8c74d60 100644 --- a/reflex/components/tags/tag.py +++ b/reflex/components/tags/tag.py @@ -101,7 +101,7 @@ def add_props(self, **kwargs: Optional[Any]) -> Tag: """ self.props.update( { - format.to_camel_case(name, allow_hyphens=True): ( + format.to_camel_case(name, treat_hyphens_as_underscores=False): ( prop if types._isinstance(prop, (EventChain, Mapping)) else LiteralVar.create(prop) diff --git a/reflex/style.py b/reflex/style.py index d4aa54177c7..fbcfb5d3458 100644 --- a/reflex/style.py +++ b/reflex/style.py @@ -191,11 +191,12 @@ def update_out_dict( for key, value in style_dict.items(): keys = ( format_style_key(key) - if not isinstance(value, (dict, ObjectVar)) + if not isinstance(value, (dict, ObjectVar, list)) or ( isinstance(value, Breakpoints) and all(not isinstance(v, dict) for v in value.values()) ) + or (isinstance(value, list) and all(not isinstance(v, dict) for v in value)) or ( isinstance(value, ObjectVar) and not issubclass(get_origin(value._var_type) or value._var_type, dict) @@ -237,6 +238,8 @@ def format_style_key(key: str) -> Tuple[str, ...]: Returns: Tuple of css style names corresponding to the key provided. """ + if key.startswith("--"): + return (key,) key = format.to_camel_case(key) return STYLE_PROP_SHORTHAND_MAPPING.get(key, (key,)) diff --git a/reflex/utils/format.py b/reflex/utils/format.py index 214c845f873..14ef8fb468c 100644 --- a/reflex/utils/format.py +++ b/reflex/utils/format.py @@ -168,7 +168,7 @@ def to_snake_case(text: str) -> str: return re.sub("([a-z0-9])([A-Z])", r"\1_\2", s1).lower().replace("-", "_") -def to_camel_case(text: str, allow_hyphens: bool = False) -> str: +def to_camel_case(text: str, treat_hyphens_as_underscores: bool = True) -> str: """Convert a string to camel case. The first word in the text is converted to lowercase and @@ -176,17 +176,16 @@ def to_camel_case(text: str, allow_hyphens: bool = False) -> str: Args: text: The string to convert. - allow_hyphens: Whether to allow hyphens in the string. + treat_hyphens_as_underscores: Whether to allow hyphens in the string. Returns: The camel case string. """ - char = "_" if allow_hyphens else "-_" - words = re.split(f"[{char}]", text.lstrip(char)) - leading_underscores_or_hyphens = "".join(re.findall(rf"^[{char}]+", text)) + char = "_" if not treat_hyphens_as_underscores else "-_" + words = re.split(f"[{char}]", text) # Capitalize the first letter of each word except the first one converted_word = words[0] + "".join(x.capitalize() for x in words[1:]) - return leading_underscores_or_hyphens + converted_word + return converted_word def to_title_case(text: str, sep: str = "") -> str: diff --git a/tests/units/utils/test_format.py b/tests/units/utils/test_format.py index 89197a03ee1..053d5a3ae21 100644 --- a/tests/units/utils/test_format.py +++ b/tests/units/utils/test_format.py @@ -189,11 +189,11 @@ def test_to_snake_case(input: str, output: str): ("kebab-case", "kebabCase"), ("kebab-case-two", "kebabCaseTwo"), ("snake_kebab-case", "snakeKebabCase"), - ("_hover", "_hover"), - ("-starts-with-hyphen", "-startsWithHyphen"), - ("--starts-with-double-hyphen", "--startsWithDoubleHyphen"), - ("_starts_with_underscore", "_startsWithUnderscore"), - ("__starts_with_double_underscore", "__startsWithDoubleUnderscore"), + ("_hover", "Hover"), + ("-starts-with-hyphen", "StartsWithHyphen"), + ("--starts-with-double-hyphen", "StartsWithDoubleHyphen"), + ("_starts_with_underscore", "StartsWithUnderscore"), + ("__starts_with_double_underscore", "StartsWithDoubleUnderscore"), (":start-with-colon", ":startWithColon"), (":-start-with-colon-dash", ":StartWithColonDash"), ],