diff --git a/docs/library/data-display/code_block.md b/docs/library/data-display/code_block.md index d7e299aa2d9..b2875611624 100644 --- a/docs/library/data-display/code_block.md +++ b/docs/library/data-display/code_block.md @@ -23,3 +23,28 @@ rx.code_block( show_line_numbers=True, ) ``` + +## Themes + +The `theme` prop must be set to a `Theme` value accessed from the `rx.code_block.themes` namespace; strings are not accepted. By default, the code block uses `one_light` in light mode and `one_dark` in dark mode. + +```python demo +rx.code_block( + """print("Hello, world!")""", + language="python", + theme=rx.code_block.themes.dracula, +) +``` + +To pick a theme that responds to the global color mode, pass `rx.color_mode_cond` with the desired light and dark variants: + +```python demo +rx.code_block( + """print("Hello, world!")""", + language="python", + theme=rx.color_mode_cond( + light=rx.code_block.themes.one_light, + dark=rx.code_block.themes.one_dark, + ), +) +``` diff --git a/packages/reflex-components-code/src/reflex_components_code/code.py b/packages/reflex-components-code/src/reflex_components_code/code.py index eb96cde27d6..a6fec988df6 100644 --- a/packages/reflex-components-code/src/reflex_components_code/code.py +++ b/packages/reflex-components-code/src/reflex_components_code/code.py @@ -387,8 +387,9 @@ class CodeBlock(Component, MarkdownComponentMap): alias = "SyntaxHighlighter" - theme: Var[Theme | str] = field( - default=Theme.one_light, doc='The theme to use ("light" or "dark").' + theme: Var[Theme] = field( + default=Theme.one_light, + doc="The theme to use, accessed via rx.code_block.themes (e.g. rx.code_block.themes.one_dark).", ) language: Var[LiteralCodeLanguage] = field( diff --git a/pyi_hashes.json b/pyi_hashes.json index b0bf954a0a2..ab26afb92c2 100644 --- a/pyi_hashes.json +++ b/pyi_hashes.json @@ -1,5 +1,5 @@ { - "packages/reflex-components-code/src/reflex_components_code/code.pyi": "a879ccd253e901964a7ab7ea7154f904", + "packages/reflex-components-code/src/reflex_components_code/code.pyi": "6ef91a4a4976e66b2761539e16d4f28e", "packages/reflex-components-code/src/reflex_components_code/shiki_code_block.pyi": "d3e0c33fdc34f5c154ac387d550c0d29", "packages/reflex-components-core/src/reflex_components_core/__init__.pyi": "82b29d23f2490161d42fd21021bd39c3", "packages/reflex-components-core/src/reflex_components_core/base/__init__.pyi": "7009187aaaf191814d031e5462c48318", diff --git a/tests/units/components/datadisplay/test_code.py b/tests/units/components/datadisplay/test_code.py index 5b20c0584ea..42b51b773e5 100644 --- a/tests/units/components/datadisplay/test_code.py +++ b/tests/units/components/datadisplay/test_code.py @@ -1,6 +1,8 @@ import pytest from reflex_components_code.code import CodeBlock, Theme +import reflex as rx + @pytest.mark.parametrize( ("theme", "expected"), @@ -10,3 +12,27 @@ def test_code_light_dark_theme(theme, expected): code_block = CodeBlock.create(theme=theme) assert code_block.theme._js_expr == expected # pyright: ignore [reportAttributeAccessIssue] + + +def test_code_block_rejects_string_theme(): + with pytest.raises(TypeError, match=r"CodeBlock\.theme"): + CodeBlock.create("print('Hello')", theme="one_dark") # pyright: ignore[reportArgumentType] + + +def test_code_block_accepts_color_mode_cond_theme(): + theme = rx.color_mode_cond( + light=rx.code_block.themes.one_light, + dark=rx.code_block.themes.one_dark, + ) + code_block = CodeBlock.create("print('Hello')", theme=theme) + + rendered = code_block.render() + style_prop = next((p for p in rendered["props"] if p.startswith("style:")), None) + assert style_prop is not None, "code block did not render a style prop" + assert "resolvedColorMode" in style_prop + assert "oneLight" in style_prop + assert "oneDark" in style_prop + + imports = code_block._get_all_imports() + assert "react-syntax-highlighter/dist/esm/styles/prism/one-light" in imports + assert "react-syntax-highlighter/dist/esm/styles/prism/one-dark" in imports