diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 4d2e76b31..e2983d1d1 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -3,7 +3,7 @@ fail_fast: true
repos:
- repo: https://github.com/charliermarsh/ruff-pre-commit
- rev: v0.6.9
+ rev: v0.7.0
hooks:
- id: ruff-format
args: [reflex, tests]
diff --git a/poetry.lock b/poetry.lock
index 2f77234d4..bbd2735ac 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -970,13 +970,13 @@ test = ["pytest (>=7.4)", "pytest-cov (>=4.1)"]
[[package]]
name = "mako"
-version = "1.3.5"
+version = "1.3.6"
description = "A super-fast templating language that borrows the best ideas from the existing templating languages."
optional = false
python-versions = ">=3.8"
files = [
- {file = "Mako-1.3.5-py3-none-any.whl", hash = "sha256:260f1dbc3a519453a9c856dedfe4beb4e50bd5a26d96386cb6c80856556bb91a"},
- {file = "Mako-1.3.5.tar.gz", hash = "sha256:48dbc20568c1d276a2698b36d968fa76161bf127194907ea6fc594fa81f943bc"},
+ {file = "Mako-1.3.6-py3-none-any.whl", hash = "sha256:a91198468092a2f1a0de86ca92690fb0cfc43ca90ee17e15d93662b4c04b241a"},
+ {file = "mako-1.3.6.tar.gz", hash = "sha256:9ec3a1583713479fae654f83ed9fa8c9a4c16b7bb0daba0e6bbebff50c0d983d"},
]
[package.dependencies]
@@ -2272,29 +2272,29 @@ jupyter = ["ipywidgets (>=7.5.1,<9)"]
[[package]]
name = "ruff"
-version = "0.6.9"
+version = "0.7.0"
description = "An extremely fast Python linter and code formatter, written in Rust."
optional = false
python-versions = ">=3.7"
files = [
- {file = "ruff-0.6.9-py3-none-linux_armv6l.whl", hash = "sha256:064df58d84ccc0ac0fcd63bc3090b251d90e2a372558c0f057c3f75ed73e1ccd"},
- {file = "ruff-0.6.9-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:140d4b5c9f5fc7a7b074908a78ab8d384dd7f6510402267bc76c37195c02a7ec"},
- {file = "ruff-0.6.9-py3-none-macosx_11_0_arm64.whl", hash = "sha256:53fd8ca5e82bdee8da7f506d7b03a261f24cd43d090ea9db9a1dc59d9313914c"},
- {file = "ruff-0.6.9-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:645d7d8761f915e48a00d4ecc3686969761df69fb561dd914a773c1a8266e14e"},
- {file = "ruff-0.6.9-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eae02b700763e3847595b9d2891488989cac00214da7f845f4bcf2989007d577"},
- {file = "ruff-0.6.9-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7d5ccc9e58112441de8ad4b29dcb7a86dc25c5f770e3c06a9d57e0e5eba48829"},
- {file = "ruff-0.6.9-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:417b81aa1c9b60b2f8edc463c58363075412866ae4e2b9ab0f690dc1e87ac1b5"},
- {file = "ruff-0.6.9-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3c866b631f5fbce896a74a6e4383407ba7507b815ccc52bcedabb6810fdb3ef7"},
- {file = "ruff-0.6.9-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7b118afbb3202f5911486ad52da86d1d52305b59e7ef2031cea3425142b97d6f"},
- {file = "ruff-0.6.9-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a67267654edc23c97335586774790cde402fb6bbdb3c2314f1fc087dee320bfa"},
- {file = "ruff-0.6.9-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:3ef0cc774b00fec123f635ce5c547dac263f6ee9fb9cc83437c5904183b55ceb"},
- {file = "ruff-0.6.9-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:12edd2af0c60fa61ff31cefb90aef4288ac4d372b4962c2864aeea3a1a2460c0"},
- {file = "ruff-0.6.9-py3-none-musllinux_1_2_i686.whl", hash = "sha256:55bb01caeaf3a60b2b2bba07308a02fca6ab56233302406ed5245180a05c5625"},
- {file = "ruff-0.6.9-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:925d26471fa24b0ce5a6cdfab1bb526fb4159952385f386bdcc643813d472039"},
- {file = "ruff-0.6.9-py3-none-win32.whl", hash = "sha256:eb61ec9bdb2506cffd492e05ac40e5bc6284873aceb605503d8494180d6fc84d"},
- {file = "ruff-0.6.9-py3-none-win_amd64.whl", hash = "sha256:785d31851c1ae91f45b3d8fe23b8ae4b5170089021fbb42402d811135f0b7117"},
- {file = "ruff-0.6.9-py3-none-win_arm64.whl", hash = "sha256:a9641e31476d601f83cd602608739a0840e348bda93fec9f1ee816f8b6798b93"},
- {file = "ruff-0.6.9.tar.gz", hash = "sha256:b076ef717a8e5bc819514ee1d602bbdca5b4420ae13a9cf61a0c0a4f53a2baa2"},
+ {file = "ruff-0.7.0-py3-none-linux_armv6l.whl", hash = "sha256:0cdf20c2b6ff98e37df47b2b0bd3a34aaa155f59a11182c1303cce79be715628"},
+ {file = "ruff-0.7.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:496494d350c7fdeb36ca4ef1c9f21d80d182423718782222c29b3e72b3512737"},
+ {file = "ruff-0.7.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:214b88498684e20b6b2b8852c01d50f0651f3cc6118dfa113b4def9f14faaf06"},
+ {file = "ruff-0.7.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:630fce3fefe9844e91ea5bbf7ceadab4f9981f42b704fae011bb8efcaf5d84be"},
+ {file = "ruff-0.7.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:211d877674e9373d4bb0f1c80f97a0201c61bcd1e9d045b6e9726adc42c156aa"},
+ {file = "ruff-0.7.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:194d6c46c98c73949a106425ed40a576f52291c12bc21399eb8f13a0f7073495"},
+ {file = "ruff-0.7.0-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:82c2579b82b9973a110fab281860403b397c08c403de92de19568f32f7178598"},
+ {file = "ruff-0.7.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9af971fe85dcd5eaed8f585ddbc6bdbe8c217fb8fcf510ea6bca5bdfff56040e"},
+ {file = "ruff-0.7.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b641c7f16939b7d24b7bfc0be4102c56562a18281f84f635604e8a6989948914"},
+ {file = "ruff-0.7.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d71672336e46b34e0c90a790afeac8a31954fd42872c1f6adaea1dff76fd44f9"},
+ {file = "ruff-0.7.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:ab7d98c7eed355166f367597e513a6c82408df4181a937628dbec79abb2a1fe4"},
+ {file = "ruff-0.7.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:1eb54986f770f49edb14f71d33312d79e00e629a57387382200b1ef12d6a4ef9"},
+ {file = "ruff-0.7.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:dc452ba6f2bb9cf8726a84aa877061a2462afe9ae0ea1d411c53d226661c601d"},
+ {file = "ruff-0.7.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:4b406c2dce5be9bad59f2de26139a86017a517e6bcd2688da515481c05a2cb11"},
+ {file = "ruff-0.7.0-py3-none-win32.whl", hash = "sha256:f6c968509f767776f524a8430426539587d5ec5c662f6addb6aa25bc2e8195ec"},
+ {file = "ruff-0.7.0-py3-none-win_amd64.whl", hash = "sha256:ff4aabfbaaba880e85d394603b9e75d32b0693152e16fa659a3064a85df7fce2"},
+ {file = "ruff-0.7.0-py3-none-win_arm64.whl", hash = "sha256:10842f69c245e78d6adec7e1db0a7d9ddc2fff0621d730e61657b64fa36f207e"},
+ {file = "ruff-0.7.0.tar.gz", hash = "sha256:47a86360cf62d9cd53ebfb0b5eb0e882193fc191c6d717e8bef4462bc3b9ea2b"},
]
[[package]]
@@ -3033,4 +3033,4 @@ type = ["pytest-mypy"]
[metadata]
lock-version = "2.0"
python-versions = "^3.9"
-content-hash = "edb7145394dd61f5a665b5519cc0c091c8c1628200ea1170857cff1a6bdb829e"
+content-hash = "8090ccaeca173bd8612e17a0b8d157d7492618e49450abd1c8373e2976349db0"
diff --git a/pyproject.toml b/pyproject.toml
index d4f583189..93f3c5d50 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -68,7 +68,7 @@ darglint = ">=1.8.1,<2.0"
toml = ">=0.10.2,<1.0"
pytest-asyncio = ">=0.24.0"
pytest-cov = ">=4.0.0,<6.0"
-ruff = "^0.6.9"
+ruff = "^0.7.0"
pandas = ">=2.1.1,<3.0"
pillow = ">=10.0.0,<12.0"
plotly = ">=5.13.0,<6.0"
@@ -91,7 +91,7 @@ build-backend = "poetry.core.masonry.api"
[tool.ruff]
target-version = "py39"
lint.select = ["B", "D", "E", "F", "I", "SIM", "W"]
-lint.ignore = ["B008", "D203", "D205", "D213", "D401", "D406", "D407", "E501", "F403", "F405", "F541"]
+lint.ignore = ["B008", "D203", "D205", "D213", "D401", "D406", "D407", "E501", "F403", "F405", "F541", "SIM115"]
lint.pydocstyle.convention = "google"
[tool.ruff.lint.per-file-ignores]
diff --git a/reflex/.templates/web/components/shiki/code.js b/reflex/.templates/web/components/shiki/code.js
new file mode 100644
index 000000000..c655c3a60
--- /dev/null
+++ b/reflex/.templates/web/components/shiki/code.js
@@ -0,0 +1,29 @@
+import { useEffect, useState } from "react"
+import { codeToHtml} from "shiki"
+
+export function Code ({code, theme, language, transformers, ...divProps}) {
+ const [codeResult, setCodeResult] = useState("")
+ useEffect(() => {
+ async function fetchCode() {
+ let final_code;
+
+ if (Array.isArray(code)) {
+ final_code = code[0];
+ } else {
+ final_code = code;
+ }
+ const result = await codeToHtml(final_code, {
+ lang: language,
+ theme,
+ transformers
+ });
+ setCodeResult(result);
+ }
+ fetchCode();
+ }, [code, language, theme, transformers]
+
+ )
+ return (
+
+ )
+}
diff --git a/reflex/components/datadisplay/shiki_code_block.py b/reflex/components/datadisplay/shiki_code_block.py
new file mode 100644
index 000000000..46199a6e4
--- /dev/null
+++ b/reflex/components/datadisplay/shiki_code_block.py
@@ -0,0 +1,813 @@
+"""Shiki syntax hghlighter component."""
+
+from __future__ import annotations
+
+import re
+from collections import defaultdict
+from typing import Any, Literal, Optional, Union
+
+from reflex.base import Base
+from reflex.components.component import Component, ComponentNamespace
+from reflex.components.core.colors import color
+from reflex.components.core.cond import color_mode_cond
+from reflex.components.el.elements.forms import Button
+from reflex.components.lucide.icon import Icon
+from reflex.components.radix.themes.layout.box import Box
+from reflex.event import call_script, set_clipboard
+from reflex.style import Style
+from reflex.utils.exceptions import VarTypeError
+from reflex.utils.imports import ImportVar
+from reflex.vars.base import LiteralVar, Var
+from reflex.vars.function import FunctionStringVar
+from reflex.vars.sequence import StringVar, string_replace_operation
+
+
+def copy_script() -> Any:
+ """Copy script for the code block and modify the child SVG element.
+
+
+ Returns:
+ Any: The result of calling the script.
+ """
+ return call_script(
+ f"""
+// Event listener for the parent click
+document.addEventListener('click', function(event) {{
+ // Find the closest div (parent element)
+ const parent = event.target.closest('div');
+ // If the parent is found
+ if (parent) {{
+ // Find the SVG element within the parent
+ const svgIcon = parent.querySelector('svg');
+ // If the SVG exists, proceed with the script
+ if (svgIcon) {{
+ const originalPath = svgIcon.innerHTML;
+ const checkmarkPath = ''; // Checkmark SVG path
+ function transition(element, scale, opacity) {{
+ element.style.transform = `scale(${{scale}})`;
+ element.style.opacity = opacity;
+ }}
+ // Animate the SVG
+ transition(svgIcon, 0, '0');
+ setTimeout(() => {{
+ svgIcon.innerHTML = checkmarkPath; // Replace content with checkmark
+ svgIcon.setAttribute('viewBox', '0 0 24 24'); // Adjust viewBox if necessary
+ transition(svgIcon, 1, '1');
+ setTimeout(() => {{
+ transition(svgIcon, 0, '0');
+ setTimeout(() => {{
+ svgIcon.innerHTML = originalPath; // Restore original SVG content
+ transition(svgIcon, 1, '1');
+ }}, 125);
+ }}, 600);
+ }}, 125);
+ }} else {{
+ // console.error('SVG element not found within the parent.');
+ }}
+ }} else {{
+ // console.error('Parent element not found.');
+ }}
+}});
+"""
+ )
+
+
+SHIKIJS_TRANSFORMER_FNS = {
+ "transformerNotationDiff",
+ "transformerNotationHighlight",
+ "transformerNotationWordHighlight",
+ "transformerNotationFocus",
+ "transformerNotationErrorLevel",
+ "transformerRenderWhitespace",
+ "transformerMetaHighlight",
+ "transformerMetaWordHighlight",
+ "transformerCompactLineOptions",
+ # TODO: this transformer when included adds a weird behavior which removes other code lines. Need to figure out why.
+ # "transformerRemoveLineBreak",
+ "transformerRemoveNotationEscape",
+}
+LINE_NUMBER_STYLING = {
+ "code": {
+ "counter-reset": "step",
+ "counter-increment": "step 0",
+ "display": "grid",
+ "line-height": "1.7",
+ "font-size": "0.875em",
+ },
+ "code .line::before": {
+ "content": "counter(step)",
+ "counter-increment": "step",
+ "width": "1rem",
+ "margin-right": "1.5rem",
+ "display": "inline-block",
+ "text-align": "right",
+ "color": "rgba(115,138,148,.4)",
+ },
+}
+BOX_PARENT_STYLING = {
+ "pre": {
+ "margin": "0",
+ "padding": "24px",
+ "background": "transparent",
+ "overflow-x": "auto",
+ "border-radius": "6px",
+ },
+}
+
+THEME_MAPPING = {
+ "light": "one-light",
+ "dark": "one-dark-pro",
+ "a11y-dark": "github-dark",
+}
+LANGUAGE_MAPPING = {"bash": "shellscript"}
+LiteralCodeLanguage = Literal[
+ "abap",
+ "actionscript-3",
+ "ada",
+ "angular-html",
+ "angular-ts",
+ "apache",
+ "apex",
+ "apl",
+ "applescript",
+ "ara",
+ "asciidoc",
+ "asm",
+ "astro",
+ "awk",
+ "ballerina",
+ "bat",
+ "beancount",
+ "berry",
+ "bibtex",
+ "bicep",
+ "blade",
+ "c",
+ "cadence",
+ "clarity",
+ "clojure",
+ "cmake",
+ "cobol",
+ "codeowners",
+ "codeql",
+ "coffee",
+ "common-lisp",
+ "coq",
+ "cpp",
+ "crystal",
+ "csharp",
+ "css",
+ "csv",
+ "cue",
+ "cypher",
+ "d",
+ "dart",
+ "dax",
+ "desktop",
+ "diff",
+ "docker",
+ "dotenv",
+ "dream-maker",
+ "edge",
+ "elixir",
+ "elm",
+ "emacs-lisp",
+ "erb",
+ "erlang",
+ "fennel",
+ "fish",
+ "fluent",
+ "fortran-fixed-form",
+ "fortran-free-form",
+ "fsharp",
+ "gdresource",
+ "gdscript",
+ "gdshader",
+ "genie",
+ "gherkin",
+ "git-commit",
+ "git-rebase",
+ "gleam",
+ "glimmer-js",
+ "glimmer-ts",
+ "glsl",
+ "gnuplot",
+ "go",
+ "graphql",
+ "groovy",
+ "hack",
+ "haml",
+ "handlebars",
+ "haskell",
+ "haxe",
+ "hcl",
+ "hjson",
+ "hlsl",
+ "html",
+ "html-derivative",
+ "http",
+ "hxml",
+ "hy",
+ "imba",
+ "ini",
+ "java",
+ "javascript",
+ "jinja",
+ "jison",
+ "json",
+ "json5",
+ "jsonc",
+ "jsonl",
+ "jsonnet",
+ "jssm",
+ "jsx",
+ "julia",
+ "kotlin",
+ "kusto",
+ "latex",
+ "lean",
+ "less",
+ "liquid",
+ "log",
+ "logo",
+ "lua",
+ "luau",
+ "make",
+ "markdown",
+ "marko",
+ "matlab",
+ "mdc",
+ "mdx",
+ "mermaid",
+ "mojo",
+ "move",
+ "narrat",
+ "nextflow",
+ "nginx",
+ "nim",
+ "nix",
+ "nushell",
+ "objective-c",
+ "objective-cpp",
+ "ocaml",
+ "pascal",
+ "perl",
+ "php",
+ "plsql",
+ "po",
+ "postcss",
+ "powerquery",
+ "powershell",
+ "prisma",
+ "prolog",
+ "proto",
+ "pug",
+ "puppet",
+ "purescript",
+ "python",
+ "qml",
+ "qmldir",
+ "qss",
+ "r",
+ "racket",
+ "raku",
+ "razor",
+ "reg",
+ "regexp",
+ "rel",
+ "riscv",
+ "rst",
+ "ruby",
+ "rust",
+ "sas",
+ "sass",
+ "scala",
+ "scheme",
+ "scss",
+ "shaderlab",
+ "shellscript",
+ "shellsession",
+ "smalltalk",
+ "solidity",
+ "soy",
+ "sparql",
+ "splunk",
+ "sql",
+ "ssh-config",
+ "stata",
+ "stylus",
+ "svelte",
+ "swift",
+ "system-verilog",
+ "systemd",
+ "tasl",
+ "tcl",
+ "templ",
+ "terraform",
+ "tex",
+ "toml",
+ "ts-tags",
+ "tsv",
+ "tsx",
+ "turtle",
+ "twig",
+ "typescript",
+ "typespec",
+ "typst",
+ "v",
+ "vala",
+ "vb",
+ "verilog",
+ "vhdl",
+ "viml",
+ "vue",
+ "vue-html",
+ "vyper",
+ "wasm",
+ "wenyan",
+ "wgsl",
+ "wikitext",
+ "wolfram",
+ "xml",
+ "xsl",
+ "yaml",
+ "zenscript",
+ "zig",
+]
+LiteralCodeTheme = Literal[
+ "andromeeda",
+ "aurora-x",
+ "ayu-dark",
+ "catppuccin-frappe",
+ "catppuccin-latte",
+ "catppuccin-macchiato",
+ "catppuccin-mocha",
+ "dark-plus",
+ "dracula",
+ "dracula-soft",
+ "everforest-dark",
+ "everforest-light",
+ "github-dark",
+ "github-dark-default",
+ "github-dark-dimmed",
+ "github-dark-high-contrast",
+ "github-light",
+ "github-light-default",
+ "github-light-high-contrast",
+ "houston",
+ "laserwave",
+ "light-plus",
+ "material-theme",
+ "material-theme-darker",
+ "material-theme-lighter",
+ "material-theme-ocean",
+ "material-theme-palenight",
+ "min-dark",
+ "min-light",
+ "monokai",
+ "night-owl",
+ "nord",
+ "one-dark-pro",
+ "one-light",
+ "plain",
+ "plastic",
+ "poimandres",
+ "red",
+ "rose-pine",
+ "rose-pine-dawn",
+ "rose-pine-moon",
+ "slack-dark",
+ "slack-ochin",
+ "snazzy-light",
+ "solarized-dark",
+ "solarized-light",
+ "synthwave-84",
+ "tokyo-night",
+ "vesper",
+ "vitesse-black",
+ "vitesse-dark",
+ "vitesse-light",
+]
+
+
+class ShikiBaseTransformers(Base):
+ """Base for creating transformers."""
+
+ library: str
+ fns: list[FunctionStringVar]
+ style: Optional[Style]
+
+
+class ShikiJsTransformer(ShikiBaseTransformers):
+ """A Wrapped shikijs transformer."""
+
+ library: str = "@shikijs/transformers"
+ fns: list[FunctionStringVar] = [
+ FunctionStringVar.create(fn) for fn in SHIKIJS_TRANSFORMER_FNS
+ ]
+ style: Optional[Style] = Style(
+ {
+ "code": {"line-height": "1.7", "font-size": "0.875em", "display": "grid"},
+ # Diffs
+ ".diff": {
+ "margin": "0 -24px",
+ "padding": "0 24px",
+ "width": "calc(100% + 48px)",
+ "display": "inline-block",
+ },
+ ".diff.add": {
+ "background-color": "rgba(16, 185, 129, .14)",
+ "position": "relative",
+ },
+ ".diff.remove": {
+ "background-color": "rgba(244, 63, 94, .14)",
+ "opacity": "0.7",
+ "position": "relative",
+ },
+ ".diff.remove:after": {
+ "position": "absolute",
+ "left": "10px",
+ "content": "'-'",
+ "color": "#b34e52",
+ },
+ ".diff.add:after": {
+ "position": "absolute",
+ "left": "10px",
+ "content": "'+'",
+ "color": "#18794e",
+ },
+ # Highlight
+ ".highlighted": {
+ "background-color": "rgba(142, 150, 170, .14)",
+ "margin": "0 -24px",
+ "padding": "0 24px",
+ "width": "calc(100% + 48px)",
+ "display": "inline-block",
+ },
+ ".highlighted.error": {
+ "background-color": "rgba(244, 63, 94, .14)",
+ },
+ ".highlighted.warning": {
+ "background-color": "rgba(234, 179, 8, .14)",
+ },
+ # Highlighted Word
+ ".highlighted-word": {
+ "background-color": color("gray", 2),
+ "border": f"1px solid {color('gray', 5)}",
+ "padding": "1px 3px",
+ "margin": "-1px -3px",
+ "border-radius": "4px",
+ },
+ # Focused Lines
+ ".has-focused .line:not(.focused)": {
+ "opacity": "0.7",
+ "filter": "blur(0.095rem)",
+ "transition": "filter .35s, opacity .35s",
+ },
+ ".has-focused:hover .line:not(.focused)": {
+ "opacity": "1",
+ "filter": "none",
+ },
+ # White Space
+ # ".tab, .space": {
+ # "position": "relative",
+ # },
+ # ".tab::before": {
+ # "content": "'⇥'",
+ # "position": "absolute",
+ # "opacity": "0.3",
+ # },
+ # ".space::before": {
+ # "content": "'·'",
+ # "position": "absolute",
+ # "opacity": "0.3",
+ # },
+ }
+ )
+
+ def __init__(self, **kwargs):
+ """Initialize the transformer.
+
+ Args:
+ kwargs: Kwargs to initialize the props.
+
+ """
+ fns = kwargs.pop("fns", None)
+ style = kwargs.pop("style", None)
+ if fns:
+ kwargs["fns"] = [
+ (
+ FunctionStringVar.create(x)
+ if not isinstance(x, FunctionStringVar)
+ else x
+ )
+ for x in fns
+ ]
+
+ if style:
+ kwargs["style"] = Style(style)
+ super().__init__(**kwargs)
+
+
+class ShikiCodeBlock(Component):
+ """A Code block."""
+
+ library = "/components/shiki/code"
+
+ tag = "Code"
+
+ alias = "ShikiCode"
+
+ lib_dependencies: list[str] = ["shiki"]
+
+ # The language to use.
+ language: Var[LiteralCodeLanguage] = Var.create("python")
+
+ # The theme to use ("light" or "dark").
+ theme: Var[LiteralCodeTheme] = Var.create("one-light")
+
+ # The set of themes to use for different modes.
+ themes: Var[Union[list[dict[str, Any]], dict[str, str]]]
+
+ # The code to display.
+ code: Var[str]
+
+ # The transformers to use for the syntax highlighter.
+ transformers: Var[list[Union[ShikiBaseTransformers, dict[str, Any]]]] = Var.create(
+ []
+ )
+
+ @classmethod
+ def create(
+ cls,
+ *children,
+ **props,
+ ) -> Component:
+ """Create a code block component using [shiki syntax highlighter](https://shiki.matsu.io/).
+
+ Args:
+ *children: The children of the component.
+ **props: The props to pass to the component.
+
+ Returns:
+ The code block component.
+ """
+ # Separate props for the code block and the wrapper
+ code_block_props = {}
+ code_wrapper_props = {}
+
+ class_props = cls.get_props()
+
+ # Distribute props between the code block and wrapper
+ for key, value in props.items():
+ (code_block_props if key in class_props else code_wrapper_props)[key] = (
+ value
+ )
+
+ code_block_props["code"] = children[0]
+ code_block = super().create(**code_block_props)
+
+ transformer_styles = {}
+ # Collect styles from transformers and wrapper
+ for transformer in code_block.transformers._var_value: # type: ignore
+ if isinstance(transformer, ShikiBaseTransformers) and transformer.style:
+ transformer_styles.update(transformer.style)
+ transformer_styles.update(code_wrapper_props.pop("style", {}))
+
+ return Box.create(
+ code_block,
+ *children[1:],
+ style=Style({**transformer_styles, **BOX_PARENT_STYLING}),
+ **code_wrapper_props,
+ )
+
+ def add_imports(self) -> dict[str, list[str]]:
+ """Add the necessary imports.
+ We add all referenced transformer functions as imports from their corresponding
+ libraries.
+
+ Returns:
+ Imports for the component.
+ """
+ imports = defaultdict(list)
+ for transformer in self.transformers._var_value:
+ if isinstance(transformer, ShikiBaseTransformers):
+ imports[transformer.library].extend(
+ [ImportVar(tag=str(fn)) for fn in transformer.fns]
+ )
+ (
+ self.lib_dependencies.append(transformer.library)
+ if transformer.library not in self.lib_dependencies
+ else None
+ )
+ return imports
+
+ @classmethod
+ def create_transformer(cls, library: str, fns: list[str]) -> ShikiBaseTransformers:
+ """Create a transformer from a third party library.
+
+ Args:
+ library: The name of the library.
+ fns: The str names of the functions/callables to invoke from the library.
+
+ Returns:
+ A transformer for the specified library.
+
+ Raises:
+ ValueError: If a supplied function name is not valid str.
+ """
+ if any(not isinstance(fn_name, str) for fn_name in fns):
+ raise ValueError(
+ f"the function names should be str names of functions in the specified transformer: {library!r}"
+ )
+ return ShikiBaseTransformers( # type: ignore
+ library=library, fns=[FunctionStringVar.create(fn) for fn in fns]
+ )
+
+ def _render(self, props: dict[str, Any] | None = None):
+ """Renders the component with the given properties, processing transformers if present.
+
+ Args:
+ props: Optional properties to pass to the render function.
+
+ Returns:
+ Rendered component output.
+ """
+ # Ensure props is initialized from class attributes if not provided
+ props = props or {
+ attr.rstrip("_"): getattr(self, attr) for attr in self.get_props()
+ }
+
+ # Extract transformers and apply transformations
+ transformers = props.get("transformers")
+ if transformers is not None:
+ transformed_values = self._process_transformers(transformers._var_value)
+ props["transformers"] = LiteralVar.create(transformed_values)
+
+ return super()._render(props)
+
+ def _process_transformers(self, transformer_list: list) -> list:
+ """Processes a list of transformers, applying transformations where necessary.
+
+ Args:
+ transformer_list: List of transformer objects or values.
+
+ Returns:
+ list: A list of transformed values.
+ """
+ processed = []
+
+ for transformer in transformer_list:
+ if isinstance(transformer, ShikiBaseTransformers):
+ processed.extend(fn.call() for fn in transformer.fns)
+ else:
+ processed.append(transformer)
+
+ return processed
+
+
+class ShikiHighLevelCodeBlock(ShikiCodeBlock):
+ """High level component for the shiki syntax highlighter."""
+
+ # If this is enabled, the default transformers(shikijs transformer) will be used.
+ use_transformers: Var[bool]
+
+ # If this is enabled line numbers will be shown next to the code block.
+ show_line_numbers: Var[bool]
+
+ # Whether a copy button should appear.
+ can_copy: Var[bool] = Var.create(False)
+
+ # copy_button: A custom copy button to override the default one.
+ copy_button: Var[Optional[Union[Component, bool]]] = Var.create(None)
+
+ @classmethod
+ def create(
+ cls,
+ *children,
+ **props,
+ ) -> Component:
+ """Create a code block component using [shiki syntax highlighter](https://shiki.matsu.io/).
+
+ Args:
+ *children: The children of the component.
+ **props: The props to pass to the component.
+
+ Returns:
+ The code block component.
+ """
+ use_transformers = props.pop("use_transformers", False)
+ show_line_numbers = props.pop("show_line_numbers", False)
+ language = props.pop("language", None)
+ can_copy = props.pop("can_copy", False)
+ copy_button = props.pop("copy_button", None)
+
+ if use_transformers:
+ props["transformers"] = [ShikiJsTransformer()]
+
+ if language is not None:
+ props["language"] = cls._map_languages(language)
+
+ # line numbers are generated via css
+ if show_line_numbers:
+ props["style"] = {**LINE_NUMBER_STYLING, **props.get("style", {})}
+
+ theme = props.pop("theme", None)
+ props["theme"] = props["theme"] = (
+ cls._map_themes(theme)
+ if theme is not None
+ else color_mode_cond( # Default color scheme responds to global color mode.
+ light="one-light",
+ dark="one-dark-pro",
+ )
+ )
+
+ if can_copy:
+ code = children[0]
+ copy_button = ( # type: ignore
+ copy_button
+ if copy_button is not None
+ else Button.create(
+ Icon.create(tag="copy", size=16, color=color("gray", 11)),
+ on_click=[
+ set_clipboard(cls._strip_transformer_triggers(code)), # type: ignore
+ copy_script(),
+ ],
+ style=Style(
+ {
+ "position": "absolute",
+ "top": "4px",
+ "right": "4px",
+ "background": color("gray", 3),
+ "border": "1px solid",
+ "border-color": color("gray", 5),
+ "border-radius": "6px",
+ "padding": "5px",
+ "opacity": "1",
+ "cursor": "pointer",
+ "_hover": {
+ "background": color("gray", 4),
+ },
+ "transition": "background 0.250s ease-out",
+ "&>svg": {
+ "transition": "transform 0.250s ease-out, opacity 0.250s ease-out",
+ },
+ "_active": {
+ "background": color("gray", 5),
+ },
+ }
+ ),
+ )
+ )
+
+ if copy_button:
+ return ShikiCodeBlock.create(
+ children[0], copy_button, position="relative", **props
+ )
+ else:
+ return ShikiCodeBlock.create(children[0], **props)
+
+ @staticmethod
+ def _map_themes(theme: str) -> str:
+ if isinstance(theme, str) and theme in THEME_MAPPING:
+ return THEME_MAPPING[theme]
+ return theme
+
+ @staticmethod
+ def _map_languages(language: str) -> str:
+ if isinstance(language, str) and language in LANGUAGE_MAPPING:
+ return LANGUAGE_MAPPING[language]
+ return language
+
+ @staticmethod
+ def _strip_transformer_triggers(code: str | StringVar) -> StringVar | str:
+ if not isinstance(code, (StringVar, str)):
+ raise VarTypeError(
+ f"code should be string literal or a StringVar type. Got {type(code)} instead."
+ )
+ regex_pattern = r"[\/#]+ *\[!code.*?\]"
+
+ if isinstance(code, Var):
+ return string_replace_operation(
+ code, StringVar(_js_expr=f"/{regex_pattern}/g", _var_type=str), ""
+ )
+ if isinstance(code, str):
+ return re.sub(regex_pattern, "", code)
+
+
+class TransformerNamespace(ComponentNamespace):
+ """Namespace for the Transformers."""
+
+ shikijs = ShikiJsTransformer
+
+
+class CodeblockNamespace(ComponentNamespace):
+ """Namespace for the CodeBlock component."""
+
+ root = staticmethod(ShikiCodeBlock.create)
+ create_transformer = staticmethod(ShikiCodeBlock.create_transformer)
+ transformers = TransformerNamespace()
+ __call__ = staticmethod(ShikiHighLevelCodeBlock.create)
+
+
+code_block = CodeblockNamespace()
diff --git a/reflex/components/datadisplay/shiki_code_block.pyi b/reflex/components/datadisplay/shiki_code_block.pyi
new file mode 100644
index 000000000..bcf2719e9
--- /dev/null
+++ b/reflex/components/datadisplay/shiki_code_block.pyi
@@ -0,0 +1,2211 @@
+"""Stub file for reflex/components/datadisplay/shiki_code_block.py"""
+
+# ------------------- DO NOT EDIT ----------------------
+# This file was generated by `reflex/utils/pyi_generator.py`!
+# ------------------------------------------------------
+from typing import Any, Dict, Literal, Optional, Union, overload
+
+from reflex.base import Base
+from reflex.components.component import Component, ComponentNamespace
+from reflex.event import EventType
+from reflex.style import Style
+from reflex.vars.base import Var
+from reflex.vars.function import FunctionStringVar
+
+def copy_script() -> Any: ...
+
+SHIKIJS_TRANSFORMER_FNS = {
+ "transformerNotationDiff",
+ "transformerNotationHighlight",
+ "transformerNotationWordHighlight",
+ "transformerNotationFocus",
+ "transformerNotationErrorLevel",
+ "transformerRenderWhitespace",
+ "transformerMetaHighlight",
+ "transformerMetaWordHighlight",
+ "transformerCompactLineOptions",
+ "transformerRemoveNotationEscape",
+}
+LINE_NUMBER_STYLING = {
+ "code": {
+ "counter-reset": "step",
+ "counter-increment": "step 0",
+ "display": "grid",
+ "line-height": "1.7",
+ "font-size": "0.875em",
+ },
+ "code .line::before": {
+ "content": "counter(step)",
+ "counter-increment": "step",
+ "width": "1rem",
+ "margin-right": "1.5rem",
+ "display": "inline-block",
+ "text-align": "right",
+ "color": "rgba(115,138,148,.4)",
+ },
+}
+BOX_PARENT_STYLING = {
+ "pre": {
+ "margin": "0",
+ "padding": "24px",
+ "background": "transparent",
+ "overflow-x": "auto",
+ "border-radius": "6px",
+ }
+}
+THEME_MAPPING = {
+ "light": "one-light",
+ "dark": "one-dark-pro",
+ "a11y-dark": "github-dark",
+}
+LANGUAGE_MAPPING = {"bash": "shellscript"}
+LiteralCodeLanguage = Literal[
+ "abap",
+ "actionscript-3",
+ "ada",
+ "angular-html",
+ "angular-ts",
+ "apache",
+ "apex",
+ "apl",
+ "applescript",
+ "ara",
+ "asciidoc",
+ "asm",
+ "astro",
+ "awk",
+ "ballerina",
+ "bat",
+ "beancount",
+ "berry",
+ "bibtex",
+ "bicep",
+ "blade",
+ "c",
+ "cadence",
+ "clarity",
+ "clojure",
+ "cmake",
+ "cobol",
+ "codeowners",
+ "codeql",
+ "coffee",
+ "common-lisp",
+ "coq",
+ "cpp",
+ "crystal",
+ "csharp",
+ "css",
+ "csv",
+ "cue",
+ "cypher",
+ "d",
+ "dart",
+ "dax",
+ "desktop",
+ "diff",
+ "docker",
+ "dotenv",
+ "dream-maker",
+ "edge",
+ "elixir",
+ "elm",
+ "emacs-lisp",
+ "erb",
+ "erlang",
+ "fennel",
+ "fish",
+ "fluent",
+ "fortran-fixed-form",
+ "fortran-free-form",
+ "fsharp",
+ "gdresource",
+ "gdscript",
+ "gdshader",
+ "genie",
+ "gherkin",
+ "git-commit",
+ "git-rebase",
+ "gleam",
+ "glimmer-js",
+ "glimmer-ts",
+ "glsl",
+ "gnuplot",
+ "go",
+ "graphql",
+ "groovy",
+ "hack",
+ "haml",
+ "handlebars",
+ "haskell",
+ "haxe",
+ "hcl",
+ "hjson",
+ "hlsl",
+ "html",
+ "html-derivative",
+ "http",
+ "hxml",
+ "hy",
+ "imba",
+ "ini",
+ "java",
+ "javascript",
+ "jinja",
+ "jison",
+ "json",
+ "json5",
+ "jsonc",
+ "jsonl",
+ "jsonnet",
+ "jssm",
+ "jsx",
+ "julia",
+ "kotlin",
+ "kusto",
+ "latex",
+ "lean",
+ "less",
+ "liquid",
+ "log",
+ "logo",
+ "lua",
+ "luau",
+ "make",
+ "markdown",
+ "marko",
+ "matlab",
+ "mdc",
+ "mdx",
+ "mermaid",
+ "mojo",
+ "move",
+ "narrat",
+ "nextflow",
+ "nginx",
+ "nim",
+ "nix",
+ "nushell",
+ "objective-c",
+ "objective-cpp",
+ "ocaml",
+ "pascal",
+ "perl",
+ "php",
+ "plsql",
+ "po",
+ "postcss",
+ "powerquery",
+ "powershell",
+ "prisma",
+ "prolog",
+ "proto",
+ "pug",
+ "puppet",
+ "purescript",
+ "python",
+ "qml",
+ "qmldir",
+ "qss",
+ "r",
+ "racket",
+ "raku",
+ "razor",
+ "reg",
+ "regexp",
+ "rel",
+ "riscv",
+ "rst",
+ "ruby",
+ "rust",
+ "sas",
+ "sass",
+ "scala",
+ "scheme",
+ "scss",
+ "shaderlab",
+ "shellscript",
+ "shellsession",
+ "smalltalk",
+ "solidity",
+ "soy",
+ "sparql",
+ "splunk",
+ "sql",
+ "ssh-config",
+ "stata",
+ "stylus",
+ "svelte",
+ "swift",
+ "system-verilog",
+ "systemd",
+ "tasl",
+ "tcl",
+ "templ",
+ "terraform",
+ "tex",
+ "toml",
+ "ts-tags",
+ "tsv",
+ "tsx",
+ "turtle",
+ "twig",
+ "typescript",
+ "typespec",
+ "typst",
+ "v",
+ "vala",
+ "vb",
+ "verilog",
+ "vhdl",
+ "viml",
+ "vue",
+ "vue-html",
+ "vyper",
+ "wasm",
+ "wenyan",
+ "wgsl",
+ "wikitext",
+ "wolfram",
+ "xml",
+ "xsl",
+ "yaml",
+ "zenscript",
+ "zig",
+]
+LiteralCodeTheme = Literal[
+ "andromeeda",
+ "aurora-x",
+ "ayu-dark",
+ "catppuccin-frappe",
+ "catppuccin-latte",
+ "catppuccin-macchiato",
+ "catppuccin-mocha",
+ "dark-plus",
+ "dracula",
+ "dracula-soft",
+ "everforest-dark",
+ "everforest-light",
+ "github-dark",
+ "github-dark-default",
+ "github-dark-dimmed",
+ "github-dark-high-contrast",
+ "github-light",
+ "github-light-default",
+ "github-light-high-contrast",
+ "houston",
+ "laserwave",
+ "light-plus",
+ "material-theme",
+ "material-theme-darker",
+ "material-theme-lighter",
+ "material-theme-ocean",
+ "material-theme-palenight",
+ "min-dark",
+ "min-light",
+ "monokai",
+ "night-owl",
+ "nord",
+ "one-dark-pro",
+ "one-light",
+ "plain",
+ "plastic",
+ "poimandres",
+ "red",
+ "rose-pine",
+ "rose-pine-dawn",
+ "rose-pine-moon",
+ "slack-dark",
+ "slack-ochin",
+ "snazzy-light",
+ "solarized-dark",
+ "solarized-light",
+ "synthwave-84",
+ "tokyo-night",
+ "vesper",
+ "vitesse-black",
+ "vitesse-dark",
+ "vitesse-light",
+]
+
+class ShikiBaseTransformers(Base):
+ library: str
+ fns: list[FunctionStringVar]
+ style: Optional[Style]
+
+class ShikiJsTransformer(ShikiBaseTransformers):
+ library: str
+ fns: list[FunctionStringVar]
+ style: Optional[Style]
+
+class ShikiCodeBlock(Component):
+ @overload
+ @classmethod
+ def create( # type: ignore
+ cls,
+ *children,
+ language: Optional[
+ Union[
+ Literal[
+ "abap",
+ "actionscript-3",
+ "ada",
+ "angular-html",
+ "angular-ts",
+ "apache",
+ "apex",
+ "apl",
+ "applescript",
+ "ara",
+ "asciidoc",
+ "asm",
+ "astro",
+ "awk",
+ "ballerina",
+ "bat",
+ "beancount",
+ "berry",
+ "bibtex",
+ "bicep",
+ "blade",
+ "c",
+ "cadence",
+ "clarity",
+ "clojure",
+ "cmake",
+ "cobol",
+ "codeowners",
+ "codeql",
+ "coffee",
+ "common-lisp",
+ "coq",
+ "cpp",
+ "crystal",
+ "csharp",
+ "css",
+ "csv",
+ "cue",
+ "cypher",
+ "d",
+ "dart",
+ "dax",
+ "desktop",
+ "diff",
+ "docker",
+ "dotenv",
+ "dream-maker",
+ "edge",
+ "elixir",
+ "elm",
+ "emacs-lisp",
+ "erb",
+ "erlang",
+ "fennel",
+ "fish",
+ "fluent",
+ "fortran-fixed-form",
+ "fortran-free-form",
+ "fsharp",
+ "gdresource",
+ "gdscript",
+ "gdshader",
+ "genie",
+ "gherkin",
+ "git-commit",
+ "git-rebase",
+ "gleam",
+ "glimmer-js",
+ "glimmer-ts",
+ "glsl",
+ "gnuplot",
+ "go",
+ "graphql",
+ "groovy",
+ "hack",
+ "haml",
+ "handlebars",
+ "haskell",
+ "haxe",
+ "hcl",
+ "hjson",
+ "hlsl",
+ "html",
+ "html-derivative",
+ "http",
+ "hxml",
+ "hy",
+ "imba",
+ "ini",
+ "java",
+ "javascript",
+ "jinja",
+ "jison",
+ "json",
+ "json5",
+ "jsonc",
+ "jsonl",
+ "jsonnet",
+ "jssm",
+ "jsx",
+ "julia",
+ "kotlin",
+ "kusto",
+ "latex",
+ "lean",
+ "less",
+ "liquid",
+ "log",
+ "logo",
+ "lua",
+ "luau",
+ "make",
+ "markdown",
+ "marko",
+ "matlab",
+ "mdc",
+ "mdx",
+ "mermaid",
+ "mojo",
+ "move",
+ "narrat",
+ "nextflow",
+ "nginx",
+ "nim",
+ "nix",
+ "nushell",
+ "objective-c",
+ "objective-cpp",
+ "ocaml",
+ "pascal",
+ "perl",
+ "php",
+ "plsql",
+ "po",
+ "postcss",
+ "powerquery",
+ "powershell",
+ "prisma",
+ "prolog",
+ "proto",
+ "pug",
+ "puppet",
+ "purescript",
+ "python",
+ "qml",
+ "qmldir",
+ "qss",
+ "r",
+ "racket",
+ "raku",
+ "razor",
+ "reg",
+ "regexp",
+ "rel",
+ "riscv",
+ "rst",
+ "ruby",
+ "rust",
+ "sas",
+ "sass",
+ "scala",
+ "scheme",
+ "scss",
+ "shaderlab",
+ "shellscript",
+ "shellsession",
+ "smalltalk",
+ "solidity",
+ "soy",
+ "sparql",
+ "splunk",
+ "sql",
+ "ssh-config",
+ "stata",
+ "stylus",
+ "svelte",
+ "swift",
+ "system-verilog",
+ "systemd",
+ "tasl",
+ "tcl",
+ "templ",
+ "terraform",
+ "tex",
+ "toml",
+ "ts-tags",
+ "tsv",
+ "tsx",
+ "turtle",
+ "twig",
+ "typescript",
+ "typespec",
+ "typst",
+ "v",
+ "vala",
+ "vb",
+ "verilog",
+ "vhdl",
+ "viml",
+ "vue",
+ "vue-html",
+ "vyper",
+ "wasm",
+ "wenyan",
+ "wgsl",
+ "wikitext",
+ "wolfram",
+ "xml",
+ "xsl",
+ "yaml",
+ "zenscript",
+ "zig",
+ ],
+ Var[
+ Literal[
+ "abap",
+ "actionscript-3",
+ "ada",
+ "angular-html",
+ "angular-ts",
+ "apache",
+ "apex",
+ "apl",
+ "applescript",
+ "ara",
+ "asciidoc",
+ "asm",
+ "astro",
+ "awk",
+ "ballerina",
+ "bat",
+ "beancount",
+ "berry",
+ "bibtex",
+ "bicep",
+ "blade",
+ "c",
+ "cadence",
+ "clarity",
+ "clojure",
+ "cmake",
+ "cobol",
+ "codeowners",
+ "codeql",
+ "coffee",
+ "common-lisp",
+ "coq",
+ "cpp",
+ "crystal",
+ "csharp",
+ "css",
+ "csv",
+ "cue",
+ "cypher",
+ "d",
+ "dart",
+ "dax",
+ "desktop",
+ "diff",
+ "docker",
+ "dotenv",
+ "dream-maker",
+ "edge",
+ "elixir",
+ "elm",
+ "emacs-lisp",
+ "erb",
+ "erlang",
+ "fennel",
+ "fish",
+ "fluent",
+ "fortran-fixed-form",
+ "fortran-free-form",
+ "fsharp",
+ "gdresource",
+ "gdscript",
+ "gdshader",
+ "genie",
+ "gherkin",
+ "git-commit",
+ "git-rebase",
+ "gleam",
+ "glimmer-js",
+ "glimmer-ts",
+ "glsl",
+ "gnuplot",
+ "go",
+ "graphql",
+ "groovy",
+ "hack",
+ "haml",
+ "handlebars",
+ "haskell",
+ "haxe",
+ "hcl",
+ "hjson",
+ "hlsl",
+ "html",
+ "html-derivative",
+ "http",
+ "hxml",
+ "hy",
+ "imba",
+ "ini",
+ "java",
+ "javascript",
+ "jinja",
+ "jison",
+ "json",
+ "json5",
+ "jsonc",
+ "jsonl",
+ "jsonnet",
+ "jssm",
+ "jsx",
+ "julia",
+ "kotlin",
+ "kusto",
+ "latex",
+ "lean",
+ "less",
+ "liquid",
+ "log",
+ "logo",
+ "lua",
+ "luau",
+ "make",
+ "markdown",
+ "marko",
+ "matlab",
+ "mdc",
+ "mdx",
+ "mermaid",
+ "mojo",
+ "move",
+ "narrat",
+ "nextflow",
+ "nginx",
+ "nim",
+ "nix",
+ "nushell",
+ "objective-c",
+ "objective-cpp",
+ "ocaml",
+ "pascal",
+ "perl",
+ "php",
+ "plsql",
+ "po",
+ "postcss",
+ "powerquery",
+ "powershell",
+ "prisma",
+ "prolog",
+ "proto",
+ "pug",
+ "puppet",
+ "purescript",
+ "python",
+ "qml",
+ "qmldir",
+ "qss",
+ "r",
+ "racket",
+ "raku",
+ "razor",
+ "reg",
+ "regexp",
+ "rel",
+ "riscv",
+ "rst",
+ "ruby",
+ "rust",
+ "sas",
+ "sass",
+ "scala",
+ "scheme",
+ "scss",
+ "shaderlab",
+ "shellscript",
+ "shellsession",
+ "smalltalk",
+ "solidity",
+ "soy",
+ "sparql",
+ "splunk",
+ "sql",
+ "ssh-config",
+ "stata",
+ "stylus",
+ "svelte",
+ "swift",
+ "system-verilog",
+ "systemd",
+ "tasl",
+ "tcl",
+ "templ",
+ "terraform",
+ "tex",
+ "toml",
+ "ts-tags",
+ "tsv",
+ "tsx",
+ "turtle",
+ "twig",
+ "typescript",
+ "typespec",
+ "typst",
+ "v",
+ "vala",
+ "vb",
+ "verilog",
+ "vhdl",
+ "viml",
+ "vue",
+ "vue-html",
+ "vyper",
+ "wasm",
+ "wenyan",
+ "wgsl",
+ "wikitext",
+ "wolfram",
+ "xml",
+ "xsl",
+ "yaml",
+ "zenscript",
+ "zig",
+ ]
+ ],
+ ]
+ ] = None,
+ theme: Optional[
+ Union[
+ Literal[
+ "andromeeda",
+ "aurora-x",
+ "ayu-dark",
+ "catppuccin-frappe",
+ "catppuccin-latte",
+ "catppuccin-macchiato",
+ "catppuccin-mocha",
+ "dark-plus",
+ "dracula",
+ "dracula-soft",
+ "everforest-dark",
+ "everforest-light",
+ "github-dark",
+ "github-dark-default",
+ "github-dark-dimmed",
+ "github-dark-high-contrast",
+ "github-light",
+ "github-light-default",
+ "github-light-high-contrast",
+ "houston",
+ "laserwave",
+ "light-plus",
+ "material-theme",
+ "material-theme-darker",
+ "material-theme-lighter",
+ "material-theme-ocean",
+ "material-theme-palenight",
+ "min-dark",
+ "min-light",
+ "monokai",
+ "night-owl",
+ "nord",
+ "one-dark-pro",
+ "one-light",
+ "plain",
+ "plastic",
+ "poimandres",
+ "red",
+ "rose-pine",
+ "rose-pine-dawn",
+ "rose-pine-moon",
+ "slack-dark",
+ "slack-ochin",
+ "snazzy-light",
+ "solarized-dark",
+ "solarized-light",
+ "synthwave-84",
+ "tokyo-night",
+ "vesper",
+ "vitesse-black",
+ "vitesse-dark",
+ "vitesse-light",
+ ],
+ Var[
+ Literal[
+ "andromeeda",
+ "aurora-x",
+ "ayu-dark",
+ "catppuccin-frappe",
+ "catppuccin-latte",
+ "catppuccin-macchiato",
+ "catppuccin-mocha",
+ "dark-plus",
+ "dracula",
+ "dracula-soft",
+ "everforest-dark",
+ "everforest-light",
+ "github-dark",
+ "github-dark-default",
+ "github-dark-dimmed",
+ "github-dark-high-contrast",
+ "github-light",
+ "github-light-default",
+ "github-light-high-contrast",
+ "houston",
+ "laserwave",
+ "light-plus",
+ "material-theme",
+ "material-theme-darker",
+ "material-theme-lighter",
+ "material-theme-ocean",
+ "material-theme-palenight",
+ "min-dark",
+ "min-light",
+ "monokai",
+ "night-owl",
+ "nord",
+ "one-dark-pro",
+ "one-light",
+ "plain",
+ "plastic",
+ "poimandres",
+ "red",
+ "rose-pine",
+ "rose-pine-dawn",
+ "rose-pine-moon",
+ "slack-dark",
+ "slack-ochin",
+ "snazzy-light",
+ "solarized-dark",
+ "solarized-light",
+ "synthwave-84",
+ "tokyo-night",
+ "vesper",
+ "vitesse-black",
+ "vitesse-dark",
+ "vitesse-light",
+ ]
+ ],
+ ]
+ ] = None,
+ themes: Optional[
+ Union[
+ Var[Union[dict[str, str], list[dict[str, Any]]]],
+ dict[str, str],
+ list[dict[str, Any]],
+ ]
+ ] = None,
+ code: Optional[Union[Var[str], str]] = None,
+ transformers: Optional[
+ Union[
+ Var[list[Union[ShikiBaseTransformers, dict[str, Any]]]],
+ list[Union[ShikiBaseTransformers, dict[str, Any]]],
+ ]
+ ] = None,
+ style: Optional[Style] = None,
+ key: Optional[Any] = None,
+ id: Optional[Any] = None,
+ class_name: Optional[Any] = None,
+ autofocus: Optional[bool] = None,
+ custom_attrs: Optional[Dict[str, Union[Var, str]]] = None,
+ on_blur: Optional[EventType[[]]] = None,
+ on_click: Optional[EventType[[]]] = None,
+ on_context_menu: Optional[EventType[[]]] = None,
+ on_double_click: Optional[EventType[[]]] = None,
+ on_focus: Optional[EventType[[]]] = None,
+ on_mount: Optional[EventType[[]]] = None,
+ on_mouse_down: Optional[EventType[[]]] = None,
+ on_mouse_enter: Optional[EventType[[]]] = None,
+ on_mouse_leave: Optional[EventType[[]]] = None,
+ on_mouse_move: Optional[EventType[[]]] = None,
+ on_mouse_out: Optional[EventType[[]]] = None,
+ on_mouse_over: Optional[EventType[[]]] = None,
+ on_mouse_up: Optional[EventType[[]]] = None,
+ on_scroll: Optional[EventType[[]]] = None,
+ on_unmount: Optional[EventType[[]]] = None,
+ **props,
+ ) -> "ShikiCodeBlock":
+ """Create a code block component using [shiki syntax highlighter](https://shiki.matsu.io/).
+
+ Args:
+ *children: The children of the component.
+ language: The language to use.
+ theme: The theme to use ("light" or "dark").
+ themes: The set of themes to use for different modes.
+ code: The code to display.
+ transformers: The transformers to use for the syntax highlighter.
+ style: The style of the component.
+ key: A unique key for the component.
+ id: The id for the component.
+ class_name: The class name for the component.
+ autofocus: Whether the component should take the focus once the page is loaded
+ custom_attrs: custom attribute
+ **props: The props to pass to the component.
+
+ Returns:
+ The code block component.
+ """
+ ...
+
+ def add_imports(self) -> dict[str, list[str]]: ...
+ @classmethod
+ def create_transformer(
+ cls, library: str, fns: list[str]
+ ) -> ShikiBaseTransformers: ...
+
+class ShikiHighLevelCodeBlock(ShikiCodeBlock):
+ @overload
+ @classmethod
+ def create( # type: ignore
+ cls,
+ *children,
+ use_transformers: Optional[Union[Var[bool], bool]] = None,
+ show_line_numbers: Optional[Union[Var[bool], bool]] = None,
+ can_copy: Optional[Union[Var[bool], bool]] = None,
+ copy_button: Optional[
+ Union[Component, Var[Optional[Union[Component, bool]]], bool]
+ ] = None,
+ language: Optional[
+ Union[
+ Literal[
+ "abap",
+ "actionscript-3",
+ "ada",
+ "angular-html",
+ "angular-ts",
+ "apache",
+ "apex",
+ "apl",
+ "applescript",
+ "ara",
+ "asciidoc",
+ "asm",
+ "astro",
+ "awk",
+ "ballerina",
+ "bat",
+ "beancount",
+ "berry",
+ "bibtex",
+ "bicep",
+ "blade",
+ "c",
+ "cadence",
+ "clarity",
+ "clojure",
+ "cmake",
+ "cobol",
+ "codeowners",
+ "codeql",
+ "coffee",
+ "common-lisp",
+ "coq",
+ "cpp",
+ "crystal",
+ "csharp",
+ "css",
+ "csv",
+ "cue",
+ "cypher",
+ "d",
+ "dart",
+ "dax",
+ "desktop",
+ "diff",
+ "docker",
+ "dotenv",
+ "dream-maker",
+ "edge",
+ "elixir",
+ "elm",
+ "emacs-lisp",
+ "erb",
+ "erlang",
+ "fennel",
+ "fish",
+ "fluent",
+ "fortran-fixed-form",
+ "fortran-free-form",
+ "fsharp",
+ "gdresource",
+ "gdscript",
+ "gdshader",
+ "genie",
+ "gherkin",
+ "git-commit",
+ "git-rebase",
+ "gleam",
+ "glimmer-js",
+ "glimmer-ts",
+ "glsl",
+ "gnuplot",
+ "go",
+ "graphql",
+ "groovy",
+ "hack",
+ "haml",
+ "handlebars",
+ "haskell",
+ "haxe",
+ "hcl",
+ "hjson",
+ "hlsl",
+ "html",
+ "html-derivative",
+ "http",
+ "hxml",
+ "hy",
+ "imba",
+ "ini",
+ "java",
+ "javascript",
+ "jinja",
+ "jison",
+ "json",
+ "json5",
+ "jsonc",
+ "jsonl",
+ "jsonnet",
+ "jssm",
+ "jsx",
+ "julia",
+ "kotlin",
+ "kusto",
+ "latex",
+ "lean",
+ "less",
+ "liquid",
+ "log",
+ "logo",
+ "lua",
+ "luau",
+ "make",
+ "markdown",
+ "marko",
+ "matlab",
+ "mdc",
+ "mdx",
+ "mermaid",
+ "mojo",
+ "move",
+ "narrat",
+ "nextflow",
+ "nginx",
+ "nim",
+ "nix",
+ "nushell",
+ "objective-c",
+ "objective-cpp",
+ "ocaml",
+ "pascal",
+ "perl",
+ "php",
+ "plsql",
+ "po",
+ "postcss",
+ "powerquery",
+ "powershell",
+ "prisma",
+ "prolog",
+ "proto",
+ "pug",
+ "puppet",
+ "purescript",
+ "python",
+ "qml",
+ "qmldir",
+ "qss",
+ "r",
+ "racket",
+ "raku",
+ "razor",
+ "reg",
+ "regexp",
+ "rel",
+ "riscv",
+ "rst",
+ "ruby",
+ "rust",
+ "sas",
+ "sass",
+ "scala",
+ "scheme",
+ "scss",
+ "shaderlab",
+ "shellscript",
+ "shellsession",
+ "smalltalk",
+ "solidity",
+ "soy",
+ "sparql",
+ "splunk",
+ "sql",
+ "ssh-config",
+ "stata",
+ "stylus",
+ "svelte",
+ "swift",
+ "system-verilog",
+ "systemd",
+ "tasl",
+ "tcl",
+ "templ",
+ "terraform",
+ "tex",
+ "toml",
+ "ts-tags",
+ "tsv",
+ "tsx",
+ "turtle",
+ "twig",
+ "typescript",
+ "typespec",
+ "typst",
+ "v",
+ "vala",
+ "vb",
+ "verilog",
+ "vhdl",
+ "viml",
+ "vue",
+ "vue-html",
+ "vyper",
+ "wasm",
+ "wenyan",
+ "wgsl",
+ "wikitext",
+ "wolfram",
+ "xml",
+ "xsl",
+ "yaml",
+ "zenscript",
+ "zig",
+ ],
+ Var[
+ Literal[
+ "abap",
+ "actionscript-3",
+ "ada",
+ "angular-html",
+ "angular-ts",
+ "apache",
+ "apex",
+ "apl",
+ "applescript",
+ "ara",
+ "asciidoc",
+ "asm",
+ "astro",
+ "awk",
+ "ballerina",
+ "bat",
+ "beancount",
+ "berry",
+ "bibtex",
+ "bicep",
+ "blade",
+ "c",
+ "cadence",
+ "clarity",
+ "clojure",
+ "cmake",
+ "cobol",
+ "codeowners",
+ "codeql",
+ "coffee",
+ "common-lisp",
+ "coq",
+ "cpp",
+ "crystal",
+ "csharp",
+ "css",
+ "csv",
+ "cue",
+ "cypher",
+ "d",
+ "dart",
+ "dax",
+ "desktop",
+ "diff",
+ "docker",
+ "dotenv",
+ "dream-maker",
+ "edge",
+ "elixir",
+ "elm",
+ "emacs-lisp",
+ "erb",
+ "erlang",
+ "fennel",
+ "fish",
+ "fluent",
+ "fortran-fixed-form",
+ "fortran-free-form",
+ "fsharp",
+ "gdresource",
+ "gdscript",
+ "gdshader",
+ "genie",
+ "gherkin",
+ "git-commit",
+ "git-rebase",
+ "gleam",
+ "glimmer-js",
+ "glimmer-ts",
+ "glsl",
+ "gnuplot",
+ "go",
+ "graphql",
+ "groovy",
+ "hack",
+ "haml",
+ "handlebars",
+ "haskell",
+ "haxe",
+ "hcl",
+ "hjson",
+ "hlsl",
+ "html",
+ "html-derivative",
+ "http",
+ "hxml",
+ "hy",
+ "imba",
+ "ini",
+ "java",
+ "javascript",
+ "jinja",
+ "jison",
+ "json",
+ "json5",
+ "jsonc",
+ "jsonl",
+ "jsonnet",
+ "jssm",
+ "jsx",
+ "julia",
+ "kotlin",
+ "kusto",
+ "latex",
+ "lean",
+ "less",
+ "liquid",
+ "log",
+ "logo",
+ "lua",
+ "luau",
+ "make",
+ "markdown",
+ "marko",
+ "matlab",
+ "mdc",
+ "mdx",
+ "mermaid",
+ "mojo",
+ "move",
+ "narrat",
+ "nextflow",
+ "nginx",
+ "nim",
+ "nix",
+ "nushell",
+ "objective-c",
+ "objective-cpp",
+ "ocaml",
+ "pascal",
+ "perl",
+ "php",
+ "plsql",
+ "po",
+ "postcss",
+ "powerquery",
+ "powershell",
+ "prisma",
+ "prolog",
+ "proto",
+ "pug",
+ "puppet",
+ "purescript",
+ "python",
+ "qml",
+ "qmldir",
+ "qss",
+ "r",
+ "racket",
+ "raku",
+ "razor",
+ "reg",
+ "regexp",
+ "rel",
+ "riscv",
+ "rst",
+ "ruby",
+ "rust",
+ "sas",
+ "sass",
+ "scala",
+ "scheme",
+ "scss",
+ "shaderlab",
+ "shellscript",
+ "shellsession",
+ "smalltalk",
+ "solidity",
+ "soy",
+ "sparql",
+ "splunk",
+ "sql",
+ "ssh-config",
+ "stata",
+ "stylus",
+ "svelte",
+ "swift",
+ "system-verilog",
+ "systemd",
+ "tasl",
+ "tcl",
+ "templ",
+ "terraform",
+ "tex",
+ "toml",
+ "ts-tags",
+ "tsv",
+ "tsx",
+ "turtle",
+ "twig",
+ "typescript",
+ "typespec",
+ "typst",
+ "v",
+ "vala",
+ "vb",
+ "verilog",
+ "vhdl",
+ "viml",
+ "vue",
+ "vue-html",
+ "vyper",
+ "wasm",
+ "wenyan",
+ "wgsl",
+ "wikitext",
+ "wolfram",
+ "xml",
+ "xsl",
+ "yaml",
+ "zenscript",
+ "zig",
+ ]
+ ],
+ ]
+ ] = None,
+ theme: Optional[
+ Union[
+ Literal[
+ "andromeeda",
+ "aurora-x",
+ "ayu-dark",
+ "catppuccin-frappe",
+ "catppuccin-latte",
+ "catppuccin-macchiato",
+ "catppuccin-mocha",
+ "dark-plus",
+ "dracula",
+ "dracula-soft",
+ "everforest-dark",
+ "everforest-light",
+ "github-dark",
+ "github-dark-default",
+ "github-dark-dimmed",
+ "github-dark-high-contrast",
+ "github-light",
+ "github-light-default",
+ "github-light-high-contrast",
+ "houston",
+ "laserwave",
+ "light-plus",
+ "material-theme",
+ "material-theme-darker",
+ "material-theme-lighter",
+ "material-theme-ocean",
+ "material-theme-palenight",
+ "min-dark",
+ "min-light",
+ "monokai",
+ "night-owl",
+ "nord",
+ "one-dark-pro",
+ "one-light",
+ "plain",
+ "plastic",
+ "poimandres",
+ "red",
+ "rose-pine",
+ "rose-pine-dawn",
+ "rose-pine-moon",
+ "slack-dark",
+ "slack-ochin",
+ "snazzy-light",
+ "solarized-dark",
+ "solarized-light",
+ "synthwave-84",
+ "tokyo-night",
+ "vesper",
+ "vitesse-black",
+ "vitesse-dark",
+ "vitesse-light",
+ ],
+ Var[
+ Literal[
+ "andromeeda",
+ "aurora-x",
+ "ayu-dark",
+ "catppuccin-frappe",
+ "catppuccin-latte",
+ "catppuccin-macchiato",
+ "catppuccin-mocha",
+ "dark-plus",
+ "dracula",
+ "dracula-soft",
+ "everforest-dark",
+ "everforest-light",
+ "github-dark",
+ "github-dark-default",
+ "github-dark-dimmed",
+ "github-dark-high-contrast",
+ "github-light",
+ "github-light-default",
+ "github-light-high-contrast",
+ "houston",
+ "laserwave",
+ "light-plus",
+ "material-theme",
+ "material-theme-darker",
+ "material-theme-lighter",
+ "material-theme-ocean",
+ "material-theme-palenight",
+ "min-dark",
+ "min-light",
+ "monokai",
+ "night-owl",
+ "nord",
+ "one-dark-pro",
+ "one-light",
+ "plain",
+ "plastic",
+ "poimandres",
+ "red",
+ "rose-pine",
+ "rose-pine-dawn",
+ "rose-pine-moon",
+ "slack-dark",
+ "slack-ochin",
+ "snazzy-light",
+ "solarized-dark",
+ "solarized-light",
+ "synthwave-84",
+ "tokyo-night",
+ "vesper",
+ "vitesse-black",
+ "vitesse-dark",
+ "vitesse-light",
+ ]
+ ],
+ ]
+ ] = None,
+ themes: Optional[
+ Union[
+ Var[Union[dict[str, str], list[dict[str, Any]]]],
+ dict[str, str],
+ list[dict[str, Any]],
+ ]
+ ] = None,
+ code: Optional[Union[Var[str], str]] = None,
+ transformers: Optional[
+ Union[
+ Var[list[Union[ShikiBaseTransformers, dict[str, Any]]]],
+ list[Union[ShikiBaseTransformers, dict[str, Any]]],
+ ]
+ ] = None,
+ style: Optional[Style] = None,
+ key: Optional[Any] = None,
+ id: Optional[Any] = None,
+ class_name: Optional[Any] = None,
+ autofocus: Optional[bool] = None,
+ custom_attrs: Optional[Dict[str, Union[Var, str]]] = None,
+ on_blur: Optional[EventType[[]]] = None,
+ on_click: Optional[EventType[[]]] = None,
+ on_context_menu: Optional[EventType[[]]] = None,
+ on_double_click: Optional[EventType[[]]] = None,
+ on_focus: Optional[EventType[[]]] = None,
+ on_mount: Optional[EventType[[]]] = None,
+ on_mouse_down: Optional[EventType[[]]] = None,
+ on_mouse_enter: Optional[EventType[[]]] = None,
+ on_mouse_leave: Optional[EventType[[]]] = None,
+ on_mouse_move: Optional[EventType[[]]] = None,
+ on_mouse_out: Optional[EventType[[]]] = None,
+ on_mouse_over: Optional[EventType[[]]] = None,
+ on_mouse_up: Optional[EventType[[]]] = None,
+ on_scroll: Optional[EventType[[]]] = None,
+ on_unmount: Optional[EventType[[]]] = None,
+ **props,
+ ) -> "ShikiHighLevelCodeBlock":
+ """Create a code block component using [shiki syntax highlighter](https://shiki.matsu.io/).
+
+ Args:
+ *children: The children of the component.
+ use_transformers: If this is enabled, the default transformers(shikijs transformer) will be used.
+ show_line_numbers: If this is enabled line numbers will be shown next to the code block.
+ can_copy: Whether a copy button should appear.
+ copy_button: copy_button: A custom copy button to override the default one.
+ language: The language to use.
+ theme: The theme to use ("light" or "dark").
+ themes: The set of themes to use for different modes.
+ code: The code to display.
+ transformers: The transformers to use for the syntax highlighter.
+ style: The style of the component.
+ key: A unique key for the component.
+ id: The id for the component.
+ class_name: The class name for the component.
+ autofocus: Whether the component should take the focus once the page is loaded
+ custom_attrs: custom attribute
+ **props: The props to pass to the component.
+
+ Returns:
+ The code block component.
+ """
+ ...
+
+class TransformerNamespace(ComponentNamespace):
+ shikijs = ShikiJsTransformer
+
+class CodeblockNamespace(ComponentNamespace):
+ root = staticmethod(ShikiCodeBlock.create)
+ create_transformer = staticmethod(ShikiCodeBlock.create_transformer)
+ transformers = TransformerNamespace()
+
+ @staticmethod
+ def __call__(
+ *children,
+ use_transformers: Optional[Union[Var[bool], bool]] = None,
+ show_line_numbers: Optional[Union[Var[bool], bool]] = None,
+ can_copy: Optional[Union[Var[bool], bool]] = None,
+ copy_button: Optional[
+ Union[Component, Var[Optional[Union[Component, bool]]], bool]
+ ] = None,
+ language: Optional[
+ Union[
+ Literal[
+ "abap",
+ "actionscript-3",
+ "ada",
+ "angular-html",
+ "angular-ts",
+ "apache",
+ "apex",
+ "apl",
+ "applescript",
+ "ara",
+ "asciidoc",
+ "asm",
+ "astro",
+ "awk",
+ "ballerina",
+ "bat",
+ "beancount",
+ "berry",
+ "bibtex",
+ "bicep",
+ "blade",
+ "c",
+ "cadence",
+ "clarity",
+ "clojure",
+ "cmake",
+ "cobol",
+ "codeowners",
+ "codeql",
+ "coffee",
+ "common-lisp",
+ "coq",
+ "cpp",
+ "crystal",
+ "csharp",
+ "css",
+ "csv",
+ "cue",
+ "cypher",
+ "d",
+ "dart",
+ "dax",
+ "desktop",
+ "diff",
+ "docker",
+ "dotenv",
+ "dream-maker",
+ "edge",
+ "elixir",
+ "elm",
+ "emacs-lisp",
+ "erb",
+ "erlang",
+ "fennel",
+ "fish",
+ "fluent",
+ "fortran-fixed-form",
+ "fortran-free-form",
+ "fsharp",
+ "gdresource",
+ "gdscript",
+ "gdshader",
+ "genie",
+ "gherkin",
+ "git-commit",
+ "git-rebase",
+ "gleam",
+ "glimmer-js",
+ "glimmer-ts",
+ "glsl",
+ "gnuplot",
+ "go",
+ "graphql",
+ "groovy",
+ "hack",
+ "haml",
+ "handlebars",
+ "haskell",
+ "haxe",
+ "hcl",
+ "hjson",
+ "hlsl",
+ "html",
+ "html-derivative",
+ "http",
+ "hxml",
+ "hy",
+ "imba",
+ "ini",
+ "java",
+ "javascript",
+ "jinja",
+ "jison",
+ "json",
+ "json5",
+ "jsonc",
+ "jsonl",
+ "jsonnet",
+ "jssm",
+ "jsx",
+ "julia",
+ "kotlin",
+ "kusto",
+ "latex",
+ "lean",
+ "less",
+ "liquid",
+ "log",
+ "logo",
+ "lua",
+ "luau",
+ "make",
+ "markdown",
+ "marko",
+ "matlab",
+ "mdc",
+ "mdx",
+ "mermaid",
+ "mojo",
+ "move",
+ "narrat",
+ "nextflow",
+ "nginx",
+ "nim",
+ "nix",
+ "nushell",
+ "objective-c",
+ "objective-cpp",
+ "ocaml",
+ "pascal",
+ "perl",
+ "php",
+ "plsql",
+ "po",
+ "postcss",
+ "powerquery",
+ "powershell",
+ "prisma",
+ "prolog",
+ "proto",
+ "pug",
+ "puppet",
+ "purescript",
+ "python",
+ "qml",
+ "qmldir",
+ "qss",
+ "r",
+ "racket",
+ "raku",
+ "razor",
+ "reg",
+ "regexp",
+ "rel",
+ "riscv",
+ "rst",
+ "ruby",
+ "rust",
+ "sas",
+ "sass",
+ "scala",
+ "scheme",
+ "scss",
+ "shaderlab",
+ "shellscript",
+ "shellsession",
+ "smalltalk",
+ "solidity",
+ "soy",
+ "sparql",
+ "splunk",
+ "sql",
+ "ssh-config",
+ "stata",
+ "stylus",
+ "svelte",
+ "swift",
+ "system-verilog",
+ "systemd",
+ "tasl",
+ "tcl",
+ "templ",
+ "terraform",
+ "tex",
+ "toml",
+ "ts-tags",
+ "tsv",
+ "tsx",
+ "turtle",
+ "twig",
+ "typescript",
+ "typespec",
+ "typst",
+ "v",
+ "vala",
+ "vb",
+ "verilog",
+ "vhdl",
+ "viml",
+ "vue",
+ "vue-html",
+ "vyper",
+ "wasm",
+ "wenyan",
+ "wgsl",
+ "wikitext",
+ "wolfram",
+ "xml",
+ "xsl",
+ "yaml",
+ "zenscript",
+ "zig",
+ ],
+ Var[
+ Literal[
+ "abap",
+ "actionscript-3",
+ "ada",
+ "angular-html",
+ "angular-ts",
+ "apache",
+ "apex",
+ "apl",
+ "applescript",
+ "ara",
+ "asciidoc",
+ "asm",
+ "astro",
+ "awk",
+ "ballerina",
+ "bat",
+ "beancount",
+ "berry",
+ "bibtex",
+ "bicep",
+ "blade",
+ "c",
+ "cadence",
+ "clarity",
+ "clojure",
+ "cmake",
+ "cobol",
+ "codeowners",
+ "codeql",
+ "coffee",
+ "common-lisp",
+ "coq",
+ "cpp",
+ "crystal",
+ "csharp",
+ "css",
+ "csv",
+ "cue",
+ "cypher",
+ "d",
+ "dart",
+ "dax",
+ "desktop",
+ "diff",
+ "docker",
+ "dotenv",
+ "dream-maker",
+ "edge",
+ "elixir",
+ "elm",
+ "emacs-lisp",
+ "erb",
+ "erlang",
+ "fennel",
+ "fish",
+ "fluent",
+ "fortran-fixed-form",
+ "fortran-free-form",
+ "fsharp",
+ "gdresource",
+ "gdscript",
+ "gdshader",
+ "genie",
+ "gherkin",
+ "git-commit",
+ "git-rebase",
+ "gleam",
+ "glimmer-js",
+ "glimmer-ts",
+ "glsl",
+ "gnuplot",
+ "go",
+ "graphql",
+ "groovy",
+ "hack",
+ "haml",
+ "handlebars",
+ "haskell",
+ "haxe",
+ "hcl",
+ "hjson",
+ "hlsl",
+ "html",
+ "html-derivative",
+ "http",
+ "hxml",
+ "hy",
+ "imba",
+ "ini",
+ "java",
+ "javascript",
+ "jinja",
+ "jison",
+ "json",
+ "json5",
+ "jsonc",
+ "jsonl",
+ "jsonnet",
+ "jssm",
+ "jsx",
+ "julia",
+ "kotlin",
+ "kusto",
+ "latex",
+ "lean",
+ "less",
+ "liquid",
+ "log",
+ "logo",
+ "lua",
+ "luau",
+ "make",
+ "markdown",
+ "marko",
+ "matlab",
+ "mdc",
+ "mdx",
+ "mermaid",
+ "mojo",
+ "move",
+ "narrat",
+ "nextflow",
+ "nginx",
+ "nim",
+ "nix",
+ "nushell",
+ "objective-c",
+ "objective-cpp",
+ "ocaml",
+ "pascal",
+ "perl",
+ "php",
+ "plsql",
+ "po",
+ "postcss",
+ "powerquery",
+ "powershell",
+ "prisma",
+ "prolog",
+ "proto",
+ "pug",
+ "puppet",
+ "purescript",
+ "python",
+ "qml",
+ "qmldir",
+ "qss",
+ "r",
+ "racket",
+ "raku",
+ "razor",
+ "reg",
+ "regexp",
+ "rel",
+ "riscv",
+ "rst",
+ "ruby",
+ "rust",
+ "sas",
+ "sass",
+ "scala",
+ "scheme",
+ "scss",
+ "shaderlab",
+ "shellscript",
+ "shellsession",
+ "smalltalk",
+ "solidity",
+ "soy",
+ "sparql",
+ "splunk",
+ "sql",
+ "ssh-config",
+ "stata",
+ "stylus",
+ "svelte",
+ "swift",
+ "system-verilog",
+ "systemd",
+ "tasl",
+ "tcl",
+ "templ",
+ "terraform",
+ "tex",
+ "toml",
+ "ts-tags",
+ "tsv",
+ "tsx",
+ "turtle",
+ "twig",
+ "typescript",
+ "typespec",
+ "typst",
+ "v",
+ "vala",
+ "vb",
+ "verilog",
+ "vhdl",
+ "viml",
+ "vue",
+ "vue-html",
+ "vyper",
+ "wasm",
+ "wenyan",
+ "wgsl",
+ "wikitext",
+ "wolfram",
+ "xml",
+ "xsl",
+ "yaml",
+ "zenscript",
+ "zig",
+ ]
+ ],
+ ]
+ ] = None,
+ theme: Optional[
+ Union[
+ Literal[
+ "andromeeda",
+ "aurora-x",
+ "ayu-dark",
+ "catppuccin-frappe",
+ "catppuccin-latte",
+ "catppuccin-macchiato",
+ "catppuccin-mocha",
+ "dark-plus",
+ "dracula",
+ "dracula-soft",
+ "everforest-dark",
+ "everforest-light",
+ "github-dark",
+ "github-dark-default",
+ "github-dark-dimmed",
+ "github-dark-high-contrast",
+ "github-light",
+ "github-light-default",
+ "github-light-high-contrast",
+ "houston",
+ "laserwave",
+ "light-plus",
+ "material-theme",
+ "material-theme-darker",
+ "material-theme-lighter",
+ "material-theme-ocean",
+ "material-theme-palenight",
+ "min-dark",
+ "min-light",
+ "monokai",
+ "night-owl",
+ "nord",
+ "one-dark-pro",
+ "one-light",
+ "plain",
+ "plastic",
+ "poimandres",
+ "red",
+ "rose-pine",
+ "rose-pine-dawn",
+ "rose-pine-moon",
+ "slack-dark",
+ "slack-ochin",
+ "snazzy-light",
+ "solarized-dark",
+ "solarized-light",
+ "synthwave-84",
+ "tokyo-night",
+ "vesper",
+ "vitesse-black",
+ "vitesse-dark",
+ "vitesse-light",
+ ],
+ Var[
+ Literal[
+ "andromeeda",
+ "aurora-x",
+ "ayu-dark",
+ "catppuccin-frappe",
+ "catppuccin-latte",
+ "catppuccin-macchiato",
+ "catppuccin-mocha",
+ "dark-plus",
+ "dracula",
+ "dracula-soft",
+ "everforest-dark",
+ "everforest-light",
+ "github-dark",
+ "github-dark-default",
+ "github-dark-dimmed",
+ "github-dark-high-contrast",
+ "github-light",
+ "github-light-default",
+ "github-light-high-contrast",
+ "houston",
+ "laserwave",
+ "light-plus",
+ "material-theme",
+ "material-theme-darker",
+ "material-theme-lighter",
+ "material-theme-ocean",
+ "material-theme-palenight",
+ "min-dark",
+ "min-light",
+ "monokai",
+ "night-owl",
+ "nord",
+ "one-dark-pro",
+ "one-light",
+ "plain",
+ "plastic",
+ "poimandres",
+ "red",
+ "rose-pine",
+ "rose-pine-dawn",
+ "rose-pine-moon",
+ "slack-dark",
+ "slack-ochin",
+ "snazzy-light",
+ "solarized-dark",
+ "solarized-light",
+ "synthwave-84",
+ "tokyo-night",
+ "vesper",
+ "vitesse-black",
+ "vitesse-dark",
+ "vitesse-light",
+ ]
+ ],
+ ]
+ ] = None,
+ themes: Optional[
+ Union[
+ Var[Union[dict[str, str], list[dict[str, Any]]]],
+ dict[str, str],
+ list[dict[str, Any]],
+ ]
+ ] = None,
+ code: Optional[Union[Var[str], str]] = None,
+ transformers: Optional[
+ Union[
+ Var[list[Union[ShikiBaseTransformers, dict[str, Any]]]],
+ list[Union[ShikiBaseTransformers, dict[str, Any]]],
+ ]
+ ] = None,
+ style: Optional[Style] = None,
+ key: Optional[Any] = None,
+ id: Optional[Any] = None,
+ class_name: Optional[Any] = None,
+ autofocus: Optional[bool] = None,
+ custom_attrs: Optional[Dict[str, Union[Var, str]]] = None,
+ on_blur: Optional[EventType[[]]] = None,
+ on_click: Optional[EventType[[]]] = None,
+ on_context_menu: Optional[EventType[[]]] = None,
+ on_double_click: Optional[EventType[[]]] = None,
+ on_focus: Optional[EventType[[]]] = None,
+ on_mount: Optional[EventType[[]]] = None,
+ on_mouse_down: Optional[EventType[[]]] = None,
+ on_mouse_enter: Optional[EventType[[]]] = None,
+ on_mouse_leave: Optional[EventType[[]]] = None,
+ on_mouse_move: Optional[EventType[[]]] = None,
+ on_mouse_out: Optional[EventType[[]]] = None,
+ on_mouse_over: Optional[EventType[[]]] = None,
+ on_mouse_up: Optional[EventType[[]]] = None,
+ on_scroll: Optional[EventType[[]]] = None,
+ on_unmount: Optional[EventType[[]]] = None,
+ **props,
+ ) -> "ShikiHighLevelCodeBlock":
+ """Create a code block component using [shiki syntax highlighter](https://shiki.matsu.io/).
+
+ Args:
+ *children: The children of the component.
+ use_transformers: If this is enabled, the default transformers(shikijs transformer) will be used.
+ show_line_numbers: If this is enabled line numbers will be shown next to the code block.
+ can_copy: Whether a copy button should appear.
+ copy_button: copy_button: A custom copy button to override the default one.
+ language: The language to use.
+ theme: The theme to use ("light" or "dark").
+ themes: The set of themes to use for different modes.
+ code: The code to display.
+ transformers: The transformers to use for the syntax highlighter.
+ style: The style of the component.
+ key: A unique key for the component.
+ id: The id for the component.
+ class_name: The class name for the component.
+ autofocus: Whether the component should take the focus once the page is loaded
+ custom_attrs: custom attribute
+ **props: The props to pass to the component.
+
+ Returns:
+ The code block component.
+ """
+ ...
+
+code_block = CodeblockNamespace()
diff --git a/reflex/components/markdown/markdown.py b/reflex/components/markdown/markdown.py
index 1665144fd..b790bf7a1 100644
--- a/reflex/components/markdown/markdown.py
+++ b/reflex/components/markdown/markdown.py
@@ -20,6 +20,8 @@ from reflex.components.tags.tag import Tag
from reflex.utils import types
from reflex.utils.imports import ImportDict, ImportVar
from reflex.vars.base import LiteralVar, Var
+from reflex.vars.function import ARRAY_ISARRAY
+from reflex.vars.number import ternary_operation
# Special vars used in the component map.
_CHILDREN = Var(_js_expr="children", _var_type=str)
@@ -199,7 +201,16 @@ class Markdown(Component):
raise ValueError(f"No markdown component found for tag: {tag}.")
special_props = [_PROPS_IN_TAG]
- children = [_CHILDREN]
+ children = [
+ _CHILDREN
+ if tag != "codeblock"
+ # For codeblock, the mapping for some cases returns an array of elements. Let's join them into a string.
+ else ternary_operation(
+ ARRAY_ISARRAY.call(_CHILDREN), # type: ignore
+ _CHILDREN.to(list).join("\n"),
+ _CHILDREN,
+ ).to(str)
+ ]
# For certain tags, the props from the markdown renderer are not actually valid for the component.
if tag in NO_PROPS_TAGS:
diff --git a/reflex/config.py b/reflex/config.py
index 2e16e2eb0..00f33b653 100644
--- a/reflex/config.py
+++ b/reflex/config.py
@@ -418,6 +418,12 @@ class Config(Base):
# Number of gunicorn workers from user
gunicorn_workers: Optional[int] = None
+ # Number of requests before a worker is restarted
+ gunicorn_max_requests: int = 100
+
+ # Variance limit for max requests; gunicorn only
+ gunicorn_max_requests_jitter: int = 25
+
# Indicate which type of state manager to use
state_manager_mode: constants.StateManagerMode = constants.StateManagerMode.DISK
diff --git a/reflex/experimental/__init__.py b/reflex/experimental/__init__.py
index 0c11deb85..164790fe5 100644
--- a/reflex/experimental/__init__.py
+++ b/reflex/experimental/__init__.py
@@ -2,6 +2,7 @@
from types import SimpleNamespace
+from reflex.components.datadisplay.shiki_code_block import code_block as code_block
from reflex.components.props import PropsBase
from reflex.components.radix.themes.components.progress import progress as progress
from reflex.components.sonner.toast import toast as toast
@@ -67,4 +68,5 @@ _x = ExperimentalNamespace(
layout=layout,
PropsBase=PropsBase,
run_in_thread=run_in_thread,
+ code_block=code_block,
)
diff --git a/reflex/utils/exec.py b/reflex/utils/exec.py
index f5521c91f..bdc9be4ae 100644
--- a/reflex/utils/exec.py
+++ b/reflex/utils/exec.py
@@ -337,8 +337,8 @@ def run_uvicorn_backend_prod(host, port, loglevel):
app_module = get_app_module()
- RUN_BACKEND_PROD = f"gunicorn --worker-class {config.gunicorn_worker_class} --preload --timeout {config.timeout} --log-level critical".split()
- RUN_BACKEND_PROD_WINDOWS = f"uvicorn --timeout-keep-alive {config.timeout}".split()
+ RUN_BACKEND_PROD = f"gunicorn --worker-class {config.gunicorn_worker_class} --max-requests {config.gunicorn_max_requests} --max-requests-jitter {config.gunicorn_max_requests_jitter} --preload --timeout {config.timeout} --log-level critical".split()
+ RUN_BACKEND_PROD_WINDOWS = f"uvicorn --limit-max-requests {config.gunicorn_max_requests} --timeout-keep-alive {config.timeout}".split()
command = (
[
*RUN_BACKEND_PROD_WINDOWS,
diff --git a/reflex/vars/function.py b/reflex/vars/function.py
index a1f7fb7bd..9d734a458 100644
--- a/reflex/vars/function.py
+++ b/reflex/vars/function.py
@@ -180,6 +180,7 @@ class ArgsFunctionOperation(CachedVarOperation, FunctionVar):
JSON_STRINGIFY = FunctionStringVar.create("JSON.stringify")
+ARRAY_ISARRAY = FunctionStringVar.create("Array.isArray")
PROTOTYPE_TO_STRING = FunctionStringVar.create(
"((__to_string) => __to_string.toString())"
)
diff --git a/reflex/vars/sequence.py b/reflex/vars/sequence.py
index 149300028..39139ce3f 100644
--- a/reflex/vars/sequence.py
+++ b/reflex/vars/sequence.py
@@ -529,6 +529,26 @@ def array_join_operation(array: ArrayVar, sep: StringVar[Any] | str = ""):
return var_operation_return(js_expression=f"{array}.join({sep})", var_type=str)
+@var_operation
+def string_replace_operation(
+ string: StringVar, search_value: StringVar | str, new_value: StringVar | str
+):
+ """Replace a string with a value.
+
+ Args:
+ string: The string.
+ search_value: The string to search.
+ new_value: The value to be replaced with.
+
+ Returns:
+ The string replace operation.
+ """
+ return var_operation_return(
+ js_expression=f"{string}.replace({search_value}, {new_value})",
+ var_type=str,
+ )
+
+
# Compile regex for finding reflex var tags.
_decode_var_pattern_re = (
rf"{constants.REFLEX_VAR_OPENING_TAG}(.*?){constants.REFLEX_VAR_CLOSING_TAG}"
diff --git a/tests/units/components/datadisplay/test_shiki_code.py b/tests/units/components/datadisplay/test_shiki_code.py
new file mode 100644
index 000000000..eb473ba06
--- /dev/null
+++ b/tests/units/components/datadisplay/test_shiki_code.py
@@ -0,0 +1,172 @@
+import pytest
+
+from reflex.components.datadisplay.shiki_code_block import (
+ ShikiBaseTransformers,
+ ShikiCodeBlock,
+ ShikiHighLevelCodeBlock,
+ ShikiJsTransformer,
+)
+from reflex.components.el.elements.forms import Button
+from reflex.components.lucide.icon import Icon
+from reflex.components.radix.themes.layout.box import Box
+from reflex.style import Style
+from reflex.vars import Var
+
+
+@pytest.mark.parametrize(
+ "library, fns, expected_output, raises_exception",
+ [
+ ("some_library", ["function_one"], ["function_one"], False),
+ ("some_library", [123], None, True),
+ ("some_library", [], [], False),
+ (
+ "some_library",
+ ["function_one", "function_two"],
+ ["function_one", "function_two"],
+ False,
+ ),
+ ("", ["function_one"], ["function_one"], False),
+ ("some_library", ["function_one", 789], None, True),
+ ("", [], [], False),
+ ],
+)
+def test_create_transformer(library, fns, expected_output, raises_exception):
+ if raises_exception:
+ # Ensure ValueError is raised for invalid cases
+ with pytest.raises(ValueError):
+ ShikiCodeBlock.create_transformer(library, fns)
+ else:
+ transformer = ShikiCodeBlock.create_transformer(library, fns)
+ assert isinstance(transformer, ShikiBaseTransformers)
+ assert transformer.library == library
+
+ # Verify that the functions are correctly wrapped in FunctionStringVar
+ function_names = [str(fn) for fn in transformer.fns]
+ assert function_names == expected_output
+
+
+@pytest.mark.parametrize(
+ "code_block, children, props, expected_first_child, expected_styles",
+ [
+ ("print('Hello')", ["print('Hello')"], {}, "print('Hello')", {}),
+ (
+ "print('Hello')",
+ ["print('Hello')", "More content"],
+ {},
+ "print('Hello')",
+ {},
+ ),
+ (
+ "print('Hello')",
+ ["print('Hello')"],
+ {
+ "transformers": [
+ ShikiBaseTransformers(
+ library="lib", fns=[], style=Style({"color": "red"})
+ )
+ ]
+ },
+ "print('Hello')",
+ {"color": "red"},
+ ),
+ (
+ "print('Hello')",
+ ["print('Hello')"],
+ {
+ "transformers": [
+ ShikiBaseTransformers(
+ library="lib", fns=[], style=Style({"color": "red"})
+ )
+ ],
+ "style": {"background": "blue"},
+ },
+ "print('Hello')",
+ {"color": "red", "background": "blue"},
+ ),
+ ],
+)
+def test_create_shiki_code_block(
+ code_block, children, props, expected_first_child, expected_styles
+):
+ component = ShikiCodeBlock.create(code_block, *children, **props)
+
+ # Test that the created component is a Box
+ assert isinstance(component, Box)
+
+ # Test that the first child is the code
+ code_block_component = component.children[0]
+ assert code_block_component.code._var_value == expected_first_child # type: ignore
+
+ applied_styles = component.style
+ for key, value in expected_styles.items():
+ assert Var.create(applied_styles[key])._var_value == value
+
+
+@pytest.mark.parametrize(
+ "children, props, expected_transformers, expected_button_type",
+ [
+ (["print('Hello')"], {"use_transformers": True}, [ShikiJsTransformer], None),
+ (["print('Hello')"], {"can_copy": True}, None, Button),
+ (
+ ["print('Hello')"],
+ {
+ "can_copy": True,
+ "copy_button": Button.create(Icon.create(tag="a_arrow_down")),
+ },
+ None,
+ Button,
+ ),
+ ],
+)
+def test_create_shiki_high_level_code_block(
+ children, props, expected_transformers, expected_button_type
+):
+ component = ShikiHighLevelCodeBlock.create(*children, **props)
+
+ # Test that the created component is a Box
+ assert isinstance(component, Box)
+
+ # Test that the first child is the code block component
+ code_block_component = component.children[0]
+ assert code_block_component.code._var_value == children[0] # type: ignore
+
+ # Check if the transformer is set correctly if expected
+ if expected_transformers:
+ exp_trans_names = [t.__name__ for t in expected_transformers]
+ for transformer in code_block_component.transformers._var_value: # type: ignore
+ assert type(transformer).__name__ in exp_trans_names
+
+ # Check if the second child is the copy button if can_copy is True
+ if props.get("can_copy", False):
+ if props.get("copy_button"):
+ assert isinstance(component.children[1], expected_button_type)
+ assert component.children[1] == props["copy_button"]
+ else:
+ assert isinstance(component.children[1], expected_button_type)
+ else:
+ assert len(component.children) == 1
+
+
+@pytest.mark.parametrize(
+ "children, props",
+ [
+ (["print('Hello')"], {"theme": "dark"}),
+ (["print('Hello')"], {"language": "javascript"}),
+ ],
+)
+def test_shiki_high_level_code_block_theme_language_mapping(children, props):
+ component = ShikiHighLevelCodeBlock.create(*children, **props)
+
+ # Test that the theme is mapped correctly
+ if "theme" in props:
+ assert component.children[
+ 0
+ ].theme._var_value == ShikiHighLevelCodeBlock._map_themes(props["theme"]) # type: ignore
+
+ # Test that the language is mapped correctly
+ if "language" in props:
+ assert component.children[
+ 0
+ ].language._var_value == ShikiHighLevelCodeBlock._map_languages( # type: ignore
+ props["language"]
+ )