Merge remote-tracking branch 'upstream/main' into hybrid-properties
This commit is contained in:
commit
c8527676d4
@ -11,7 +11,7 @@ omit =
|
||||
[report]
|
||||
show_missing = true
|
||||
# TODO bump back to 79
|
||||
fail_under = 60
|
||||
fail_under = 70
|
||||
precision = 2
|
||||
|
||||
# Regexes for lines to exclude from consideration
|
||||
|
2
.github/actions/setup_build_env/action.yml
vendored
2
.github/actions/setup_build_env/action.yml
vendored
@ -18,7 +18,7 @@ inputs:
|
||||
poetry-version:
|
||||
description: 'Poetry version to install'
|
||||
required: false
|
||||
default: '1.3.1'
|
||||
default: '1.8.3'
|
||||
run-poetry-install:
|
||||
description: 'Whether to run poetry install on current dir'
|
||||
required: false
|
||||
|
8
.github/workflows/benchmarks.yml
vendored
8
.github/workflows/benchmarks.yml
vendored
@ -81,17 +81,13 @@ jobs:
|
||||
matrix:
|
||||
# Show OS combos first in GUI
|
||||
os: [ubuntu-latest, windows-latest, macos-12]
|
||||
python-version: ['3.8.18', '3.9.18', '3.10.13', '3.11.5', '3.12.0']
|
||||
python-version: ['3.9.18', '3.10.13', '3.11.5', '3.12.0']
|
||||
exclude:
|
||||
- os: windows-latest
|
||||
python-version: '3.10.13'
|
||||
- os: windows-latest
|
||||
python-version: '3.9.18'
|
||||
- os: windows-latest
|
||||
python-version: '3.8.18'
|
||||
# keep only one python version for MacOS
|
||||
- os: macos-latest
|
||||
python-version: '3.8.18'
|
||||
- os: macos-latest
|
||||
python-version: '3.9.18'
|
||||
- os: macos-latest
|
||||
@ -103,8 +99,6 @@ jobs:
|
||||
python-version: '3.10.11'
|
||||
- os: windows-latest
|
||||
python-version: '3.9.13'
|
||||
- os: windows-latest
|
||||
python-version: '3.8.10'
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
|
40
.github/workflows/check_node_latest.yml
vendored
Normal file
40
.github/workflows/check_node_latest.yml
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
name: integration-node-latest
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
|
||||
env:
|
||||
TELEMETRY_ENABLED: false
|
||||
REFLEX_USE_SYSTEM_NODE: true
|
||||
|
||||
jobs:
|
||||
check_latest_node:
|
||||
runs-on: ubuntu-22.04
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: ['3.12']
|
||||
node-version: ['node']
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ./.github/actions/setup_build_env
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
run-poetry-install: true
|
||||
create-venv-at-path: .venv
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- run: |
|
||||
poetry run uv pip install pyvirtualdisplay pillow
|
||||
poetry run playwright install --with-deps
|
||||
- run: |
|
||||
poetry run pytest tests/test_node_version.py
|
||||
poetry run pytest tests/integration
|
||||
|
||||
|
||||
|
88
.github/workflows/check_outdated_dependencies.yml
vendored
Normal file
88
.github/workflows/check_outdated_dependencies.yml
vendored
Normal file
@ -0,0 +1,88 @@
|
||||
name: check-outdated-dependencies
|
||||
|
||||
on:
|
||||
push: # This will trigger the action when a pull request is opened or updated.
|
||||
branches:
|
||||
- 'release/**' # This will trigger the action when any branch starting with "release/" is created.
|
||||
workflow_dispatch: # Allow manual triggering if needed.
|
||||
|
||||
jobs:
|
||||
backend:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- uses: ./.github/actions/setup_build_env
|
||||
with:
|
||||
python-version: '3.9'
|
||||
run-poetry-install: true
|
||||
create-venv-at-path: .venv
|
||||
|
||||
- name: Check outdated backend dependencies
|
||||
run: |
|
||||
outdated=$(poetry show -oT)
|
||||
echo "Outdated:"
|
||||
echo "$outdated"
|
||||
|
||||
filtered_outdated=$(echo "$outdated" | grep -vE 'pyright|ruff' || true)
|
||||
|
||||
if [ ! -z "$filtered_outdated" ]; then
|
||||
echo "Outdated dependencies found:"
|
||||
echo "$filtered_outdated"
|
||||
exit 1
|
||||
else
|
||||
echo "All dependencies are up to date. (pyright and ruff are ignored)"
|
||||
fi
|
||||
|
||||
|
||||
frontend:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
- uses: ./.github/actions/setup_build_env
|
||||
with:
|
||||
python-version: '3.10.11'
|
||||
run-poetry-install: true
|
||||
create-venv-at-path: .venv
|
||||
- name: Clone Reflex Website Repo
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: reflex-dev/reflex-web
|
||||
ref: main
|
||||
path: reflex-web
|
||||
- name: Install Requirements for reflex-web
|
||||
working-directory: ./reflex-web
|
||||
run: poetry run uv pip install -r requirements.txt
|
||||
- name: Install additional dependencies for DB access
|
||||
run: poetry run uv pip install psycopg2-binary
|
||||
- name: Init Website for reflex-web
|
||||
working-directory: ./reflex-web
|
||||
run: poetry run reflex init
|
||||
- name: Run Website and Check for errors
|
||||
run: |
|
||||
poetry run bash scripts/integration.sh ./reflex-web dev
|
||||
- name: Check outdated frontend dependencies
|
||||
working-directory: ./reflex-web/.web
|
||||
run: |
|
||||
raw_outdated=$(/home/runner/.local/share/reflex/bun/bin/bun outdated)
|
||||
outdated=$(echo "$raw_outdated" | grep -vE '\|\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\|' || true)
|
||||
echo "Outdated:"
|
||||
echo "$outdated"
|
||||
|
||||
# Ignore 3rd party dependencies that are not updated.
|
||||
filtered_outdated=$(echo "$outdated" | grep -vE 'Package|@chakra-ui|lucide-react|@splinetool/runtime|ag-grid-react|framer-motion|react-markdown|remark-math|remark-gfm|rehype-katex|rehype-raw|remark-unwrap-images' || true)
|
||||
no_extra=$(echo "$filtered_outdated" | grep -vE '\|\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-' || true)
|
||||
|
||||
|
||||
if [ ! -z "$no_extra" ]; then
|
||||
echo "Outdated dependencies found:"
|
||||
echo "$filtered_outdated"
|
||||
exit 1
|
||||
else
|
||||
echo "All dependencies are up to date. (3rd party packages are ignored)"
|
||||
fi
|
||||
|
@ -23,8 +23,8 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
state_manager: ['redis', 'memory']
|
||||
python-version: ['3.8.18', '3.11.5', '3.12.0']
|
||||
runs-on: ubuntu-latest
|
||||
python-version: ['3.11.5', '3.12.0']
|
||||
runs-on: ubuntu-22.04
|
||||
services:
|
||||
# Label used to access the service container
|
||||
redis:
|
||||
@ -51,7 +51,8 @@ jobs:
|
||||
SCREENSHOT_DIR: /tmp/screenshots
|
||||
REDIS_URL: ${{ matrix.state_manager == 'redis' && 'redis://localhost:6379' || '' }}
|
||||
run: |
|
||||
poetry run pytest integration
|
||||
poetry run playwright install --with-deps
|
||||
poetry run pytest tests/integration
|
||||
- uses: actions/upload-artifact@v4
|
||||
name: Upload failed test screenshots
|
||||
if: always()
|
||||
|
53
.github/workflows/integration_tests.yml
vendored
53
.github/workflows/integration_tests.yml
vendored
@ -42,22 +42,18 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
# Show OS combos first in GUI
|
||||
os: [ubuntu-latest, windows-latest, macos-12]
|
||||
python-version: ['3.8.18', '3.9.18', '3.10.13', '3.11.5', '3.12.0']
|
||||
os: [ubuntu-latest, windows-latest]
|
||||
python-version: ['3.9.18', '3.10.13', '3.11.5', '3.12.0']
|
||||
exclude:
|
||||
- os: windows-latest
|
||||
python-version: '3.10.13'
|
||||
- os: windows-latest
|
||||
python-version: '3.9.18'
|
||||
- os: windows-latest
|
||||
python-version: '3.8.18'
|
||||
include:
|
||||
- os: windows-latest
|
||||
python-version: '3.10.11'
|
||||
- os: windows-latest
|
||||
python-version: '3.9.13'
|
||||
- os: windows-latest
|
||||
python-version: '3.8.10'
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
@ -126,7 +122,7 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
# Show OS combos first in GUI
|
||||
os: [ubuntu-latest, windows-latest, macos-12]
|
||||
os: [ubuntu-latest]
|
||||
python-version: ['3.10.11', '3.11.4']
|
||||
|
||||
env:
|
||||
@ -165,4 +161,45 @@ jobs:
|
||||
poetry run python benchmarks/benchmark_web_size.py --os "${{ matrix.os }}"
|
||||
--python-version "${{ matrix.python-version }}" --commit-sha "${{ github.sha }}"
|
||||
--pr-id "${{ github.event.pull_request.id }}" --branch-name "${{ github.head_ref || github.ref_name }}"
|
||||
--app-name "reflex-web" --path ./reflex-web/.web
|
||||
--app-name "reflex-web" --path ./reflex-web/.web
|
||||
|
||||
reflex-web-macos:
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
python-version: ['3.11.5', '3.12.0']
|
||||
runs-on: macos-12
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ./.github/actions/setup_build_env
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
run-poetry-install: true
|
||||
create-venv-at-path: .venv
|
||||
- name: Clone Reflex Website Repo
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: reflex-dev/reflex-web
|
||||
ref: main
|
||||
path: reflex-web
|
||||
- name: Install Requirements for reflex-web
|
||||
working-directory: ./reflex-web
|
||||
run: poetry run uv pip install -r requirements.txt
|
||||
- name: Install additional dependencies for DB access
|
||||
run: poetry run uv pip install psycopg2-binary
|
||||
- name: Init Website for reflex-web
|
||||
working-directory: ./reflex-web
|
||||
run: poetry run reflex init
|
||||
- name: Run Website and Check for errors
|
||||
run: |
|
||||
# Check that npm is home
|
||||
npm -v
|
||||
poetry run bash scripts/integration.sh ./reflex-web prod
|
||||
- name: Measure and upload .web size
|
||||
run:
|
||||
poetry run python benchmarks/benchmark_web_size.py --os "${{ matrix.os }}"
|
||||
--python-version "${{ matrix.python-version }}" --commit-sha "${{ github.sha }}"
|
||||
--pr-id "${{ github.event.pull_request.id }}" --branch-name "${{ github.head_ref || github.ref_name }}"
|
||||
--app-name "reflex-web" --path ./reflex-web/.web
|
||||
|
2
.github/workflows/integration_tests_wsl.yml
vendored
2
.github/workflows/integration_tests_wsl.yml
vendored
@ -37,6 +37,8 @@ jobs:
|
||||
path: reflex-examples
|
||||
|
||||
- uses: Vampire/setup-wsl@v3
|
||||
with:
|
||||
distribution: Ubuntu-24.04
|
||||
|
||||
- name: Install Python
|
||||
shell: wsl-bash {0}
|
||||
|
@ -28,5 +28,5 @@ jobs:
|
||||
# Run reflex init in a docker container
|
||||
|
||||
# cwd is repo root
|
||||
docker build -f integration/init-test/Dockerfile -t reflex-init-test integration/init-test
|
||||
docker run --rm -v $(pwd):/reflex-repo/ reflex-init-test /reflex-repo/integration/init-test/in_docker_test_script.sh
|
||||
docker build -f tests/integration/init-test/Dockerfile -t reflex-init-test tests/integration/init-test
|
||||
docker run --rm -v $(pwd):/reflex-repo/ reflex-init-test /reflex-repo/tests/integration/init-test/in_docker_test_script.sh
|
||||
|
43
.github/workflows/unit_tests.yml
vendored
43
.github/workflows/unit_tests.yml
vendored
@ -27,24 +27,21 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest, macos-12]
|
||||
python-version: ['3.8.18', '3.9.18', '3.10.13', '3.11.5', '3.12.0']
|
||||
os: [ubuntu-latest, windows-latest]
|
||||
python-version: ['3.9.18', '3.10.13', '3.11.5', '3.12.0']
|
||||
# Windows is a bit behind on Python version availability in Github
|
||||
exclude:
|
||||
- os: windows-latest
|
||||
python-version: '3.10.13'
|
||||
- os: windows-latest
|
||||
python-version: '3.9.18'
|
||||
- os: windows-latest
|
||||
python-version: '3.8.18'
|
||||
include:
|
||||
- os: windows-latest
|
||||
python-version: '3.10.11'
|
||||
- os: windows-latest
|
||||
python-version: '3.9.13'
|
||||
- os: windows-latest
|
||||
python-version: '3.8.10'
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
# Service containers to run with `runner-job`
|
||||
services:
|
||||
# Label used to access the service container
|
||||
@ -69,17 +66,43 @@ jobs:
|
||||
- name: Run unit tests
|
||||
run: |
|
||||
export PYTHONUNBUFFERED=1
|
||||
poetry run pytest tests --cov --no-cov-on-fail --cov-report=
|
||||
poetry run pytest tests/units --cov --no-cov-on-fail --cov-report=
|
||||
- name: Run unit tests w/ redis
|
||||
if: ${{ matrix.os == 'ubuntu-latest' }}
|
||||
run: |
|
||||
export PYTHONUNBUFFERED=1
|
||||
export REDIS_URL=redis://localhost:6379
|
||||
poetry run pytest tests --cov --no-cov-on-fail --cov-report=
|
||||
poetry run pytest tests/units --cov --no-cov-on-fail --cov-report=
|
||||
# Change to explicitly install v1 when reflex-hosting-cli is compatible with v2
|
||||
- name: Run unit tests w/ pydantic v1
|
||||
run: |
|
||||
export PYTHONUNBUFFERED=1
|
||||
poetry run uv pip install "pydantic~=1.10"
|
||||
poetry run pytest tests --cov --no-cov-on-fail --cov-report=
|
||||
- run: poetry run coverage html
|
||||
poetry run pytest tests/units --cov --no-cov-on-fail --cov-report=
|
||||
- name: Generate coverage report
|
||||
run: poetry run coverage html
|
||||
|
||||
unit-tests-macos:
|
||||
timeout-minutes: 30
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
python-version: ['3.9.18', '3.10.13', '3.11.5', '3.12.0']
|
||||
runs-on: macos-12
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ./.github/actions/setup_build_env
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
run-poetry-install: true
|
||||
create-venv-at-path: .venv
|
||||
- name: Run unit tests
|
||||
run: |
|
||||
export PYTHONUNBUFFERED=1
|
||||
poetry run pytest tests/units --cov --no-cov-on-fail --cov-report=
|
||||
- name: Run unit tests w/ pydantic v1
|
||||
run: |
|
||||
export PYTHONUNBUFFERED=1
|
||||
poetry run uv pip install "pydantic~=1.10"
|
||||
poetry run pytest tests/units --cov --no-cov-on-fail --cov-report=
|
@ -3,10 +3,10 @@ fail_fast: true
|
||||
repos:
|
||||
|
||||
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
||||
rev: v0.4.10
|
||||
rev: v0.7.1
|
||||
hooks:
|
||||
- id: ruff-format
|
||||
args: [integration, reflex, tests]
|
||||
args: [reflex, tests]
|
||||
- id: ruff
|
||||
args: ["--fix", "--exit-non-zero-on-fix"]
|
||||
exclude: '^integration/benchmarks/'
|
||||
@ -25,7 +25,7 @@ repos:
|
||||
rev: v1.1.313
|
||||
hooks:
|
||||
- id: pyright
|
||||
args: [integration, reflex, tests]
|
||||
args: [reflex, tests]
|
||||
language: system
|
||||
|
||||
- repo: https://github.com/terrencepreilly/darglint
|
||||
|
@ -8,7 +8,7 @@ Here is a quick guide on how to run Reflex repo locally so you can start contrib
|
||||
|
||||
**Prerequisites:**
|
||||
|
||||
- Python >= 3.8
|
||||
- Python >= 3.9
|
||||
- Poetry version >= 1.4.0 and add it to your path (see [Poetry Docs](https://python-poetry.org/docs/#installation) for more info).
|
||||
|
||||
**1. Fork this repository:**
|
||||
@ -69,7 +69,7 @@ In your `reflex` directory run make sure all the unit tests are still passing us
|
||||
This will fail if code coverage is below 70%.
|
||||
|
||||
``` bash
|
||||
poetry run pytest tests --cov --no-cov-on-fail --cov-report=
|
||||
poetry run pytest tests/units --cov --no-cov-on-fail --cov-report=
|
||||
```
|
||||
|
||||
Next make sure all the following tests pass. This ensures that every new change has proper documentation and type checking.
|
||||
@ -87,7 +87,7 @@ poetry run ruff format .
|
||||
```
|
||||
|
||||
Consider installing git pre-commit hooks so Ruff, Pyright, Darglint and `make_pyi` will run automatically before each commit.
|
||||
Note that pre-commit will only be installed when you use a Python version >= 3.8.
|
||||
Note that pre-commit will only be installed when you use a Python version >= 3.9.
|
||||
|
||||
``` bash
|
||||
pre-commit install
|
||||
|
@ -10,7 +10,6 @@
|
||||
|
||||
### **✨ Performant, customizable web apps in pure Python. Deploy in seconds. ✨**
|
||||
[](https://badge.fury.io/py/reflex)
|
||||

|
||||

|
||||
[](https://reflex.dev/docs/getting-started/introduction)
|
||||
[](https://discord.gg/T5WSbC2YtQ)
|
||||
@ -18,7 +17,7 @@
|
||||
|
||||
---
|
||||
|
||||
[English](https://github.com/reflex-dev/reflex/blob/main/README.md) | [简体中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_cn/README.md) | [繁體中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_tw/README.md) | [Türkçe](https://github.com/reflex-dev/reflex/blob/main/docs/tr/README.md) | [हिंदी](https://github.com/reflex-dev/reflex/blob/main/docs/in/README.md) | [Português (Brasil)](https://github.com/reflex-dev/reflex/blob/main/docs/pt/pt_br/README.md) | [Italiano](https://github.com/reflex-dev/reflex/blob/main/docs/it/README.md) | [Español](https://github.com/reflex-dev/reflex/blob/main/docs/es/README.md) | [한국어](https://github.com/reflex-dev/reflex/blob/main/docs/kr/README.md) | [日本語](https://github.com/reflex-dev/reflex/blob/main/docs/ja/README.md) | [Deutsch](https://github.com/reflex-dev/reflex/blob/main/docs/de/README.md) | [Persian (پارسی)](https://github.com/reflex-dev/reflex/blob/main/docs/pe/README.md)
|
||||
[English](https://github.com/reflex-dev/reflex/blob/main/README.md) | [简体中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_cn/README.md) | [繁體中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_tw/README.md) | [Türkçe](https://github.com/reflex-dev/reflex/blob/main/docs/tr/README.md) | [हिंदी](https://github.com/reflex-dev/reflex/blob/main/docs/in/README.md) | [Português (Brasil)](https://github.com/reflex-dev/reflex/blob/main/docs/pt/pt_br/README.md) | [Italiano](https://github.com/reflex-dev/reflex/blob/main/docs/it/README.md) | [Español](https://github.com/reflex-dev/reflex/blob/main/docs/es/README.md) | [한국어](https://github.com/reflex-dev/reflex/blob/main/docs/kr/README.md) | [日本語](https://github.com/reflex-dev/reflex/blob/main/docs/ja/README.md) | [Deutsch](https://github.com/reflex-dev/reflex/blob/main/docs/de/README.md) | [Persian (پارسی)](https://github.com/reflex-dev/reflex/blob/main/docs/pe/README.md) | [Tiếng Việt](https://github.com/reflex-dev/reflex/blob/main/docs/vi/README.md)
|
||||
|
||||
---
|
||||
|
||||
@ -35,7 +34,7 @@ See our [architecture page](https://reflex.dev/blog/2024-03-21-reflex-architectu
|
||||
|
||||
## ⚙️ Installation
|
||||
|
||||
Open a terminal and run (Requires Python 3.8+):
|
||||
Open a terminal and run (Requires Python 3.9+):
|
||||
|
||||
```bash
|
||||
pip install reflex
|
||||
@ -229,7 +228,7 @@ You can create a multi-page app by adding more pages.
|
||||
|
||||
<div align="center">
|
||||
|
||||
📑 [Docs](https://reflex.dev/docs/getting-started/introduction) | 🗞️ [Blog](https://reflex.dev/blog) | 📱 [Component Library](https://reflex.dev/docs/library) | 🖼️ [Gallery](https://reflex.dev/docs/gallery) | 🛸 [Deployment](https://reflex.dev/docs/hosting/deploy-quick-start)
|
||||
📑 [Docs](https://reflex.dev/docs/getting-started/introduction) | 🗞️ [Blog](https://reflex.dev/blog) | 📱 [Component Library](https://reflex.dev/docs/library) | 🖼️ [Templates](https://reflex.dev/templates/) | 🛸 [Deployment](https://reflex.dev/docs/hosting/deploy-quick-start)
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -3,8 +3,8 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from utils import send_data_to_posthog
|
||||
|
||||
@ -28,7 +28,7 @@ def insert_benchmarking_data(
|
||||
send_data_to_posthog("lighthouse_benchmark", properties)
|
||||
|
||||
|
||||
def get_lighthouse_scores(directory_path: str) -> dict:
|
||||
def get_lighthouse_scores(directory_path: str | Path) -> dict:
|
||||
"""Extracts the Lighthouse scores from the JSON files in the specified directory.
|
||||
|
||||
Args:
|
||||
@ -38,24 +38,20 @@ def get_lighthouse_scores(directory_path: str) -> dict:
|
||||
dict: The Lighthouse scores.
|
||||
"""
|
||||
scores = {}
|
||||
|
||||
directory_path = Path(directory_path)
|
||||
try:
|
||||
for filename in os.listdir(directory_path):
|
||||
if filename.endswith(".json") and filename != "manifest.json":
|
||||
file_path = os.path.join(directory_path, filename)
|
||||
with open(file_path, "r") as file:
|
||||
data = json.load(file)
|
||||
# Extract scores and add them to the dictionary with the filename as key
|
||||
scores[data["finalUrl"].replace("http://localhost:3000/", "/")] = {
|
||||
"performance_score": data["categories"]["performance"]["score"],
|
||||
"accessibility_score": data["categories"]["accessibility"][
|
||||
"score"
|
||||
],
|
||||
"best_practices_score": data["categories"]["best-practices"][
|
||||
"score"
|
||||
],
|
||||
"seo_score": data["categories"]["seo"]["score"],
|
||||
}
|
||||
for filename in directory_path.iterdir():
|
||||
if filename.suffix == ".json" and filename.stem != "manifest":
|
||||
data = json.loads(filename.read_text())
|
||||
# Extract scores and add them to the dictionary with the filename as key
|
||||
scores[data["finalUrl"].replace("http://localhost:3000/", "/")] = {
|
||||
"performance_score": data["categories"]["performance"]["score"],
|
||||
"accessibility_score": data["categories"]["accessibility"]["score"],
|
||||
"best_practices_score": data["categories"]["best-practices"][
|
||||
"score"
|
||||
],
|
||||
"seo_score": data["categories"]["seo"]["score"],
|
||||
}
|
||||
except Exception as e:
|
||||
return {"error": e}
|
||||
|
||||
|
@ -2,11 +2,12 @@
|
||||
|
||||
import argparse
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
from utils import get_directory_size, get_python_version, send_data_to_posthog
|
||||
|
||||
|
||||
def get_package_size(venv_path, os_name):
|
||||
def get_package_size(venv_path: Path, os_name):
|
||||
"""Get the size of a specified package.
|
||||
|
||||
Args:
|
||||
@ -26,14 +27,12 @@ def get_package_size(venv_path, os_name):
|
||||
|
||||
is_windows = "windows" in os_name
|
||||
|
||||
full_path = (
|
||||
["lib", f"python{python_version}", "site-packages"]
|
||||
package_dir: Path = (
|
||||
venv_path / "lib" / f"python{python_version}" / "site-packages"
|
||||
if not is_windows
|
||||
else ["Lib", "site-packages"]
|
||||
else venv_path / "Lib" / "site-packages"
|
||||
)
|
||||
|
||||
package_dir = os.path.join(venv_path, *full_path)
|
||||
if not os.path.exists(package_dir):
|
||||
if not package_dir.exists():
|
||||
raise ValueError(
|
||||
"Error: Virtual environment does not exist or is not activated."
|
||||
)
|
||||
@ -63,9 +62,9 @@ def insert_benchmarking_data(
|
||||
path: The path to the dir or file to check size.
|
||||
"""
|
||||
if "./dist" in path:
|
||||
size = get_directory_size(path)
|
||||
size = get_directory_size(Path(path))
|
||||
else:
|
||||
size = get_package_size(path, os_type_version)
|
||||
size = get_package_size(Path(path), os_type_version)
|
||||
|
||||
# Prepare the event data
|
||||
properties = {
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
import argparse
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
from utils import get_directory_size, send_data_to_posthog
|
||||
|
||||
@ -28,7 +29,7 @@ def insert_benchmarking_data(
|
||||
pr_id: The id of the PR.
|
||||
path: The path to the dir or file to check size.
|
||||
"""
|
||||
size = get_directory_size(path)
|
||||
size = get_directory_size(Path(path))
|
||||
|
||||
# Prepare the event data
|
||||
properties = {
|
||||
|
@ -130,7 +130,6 @@ def render_multiple_pages(app, num: int):
|
||||
|
||||
def AppWithOnePage():
|
||||
"""A reflex app with one page."""
|
||||
import reflex_chakra as rc
|
||||
from rxconfig import config # type: ignore
|
||||
|
||||
import reflex as rx
|
||||
@ -145,7 +144,7 @@ def AppWithOnePage():
|
||||
|
||||
def index() -> rx.Component:
|
||||
return rx.center(
|
||||
rc.input(
|
||||
rx.input(
|
||||
id="token", value=State.router.session.client_token, is_read_only=True
|
||||
),
|
||||
rx.vstack(
|
||||
|
@ -2,12 +2,13 @@
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
import httpx
|
||||
from httpx import HTTPError
|
||||
|
||||
|
||||
def get_python_version(venv_path, os_name):
|
||||
def get_python_version(venv_path: Path, os_name):
|
||||
"""Get the python version of python in a virtual env.
|
||||
|
||||
Args:
|
||||
@ -18,13 +19,13 @@ def get_python_version(venv_path, os_name):
|
||||
The python version.
|
||||
"""
|
||||
python_executable = (
|
||||
os.path.join(venv_path, "bin", "python")
|
||||
venv_path / "bin" / "python"
|
||||
if "windows" not in os_name
|
||||
else os.path.join(venv_path, "Scripts", "python.exe")
|
||||
else venv_path / "Scripts" / "python.exe"
|
||||
)
|
||||
try:
|
||||
output = subprocess.check_output(
|
||||
[python_executable, "--version"], stderr=subprocess.STDOUT
|
||||
[str(python_executable), "--version"], stderr=subprocess.STDOUT
|
||||
)
|
||||
python_version = output.decode("utf-8").strip().split()[1]
|
||||
return ".".join(python_version.split(".")[:-1])
|
||||
@ -32,7 +33,7 @@ def get_python_version(venv_path, os_name):
|
||||
return None
|
||||
|
||||
|
||||
def get_directory_size(directory):
|
||||
def get_directory_size(directory: Path):
|
||||
"""Get the size of a directory in bytes.
|
||||
|
||||
Args:
|
||||
@ -44,8 +45,8 @@ def get_directory_size(directory):
|
||||
total_size = 0
|
||||
for dirpath, _, filenames in os.walk(directory):
|
||||
for f in filenames:
|
||||
fp = os.path.join(dirpath, f)
|
||||
total_size += os.path.getsize(fp)
|
||||
fp = Path(dirpath) / f
|
||||
total_size += fp.stat().st_size
|
||||
return total_size
|
||||
|
||||
|
||||
|
@ -10,7 +10,6 @@
|
||||
|
||||
### **✨ Performante, anpassbare Web-Apps in purem Python. Bereitstellung in Sekunden. ✨**
|
||||
[](https://badge.fury.io/py/reflex)
|
||||

|
||||

|
||||
[](https://reflex.dev/docs/getting-started/introduction)
|
||||
[](https://discord.gg/T5WSbC2YtQ)
|
||||
@ -35,7 +34,7 @@ Auf unserer [Architektur-Seite](https://reflex.dev/blog/2024-03-21-reflex-archit
|
||||
|
||||
## ⚙️ Installation
|
||||
|
||||
Öffne ein Terminal und führe den folgenden Befehl aus (benötigt Python 3.8+):
|
||||
Öffne ein Terminal und führe den folgenden Befehl aus (benötigt Python 3.9+):
|
||||
|
||||
```bash
|
||||
pip install reflex
|
||||
|
@ -35,7 +35,7 @@ Consulta nuestra [página de arquitectura](https://reflex.dev/blog/2024-03-21-re
|
||||
|
||||
## ⚙️ Instalación
|
||||
|
||||
Abra un terminal y ejecute (Requiere Python 3.8+):
|
||||
Abra un terminal y ejecute (Requiere Python 3.9+):
|
||||
|
||||
```bash
|
||||
pip install reflex
|
||||
|
@ -11,7 +11,6 @@ Pynecone की तलाश हैं? आप सही रेपो में
|
||||
### **✨ प्रदर्शनकारी, अनुकूलित वेब ऐप्स, शुद्ध Python में। सेकंडों में तैनात करें। ✨**
|
||||
|
||||
[](https://badge.fury.io/py/reflex)
|
||||

|
||||

|
||||
[](https://reflex.dev/docs/getting-started/introduction)
|
||||
[](https://discord.gg/T5WSbC2YtQ)
|
||||
@ -36,7 +35,7 @@ Reflex के अंदर के कामकाज को जानने क
|
||||
|
||||
## ⚙️ इंस्टॉलेशन (Installation)
|
||||
|
||||
एक टर्मिनल खोलें और चलाएं (Python 3.8+ की आवश्यकता है):
|
||||
एक टर्मिनल खोलें और चलाएं (Python 3.9+ की आवश्यकता है):
|
||||
|
||||
```bash
|
||||
pip install reflex
|
||||
|
@ -10,7 +10,6 @@
|
||||
|
||||
### **✨ App web performanti e personalizzabili in puro Python. Distribuisci in pochi secondi. ✨**
|
||||
[](https://badge.fury.io/py/reflex)
|
||||

|
||||

|
||||
[](https://reflex.dev/docs/getting-started/introduction)
|
||||
[](https://discord.gg/T5WSbC2YtQ)
|
||||
@ -23,7 +22,7 @@
|
||||
|
||||
## ⚙️ Installazione
|
||||
|
||||
Apri un terminale ed esegui (Richiede Python 3.8+):
|
||||
Apri un terminale ed esegui (Richiede Python 3.9+):
|
||||
|
||||
```bash
|
||||
pip install reflex
|
||||
|
@ -11,7 +11,6 @@
|
||||
### **✨ 即時デプロイが可能な、Pure Python で作ったパフォーマンスと汎用性が高い Web アプリケーション ✨**
|
||||
|
||||
[](https://badge.fury.io/py/reflex)
|
||||

|
||||

|
||||
[](https://reflex.dev/docs/getting-started/introduction)
|
||||
[](https://discord.gg/T5WSbC2YtQ)
|
||||
@ -38,7 +37,7 @@ Reflex がどのように動作しているかを知るには、[アーキテク
|
||||
|
||||
## ⚙️ インストール
|
||||
|
||||
ターミナルを開いて以下のコマンドを実行してください。(Python 3.8 以上が必要です。):
|
||||
ターミナルを開いて以下のコマンドを実行してください。(Python 3.9 以上が必要です。):
|
||||
|
||||
```bash
|
||||
pip install reflex
|
||||
|
@ -10,7 +10,6 @@
|
||||
|
||||
### **✨ 순수 Python으로 고성능 사용자 정의 웹앱을 만들어 보세요. 몇 초만에 배포 가능합니다. ✨**
|
||||
[](https://badge.fury.io/py/reflex)
|
||||

|
||||

|
||||
[](https://reflex.dev/docs/getting-started/introduction)
|
||||
[](https://discord.gg/T5WSbC2YtQ)
|
||||
@ -21,7 +20,7 @@
|
||||
---
|
||||
## ⚙️ 설치
|
||||
|
||||
터미널을 열고 실행하세요. (Python 3.8+ 필요):
|
||||
터미널을 열고 실행하세요. (Python 3.9+ 필요):
|
||||
|
||||
```bash
|
||||
pip install reflex
|
||||
|
@ -10,7 +10,6 @@
|
||||
|
||||
### **✨ برنامه های تحت وب قابل تنظیم، کارآمد تماما پایتونی که در چند ثانیه مستقر(دپلوی) میشود. ✨**
|
||||
[](https://badge.fury.io/py/reflex)
|
||||

|
||||

|
||||
[](https://reflex.dev/docs/getting-started/introduction)
|
||||
[](https://discord.gg/T5WSbC2YtQ)
|
||||
@ -35,7 +34,7 @@
|
||||
|
||||
## ⚙️ Installation - نصب و راه اندازی
|
||||
|
||||
یک ترمینال را باز کنید و اجرا کنید (نیازمند Python 3.8+):
|
||||
یک ترمینال را باز کنید و اجرا کنید (نیازمند Python 3.9+):
|
||||
|
||||
```bash
|
||||
pip install reflex
|
||||
|
@ -21,7 +21,7 @@
|
||||
---
|
||||
## ⚙️ Instalação
|
||||
|
||||
Abra um terminal e execute (Requer Python 3.8+):
|
||||
Abra um terminal e execute (Requer Python 3.9+):
|
||||
|
||||
```bash
|
||||
pip install reflex
|
||||
|
@ -11,7 +11,6 @@
|
||||
### **✨ Saf Python'da performanslı, özelleştirilebilir web uygulamaları. Saniyeler içinde dağıtın. ✨**
|
||||
|
||||
[](https://badge.fury.io/py/reflex)
|
||||

|
||||

|
||||
[](https://reflex.dev/docs/getting-started/introduction)
|
||||
[](https://discord.gg/T5WSbC2YtQ)
|
||||
@ -25,7 +24,7 @@
|
||||
|
||||
## ⚙️ Kurulum
|
||||
|
||||
Bir terminal açın ve çalıştırın (Python 3.8+ gerekir):
|
||||
Bir terminal açın ve çalıştırın (Python 3.9+ gerekir):
|
||||
|
||||
```bash
|
||||
pip install reflex
|
||||
|
267
docs/vi/README.md
Normal file
267
docs/vi/README.md
Normal file
@ -0,0 +1,267 @@
|
||||
```diff
|
||||
+ Bạn đang tìm kiếm Pynecone? Bạn đã tìm đúng. Pynecone đã được đổi tên thành Reflex. +
|
||||
```
|
||||
|
||||
<div align="center">
|
||||
<img src="https://raw.githubusercontent.com/reflex-dev/reflex/main/docs/images/reflex_dark.svg#gh-light-mode-only" alt="Reflex Logo" width="300px">
|
||||
<img src="https://raw.githubusercontent.com/reflex-dev/reflex/main/docs/images/reflex_light.svg#gh-dark-mode-only" alt="Reflex Logo" width="300px">
|
||||
|
||||
<hr>
|
||||
|
||||
### **✨ Ứng dụng web hiệu suất cao, tùy chỉnh bằng Python thuần. Deploy trong vài giây. ✨**
|
||||
[](https://badge.fury.io/py/reflex)
|
||||

|
||||
[](https://reflex.dev/docs/getting-started/introduction)
|
||||
[](https://discord.gg/T5WSbC2YtQ)
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
[English](https://github.com/reflex-dev/reflex/blob/main/README.md) | [简体中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_cn/README.md) | [繁體中文](https://github.com/reflex-dev/reflex/blob/main/docs/zh/zh_tw/README.md) | [Türkçe](https://github.com/reflex-dev/reflex/blob/main/docs/tr/README.md) | [हिंदी](https://github.com/reflex-dev/reflex/blob/main/docs/in/README.md) | [Português (Brasil)](https://github.com/reflex-dev/reflex/blob/main/docs/pt/pt_br/README.md) | [Italiano](https://github.com/reflex-dev/reflex/blob/main/docs/it/README.md) | [Español](https://github.com/reflex-dev/reflex/blob/main/docs/es/README.md) | [한국어](https://github.com/reflex-dev/reflex/blob/main/docs/kr/README.md) | [日本語](https://github.com/reflex-dev/reflex/blob/main/docs/ja/README.md) | [Deutsch](https://github.com/reflex-dev/reflex/blob/main/docs/de/README.md) | [Persian (پارسی)](https://github.com/reflex-dev/reflex/blob/main/docs/pe/README.md) | [Tiếng Việt](https://github.com/reflex-dev/reflex/blob/main/docs/vi/README.md)
|
||||
|
||||
---
|
||||
|
||||
# Reflex
|
||||
|
||||
Reflex là một thư viện để xây dựng ứng dụng web toàn bộ bằng Python thuần.
|
||||
|
||||
Các tính năng chính:
|
||||
* **Python thuần tuý** - Viết toàn bộ ứng dụng cả backend và frontend hoàn toàn bằng Python, không cần học JavaScript.
|
||||
* **Full Flexibility** - Reflex dễ dàng để bắt đầu, nhưng cũng có thể mở rộng lên các ứng dụng phức tạp.
|
||||
* **Deploy Instantly** - Sau khi xây dựng ứng dụng, bạn có thể triển khai bằng [một dòng lệnh](https://reflex.dev/docs/hosting/deploy-quick-start/) hoặc triển khai trên server của riêng bạn.
|
||||
|
||||
Đọc [bài viết về kiến trúc hệ thống](https://reflex.dev/blog/2024-03-21-reflex-architecture/#the-reflex-architecture) để hiểu rõ các hoạt động của Reflex.
|
||||
|
||||
## ⚙️ Cài đặt
|
||||
|
||||
Mở cửa sổ lệnh và chạy (Yêu cầu Python phiên bản 3.9+):
|
||||
|
||||
```bash
|
||||
pip install reflex
|
||||
```
|
||||
|
||||
## 🥳 Tạo ứng dụng đầu tiên
|
||||
|
||||
Cài đặt `reflex` cũng như cài đặt công cụ dòng lệnh `reflex`.
|
||||
|
||||
Kiểm tra việc cài đặt đã thành công hay chưa bằng cách tạo mới một ứng dụng. (Thay `my_app_name` bằng tên ứng dụng của bạn):
|
||||
|
||||
```bash
|
||||
mkdir my_app_name
|
||||
cd my_app_name
|
||||
reflex init
|
||||
```
|
||||
|
||||
Lệnh này tạo ra một ứng dụng mẫu trong một thư mục mới.
|
||||
|
||||
Bạn có thể chạy ứng dụng ở chế độ phát triển.
|
||||
|
||||
```bash
|
||||
reflex run
|
||||
```
|
||||
|
||||
Bạn có thể xem ứng dụng của bạn ở địa chỉ http://localhost:3000.
|
||||
|
||||
Bạn có thể thay đổi mã nguồn ở `my_app_name/my_app_name.py`. Reflex nhanh chóng làm mới và bạn có thể thấy thay đổi trên ứng dụng của bạn ngay lập tức khi bạn lưu file.
|
||||
|
||||
|
||||
## 🫧 Ứng dụng ví dụ
|
||||
|
||||
Bắt đầu với ví dụ: tạo một ứng dụng tạo ảnh bằng [DALL·E](https://platform.openai.com/docs/guides/images/image-generation?context=node). Để cho đơn giản, chúng ta sẽ sử dụng [OpenAI API](https://platform.openai.com/docs/api-reference/authentication), nhưng bạn có thể sử dụng model của chính bạn được triển khai trên local.
|
||||
|
||||
|
||||
|
||||
<div align="center">
|
||||
<img src="https://raw.githubusercontent.com/reflex-dev/reflex/main/docs/images/dalle.gif" alt="A frontend wrapper for DALL·E, shown in the process of generating an image." width="550" />
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
Đây là toàn bộ đoạn mã để xây dựng ứng dụng trên. Nó được viết hoàn toàn trong một file Python!
|
||||
|
||||
|
||||
|
||||
```python
|
||||
import reflex as rx
|
||||
import openai
|
||||
|
||||
openai_client = openai.OpenAI()
|
||||
|
||||
|
||||
class State(rx.State):
|
||||
"""The app state."""
|
||||
|
||||
prompt = ""
|
||||
image_url = ""
|
||||
processing = False
|
||||
complete = False
|
||||
|
||||
def get_image(self):
|
||||
"""Get the image from the prompt."""
|
||||
if self.prompt == "":
|
||||
return rx.window_alert("Prompt Empty")
|
||||
|
||||
self.processing, self.complete = True, False
|
||||
yield
|
||||
response = openai_client.images.generate(
|
||||
prompt=self.prompt, n=1, size="1024x1024"
|
||||
)
|
||||
self.image_url = response.data[0].url
|
||||
self.processing, self.complete = False, True
|
||||
|
||||
|
||||
def index():
|
||||
return rx.center(
|
||||
rx.vstack(
|
||||
rx.heading("DALL-E", font_size="1.5em"),
|
||||
rx.input(
|
||||
placeholder="Enter a prompt..",
|
||||
on_blur=State.set_prompt,
|
||||
width="25em",
|
||||
),
|
||||
rx.button(
|
||||
"Generate Image",
|
||||
on_click=State.get_image,
|
||||
width="25em",
|
||||
loading=State.processing
|
||||
),
|
||||
rx.cond(
|
||||
State.complete,
|
||||
rx.image(src=State.image_url, width="20em"),
|
||||
),
|
||||
align="center",
|
||||
),
|
||||
width="100%",
|
||||
height="100vh",
|
||||
)
|
||||
|
||||
# Add state and page to the app.
|
||||
app = rx.App()
|
||||
app.add_page(index, title="Reflex:DALL-E")
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## Hãy phân tích chi tiết.
|
||||
|
||||
<div align="center">
|
||||
<img src="../images/dalle_colored_code_example.png" alt="Explaining the differences between backend and frontend parts of the DALL-E app." width="900" />
|
||||
</div>
|
||||
|
||||
|
||||
### **Reflex UI**
|
||||
|
||||
Bắt đầu với giao diện chính.
|
||||
|
||||
```python
|
||||
def index():
|
||||
return rx.center(
|
||||
...
|
||||
)
|
||||
```
|
||||
|
||||
Hàm `index` định nghĩa phần giao diện chính của ứng dụng.
|
||||
|
||||
Chúng tôi sử dụng các component (thành phần) khác nhau như `center`, `vstack`, `input` và `button` để xây dựng giao diện phía trước.
|
||||
Các component có thể được lồng vào nhau để tạo ra các bố cục phức tạp. Và bạn cũng có thể sử dụng từ khoá `args` để tận dụng đầy đủ sức mạnh của CSS.
|
||||
|
||||
Reflex có đến hơn [60 component được xây dựng sẵn](https://reflex.dev/docs/library) để giúp bạn bắt đầu. Chúng ta có thể tạo ra một component mới khá dễ dàng, thao khảo: [xây dựng component của riêng bạn](https://reflex.dev/docs/wrapping-react/overview/).
|
||||
|
||||
### **State**
|
||||
|
||||
Reflex biểu diễn giao diện bằng các hàm của state (trạng thái).
|
||||
|
||||
```python
|
||||
class State(rx.State):
|
||||
"""The app state."""
|
||||
prompt = ""
|
||||
image_url = ""
|
||||
processing = False
|
||||
complete = False
|
||||
|
||||
```
|
||||
|
||||
Một state định nghĩa các biến (được gọi là vars) có thể thay đổi trong một ứng dụng và cho phép các hàm có thể thay đổi chúng.
|
||||
|
||||
Tại đây state được cấu thành từ một `prompt` và `image_url`.
|
||||
Có cũng những biến boolean `processing` và `complete`
|
||||
để chỉ ra khi nào tắt nút (trong quá trình tạo hình ảnh)
|
||||
và khi nào hiển thị hình ảnh kết quả.
|
||||
|
||||
### **Event Handlers**
|
||||
|
||||
```python
|
||||
def get_image(self):
|
||||
"""Get the image from the prompt."""
|
||||
if self.prompt == "":
|
||||
return rx.window_alert("Prompt Empty")
|
||||
|
||||
self.processing, self.complete = True, False
|
||||
yield
|
||||
response = openai_client.images.generate(
|
||||
prompt=self.prompt, n=1, size="1024x1024"
|
||||
)
|
||||
self.image_url = response.data[0].url
|
||||
self.processing, self.complete = False, True
|
||||
```
|
||||
|
||||
Với các state, chúng ta định nghĩa các hàm có thể thay đổi state vars được gọi là event handlers. Event handler là cách chúng ta có thể thay đổi state trong Reflex. Chúng có thể là phản hồi khi người dùng thao tác, chằng hạn khi nhấn vào nút hoặc khi đang nhập trong text box. Các hành động này được gọi là event.
|
||||
|
||||
Ứng dụng DALL·E. của chúng ta có một event handler, `get_image` để lấy hình ảnh từ OpenAI API. Sử dụng từ khoá `yield` in ở giữa event handler để cập nhật giao diện. Hoặc giao diện có thể cập nhật ở cuối event handler.
|
||||
|
||||
### **Routing**
|
||||
|
||||
Cuối cùng, chúng ta định nghĩa một ứng dụng.
|
||||
|
||||
```python
|
||||
app = rx.App()
|
||||
```
|
||||
|
||||
Chúng ta thêm một trang ở đầu ứng dụng bằng index component. Chúng ta cũng thêm tiêu đề của ứng dụng để hiển thị lên trình duyệt.
|
||||
|
||||
|
||||
```python
|
||||
app.add_page(index, title="DALL-E")
|
||||
```
|
||||
|
||||
Bạn có thể tạo một ứng dụng nhiều trang bằng cách thêm trang.
|
||||
|
||||
## 📑 Tài liệu
|
||||
|
||||
<div align="center">
|
||||
|
||||
📑 [Docs](https://reflex.dev/docs/getting-started/introduction) | 🗞️ [Blog](https://reflex.dev/blog) | 📱 [Component Library](https://reflex.dev/docs/library) | 🖼️ [Gallery](https://reflex.dev/docs/gallery) | 🛸 [Deployment](https://reflex.dev/docs/hosting/deploy-quick-start)
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
## ✅ Status
|
||||
|
||||
Reflex phát hành vào tháng 12/2022 với tên là Pynecone.
|
||||
|
||||
Đến tháng 02/2024, chúng tôi tạo ra dịch vụ dưới phiên bản alpha! Trong thời gian này mọi người có thể triển khai ứng dụng hoàn toàn miễn phí. Xem [roadmap](https://github.com/reflex-dev/reflex/issues/2727) để biết thêm chi tiết.
|
||||
|
||||
Reflex ra phiên bản mới với các tính năng mới hàng tuần! Hãy :star: star và :eyes: watch repo này để thấy các cập nhật mới nhất.
|
||||
|
||||
## Contributing
|
||||
|
||||
Chúng tôi chào đón mọi đóng góp dù lớn hay nhỏ. Dưới đây là các cách để bắt đầu với cộng đồng Reflex.
|
||||
|
||||
- **Discord**: [Discord](https://discord.gg/T5WSbC2YtQ) của chúng tôi là nơi tốt nhất để nhờ sự giúp đỡ và thảo luận các bạn có thể đóng góp.
|
||||
- **GitHub Discussions**: Là cách tốt nhất để thảo luận về các tính năng mà bạn có thể đóng góp hoặc những điều bạn chưa rõ.
|
||||
- **GitHub Issues**: [Issues](https://github.com/reflex-dev/reflex/issues) là nơi tốt nhất để thông báo. Ngoài ra bạn có thể sửa chữa các vấn đề bằng cách tạo PR.
|
||||
|
||||
Chúng tôi luôn sẵn sàng tìm kiếm các contributor, bất kể kinh nghiệm. Để tham gia đóng góp, xin mời xem
|
||||
[CONTIBUTING.md](https://github.com/reflex-dev/reflex/blob/main/CONTRIBUTING.md)
|
||||
|
||||
|
||||
## Xin cảm ơn các Contributors:
|
||||
<a href="https://github.com/reflex-dev/reflex/graphs/contributors">
|
||||
<img src="https://contrib.rocks/image?repo=reflex-dev/reflex" />
|
||||
</a>
|
||||
|
||||
## License
|
||||
|
||||
Reflex là mã nguồn mở và sử dụng giấy phép [Apache License 2.0](LICENSE).
|
@ -10,7 +10,6 @@
|
||||
|
||||
### **✨ 使用 Python 创建高效且可自定义的网页应用程序,几秒钟内即可部署.✨**
|
||||
[](https://badge.fury.io/py/reflex)
|
||||

|
||||

|
||||
[](https://reflex.dev/docs/getting-started/introduction)
|
||||
[](https://discord.gg/T5WSbC2YtQ)
|
||||
@ -35,7 +34,7 @@ Reflex 是一个使用纯Python构建全栈web应用的库。
|
||||
|
||||
## ⚙️ 安装
|
||||
|
||||
打开一个终端并且运行(要求Python3.8+):
|
||||
打开一个终端并且运行(要求Python3.9+):
|
||||
|
||||
```bash
|
||||
pip install reflex
|
||||
|
@ -11,7 +11,6 @@
|
||||
**✨ 使用 Python 建立高效且可自訂的網頁應用程式,幾秒鐘內即可部署。✨**
|
||||
|
||||
[](https://badge.fury.io/py/reflex)
|
||||

|
||||

|
||||
[](https://reflex.dev/docs/getting-started/introduction)
|
||||
[](https://discord.gg/T5WSbC2YtQ)
|
||||
@ -37,7 +36,7 @@ Reflex 是一個可以用純 Python 構建全端網頁應用程式的函式庫
|
||||
|
||||
## ⚙️ 安裝
|
||||
|
||||
開啟一個終端機並且執行 (需要 Python 3.8+):
|
||||
開啟一個終端機並且執行 (需要 Python 3.9+):
|
||||
|
||||
```bash
|
||||
pip install reflex
|
||||
|
@ -1,107 +0,0 @@
|
||||
"""Test that per-component state scaffold works and operates independently."""
|
||||
|
||||
from typing import Generator
|
||||
|
||||
import pytest
|
||||
from selenium.webdriver.common.by import By
|
||||
|
||||
from reflex.testing import AppHarness
|
||||
|
||||
from . import utils
|
||||
|
||||
|
||||
def ComponentStateApp():
|
||||
"""App using per component state."""
|
||||
import reflex as rx
|
||||
|
||||
class MultiCounter(rx.ComponentState):
|
||||
count: int = 0
|
||||
|
||||
def increment(self):
|
||||
self.count += 1
|
||||
|
||||
@classmethod
|
||||
def get_component(cls, *children, **props):
|
||||
return rx.vstack(
|
||||
*children,
|
||||
rx.heading(cls.count, id=f"count-{props.get('id', 'default')}"),
|
||||
rx.button(
|
||||
"Increment",
|
||||
on_click=cls.increment,
|
||||
id=f"button-{props.get('id', 'default')}",
|
||||
),
|
||||
**props,
|
||||
)
|
||||
|
||||
app = rx.App(state=rx.State) # noqa
|
||||
|
||||
@rx.page()
|
||||
def index():
|
||||
mc_a = MultiCounter.create(id="a")
|
||||
mc_b = MultiCounter.create(id="b")
|
||||
assert mc_a.State != mc_b.State
|
||||
return rx.vstack(
|
||||
mc_a,
|
||||
mc_b,
|
||||
rx.button(
|
||||
"Inc A",
|
||||
on_click=mc_a.State.increment, # type: ignore
|
||||
id="inc-a",
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def component_state_app(tmp_path) -> Generator[AppHarness, None, None]:
|
||||
"""Start ComponentStateApp app at tmp_path via AppHarness.
|
||||
|
||||
Args:
|
||||
tmp_path: pytest tmp_path fixture
|
||||
|
||||
Yields:
|
||||
running AppHarness instance
|
||||
"""
|
||||
with AppHarness.create(
|
||||
root=tmp_path,
|
||||
app_source=ComponentStateApp, # type: ignore
|
||||
) as harness:
|
||||
yield harness
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_component_state_app(component_state_app: AppHarness):
|
||||
"""Increment counters independently.
|
||||
|
||||
Args:
|
||||
component_state_app: harness for ComponentStateApp app
|
||||
"""
|
||||
assert component_state_app.app_instance is not None, "app is not running"
|
||||
driver = component_state_app.frontend()
|
||||
|
||||
ss = utils.SessionStorage(driver)
|
||||
assert AppHarness._poll_for(lambda: ss.get("token") is not None), "token not found"
|
||||
|
||||
count_a = driver.find_element(By.ID, "count-a")
|
||||
count_b = driver.find_element(By.ID, "count-b")
|
||||
button_a = driver.find_element(By.ID, "button-a")
|
||||
button_b = driver.find_element(By.ID, "button-b")
|
||||
button_inc_a = driver.find_element(By.ID, "inc-a")
|
||||
|
||||
assert count_a.text == "0"
|
||||
|
||||
button_a.click()
|
||||
assert component_state_app.poll_for_content(count_a, exp_not_equal="0") == "1"
|
||||
|
||||
button_a.click()
|
||||
assert component_state_app.poll_for_content(count_a, exp_not_equal="1") == "2"
|
||||
|
||||
button_inc_a.click()
|
||||
assert component_state_app.poll_for_content(count_a, exp_not_equal="2") == "3"
|
||||
|
||||
assert count_b.text == "0"
|
||||
|
||||
button_b.click()
|
||||
assert component_state_app.poll_for_content(count_b, exp_not_equal="0") == "1"
|
||||
|
||||
button_b.click()
|
||||
assert component_state_app.poll_for_content(count_b, exp_not_equal="1") == "2"
|
@ -1,173 +0,0 @@
|
||||
"""Integration tests for table and related components."""
|
||||
|
||||
from typing import Generator
|
||||
|
||||
import pytest
|
||||
from selenium.webdriver.common.by import By
|
||||
|
||||
from reflex.testing import AppHarness
|
||||
|
||||
|
||||
def Table():
|
||||
"""App using table component."""
|
||||
from typing import List
|
||||
|
||||
import reflex_chakra as rc
|
||||
|
||||
import reflex as rx
|
||||
|
||||
class TableState(rx.State):
|
||||
rows: List[List[str]] = [
|
||||
["John", "30", "New York"],
|
||||
["Jane", "31", "San Fransisco"],
|
||||
["Joe", "32", "Los Angeles"],
|
||||
]
|
||||
|
||||
headers: List[str] = ["Name", "Age", "Location"]
|
||||
|
||||
footers: List[str] = ["footer1", "footer2", "footer3"]
|
||||
|
||||
caption: str = "random caption"
|
||||
|
||||
app = rx.App(state=rx.State)
|
||||
|
||||
@app.add_page
|
||||
def index():
|
||||
return rx.center(
|
||||
rc.input(
|
||||
id="token",
|
||||
value=TableState.router.session.client_token,
|
||||
is_read_only=True,
|
||||
),
|
||||
rc.table_container(
|
||||
rc.table(
|
||||
headers=TableState.headers,
|
||||
rows=TableState.rows,
|
||||
footers=TableState.footers,
|
||||
caption=TableState.caption,
|
||||
variant="striped",
|
||||
color_scheme="blue",
|
||||
width="100%",
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
@app.add_page
|
||||
def another():
|
||||
return rx.center(
|
||||
rc.table_container(
|
||||
rc.table( # type: ignore
|
||||
rc.thead( # type: ignore
|
||||
rc.tr( # type: ignore
|
||||
rc.th("Name"),
|
||||
rc.th("Age"),
|
||||
rc.th("Location"),
|
||||
)
|
||||
),
|
||||
rc.tbody( # type: ignore
|
||||
rc.tr( # type: ignore
|
||||
rc.td("John"),
|
||||
rc.td(30),
|
||||
rc.td("New York"),
|
||||
),
|
||||
rc.tr( # type: ignore
|
||||
rc.td("Jane"),
|
||||
rc.td(31),
|
||||
rc.td("San Francisco"),
|
||||
),
|
||||
rc.tr( # type: ignore
|
||||
rc.td("Joe"),
|
||||
rc.td(32),
|
||||
rc.td("Los Angeles"),
|
||||
),
|
||||
),
|
||||
rc.tfoot( # type: ignore
|
||||
rc.tr(
|
||||
rc.td("footer1"),
|
||||
rc.td("footer2"),
|
||||
rc.td("footer3"),
|
||||
) # type: ignore
|
||||
),
|
||||
rc.table_caption("random caption"),
|
||||
variant="striped",
|
||||
color_scheme="teal",
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def table(tmp_path_factory) -> Generator[AppHarness, None, None]:
|
||||
"""Start Table app at tmp_path via AppHarness.
|
||||
|
||||
Args:
|
||||
tmp_path_factory: pytest tmp_path_factory fixture
|
||||
|
||||
Yields:
|
||||
running AppHarness instance
|
||||
|
||||
"""
|
||||
with AppHarness.create(
|
||||
root=tmp_path_factory.mktemp("table"),
|
||||
app_source=Table, # type: ignore
|
||||
) as harness:
|
||||
assert harness.app_instance is not None, "app is not running"
|
||||
yield harness
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def driver(table: AppHarness):
|
||||
"""GEt an instance of the browser open to the table app.
|
||||
|
||||
Args:
|
||||
table: harness for Table app
|
||||
|
||||
Yields:
|
||||
WebDriver instance.
|
||||
"""
|
||||
driver = table.frontend()
|
||||
try:
|
||||
token_input = driver.find_element(By.ID, "token")
|
||||
assert token_input
|
||||
# wait for the backend connection to send the token
|
||||
token = table.poll_for_value(token_input)
|
||||
assert token is not None
|
||||
|
||||
yield driver
|
||||
finally:
|
||||
driver.quit()
|
||||
|
||||
|
||||
@pytest.mark.parametrize("route", ["", "/another"])
|
||||
def test_table(driver, table: AppHarness, route):
|
||||
"""Test that a table component is rendered properly.
|
||||
|
||||
Args:
|
||||
driver: Selenium WebDriver open to the app
|
||||
table: Harness for Table app
|
||||
route: Page route or path.
|
||||
"""
|
||||
driver.get(f"{table.frontend_url}/{route}")
|
||||
assert table.app_instance is not None, "app is not running"
|
||||
|
||||
thead = driver.find_element(By.TAG_NAME, "thead")
|
||||
# poll till page is fully loaded.
|
||||
table.poll_for_content(element=thead)
|
||||
# check headers
|
||||
assert thead.find_element(By.TAG_NAME, "tr").text == "NAME AGE LOCATION"
|
||||
# check first row value
|
||||
assert (
|
||||
driver.find_element(By.TAG_NAME, "tbody")
|
||||
.find_elements(By.TAG_NAME, "tr")[0]
|
||||
.text
|
||||
== "John 30 New York"
|
||||
)
|
||||
# check footer
|
||||
assert (
|
||||
driver.find_element(By.TAG_NAME, "tfoot")
|
||||
.find_element(By.TAG_NAME, "tr")
|
||||
.text.lower()
|
||||
== "footer1 footer2 footer3"
|
||||
)
|
||||
# check caption
|
||||
assert driver.find_element(By.TAG_NAME, "caption").text == "random caption"
|
@ -1,68 +0,0 @@
|
||||
"""Integration tests for all urls in Reflex."""
|
||||
|
||||
import os
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
import requests
|
||||
|
||||
|
||||
def check_urls(repo_dir):
|
||||
"""Check that all URLs in the repo are valid and secure.
|
||||
|
||||
Args:
|
||||
repo_dir: The directory of the repo.
|
||||
|
||||
Returns:
|
||||
A list of errors.
|
||||
"""
|
||||
url_pattern = re.compile(r'http[s]?://reflex\.dev[^\s")]*')
|
||||
errors = []
|
||||
|
||||
for root, _dirs, files in os.walk(repo_dir):
|
||||
if "__pycache__" in root:
|
||||
continue
|
||||
|
||||
for file_name in files:
|
||||
if not file_name.endswith(".py") and not file_name.endswith(".md"):
|
||||
continue
|
||||
|
||||
file_path = os.path.join(root, file_name)
|
||||
try:
|
||||
with open(file_path, "r", encoding="utf-8", errors="ignore") as file:
|
||||
for line in file:
|
||||
urls = url_pattern.findall(line)
|
||||
for url in set(urls):
|
||||
if url.startswith("http://"):
|
||||
errors.append(
|
||||
f"Found insecure HTTP URL: {url} in {file_path}"
|
||||
)
|
||||
url = url.strip('"\n')
|
||||
try:
|
||||
response = requests.head(
|
||||
url, allow_redirects=True, timeout=5
|
||||
)
|
||||
response.raise_for_status()
|
||||
except requests.RequestException as e:
|
||||
errors.append(
|
||||
f"Error accessing URL: {url} in {file_path} | Error: {e}, , Check your path ends with a /"
|
||||
)
|
||||
except Exception as e:
|
||||
errors.append(f"Error reading file: {file_path} | Error: {e}")
|
||||
|
||||
return errors
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"repo_dir",
|
||||
[Path(__file__).resolve().parent.parent / "reflex"],
|
||||
)
|
||||
def test_find_and_check_urls(repo_dir):
|
||||
"""Test that all URLs in the repo are valid and secure.
|
||||
|
||||
Args:
|
||||
repo_dir: The directory of the repo.
|
||||
"""
|
||||
errors = check_urls(repo_dir)
|
||||
assert not errors, "\n".join(errors)
|
2095
poetry.lock
generated
2095
poetry.lock
generated
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
[tool.poetry]
|
||||
name = "reflex"
|
||||
version = "0.6.0a1"
|
||||
version = "0.6.5dev1"
|
||||
description = "Web apps in pure Python."
|
||||
license = "Apache-2.0"
|
||||
authors = [
|
||||
@ -26,8 +26,7 @@ packages = [
|
||||
]
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.8"
|
||||
dill = ">=0.3.8,<0.4"
|
||||
python = "^3.9"
|
||||
fastapi = ">=0.96.0,!=0.111.0,!=0.111.1"
|
||||
gunicorn = ">=20.1.0,<24.0"
|
||||
jinja2 = ">=3.1.2,<4.0"
|
||||
@ -54,34 +53,32 @@ reflex-hosting-cli = ">=0.1.2,<2.0"
|
||||
charset-normalizer = ">=3.3.2,<4.0"
|
||||
wheel = ">=0.42.0,<1.0"
|
||||
build = ">=1.0.3,<2.0"
|
||||
setuptools = ">=69.1.1,<70.2"
|
||||
setuptools = ">=75.0"
|
||||
httpx = ">=0.25.1,<1.0"
|
||||
twine = ">=4.0.0,<6.0"
|
||||
tomlkit = ">=0.12.4,<1.0"
|
||||
lazy_loader = ">=0.4"
|
||||
reflex-chakra = ">=0.6.0a"
|
||||
reflex-chakra = ">=0.6.0"
|
||||
|
||||
[tool.poetry.group.dev.dependencies]
|
||||
pytest = ">=7.1.2,<8.0"
|
||||
pytest = ">=7.1.2,<9.0"
|
||||
pytest-mock = ">=3.10.0,<4.0"
|
||||
pyright = ">=1.1.229,<1.1.335"
|
||||
darglint = ">=1.8.1,<2.0"
|
||||
dill = ">=0.3.8"
|
||||
toml = ">=0.10.2,<1.0"
|
||||
pytest-asyncio = ">=0.20.1,<0.22.0" # https://github.com/pytest-dev/pytest-asyncio/issues/706
|
||||
pytest-cov = ">=4.0.0,<5.0"
|
||||
ruff = "^0.4.9"
|
||||
pandas = [
|
||||
{version = ">=2.1.1,<3.0", python = ">=3.9,<3.13"},
|
||||
{version = ">=1.5.3,<2.0", python = ">=3.8,<3.9"},
|
||||
]
|
||||
pillow = [
|
||||
{version = ">=10.0.0,<11.0", python = ">=3.8,<4.0"}
|
||||
]
|
||||
pytest-asyncio = ">=0.24.0"
|
||||
pytest-cov = ">=4.0.0,<6.0"
|
||||
ruff = "0.7.1"
|
||||
pandas = ">=2.1.1,<3.0"
|
||||
pillow = ">=10.0.0,<12.0"
|
||||
plotly = ">=5.13.0,<6.0"
|
||||
asynctest = ">=0.13.0,<1.0"
|
||||
pre-commit = {version = ">=3.2.1", python = ">=3.8,<4.0"}
|
||||
pre-commit = ">=3.2.1"
|
||||
selenium = ">=4.11.0,<5.0"
|
||||
pytest-benchmark = ">=4.0.0,<5.0"
|
||||
playwright = ">=1.46.0"
|
||||
pytest-playwright = ">=0.5.1"
|
||||
|
||||
[tool.poetry.scripts]
|
||||
reflex = "reflex.reflex:cli"
|
||||
@ -93,9 +90,9 @@ build-backend = "poetry.core.masonry.api"
|
||||
[tool.pyright]
|
||||
|
||||
[tool.ruff]
|
||||
target-version = "py38"
|
||||
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]
|
||||
@ -104,3 +101,7 @@ lint.pydocstyle.convention = "google"
|
||||
"reflex/.templates/*.py" = ["D100", "D103", "D104"]
|
||||
"*.pyi" = ["D301", "D415", "D417", "D418", "E742"]
|
||||
"*/blank.py" = ["I001"]
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
asyncio_default_fixture_loop_scope = "function"
|
||||
asyncio_mode = "auto"
|
||||
|
@ -8,11 +8,11 @@ version = "0.0.1"
|
||||
description = "Reflex custom component {{ module_name }}"
|
||||
readme = "README.md"
|
||||
license = { text = "Apache-2.0" }
|
||||
requires-python = ">=3.8"
|
||||
requires-python = ">=3.9"
|
||||
authors = [{ name = "", email = "YOUREMAIL@domain.com" }]
|
||||
keywords = ["reflex","reflex-custom-components"]
|
||||
|
||||
dependencies = ["reflex>=0.4.2"]
|
||||
dependencies = ["reflex>={{ reflex_version }}"]
|
||||
|
||||
classifiers = ["Development Status :: 4 - Beta"]
|
||||
|
||||
|
@ -1,12 +1,15 @@
|
||||
{% extends "web/pages/base_page.js.jinja2" %}
|
||||
|
||||
{% block early_imports %}
|
||||
import '/styles/styles.css'
|
||||
import '$/styles/styles.css'
|
||||
{% endblock %}
|
||||
|
||||
{% block declaration %}
|
||||
import { EventLoopProvider, StateProvider, defaultColorMode } from "/utils/context.js";
|
||||
import { EventLoopProvider, StateProvider, defaultColorMode } from "$/utils/context.js";
|
||||
import { ThemeProvider } from 'next-themes'
|
||||
{% for library_alias, library_path in window_libraries %}
|
||||
import * as {{library_alias}} from "{{library_path}}";
|
||||
{% endfor %}
|
||||
|
||||
{% for custom_code in custom_codes %}
|
||||
{{custom_code}}
|
||||
@ -26,8 +29,17 @@ function AppWrap({children}) {
|
||||
}
|
||||
|
||||
export default function MyApp({ Component, pageProps }) {
|
||||
React.useEffect(() => {
|
||||
// Make contexts and state objects available globally for dynamic eval'd components
|
||||
let windowImports = {
|
||||
{% for library_alias, library_path in window_libraries %}
|
||||
"{{library_path}}": {{library_alias}},
|
||||
{% endfor %}
|
||||
};
|
||||
window["__reflex"] = windowImports;
|
||||
}, []);
|
||||
return (
|
||||
<ThemeProvider defaultTheme={ defaultColorMode } storageKey="chakra-ui-color-mode" attribute="class">
|
||||
<ThemeProvider defaultTheme={ defaultColorMode } attribute="class">
|
||||
<AppWrap>
|
||||
<StateProvider>
|
||||
<EventLoopProvider>
|
||||
|
@ -36,14 +36,10 @@
|
||||
{# component: component dictionary #}
|
||||
{% macro render_tag(component) %}
|
||||
<{{component.name}} {{- render_props(component.props) }}>
|
||||
{%- if component.args is not none -%}
|
||||
{{- render_arg_content(component) }}
|
||||
{%- else -%}
|
||||
{{ component.contents }}
|
||||
{% for child in component.children %}
|
||||
{{ render(child) }}
|
||||
{% endfor %}
|
||||
{%- endif -%}
|
||||
{{ component.contents }}
|
||||
{% for child in component.children %}
|
||||
{{ render(child) }}
|
||||
{% endfor %}
|
||||
</{{component.name}}>
|
||||
{%- endmacro %}
|
||||
|
||||
@ -85,10 +81,10 @@
|
||||
{% macro render_match_tag(component) %}
|
||||
{
|
||||
(() => {
|
||||
switch (JSON.stringify({{ component.cond._var_name }})) {
|
||||
switch (JSON.stringify({{ component.cond._js_expr }})) {
|
||||
{% for case in component.match_cases %}
|
||||
{% for condition in case[:-1] %}
|
||||
case JSON.stringify({{ condition._var_name }}):
|
||||
case JSON.stringify({{ condition._js_expr }}):
|
||||
{% endfor %}
|
||||
return {{ case[-1] }};
|
||||
break;
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { createContext, useContext, useMemo, useReducer, useState } from "react"
|
||||
import { applyDelta, Event, hydrateClientStorage, useEventLoop, refs } from "/utils/state.js"
|
||||
import { applyDelta, Event, hydrateClientStorage, useEventLoop, refs } from "$/utils/state.js"
|
||||
|
||||
{% if initial_state %}
|
||||
export const initialState = {{ initial_state|json_dumps }}
|
||||
@ -59,6 +59,8 @@ export const initialEvents = () => [
|
||||
{% else %}
|
||||
export const state_name = undefined
|
||||
|
||||
export const exception_state_name = undefined
|
||||
|
||||
export const onLoadInternalEvent = () => []
|
||||
|
||||
export const initialEvents = () => []
|
||||
|
@ -1,36 +0,0 @@
|
||||
import { useColorMode as chakraUseColorMode } from "@chakra-ui/react";
|
||||
import { useTheme } from "next-themes";
|
||||
import { useEffect, useState } from "react";
|
||||
import { ColorModeContext, defaultColorMode } from "/utils/context.js";
|
||||
|
||||
export default function ChakraColorModeProvider({ children }) {
|
||||
const { theme, resolvedTheme, setTheme } = useTheme();
|
||||
const { colorMode, toggleColorMode } = chakraUseColorMode();
|
||||
const [resolvedColorMode, setResolvedColorMode] = useState(colorMode);
|
||||
|
||||
useEffect(() => {
|
||||
if (colorMode != resolvedTheme) {
|
||||
toggleColorMode();
|
||||
}
|
||||
setResolvedColorMode(resolvedTheme);
|
||||
}, [theme, resolvedTheme]);
|
||||
|
||||
const rawColorMode = colorMode;
|
||||
const setColorMode = (mode) => {
|
||||
const allowedModes = ["light", "dark", "system"];
|
||||
if (!allowedModes.includes(mode)) {
|
||||
console.error(
|
||||
`Invalid color mode "${mode}". Defaulting to "${defaultColorMode}".`
|
||||
);
|
||||
mode = defaultColorMode;
|
||||
}
|
||||
setTheme(mode);
|
||||
};
|
||||
return (
|
||||
<ColorModeContext.Provider
|
||||
value={{ rawColorMode, resolvedColorMode, toggleColorMode, setColorMode }}
|
||||
>
|
||||
{children}
|
||||
</ColorModeContext.Provider>
|
||||
);
|
||||
}
|
@ -4,8 +4,8 @@ import {
|
||||
ColorModeContext,
|
||||
defaultColorMode,
|
||||
isDevMode,
|
||||
lastCompiledTimeStamp
|
||||
} from "/utils/context.js";
|
||||
lastCompiledTimeStamp,
|
||||
} from "$/utils/context.js";
|
||||
|
||||
export default function RadixThemesColorModeProvider({ children }) {
|
||||
const { theme, resolvedTheme, setTheme } = useTheme();
|
||||
@ -37,7 +37,7 @@ export default function RadixThemesColorModeProvider({ children }) {
|
||||
const allowedModes = ["light", "dark", "system"];
|
||||
if (!allowedModes.includes(mode)) {
|
||||
console.error(
|
||||
`Invalid color mode "${mode}". Defaulting to "${defaultColorMode}".`,
|
||||
`Invalid color mode "${mode}". Defaulting to "${defaultColorMode}".`
|
||||
);
|
||||
mode = defaultColorMode;
|
||||
}
|
||||
|
34
reflex/.templates/web/components/shiki/code.js
Normal file
34
reflex/.templates/web/components/shiki/code.js
Normal file
@ -0,0 +1,34 @@
|
||||
import { useEffect, useState } from "react"
|
||||
import { codeToHtml} from "shiki"
|
||||
|
||||
/**
|
||||
* Code component that uses Shiki to convert code to HTML and render it.
|
||||
*
|
||||
* @param code - The code to be highlighted.
|
||||
* @param theme - The theme to be used for highlighting.
|
||||
* @param language - The language of the code.
|
||||
* @param transformers - The transformers to be applied to the code.
|
||||
* @param decorations - The decorations to be applied to the code.
|
||||
* @param divProps - Additional properties to be passed to the div element.
|
||||
* @returns The rendered code block.
|
||||
*/
|
||||
export function Code ({code, theme, language, transformers, decorations, ...divProps}) {
|
||||
const [codeResult, setCodeResult] = useState("")
|
||||
useEffect(() => {
|
||||
async function fetchCode() {
|
||||
const result = await codeToHtml(code, {
|
||||
lang: language,
|
||||
theme,
|
||||
transformers,
|
||||
decorations
|
||||
});
|
||||
setCodeResult(result);
|
||||
}
|
||||
fetchCode();
|
||||
}, [code, language, theme, transformers, decorations]
|
||||
|
||||
)
|
||||
return (
|
||||
<div dangerouslySetInnerHTML={{__html: codeResult}} {...divProps} ></div>
|
||||
)
|
||||
}
|
@ -2,7 +2,8 @@
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"$/*": ["*"],
|
||||
"@/*": ["public/*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
import axios from "axios";
|
||||
import io from "socket.io-client";
|
||||
import JSON5 from "json5";
|
||||
import env from "/env.json";
|
||||
import env from "$/env.json";
|
||||
import Cookies from "universal-cookie";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import Router, { useRouter } from "next/router";
|
||||
@ -12,9 +12,9 @@ import {
|
||||
onLoadInternalEvent,
|
||||
state_name,
|
||||
exception_state_name,
|
||||
} from "utils/context.js";
|
||||
import debounce from "/utils/helpers/debounce";
|
||||
import throttle from "/utils/helpers/throttle";
|
||||
} from "$/utils/context.js";
|
||||
import debounce from "$/utils/helpers/debounce";
|
||||
import throttle from "$/utils/helpers/throttle";
|
||||
|
||||
// Endpoint URLs.
|
||||
const EVENTURL = env.EVENT;
|
||||
@ -117,8 +117,8 @@ export const isStateful = () => {
|
||||
if (event_queue.length === 0) {
|
||||
return false;
|
||||
}
|
||||
return event_queue.some(event => event.name.startsWith("reflex___state"));
|
||||
}
|
||||
return event_queue.some((event) => event.name.startsWith("reflex___state"));
|
||||
};
|
||||
|
||||
/**
|
||||
* Apply a delta to the state.
|
||||
@ -129,6 +129,21 @@ export const applyDelta = (state, delta) => {
|
||||
return { ...state, ...delta };
|
||||
};
|
||||
|
||||
/**
|
||||
* Evaluate a dynamic component.
|
||||
* @param component The component to evaluate.
|
||||
* @returns The evaluated component.
|
||||
*/
|
||||
export const evalReactComponent = async (component) => {
|
||||
if (!window.React && window.__reflex) {
|
||||
window.React = window.__reflex.react;
|
||||
}
|
||||
const encodedJs = encodeURIComponent(component);
|
||||
const dataUri = "data:text/javascript;charset=utf-8," + encodedJs;
|
||||
const module = await eval(`import(dataUri)`);
|
||||
return module.default;
|
||||
};
|
||||
|
||||
/**
|
||||
* Only Queue and process events when websocket connection exists.
|
||||
* @param event The event to queue.
|
||||
@ -141,7 +156,7 @@ export const queueEventIfSocketExists = async (events, socket) => {
|
||||
return;
|
||||
}
|
||||
await queueEvents(events, socket);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle frontend event or send the event to the backend via Websocket.
|
||||
@ -208,7 +223,10 @@ export const applyEvent = async (event, socket) => {
|
||||
const a = document.createElement("a");
|
||||
a.hidden = true;
|
||||
// Special case when linking to uploaded files
|
||||
a.href = event.payload.url.replace("${getBackendURL(env.UPLOAD)}", getBackendURL(env.UPLOAD))
|
||||
a.href = event.payload.url.replace(
|
||||
"${getBackendURL(env.UPLOAD)}",
|
||||
getBackendURL(env.UPLOAD)
|
||||
);
|
||||
a.download = event.payload.filename;
|
||||
a.click();
|
||||
a.remove();
|
||||
@ -249,7 +267,7 @@ export const applyEvent = async (event, socket) => {
|
||||
} catch (e) {
|
||||
console.log("_call_script", e);
|
||||
if (window && window?.onerror) {
|
||||
window.onerror(e.message, null, null, null, e)
|
||||
window.onerror(e.message, null, null, null, e);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@ -290,10 +308,9 @@ export const applyEvent = async (event, socket) => {
|
||||
export const applyRestEvent = async (event, socket) => {
|
||||
let eventSent = false;
|
||||
if (event.handler === "uploadFiles") {
|
||||
|
||||
if (event.payload.files === undefined || event.payload.files.length === 0) {
|
||||
// Submit the event over the websocket to trigger the event handler.
|
||||
return await applyEvent(Event(event.name), socket)
|
||||
return await applyEvent(Event(event.name), socket);
|
||||
}
|
||||
|
||||
// Start upload, but do not wait for it, which would block other events.
|
||||
@ -397,7 +414,7 @@ export const connect = async (
|
||||
console.log("Disconnect backend before bfcache on navigation");
|
||||
socket.current.disconnect();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Once the socket is open, hydrate the page.
|
||||
socket.current.on("connect", () => {
|
||||
@ -416,7 +433,7 @@ export const connect = async (
|
||||
});
|
||||
|
||||
// On each received message, queue the updates and events.
|
||||
socket.current.on("event", (message) => {
|
||||
socket.current.on("event", async (message) => {
|
||||
const update = JSON5.parse(message);
|
||||
for (const substate in update.delta) {
|
||||
dispatch[substate](update.delta[substate]);
|
||||
@ -525,13 +542,19 @@ export const uploadFiles = async (
|
||||
|
||||
/**
|
||||
* Create an event object.
|
||||
* @param name The name of the event.
|
||||
* @param payload The payload of the event.
|
||||
* @param handler The client handler to process event.
|
||||
* @param {string} name The name of the event.
|
||||
* @param {Object.<string, Any>} payload The payload of the event.
|
||||
* @param {Object.<string, (number|boolean)>} event_actions The actions to take on the event.
|
||||
* @param {string} handler The client handler to process event.
|
||||
* @returns The event object.
|
||||
*/
|
||||
export const Event = (name, payload = {}, handler = null) => {
|
||||
return { name, payload, handler };
|
||||
export const Event = (
|
||||
name,
|
||||
payload = {},
|
||||
event_actions = {},
|
||||
handler = null
|
||||
) => {
|
||||
return { name, payload, handler, event_actions };
|
||||
};
|
||||
|
||||
/**
|
||||
@ -574,7 +597,11 @@ export const hydrateClientStorage = (client_storage) => {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (client_storage.cookies || client_storage.local_storage || client_storage.session_storage) {
|
||||
if (
|
||||
client_storage.cookies ||
|
||||
client_storage.local_storage ||
|
||||
client_storage.session_storage
|
||||
) {
|
||||
return client_storage_values;
|
||||
}
|
||||
return {};
|
||||
@ -614,15 +641,17 @@ const applyClientStorageDelta = (client_storage, delta) => {
|
||||
) {
|
||||
const options = client_storage.local_storage[state_key];
|
||||
localStorage.setItem(options.name || state_key, delta[substate][key]);
|
||||
} else if(
|
||||
} else if (
|
||||
client_storage.session_storage &&
|
||||
state_key in client_storage.session_storage &&
|
||||
typeof window !== "undefined"
|
||||
) {
|
||||
const session_options = client_storage.session_storage[state_key];
|
||||
sessionStorage.setItem(session_options.name || state_key, delta[substate][key]);
|
||||
sessionStorage.setItem(
|
||||
session_options.name || state_key,
|
||||
delta[substate][key]
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -651,7 +680,13 @@ export const useEventLoop = (
|
||||
if (!(args instanceof Array)) {
|
||||
args = [args];
|
||||
}
|
||||
const _e = args.filter((o) => o?.preventDefault !== undefined)[0]
|
||||
|
||||
event_actions = events.reduce(
|
||||
(acc, e) => ({ ...acc, ...e.event_actions }),
|
||||
event_actions ?? {}
|
||||
);
|
||||
|
||||
const _e = args.filter((o) => o?.preventDefault !== undefined)[0];
|
||||
|
||||
if (event_actions?.preventDefault && _e?.preventDefault) {
|
||||
_e.preventDefault();
|
||||
@ -671,7 +706,7 @@ export const useEventLoop = (
|
||||
debounce(
|
||||
combined_name,
|
||||
() => queueEvents(events, socket),
|
||||
event_actions.debounce,
|
||||
event_actions.debounce
|
||||
);
|
||||
} else {
|
||||
queueEvents(events, socket);
|
||||
@ -696,30 +731,34 @@ export const useEventLoop = (
|
||||
}
|
||||
}, [router.isReady]);
|
||||
|
||||
// Handle frontend errors and send them to the backend via websocket.
|
||||
useEffect(() => {
|
||||
|
||||
if (typeof window === 'undefined') {
|
||||
return;
|
||||
}
|
||||
|
||||
window.onerror = function (msg, url, lineNo, columnNo, error) {
|
||||
addEvents([Event(`${exception_state_name}.handle_frontend_exception`, {
|
||||
stack: error.stack,
|
||||
})])
|
||||
return false;
|
||||
}
|
||||
// Handle frontend errors and send them to the backend via websocket.
|
||||
useEffect(() => {
|
||||
if (typeof window === "undefined") {
|
||||
return;
|
||||
}
|
||||
|
||||
//NOTE: Only works in Chrome v49+
|
||||
//https://github.com/mknichel/javascript-errors?tab=readme-ov-file#promise-rejection-events
|
||||
window.onunhandledrejection = function (event) {
|
||||
addEvents([Event(`${exception_state_name}.handle_frontend_exception`, {
|
||||
stack: event.reason.stack,
|
||||
})])
|
||||
return false;
|
||||
}
|
||||
|
||||
},[])
|
||||
window.onerror = function (msg, url, lineNo, columnNo, error) {
|
||||
addEvents([
|
||||
Event(`${exception_state_name}.handle_frontend_exception`, {
|
||||
stack: error.stack,
|
||||
component_stack: "",
|
||||
}),
|
||||
]);
|
||||
return false;
|
||||
};
|
||||
|
||||
//NOTE: Only works in Chrome v49+
|
||||
//https://github.com/mknichel/javascript-errors?tab=readme-ov-file#promise-rejection-events
|
||||
window.onunhandledrejection = function (event) {
|
||||
addEvents([
|
||||
Event(`${exception_state_name}.handle_frontend_exception`, {
|
||||
stack: event.reason.stack,
|
||||
component_stack: "",
|
||||
}),
|
||||
]);
|
||||
return false;
|
||||
};
|
||||
}, []);
|
||||
|
||||
// Main event loop.
|
||||
useEffect(() => {
|
||||
@ -782,11 +821,11 @@ export const useEventLoop = (
|
||||
// Route after the initial page hydration.
|
||||
useEffect(() => {
|
||||
const change_start = () => {
|
||||
const main_state_dispatch = dispatch["reflex___state____state"]
|
||||
const main_state_dispatch = dispatch["reflex___state____state"];
|
||||
if (main_state_dispatch !== undefined) {
|
||||
main_state_dispatch({ is_hydrated: false })
|
||||
main_state_dispatch({ is_hydrated: false });
|
||||
}
|
||||
}
|
||||
};
|
||||
const change_complete = () => addEvents(onLoadInternalEvent());
|
||||
router.events.on("routeChangeStart", change_start);
|
||||
router.events.on("routeChangeComplete", change_complete);
|
||||
@ -805,7 +844,9 @@ export const useEventLoop = (
|
||||
* @returns True if the value is truthy, false otherwise.
|
||||
*/
|
||||
export const isTrue = (val) => {
|
||||
return Array.isArray(val) ? val.length > 0 : !!val;
|
||||
if (Array.isArray(val)) return val.length > 0;
|
||||
if (val === Object(val)) return Object.keys(val).length > 0;
|
||||
return Boolean(val);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -89,6 +89,8 @@ from reflex.utils import (
|
||||
lazy_loader,
|
||||
)
|
||||
|
||||
from .event import event as event
|
||||
|
||||
# import this here explicitly to avoid returning the page module since page attr has the
|
||||
# same name as page module(page.py)
|
||||
from .page import page as page
|
||||
@ -206,6 +208,13 @@ RADIX_PRIMITIVES_MAPPING: dict = {
|
||||
"components.radix.primitives.form": [
|
||||
"form",
|
||||
],
|
||||
"components.radix.primitives.progress": [
|
||||
"progress",
|
||||
],
|
||||
}
|
||||
|
||||
RADIX_PRIMITIVES_SHORTCUT_MAPPING: dict = {
|
||||
k: v for k, v in RADIX_PRIMITIVES_MAPPING.items() if "progress" not in k
|
||||
}
|
||||
|
||||
COMPONENTS_CORE_MAPPING: dict = {
|
||||
@ -248,7 +257,7 @@ RADIX_MAPPING: dict = {
|
||||
**RADIX_THEMES_COMPONENTS_MAPPING,
|
||||
**RADIX_THEMES_TYPOGRAPHY_MAPPING,
|
||||
**RADIX_THEMES_LAYOUT_MAPPING,
|
||||
**RADIX_PRIMITIVES_MAPPING,
|
||||
**RADIX_PRIMITIVES_SHORTCUT_MAPPING,
|
||||
}
|
||||
|
||||
_MAPPING: dict = {
|
||||
@ -311,25 +320,27 @@ _MAPPING: dict = {
|
||||
"upload_files",
|
||||
"window_alert",
|
||||
],
|
||||
"istate.storage": [
|
||||
"Cookie",
|
||||
"LocalStorage",
|
||||
"SessionStorage",
|
||||
],
|
||||
"middleware": ["middleware", "Middleware"],
|
||||
"model": ["session", "Model"],
|
||||
"state": [
|
||||
"var",
|
||||
"Cookie",
|
||||
"LocalStorage",
|
||||
"SessionStorage",
|
||||
"ComponentState",
|
||||
"State",
|
||||
"dynamic",
|
||||
],
|
||||
"style": ["Style", "toggle_color_mode"],
|
||||
"utils.imports": ["ImportVar"],
|
||||
"utils.serializers": ["serializer"],
|
||||
"vars": ["Var"],
|
||||
"vars": ["Var", "field", "Field"],
|
||||
}
|
||||
|
||||
_SUBMODULES: set[str] = {
|
||||
"components",
|
||||
"event",
|
||||
"app",
|
||||
"style",
|
||||
"admin",
|
||||
@ -338,7 +349,6 @@ _SUBMODULES: set[str] = {
|
||||
"testing",
|
||||
"utils",
|
||||
"vars",
|
||||
"ivars",
|
||||
"config",
|
||||
"compiler",
|
||||
}
|
||||
|
@ -11,8 +11,6 @@ from . import base as base
|
||||
from . import compiler as compiler
|
||||
from . import components as components
|
||||
from . import config as config
|
||||
from . import event as event
|
||||
from . import ivars as ivars
|
||||
from . import model as model
|
||||
from . import style as style
|
||||
from . import testing as testing
|
||||
@ -132,6 +130,7 @@ from .components.radix.themes.layout.container import container as container
|
||||
from .components.radix.themes.layout.flex import flex as flex
|
||||
from .components.radix.themes.layout.grid import grid as grid
|
||||
from .components.radix.themes.layout.list import list_item as list_item
|
||||
from .components.radix.themes.layout.list import list_ns as list # noqa
|
||||
from .components.radix.themes.layout.list import ordered_list as ordered_list
|
||||
from .components.radix.themes.layout.list import unordered_list as unordered_list
|
||||
from .components.radix.themes.layout.section import section as section
|
||||
@ -161,6 +160,7 @@ from .event import clear_local_storage as clear_local_storage
|
||||
from .event import clear_session_storage as clear_session_storage
|
||||
from .event import console_log as console_log
|
||||
from .event import download as download
|
||||
from .event import event as event
|
||||
from .event import prevent_default as prevent_default
|
||||
from .event import redirect as redirect
|
||||
from .event import remove_cookie as remove_cookie
|
||||
@ -174,22 +174,25 @@ from .event import stop_propagation as stop_propagation
|
||||
from .event import upload_files as upload_files
|
||||
from .event import window_alert as window_alert
|
||||
from .experimental import _x as _x
|
||||
from .istate.storage import Cookie as Cookie
|
||||
from .istate.storage import LocalStorage as LocalStorage
|
||||
from .istate.storage import SessionStorage as SessionStorage
|
||||
from .middleware import Middleware as Middleware
|
||||
from .middleware import middleware as middleware
|
||||
from .model import Model as Model
|
||||
from .model import session as session
|
||||
from .page import page as page
|
||||
from .state import ComponentState as ComponentState
|
||||
from .state import Cookie as Cookie
|
||||
from .state import LocalStorage as LocalStorage
|
||||
from .state import SessionStorage as SessionStorage
|
||||
from .state import State as State
|
||||
from .state import dynamic as dynamic
|
||||
from .state import var as var
|
||||
from .style import Style as Style
|
||||
from .style import toggle_color_mode as toggle_color_mode
|
||||
from .utils.imports import ImportVar as ImportVar
|
||||
from .utils.serializers import serializer as serializer
|
||||
from .vars import Field as Field
|
||||
from .vars import Var as Var
|
||||
from .vars import field as field
|
||||
|
||||
del compat
|
||||
RADIX_THEMES_MAPPING: dict
|
||||
@ -197,6 +200,7 @@ RADIX_THEMES_COMPONENTS_MAPPING: dict
|
||||
RADIX_THEMES_LAYOUT_MAPPING: dict
|
||||
RADIX_THEMES_TYPOGRAPHY_MAPPING: dict
|
||||
RADIX_PRIMITIVES_MAPPING: dict
|
||||
RADIX_PRIMITIVES_SHORTCUT_MAPPING: dict
|
||||
COMPONENTS_CORE_MAPPING: dict
|
||||
COMPONENTS_BASE_MAPPING: dict
|
||||
RADIX_MAPPING: dict
|
||||
|
340
reflex/app.py
340
reflex/app.py
@ -6,9 +6,11 @@ import asyncio
|
||||
import concurrent.futures
|
||||
import contextlib
|
||||
import copy
|
||||
import dataclasses
|
||||
import functools
|
||||
import inspect
|
||||
import io
|
||||
import json
|
||||
import multiprocessing
|
||||
import os
|
||||
import platform
|
||||
@ -17,6 +19,7 @@ import traceback
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from typing import (
|
||||
TYPE_CHECKING,
|
||||
Any,
|
||||
AsyncIterator,
|
||||
Callable,
|
||||
@ -43,10 +46,12 @@ from starlette_admin.contrib.sqla.view import ModelView
|
||||
from reflex import constants
|
||||
from reflex.admin import AdminDash
|
||||
from reflex.app_mixins import AppMixin, LifespanMixin, MiddlewareMixin
|
||||
from reflex.base import Base
|
||||
from reflex.compiler import compiler
|
||||
from reflex.compiler import utils as compiler_utils
|
||||
from reflex.compiler.compiler import ExecutorSafeFunctions
|
||||
from reflex.compiler.compiler import (
|
||||
ExecutorSafeFunctions,
|
||||
compile_theme,
|
||||
)
|
||||
from reflex.components.base.app_wrap import AppWrap
|
||||
from reflex.components.base.error_boundary import ErrorBoundary
|
||||
from reflex.components.base.fragment import Fragment
|
||||
@ -63,8 +68,15 @@ from reflex.components.core.client_side_routing import (
|
||||
)
|
||||
from reflex.components.core.upload import Upload, get_upload_dir
|
||||
from reflex.components.radix import themes
|
||||
from reflex.config import get_config
|
||||
from reflex.event import Event, EventHandler, EventSpec, window_alert
|
||||
from reflex.config import environment, get_config
|
||||
from reflex.event import (
|
||||
Event,
|
||||
EventHandler,
|
||||
EventSpec,
|
||||
EventType,
|
||||
IndividualEventType,
|
||||
window_alert,
|
||||
)
|
||||
from reflex.model import Model, get_db_status
|
||||
from reflex.page import (
|
||||
DECORATED_PAGES,
|
||||
@ -87,6 +99,9 @@ from reflex.utils import codespaces, console, exceptions, format, prerequisites,
|
||||
from reflex.utils.exec import is_prod_mode, is_testing_env, should_skip_compile
|
||||
from reflex.utils.imports import ImportVar
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from reflex.vars import Var
|
||||
|
||||
# Define custom types.
|
||||
ComponentCallable = Callable[[], Component]
|
||||
Reducer = Callable[[Event], Coroutine[Any, Any, StateUpdate]]
|
||||
@ -169,7 +184,23 @@ class OverlayFragment(Fragment):
|
||||
pass
|
||||
|
||||
|
||||
class App(MiddlewareMixin, LifespanMixin, Base):
|
||||
@dataclasses.dataclass(
|
||||
frozen=True,
|
||||
)
|
||||
class UnevaluatedPage:
|
||||
"""An uncompiled page."""
|
||||
|
||||
component: Union[Component, ComponentCallable]
|
||||
route: str
|
||||
title: Union[Var, str, None]
|
||||
description: Union[Var, str, None]
|
||||
image: str
|
||||
on_load: Union[EventType[[]], None]
|
||||
meta: List[Dict[str, str]]
|
||||
|
||||
|
||||
@dataclasses.dataclass()
|
||||
class App(MiddlewareMixin, LifespanMixin):
|
||||
"""The main Reflex app that encapsulates the backend and frontend.
|
||||
|
||||
Every Reflex app needs an app defined in its main module.
|
||||
@ -191,24 +222,26 @@ class App(MiddlewareMixin, LifespanMixin, Base):
|
||||
"""
|
||||
|
||||
# The global [theme](https://reflex.dev/docs/styling/theming/#theme) for the entire app.
|
||||
theme: Optional[Component] = themes.theme(accent_color="blue")
|
||||
theme: Optional[Component] = dataclasses.field(
|
||||
default_factory=lambda: themes.theme(accent_color="blue")
|
||||
)
|
||||
|
||||
# The [global style](https://reflex.dev/docs/styling/overview/#global-styles}) for the app.
|
||||
style: ComponentStyle = {}
|
||||
style: ComponentStyle = dataclasses.field(default_factory=dict)
|
||||
|
||||
# A list of URLs to [stylesheets](https://reflex.dev/docs/styling/custom-stylesheets/) to include in the app.
|
||||
stylesheets: List[str] = []
|
||||
stylesheets: List[str] = dataclasses.field(default_factory=list)
|
||||
|
||||
# A component that is present on every page (defaults to the Connection Error banner).
|
||||
overlay_component: Optional[Union[Component, ComponentCallable]] = (
|
||||
default_overlay_component()
|
||||
dataclasses.field(default_factory=default_overlay_component)
|
||||
)
|
||||
|
||||
# Error boundary component to wrap the app with.
|
||||
error_boundary: Optional[ComponentCallable] = default_error_boundary
|
||||
|
||||
# Components to add to the head of every page.
|
||||
head_components: List[Component] = []
|
||||
head_components: List[Component] = dataclasses.field(default_factory=list)
|
||||
|
||||
# The Socket.IO AsyncServer instance.
|
||||
sio: Optional[AsyncServer] = None
|
||||
@ -219,8 +252,13 @@ class App(MiddlewareMixin, LifespanMixin, Base):
|
||||
# Attributes to add to the html root tag of every page.
|
||||
html_custom_attrs: Optional[Dict[str, str]] = None
|
||||
|
||||
# A map from a route to an unevaluated page. PRIVATE.
|
||||
unevaluated_pages: Dict[str, UnevaluatedPage] = dataclasses.field(
|
||||
default_factory=dict
|
||||
)
|
||||
|
||||
# A map from a page route to the component to render. Users should use `add_page`. PRIVATE.
|
||||
pages: Dict[str, Component] = {}
|
||||
pages: Dict[str, Component] = dataclasses.field(default_factory=dict)
|
||||
|
||||
# The backend API object. PRIVATE.
|
||||
api: FastAPI = None # type: ignore
|
||||
@ -232,7 +270,9 @@ class App(MiddlewareMixin, LifespanMixin, Base):
|
||||
_state_manager: Optional[StateManager] = None
|
||||
|
||||
# Mapping from a route to event handlers to trigger when the page loads. PRIVATE.
|
||||
load_events: Dict[str, List[Union[EventHandler, EventSpec]]] = {}
|
||||
load_events: Dict[str, List[IndividualEventType[[]]]] = dataclasses.field(
|
||||
default_factory=dict
|
||||
)
|
||||
|
||||
# Admin dashboard to view and manage the database. PRIVATE.
|
||||
admin_dash: Optional[AdminDash] = None
|
||||
@ -241,7 +281,7 @@ class App(MiddlewareMixin, LifespanMixin, Base):
|
||||
event_namespace: Optional[EventNamespace] = None
|
||||
|
||||
# Background tasks that are currently running. PRIVATE.
|
||||
background_tasks: Set[asyncio.Task] = set()
|
||||
background_tasks: Set[asyncio.Task] = dataclasses.field(default_factory=set)
|
||||
|
||||
# Frontend Error Handler Function
|
||||
frontend_exception_handler: Callable[[Exception], None] = (
|
||||
@ -253,23 +293,14 @@ class App(MiddlewareMixin, LifespanMixin, Base):
|
||||
[Exception], Union[EventSpec, List[EventSpec], None]
|
||||
] = default_backend_exception_handler
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
def __post_init__(self):
|
||||
"""Initialize the app.
|
||||
|
||||
Args:
|
||||
**kwargs: Kwargs to initialize the app with.
|
||||
|
||||
Raises:
|
||||
ValueError: If the event namespace is not provided in the config.
|
||||
Also, if there are multiple client subclasses of rx.BaseState(Subclasses of rx.BaseState should consist
|
||||
of the DefaultState and the client app state).
|
||||
"""
|
||||
if "connect_error_component" in kwargs:
|
||||
raise ValueError(
|
||||
"`connect_error_component` is deprecated, use `overlay_component` instead"
|
||||
)
|
||||
super().__init__(**kwargs)
|
||||
|
||||
# Special case to allow test cases have multiple subclasses of rx.BaseState.
|
||||
if not is_testing_env() and BaseState.__subclasses__() != [State]:
|
||||
# Only rx.State is allowed as Base State subclass.
|
||||
@ -380,8 +411,8 @@ class App(MiddlewareMixin, LifespanMixin, Base):
|
||||
|
||||
def _add_optional_endpoints(self):
|
||||
"""Add optional api endpoints (_upload)."""
|
||||
# To upload files.
|
||||
if Upload.is_used:
|
||||
# To upload files.
|
||||
self.api.post(str(constants.Endpoint.UPLOAD))(upload(self))
|
||||
|
||||
# To access uploaded files.
|
||||
@ -430,36 +461,21 @@ class App(MiddlewareMixin, LifespanMixin, Base):
|
||||
The generated component.
|
||||
|
||||
Raises:
|
||||
VarOperationTypeError: When an invalid component var related function is passed.
|
||||
TypeError: When an invalid component function is passed.
|
||||
exceptions.MatchTypeError: If the return types of match cases in rx.match are different.
|
||||
"""
|
||||
from reflex.utils.exceptions import VarOperationTypeError
|
||||
|
||||
try:
|
||||
return component if isinstance(component, Component) else component()
|
||||
except exceptions.MatchTypeError:
|
||||
raise
|
||||
except TypeError as e:
|
||||
message = str(e)
|
||||
if "Var" in message:
|
||||
raise VarOperationTypeError(
|
||||
"You may be trying to use an invalid Python function on a state var. "
|
||||
"When referencing a var inside your render code, only limited var operations are supported. "
|
||||
"See the var operation docs here: https://reflex.dev/docs/vars/var-operations/"
|
||||
) from e
|
||||
raise e
|
||||
|
||||
def add_page(
|
||||
self,
|
||||
component: Component | ComponentCallable,
|
||||
route: str | None = None,
|
||||
title: str | None = None,
|
||||
description: str | None = None,
|
||||
title: str | Var | None = None,
|
||||
description: str | Var | None = None,
|
||||
image: str = constants.DefaultPage.IMAGE,
|
||||
on_load: (
|
||||
EventHandler | EventSpec | list[EventHandler | EventSpec] | None
|
||||
) = None,
|
||||
on_load: EventType[[]] | None = None,
|
||||
meta: list[dict[str, str]] = constants.DefaultPage.META_LIST,
|
||||
):
|
||||
"""Add a page to the app.
|
||||
@ -481,9 +497,8 @@ class App(MiddlewareMixin, LifespanMixin, Base):
|
||||
"""
|
||||
# If the route is not set, get it from the callable.
|
||||
if route is None:
|
||||
assert isinstance(
|
||||
component, Callable
|
||||
), "Route must be set if component is not a callable."
|
||||
if not isinstance(component, Callable):
|
||||
raise ValueError("Route must be set if component is not a callable.")
|
||||
# Format the route.
|
||||
route = format.format_route(component.__name__)
|
||||
else:
|
||||
@ -492,13 +507,13 @@ class App(MiddlewareMixin, LifespanMixin, Base):
|
||||
# Check if the route given is valid
|
||||
verify_route_validity(route)
|
||||
|
||||
if route in self.pages and os.getenv(constants.RELOAD_CONFIG):
|
||||
if route in self.unevaluated_pages and os.getenv(constants.RELOAD_CONFIG):
|
||||
# when the app is reloaded(typically for app harness tests), we should maintain
|
||||
# the latest render function of a route.This applies typically to decorated pages
|
||||
# since they are only added when app._compile is called.
|
||||
self.pages.pop(route)
|
||||
self.unevaluated_pages.pop(route)
|
||||
|
||||
if route in self.pages:
|
||||
if route in self.unevaluated_pages:
|
||||
route_name = (
|
||||
f"`{route}` or `/`"
|
||||
if route == constants.PageNames.INDEX_ROUTE
|
||||
@ -514,59 +529,39 @@ class App(MiddlewareMixin, LifespanMixin, Base):
|
||||
state = self.state if self.state else State
|
||||
state.setup_dynamic_args(get_route_args(route))
|
||||
|
||||
# Generate the component if it is a callable.
|
||||
component = self._generate_component(component)
|
||||
if on_load:
|
||||
self.load_events[route] = (
|
||||
on_load if isinstance(on_load, list) else [on_load]
|
||||
)
|
||||
|
||||
# unpack components that return tuples in an rx.fragment.
|
||||
if isinstance(component, tuple):
|
||||
component = Fragment.create(*component)
|
||||
|
||||
# Ensure state is enabled if this page uses state.
|
||||
if self.state is None:
|
||||
if on_load or component._has_stateful_event_triggers():
|
||||
self._enable_state()
|
||||
else:
|
||||
for var in component._get_vars(include_children=True):
|
||||
var_data = var._get_all_var_data()
|
||||
if not var_data:
|
||||
continue
|
||||
if not var_data.state:
|
||||
continue
|
||||
self._enable_state()
|
||||
break
|
||||
|
||||
component = OverlayFragment.create(component)
|
||||
|
||||
meta_args = {
|
||||
"title": (
|
||||
title
|
||||
if title is not None
|
||||
else format.make_default_page_title(get_config().app_name, route)
|
||||
),
|
||||
"image": image,
|
||||
"meta": meta,
|
||||
}
|
||||
|
||||
if description is not None:
|
||||
meta_args["description"] = description
|
||||
|
||||
# Add meta information to the component.
|
||||
compiler_utils.add_meta(
|
||||
component,
|
||||
**meta_args,
|
||||
self.unevaluated_pages[route] = UnevaluatedPage(
|
||||
component=component,
|
||||
route=route,
|
||||
title=title,
|
||||
description=description,
|
||||
image=image,
|
||||
on_load=on_load,
|
||||
meta=meta,
|
||||
)
|
||||
|
||||
def _compile_page(self, route: str):
|
||||
"""Compile a page.
|
||||
|
||||
Args:
|
||||
route: The route of the page to compile.
|
||||
"""
|
||||
component, enable_state = compiler.compile_unevaluated_page(
|
||||
route, self.unevaluated_pages[route], self.state, self.style, self.theme
|
||||
)
|
||||
|
||||
if enable_state:
|
||||
self._enable_state()
|
||||
|
||||
# Add the page.
|
||||
self._check_routes_conflict(route)
|
||||
self.pages[route] = component
|
||||
|
||||
# Add the load events.
|
||||
if on_load:
|
||||
if not isinstance(on_load, list):
|
||||
on_load = [on_load]
|
||||
self.load_events[route] = on_load
|
||||
|
||||
def get_load_events(self, route: str) -> list[EventHandler | EventSpec]:
|
||||
def get_load_events(self, route: str) -> list[IndividualEventType[[]]]:
|
||||
"""Get the load events for a route.
|
||||
|
||||
Args:
|
||||
@ -625,9 +620,7 @@ class App(MiddlewareMixin, LifespanMixin, Base):
|
||||
title: str = constants.Page404.TITLE,
|
||||
image: str = constants.Page404.IMAGE,
|
||||
description: str = constants.Page404.DESCRIPTION,
|
||||
on_load: (
|
||||
EventHandler | EventSpec | list[EventHandler | EventSpec] | None
|
||||
) = None,
|
||||
on_load: EventType[[]] | None = None,
|
||||
meta: list[dict[str, str]] = constants.DefaultPage.META_LIST,
|
||||
):
|
||||
"""Define a custom 404 page for any url having no match.
|
||||
@ -692,7 +685,7 @@ class App(MiddlewareMixin, LifespanMixin, Base):
|
||||
for i, tags in imports.items()
|
||||
if i not in constants.PackageJson.DEPENDENCIES
|
||||
and i not in constants.PackageJson.DEV_DEPENDENCIES
|
||||
and not any(i.startswith(prefix) for prefix in ["/", ".", "next/"])
|
||||
and not any(i.startswith(prefix) for prefix in ["/", "$/", ".", "next/"])
|
||||
and i != ""
|
||||
and any(tag.install for tag in tags)
|
||||
}
|
||||
@ -823,7 +816,7 @@ class App(MiddlewareMixin, LifespanMixin, Base):
|
||||
for dep in deps:
|
||||
if dep not in state.vars and dep not in state.backend_vars:
|
||||
raise exceptions.VarDependencyError(
|
||||
f"ComputedVar {var._var_name} on state {state.__name__} has an invalid dependency {dep}"
|
||||
f"ComputedVar {var._js_expr} on state {state.__name__} has an invalid dependency {dep}"
|
||||
)
|
||||
|
||||
for substate in state.class_subclasses:
|
||||
@ -840,13 +833,33 @@ class App(MiddlewareMixin, LifespanMixin, Base):
|
||||
"""
|
||||
from reflex.utils.exceptions import ReflexRuntimeError
|
||||
|
||||
self.pages = {}
|
||||
|
||||
def get_compilation_time() -> str:
|
||||
return str(datetime.now().time()).split(".")[0]
|
||||
|
||||
# Render a default 404 page if the user didn't supply one
|
||||
if constants.Page404.SLUG not in self.pages:
|
||||
if constants.Page404.SLUG not in self.unevaluated_pages:
|
||||
self.add_custom_404_page()
|
||||
|
||||
# Fix up the style.
|
||||
self.style = evaluate_style_namespaces(self.style)
|
||||
|
||||
# Add the app wrappers.
|
||||
app_wrappers: Dict[tuple[int, str], Component] = {
|
||||
# Default app wrap component renders {children}
|
||||
(0, "AppWrap"): AppWrap.create()
|
||||
}
|
||||
|
||||
if self.theme is not None:
|
||||
# If a theme component was provided, wrap the app with it
|
||||
app_wrappers[(20, "Theme")] = self.theme
|
||||
# Fix #2992 by removing the top-level appearance prop
|
||||
self.theme.appearance = None
|
||||
|
||||
for route in self.unevaluated_pages:
|
||||
self._compile_page(route)
|
||||
|
||||
# Add the optional endpoints (_upload)
|
||||
self._add_optional_endpoints()
|
||||
|
||||
@ -881,28 +894,15 @@ class App(MiddlewareMixin, LifespanMixin, Base):
|
||||
# Store the compile results.
|
||||
compile_results = []
|
||||
|
||||
# Add the app wrappers.
|
||||
app_wrappers: Dict[tuple[int, str], Component] = {
|
||||
# Default app wrap component renders {children}
|
||||
(0, "AppWrap"): AppWrap.create()
|
||||
}
|
||||
if self.theme is not None:
|
||||
# If a theme component was provided, wrap the app with it
|
||||
app_wrappers[(20, "Theme")] = self.theme
|
||||
|
||||
progress.advance(task)
|
||||
|
||||
# Fix up the style.
|
||||
self.style = evaluate_style_namespaces(self.style)
|
||||
|
||||
# Track imports and custom components found.
|
||||
all_imports = {}
|
||||
custom_components = set()
|
||||
|
||||
for _route, component in self.pages.items():
|
||||
# Merge the component style with the app style.
|
||||
component._add_style_recursive(self.style, self.theme)
|
||||
|
||||
# This has to happen before compiling stateful components as that
|
||||
# prevents recursive functions from reaching all components.
|
||||
for component in self.pages.values():
|
||||
# Add component._get_all_imports() to all_imports.
|
||||
all_imports.update(component._get_all_imports())
|
||||
|
||||
@ -912,8 +912,6 @@ class App(MiddlewareMixin, LifespanMixin, Base):
|
||||
# Add the custom components from the page to the set.
|
||||
custom_components |= component._get_all_custom_components()
|
||||
|
||||
progress.advance(task)
|
||||
|
||||
# Perform auto-memoization of stateful components.
|
||||
(
|
||||
stateful_components_path,
|
||||
@ -931,6 +929,8 @@ class App(MiddlewareMixin, LifespanMixin, Base):
|
||||
)
|
||||
compile_results.append((stateful_components_path, stateful_components_code))
|
||||
|
||||
progress.advance(task)
|
||||
|
||||
# Compile the root document before fork.
|
||||
compile_results.append(
|
||||
compiler.compile_document_root(
|
||||
@ -940,77 +940,50 @@ class App(MiddlewareMixin, LifespanMixin, Base):
|
||||
)
|
||||
)
|
||||
|
||||
# Compile the contexts before fork.
|
||||
compile_results.append(
|
||||
compiler.compile_contexts(self.state, self.theme),
|
||||
)
|
||||
# Fix #2992 by removing the top-level appearance prop
|
||||
if self.theme is not None:
|
||||
self.theme.appearance = None
|
||||
|
||||
app_root = self._app_root(app_wrappers=app_wrappers)
|
||||
|
||||
progress.advance(task)
|
||||
|
||||
# Prepopulate the global ExecutorSafeFunctions class with input data required by the compile functions.
|
||||
# This is required for multiprocessing to work, in presence of non-picklable inputs.
|
||||
for route, component in zip(self.pages, page_components):
|
||||
ExecutorSafeFunctions.COMPILE_PAGE_ARGS_BY_ROUTE[route] = (
|
||||
route,
|
||||
component,
|
||||
self.state,
|
||||
)
|
||||
|
||||
ExecutorSafeFunctions.COMPILE_APP_APP_ROOT = app_root
|
||||
ExecutorSafeFunctions.CUSTOM_COMPONENTS = custom_components
|
||||
ExecutorSafeFunctions.STYLE = self.style
|
||||
|
||||
# Use a forking process pool, if possible. Much faster, especially for large sites.
|
||||
# Fallback to ThreadPoolExecutor as something that will always work.
|
||||
executor = None
|
||||
if (
|
||||
platform.system() in ("Linux", "Darwin")
|
||||
and os.environ.get("REFLEX_COMPILE_PROCESSES") is not None
|
||||
and (number_of_processes := environment.REFLEX_COMPILE_PROCESSES)
|
||||
is not None
|
||||
):
|
||||
executor = concurrent.futures.ProcessPoolExecutor(
|
||||
max_workers=int(os.environ.get("REFLEX_COMPILE_PROCESSES", 0)) or None,
|
||||
max_workers=number_of_processes,
|
||||
mp_context=multiprocessing.get_context("fork"),
|
||||
)
|
||||
else:
|
||||
executor = concurrent.futures.ThreadPoolExecutor(
|
||||
max_workers=int(os.environ.get("REFLEX_COMPILE_THREADS", 0)) or None,
|
||||
max_workers=environment.REFLEX_COMPILE_THREADS
|
||||
)
|
||||
|
||||
for route, component in zip(self.pages, page_components):
|
||||
ExecutorSafeFunctions.COMPONENTS[route] = component
|
||||
|
||||
ExecutorSafeFunctions.STATE = self.state
|
||||
|
||||
with executor:
|
||||
result_futures = []
|
||||
custom_components_future = None
|
||||
|
||||
def _mark_complete(_=None):
|
||||
progress.advance(task)
|
||||
|
||||
def _submit_work(fn, *args, **kwargs):
|
||||
f = executor.submit(fn, *args, **kwargs)
|
||||
f.add_done_callback(_mark_complete)
|
||||
# f = executor.apipe(fn, *args, **kwargs)
|
||||
result_futures.append(f)
|
||||
|
||||
# Compile all page components.
|
||||
# Compile the pre-compiled pages.
|
||||
for route in self.pages:
|
||||
_submit_work(ExecutorSafeFunctions.compile_page, route)
|
||||
|
||||
# Compile the app wrapper.
|
||||
_submit_work(ExecutorSafeFunctions.compile_app)
|
||||
|
||||
# Compile the custom components.
|
||||
custom_components_future = executor.submit(
|
||||
ExecutorSafeFunctions.compile_custom_components,
|
||||
)
|
||||
custom_components_future.add_done_callback(_mark_complete)
|
||||
_submit_work(
|
||||
ExecutorSafeFunctions.compile_page,
|
||||
route,
|
||||
)
|
||||
|
||||
# Compile the root stylesheet with base styles.
|
||||
_submit_work(compiler.compile_root_stylesheet, self.stylesheets)
|
||||
|
||||
# Compile the theme.
|
||||
_submit_work(ExecutorSafeFunctions.compile_theme)
|
||||
_submit_work(compile_theme, self.style)
|
||||
|
||||
# Compile the Tailwind config.
|
||||
if config.tailwind is not None:
|
||||
@ -1024,21 +997,34 @@ class App(MiddlewareMixin, LifespanMixin, Base):
|
||||
# Wait for all compilation tasks to complete.
|
||||
for future in concurrent.futures.as_completed(result_futures):
|
||||
compile_results.append(future.result())
|
||||
progress.advance(task)
|
||||
|
||||
# Special case for custom_components, since we need the compiled imports
|
||||
# to install proper frontend packages.
|
||||
(
|
||||
*custom_components_result,
|
||||
custom_components_imports,
|
||||
) = custom_components_future.result()
|
||||
compile_results.append(custom_components_result)
|
||||
all_imports.update(custom_components_imports)
|
||||
app_root = self._app_root(app_wrappers=app_wrappers)
|
||||
|
||||
# Get imports from AppWrap components.
|
||||
all_imports.update(app_root._get_all_imports())
|
||||
|
||||
progress.advance(task)
|
||||
|
||||
# Compile the contexts.
|
||||
compile_results.append(
|
||||
compiler.compile_contexts(self.state, self.theme),
|
||||
)
|
||||
progress.advance(task)
|
||||
|
||||
# Compile the app root.
|
||||
compile_results.append(
|
||||
compiler.compile_app(app_root),
|
||||
)
|
||||
progress.advance(task)
|
||||
|
||||
# Compile custom components.
|
||||
*custom_components_result, custom_components_imports = (
|
||||
compiler.compile_components(custom_components)
|
||||
)
|
||||
compile_results.append(custom_components_result)
|
||||
all_imports.update(custom_components_imports)
|
||||
|
||||
progress.advance(task)
|
||||
progress.stop()
|
||||
|
||||
@ -1405,7 +1391,7 @@ def upload(app: App):
|
||||
if isinstance(func, EventHandler):
|
||||
if func.is_background:
|
||||
raise UploadTypeError(
|
||||
f"@rx.background is not supported for upload handler `{handler}`.",
|
||||
f"@rx.event(background=True) is not supported for upload handler `{handler}`.",
|
||||
)
|
||||
func = func.fn
|
||||
if isinstance(func, functools.partial):
|
||||
@ -1527,20 +1513,28 @@ class EventNamespace(AsyncNamespace):
|
||||
async def on_event(self, sid, data):
|
||||
"""Event for receiving front-end websocket events.
|
||||
|
||||
Raises:
|
||||
RuntimeError: If the Socket.IO is badly initialized.
|
||||
|
||||
Args:
|
||||
sid: The Socket.IO session id.
|
||||
data: The event data.
|
||||
"""
|
||||
fields = json.loads(data)
|
||||
# Get the event.
|
||||
event = Event.parse_raw(data)
|
||||
event = Event(
|
||||
**{k: v for k, v in fields.items() if k not in ("handler", "event_actions")}
|
||||
)
|
||||
|
||||
self.token_to_sid[event.token] = sid
|
||||
self.sid_to_token[sid] = event.token
|
||||
|
||||
# Get the event environment.
|
||||
assert self.app.sio is not None
|
||||
if self.app.sio is None:
|
||||
raise RuntimeError("Socket.IO is not initialized.")
|
||||
environ = self.app.sio.get_environ(sid, self.namespace)
|
||||
assert environ is not None
|
||||
if environ is None:
|
||||
raise RuntimeError("Socket.IO environ is not initialized.")
|
||||
|
||||
# Get the client headers.
|
||||
headers = {
|
||||
|
@ -4,21 +4,27 @@ from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import contextlib
|
||||
import dataclasses
|
||||
import functools
|
||||
import inspect
|
||||
import sys
|
||||
from typing import Callable, Coroutine, Set, Union
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
from reflex.utils import console
|
||||
from reflex.utils.exceptions import InvalidLifespanTaskType
|
||||
|
||||
from .mixin import AppMixin
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
class LifespanMixin(AppMixin):
|
||||
"""A Mixin that allow tasks to run during the whole app lifespan."""
|
||||
|
||||
# Lifespan tasks that are planned to run.
|
||||
lifespan_tasks: Set[Union[asyncio.Task, Callable]] = set()
|
||||
lifespan_tasks: Set[Union[asyncio.Task, Callable]] = dataclasses.field(
|
||||
default_factory=set
|
||||
)
|
||||
|
||||
@contextlib.asynccontextmanager
|
||||
async def _run_lifespan_tasks(self, app: FastAPI):
|
||||
@ -26,6 +32,7 @@ class LifespanMixin(AppMixin):
|
||||
try:
|
||||
async with contextlib.AsyncExitStack() as stack:
|
||||
for task in self.lifespan_tasks:
|
||||
run_msg = f"Started lifespan task: {task.__name__} as {{type}}" # type: ignore
|
||||
if isinstance(task, asyncio.Task):
|
||||
running_tasks.append(task)
|
||||
else:
|
||||
@ -35,15 +42,19 @@ class LifespanMixin(AppMixin):
|
||||
_t = task()
|
||||
if isinstance(_t, contextlib._AsyncGeneratorContextManager):
|
||||
await stack.enter_async_context(_t)
|
||||
console.debug(run_msg.format(type="asynccontextmanager"))
|
||||
elif isinstance(_t, Coroutine):
|
||||
running_tasks.append(asyncio.create_task(_t))
|
||||
task_ = asyncio.create_task(_t)
|
||||
task_.add_done_callback(lambda t: t.result())
|
||||
running_tasks.append(task_)
|
||||
console.debug(run_msg.format(type="coroutine"))
|
||||
else:
|
||||
console.debug(run_msg.format(type="function"))
|
||||
yield
|
||||
finally:
|
||||
cancel_kwargs = (
|
||||
{"msg": "lifespan_cleanup"} if sys.version_info >= (3, 9) else {}
|
||||
)
|
||||
for task in running_tasks:
|
||||
task.cancel(**cancel_kwargs)
|
||||
console.debug(f"Canceling lifespan task: {task}")
|
||||
task.cancel(msg="lifespan_cleanup")
|
||||
|
||||
def register_lifespan_task(self, task: Callable | asyncio.Task, **task_kwargs):
|
||||
"""Register a task to run during the lifespan of the app.
|
||||
@ -51,7 +62,18 @@ class LifespanMixin(AppMixin):
|
||||
Args:
|
||||
task: The task to register.
|
||||
task_kwargs: The kwargs of the task.
|
||||
|
||||
Raises:
|
||||
InvalidLifespanTaskType: If the task is a generator function.
|
||||
"""
|
||||
if inspect.isgeneratorfunction(task) or inspect.isasyncgenfunction(task):
|
||||
raise InvalidLifespanTaskType(
|
||||
f"Task {task.__name__} of type generator must be decorated with contextlib.asynccontextmanager."
|
||||
)
|
||||
|
||||
if task_kwargs:
|
||||
original_task = task
|
||||
task = functools.partial(task, **task_kwargs) # type: ignore
|
||||
functools.update_wrapper(task, original_task) # type: ignore
|
||||
self.lifespan_tasks.add(task) # type: ignore
|
||||
console.debug(f"Registered lifespan task: {task.__name__}") # type: ignore
|
||||
|
@ -3,6 +3,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import dataclasses
|
||||
from typing import List
|
||||
|
||||
from reflex.event import Event
|
||||
@ -12,11 +13,12 @@ from reflex.state import BaseState, StateUpdate
|
||||
from .mixin import AppMixin
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
class MiddlewareMixin(AppMixin):
|
||||
"""Middleware Mixin that allow to add middleware to the app."""
|
||||
|
||||
# Middleware to add to the app. Users should use `add_middleware`. PRIVATE.
|
||||
middleware: List[Middleware] = []
|
||||
middleware: List[Middleware] = dataclasses.field(default_factory=list)
|
||||
|
||||
def _init_mixin(self):
|
||||
self.middleware.append(HydrateMiddleware())
|
||||
|
@ -1,9 +1,10 @@
|
||||
"""Default mixin for all app mixins."""
|
||||
|
||||
from reflex.base import Base
|
||||
import dataclasses
|
||||
|
||||
|
||||
class AppMixin(Base):
|
||||
@dataclasses.dataclass
|
||||
class AppMixin:
|
||||
"""Define the base class for all app mixins."""
|
||||
|
||||
def _init_mixin(self):
|
||||
|
@ -15,7 +15,7 @@ if constants.CompileVars.APP != "app":
|
||||
telemetry.send("compile")
|
||||
app_module = get_app(reload=False)
|
||||
app = getattr(app_module, constants.CompileVars.APP)
|
||||
# For py3.8 and py3.9 compatibility when redis is used, we MUST add any decorator pages
|
||||
# For py3.9 compatibility when redis is used, we MUST add any decorator pages
|
||||
# before compiling the app in a thread to avoid event loop error (REF-2172).
|
||||
app._apply_decorated_pages()
|
||||
compile_future = ThreadPoolExecutor(max_workers=1).submit(app._compile)
|
||||
|
@ -47,6 +47,9 @@ def validate_field_name(bases: List[Type["BaseModel"]], field_name: str) -> None
|
||||
# shadowed state vars when reloading app via utils.prerequisites.get_app(reload=True)
|
||||
pydantic_main.validate_field_name = validate_field_name # type: ignore
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from reflex.vars import Var
|
||||
|
||||
|
||||
class Base(BaseModel): # pyright: ignore [reportUnboundVariable]
|
||||
"""The base class subclassed by all Reflex classes.
|
||||
@ -92,7 +95,7 @@ class Base(BaseModel): # pyright: ignore [reportUnboundVariable]
|
||||
return self
|
||||
|
||||
@classmethod
|
||||
def get_fields(cls) -> dict[str, Any]:
|
||||
def get_fields(cls) -> dict[str, ModelField]:
|
||||
"""Get the fields of the object.
|
||||
|
||||
Returns:
|
||||
@ -101,7 +104,7 @@ class Base(BaseModel): # pyright: ignore [reportUnboundVariable]
|
||||
return cls.__fields__
|
||||
|
||||
@classmethod
|
||||
def add_field(cls, var: Any, default_value: Any):
|
||||
def add_field(cls, var: Var, default_value: Any):
|
||||
"""Add a pydantic field after class definition.
|
||||
|
||||
Used by State.add_var() to correctly handle the new variable.
|
||||
@ -110,7 +113,7 @@ class Base(BaseModel): # pyright: ignore [reportUnboundVariable]
|
||||
var: The variable to add a pydantic field for.
|
||||
default_value: The default value of the field
|
||||
"""
|
||||
var_name = var._var_name.split(".")[-1]
|
||||
var_name = var._var_field_name
|
||||
new_field = ModelField.infer(
|
||||
name=var_name,
|
||||
value=default_value,
|
||||
@ -133,13 +136,4 @@ class Base(BaseModel): # pyright: ignore [reportUnboundVariable]
|
||||
# Seems like this function signature was wrong all along?
|
||||
# If the user wants a field that we know of, get it and pass it off to _get_value
|
||||
key = getattr(self, key)
|
||||
return self._get_value(
|
||||
key,
|
||||
to_dict=True,
|
||||
by_alias=False,
|
||||
include=None,
|
||||
exclude=None,
|
||||
exclude_unset=False,
|
||||
exclude_defaults=False,
|
||||
exclude_none=False,
|
||||
)
|
||||
return key
|
||||
|
@ -2,13 +2,13 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from typing import Dict, Iterable, Optional, Type, Union
|
||||
from typing import TYPE_CHECKING, Dict, Iterable, Optional, Tuple, Type, Union
|
||||
|
||||
from reflex import constants
|
||||
from reflex.compiler import templates, utils
|
||||
from reflex.components.base.fragment import Fragment
|
||||
from reflex.components.component import (
|
||||
BaseComponent,
|
||||
Component,
|
||||
@ -16,13 +16,13 @@ from reflex.components.component import (
|
||||
CustomComponent,
|
||||
StatefulComponent,
|
||||
)
|
||||
from reflex.config import get_config
|
||||
from reflex.ivars.base import ImmutableVar, LiteralVar
|
||||
from reflex.config import environment, get_config
|
||||
from reflex.state import BaseState
|
||||
from reflex.style import SYSTEM_COLOR_MODE
|
||||
from reflex.utils.exec import is_prod_mode
|
||||
from reflex.utils.imports import ImportVar
|
||||
from reflex.utils.prerequisites import get_web_dir
|
||||
from reflex.vars.base import LiteralVar, Var
|
||||
|
||||
|
||||
def _compile_document_root(root: Component) -> str:
|
||||
@ -40,6 +40,20 @@ def _compile_document_root(root: Component) -> str:
|
||||
)
|
||||
|
||||
|
||||
def _normalize_library_name(lib: str) -> str:
|
||||
"""Normalize the library name.
|
||||
|
||||
Args:
|
||||
lib: The library name to normalize.
|
||||
|
||||
Returns:
|
||||
The normalized library name.
|
||||
"""
|
||||
if lib == "react":
|
||||
return "React"
|
||||
return lib.replace("@", "").replace("/", "_").replace("-", "_")
|
||||
|
||||
|
||||
def _compile_app(app_root: Component) -> str:
|
||||
"""Compile the app template component.
|
||||
|
||||
@ -49,10 +63,20 @@ def _compile_app(app_root: Component) -> str:
|
||||
Returns:
|
||||
The compiled app.
|
||||
"""
|
||||
from reflex.components.dynamic import bundled_libraries
|
||||
|
||||
window_libraries = [
|
||||
(_normalize_library_name(name), name) for name in bundled_libraries
|
||||
] + [
|
||||
("utils_context", f"$/{constants.Dirs.UTILS}/context"),
|
||||
("utils_state", f"$/{constants.Dirs.UTILS}/state"),
|
||||
]
|
||||
|
||||
return templates.APP_ROOT.render(
|
||||
imports=utils.compile_imports(app_root._get_all_imports()),
|
||||
custom_codes=app_root._get_all_custom_code(),
|
||||
hooks={**app_root._get_all_hooks_internal(), **app_root._get_all_hooks()},
|
||||
window_libraries=window_libraries,
|
||||
render=app_root.render(),
|
||||
)
|
||||
|
||||
@ -103,8 +127,8 @@ def _compile_contexts(state: Optional[Type[BaseState]], theme: Component | None)
|
||||
|
||||
|
||||
def _compile_page(
|
||||
component: Component,
|
||||
state: Type[BaseState],
|
||||
component: BaseComponent,
|
||||
state: Type[BaseState] | None,
|
||||
) -> str:
|
||||
"""Compile the component given the app state.
|
||||
|
||||
@ -119,7 +143,7 @@ def _compile_page(
|
||||
imports = utils.compile_imports(imports)
|
||||
|
||||
# Compile the code to render the component.
|
||||
kwargs = {"state_name": state.get_name()} if state else {}
|
||||
kwargs = {"state_name": state.get_name()} if state is not None else {}
|
||||
|
||||
return templates.PAGE.render(
|
||||
imports=imports,
|
||||
@ -171,7 +195,7 @@ def _compile_root_stylesheet(stylesheets: list[str]) -> str:
|
||||
stylesheet_full_path = (
|
||||
Path.cwd() / constants.Dirs.APP_ASSETS / stylesheet.strip("/")
|
||||
)
|
||||
if not os.path.exists(stylesheet_full_path):
|
||||
if not stylesheet_full_path.exists():
|
||||
raise FileNotFoundError(
|
||||
f"The stylesheet file {stylesheet_full_path} does not exist."
|
||||
)
|
||||
@ -205,7 +229,7 @@ def _compile_components(
|
||||
"""
|
||||
imports = {
|
||||
"react": [ImportVar(tag="memo")],
|
||||
f"/{constants.Dirs.STATE_PATH}": [ImportVar(tag="E"), ImportVar(tag="isTrue")],
|
||||
f"$/{constants.Dirs.STATE_PATH}": [ImportVar(tag="E"), ImportVar(tag="isTrue")],
|
||||
}
|
||||
component_renders = []
|
||||
|
||||
@ -292,7 +316,7 @@ def _compile_stateful_components(
|
||||
# Don't import from the file that we're about to create.
|
||||
all_imports = utils.merge_imports(*all_import_dicts)
|
||||
all_imports.pop(
|
||||
f"/{constants.Dirs.UTILS}/{constants.PageNames.STATEFUL_COMPONENTS}", None
|
||||
f"$/{constants.Dirs.UTILS}/{constants.PageNames.STATEFUL_COMPONENTS}", None
|
||||
)
|
||||
|
||||
return templates.STATEFUL_COMPONENTS.render(
|
||||
@ -320,7 +344,7 @@ def _compile_tailwind(
|
||||
def compile_document_root(
|
||||
head_components: list[Component],
|
||||
html_lang: Optional[str] = None,
|
||||
html_custom_attrs: Optional[Dict[str, Union[ImmutableVar, str]]] = None,
|
||||
html_custom_attrs: Optional[Dict[str, Union[Var, str]]] = None,
|
||||
) -> tuple[str, str]:
|
||||
"""Compile the document root.
|
||||
|
||||
@ -401,7 +425,7 @@ def compile_contexts(
|
||||
|
||||
|
||||
def compile_page(
|
||||
path: str, component: Component, state: Type[BaseState]
|
||||
path: str, component: BaseComponent, state: Type[BaseState] | None
|
||||
) -> tuple[str, str]:
|
||||
"""Compile a single page.
|
||||
|
||||
@ -503,7 +527,7 @@ def remove_tailwind_from_postcss() -> tuple[str, str]:
|
||||
|
||||
def purge_web_pages_dir():
|
||||
"""Empty out .web/pages directory."""
|
||||
if not is_prod_mode() and os.environ.get("REFLEX_PERSIST_WEB_DIR"):
|
||||
if not is_prod_mode() and environment.REFLEX_PERSIST_WEB_DIR:
|
||||
# Skip purging the web directory in dev mode if REFLEX_PERSIST_WEB_DIR is set.
|
||||
return
|
||||
|
||||
@ -511,6 +535,81 @@ def purge_web_pages_dir():
|
||||
utils.empty_dir(get_web_dir() / constants.Dirs.PAGES, keep_files=["_app.js"])
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from reflex.app import UnevaluatedPage
|
||||
|
||||
|
||||
def compile_unevaluated_page(
|
||||
route: str,
|
||||
page: UnevaluatedPage,
|
||||
state: Type[BaseState] | None = None,
|
||||
style: ComponentStyle | None = None,
|
||||
theme: Component | None = None,
|
||||
) -> Tuple[Component, bool]:
|
||||
"""Compiles an uncompiled page into a component and adds meta information.
|
||||
|
||||
Args:
|
||||
route: The route of the page.
|
||||
page: The uncompiled page object.
|
||||
state: The state of the app.
|
||||
style: The style of the page.
|
||||
theme: The theme of the page.
|
||||
|
||||
Returns:
|
||||
The compiled component and whether state should be enabled.
|
||||
"""
|
||||
# Generate the component if it is a callable.
|
||||
component = page.component
|
||||
component = component if isinstance(component, Component) else component()
|
||||
|
||||
# unpack components that return tuples in an rx.fragment.
|
||||
if isinstance(component, tuple):
|
||||
component = Fragment.create(*component)
|
||||
|
||||
component._add_style_recursive(style or {}, theme)
|
||||
|
||||
enable_state = False
|
||||
# Ensure state is enabled if this page uses state.
|
||||
if state is None:
|
||||
if page.on_load or component._has_stateful_event_triggers():
|
||||
enable_state = True
|
||||
else:
|
||||
for var in component._get_vars(include_children=True):
|
||||
var_data = var._get_all_var_data()
|
||||
if not var_data:
|
||||
continue
|
||||
if not var_data.state:
|
||||
continue
|
||||
enable_state = True
|
||||
break
|
||||
|
||||
from reflex.app import OverlayFragment
|
||||
from reflex.utils.format import make_default_page_title
|
||||
|
||||
component = OverlayFragment.create(component)
|
||||
|
||||
meta_args = {
|
||||
"title": (
|
||||
page.title
|
||||
if page.title is not None
|
||||
else make_default_page_title(get_config().app_name, route)
|
||||
),
|
||||
"image": page.image,
|
||||
"meta": page.meta,
|
||||
}
|
||||
|
||||
if page.description is not None:
|
||||
meta_args["description"] = page.description
|
||||
|
||||
# Add meta information to the component.
|
||||
utils.add_meta(
|
||||
component,
|
||||
**meta_args,
|
||||
)
|
||||
|
||||
return component, enable_state
|
||||
|
||||
|
||||
class ExecutorSafeFunctions:
|
||||
"""Helper class to allow parallelisation of parts of the compilation process.
|
||||
|
||||
@ -536,13 +635,12 @@ class ExecutorSafeFunctions:
|
||||
|
||||
"""
|
||||
|
||||
COMPILE_PAGE_ARGS_BY_ROUTE = {}
|
||||
COMPILE_APP_APP_ROOT: Component | None = None
|
||||
CUSTOM_COMPONENTS: set[CustomComponent] | None = None
|
||||
STYLE: ComponentStyle | None = None
|
||||
COMPONENTS: Dict[str, BaseComponent] = {}
|
||||
UNCOMPILED_PAGES: Dict[str, UnevaluatedPage] = {}
|
||||
STATE: Optional[Type[BaseState]] = None
|
||||
|
||||
@classmethod
|
||||
def compile_page(cls, route: str):
|
||||
def compile_page(cls, route: str) -> tuple[str, str]:
|
||||
"""Compile a page.
|
||||
|
||||
Args:
|
||||
@ -551,46 +649,45 @@ class ExecutorSafeFunctions:
|
||||
Returns:
|
||||
The path and code of the compiled page.
|
||||
"""
|
||||
return compile_page(*cls.COMPILE_PAGE_ARGS_BY_ROUTE[route])
|
||||
return compile_page(route, cls.COMPONENTS[route], cls.STATE)
|
||||
|
||||
@classmethod
|
||||
def compile_app(cls):
|
||||
"""Compile the app.
|
||||
def compile_unevaluated_page(
|
||||
cls,
|
||||
route: str,
|
||||
style: ComponentStyle,
|
||||
theme: Component | None,
|
||||
) -> tuple[str, Component, tuple[str, str]]:
|
||||
"""Compile an unevaluated page.
|
||||
|
||||
Args:
|
||||
route: The route of the page to compile.
|
||||
style: The style of the page.
|
||||
theme: The theme of the page.
|
||||
|
||||
Returns:
|
||||
The path and code of the compiled app.
|
||||
|
||||
Raises:
|
||||
ValueError: If the app root is not set.
|
||||
The route, compiled component, and compiled page.
|
||||
"""
|
||||
if cls.COMPILE_APP_APP_ROOT is None:
|
||||
raise ValueError("COMPILE_APP_APP_ROOT should be set")
|
||||
return compile_app(cls.COMPILE_APP_APP_ROOT)
|
||||
component, enable_state = compile_unevaluated_page(
|
||||
route, cls.UNCOMPILED_PAGES[route]
|
||||
)
|
||||
component = component if isinstance(component, Component) else component()
|
||||
component._add_style_recursive(style, theme)
|
||||
return route, component, compile_page(route, component, cls.STATE)
|
||||
|
||||
@classmethod
|
||||
def compile_custom_components(cls):
|
||||
"""Compile the custom components.
|
||||
|
||||
Returns:
|
||||
The path and code of the compiled custom components.
|
||||
|
||||
Raises:
|
||||
ValueError: If the custom components are not set.
|
||||
"""
|
||||
if cls.CUSTOM_COMPONENTS is None:
|
||||
raise ValueError("CUSTOM_COMPONENTS should be set")
|
||||
return compile_components(cls.CUSTOM_COMPONENTS)
|
||||
|
||||
@classmethod
|
||||
def compile_theme(cls):
|
||||
def compile_theme(cls, style: ComponentStyle | None) -> tuple[str, str]:
|
||||
"""Compile the theme.
|
||||
|
||||
Args:
|
||||
style: The style to compile.
|
||||
|
||||
Returns:
|
||||
The path and code of the compiled theme.
|
||||
|
||||
Raises:
|
||||
ValueError: If the style is not set.
|
||||
"""
|
||||
if cls.STYLE is None:
|
||||
if style is None:
|
||||
raise ValueError("STYLE should be set")
|
||||
return compile_theme(cls.STYLE)
|
||||
return compile_theme(style)
|
||||
|
@ -2,13 +2,12 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
from pathlib import Path
|
||||
from typing import Any, Callable, Dict, Optional, Type, Union
|
||||
from urllib.parse import urlparse
|
||||
|
||||
from reflex.ivars.base import ImmutableVar
|
||||
from reflex.utils.prerequisites import get_web_dir
|
||||
from reflex.vars.base import Var
|
||||
|
||||
try:
|
||||
from pydantic.v1.fields import ModelField
|
||||
@ -29,7 +28,8 @@ from reflex.components.base import (
|
||||
Title,
|
||||
)
|
||||
from reflex.components.component import Component, ComponentStyle, CustomComponent
|
||||
from reflex.state import BaseState, Cookie, LocalStorage, SessionStorage
|
||||
from reflex.istate.storage import Cookie, LocalStorage, SessionStorage
|
||||
from reflex.state import BaseState
|
||||
from reflex.style import Style
|
||||
from reflex.utils import console, format, imports, path_ops
|
||||
from reflex.utils.imports import ImportVar, ParsedImportDict
|
||||
@ -44,6 +44,9 @@ def compile_import_statement(fields: list[ImportVar]) -> tuple[str, list[str]]:
|
||||
Args:
|
||||
fields: The set of fields to import from the library.
|
||||
|
||||
Raises:
|
||||
ValueError: If there is more than one default import.
|
||||
|
||||
Returns:
|
||||
The libraries for default and rest.
|
||||
default: default library. When install "import def from library".
|
||||
@ -54,7 +57,8 @@ def compile_import_statement(fields: list[ImportVar]) -> tuple[str, list[str]]:
|
||||
|
||||
# Check for default imports.
|
||||
defaults = {field for field in fields_set if field.is_default}
|
||||
assert len(defaults) < 2
|
||||
if len(defaults) >= 2:
|
||||
raise ValueError("Only one default import is allowed.")
|
||||
|
||||
# Get the default import, and the specific imports.
|
||||
default = next(iter({field.name for field in defaults}), "")
|
||||
@ -79,6 +83,12 @@ def validate_imports(import_dict: ParsedImportDict):
|
||||
f"{_import.tag}/{_import.alias}" if _import.alias else _import.tag
|
||||
)
|
||||
if import_name in used_tags:
|
||||
already_imported = used_tags[import_name]
|
||||
if (already_imported[0] == "$" and already_imported[1:] == lib) or (
|
||||
lib[0] == "$" and lib[1:] == already_imported
|
||||
):
|
||||
used_tags[import_name] = lib if lib[0] == "$" else already_imported
|
||||
continue
|
||||
raise ValueError(
|
||||
f"Can not compile, the tag {import_name} is used multiple time from {lib} and {used_tags[import_name]}"
|
||||
)
|
||||
@ -92,6 +102,9 @@ def compile_imports(import_dict: ParsedImportDict) -> list[dict]:
|
||||
Args:
|
||||
import_dict: The import dict to compile.
|
||||
|
||||
Raises:
|
||||
ValueError: If an import in the dict is invalid.
|
||||
|
||||
Returns:
|
||||
The list of import dict.
|
||||
"""
|
||||
@ -106,8 +119,10 @@ def compile_imports(import_dict: ParsedImportDict) -> list[dict]:
|
||||
continue
|
||||
|
||||
if not lib:
|
||||
assert not default, "No default field allowed for empty library."
|
||||
assert rest is not None and len(rest) > 0, "No fields to import."
|
||||
if default:
|
||||
raise ValueError("No default field allowed for empty library.")
|
||||
if rest is None or len(rest) == 0:
|
||||
raise ValueError("No fields to import.")
|
||||
for module in sorted(rest):
|
||||
import_dicts.append(get_import_dict(module))
|
||||
continue
|
||||
@ -155,7 +170,7 @@ def compile_state(state: Type[BaseState]) -> dict:
|
||||
initial_state = state(_reflex_internal_init=True).dict(
|
||||
initial=True, include_computed=False
|
||||
)
|
||||
return format.format_state(initial_state)
|
||||
return initial_state
|
||||
|
||||
|
||||
def _compile_client_storage_field(
|
||||
@ -268,7 +283,7 @@ def compile_custom_component(
|
||||
}
|
||||
|
||||
# Concatenate the props.
|
||||
props = [prop._var_name for prop in component.get_prop_vars()]
|
||||
props = [prop._js_expr for prop in component.get_prop_vars()]
|
||||
|
||||
# Compile the component.
|
||||
return (
|
||||
@ -286,7 +301,7 @@ def compile_custom_component(
|
||||
def create_document_root(
|
||||
head_components: list[Component] | None = None,
|
||||
html_lang: Optional[str] = None,
|
||||
html_custom_attrs: Optional[Dict[str, Union[ImmutableVar, str]]] = None,
|
||||
html_custom_attrs: Optional[Dict[str, Union[Var, str]]] = None,
|
||||
) -> Component:
|
||||
"""Create the document root.
|
||||
|
||||
@ -429,11 +444,11 @@ def add_meta(
|
||||
Returns:
|
||||
The component with the metadata added.
|
||||
"""
|
||||
meta_tags = [Meta.create(**item) for item in meta]
|
||||
|
||||
children: list[Any] = [
|
||||
Title.create(title),
|
||||
meta_tags = [
|
||||
item if isinstance(item, Component) else Meta.create(**item) for item in meta
|
||||
]
|
||||
|
||||
children: list[Any] = [Title.create(title)]
|
||||
if description:
|
||||
children.append(Description.create(content=description))
|
||||
children.append(Image.create(content=image))
|
||||
@ -448,16 +463,16 @@ def add_meta(
|
||||
return page
|
||||
|
||||
|
||||
def write_page(path: str, code: str):
|
||||
def write_page(path: str | Path, code: str):
|
||||
"""Write the given code to the given path.
|
||||
|
||||
Args:
|
||||
path: The path to write the code to.
|
||||
code: The code to write.
|
||||
"""
|
||||
path_ops.mkdir(os.path.dirname(path))
|
||||
with open(path, "w", encoding="utf-8") as f:
|
||||
f.write(code)
|
||||
path = Path(path)
|
||||
path_ops.mkdir(path.parent)
|
||||
path.write_text(code, encoding="utf-8")
|
||||
|
||||
|
||||
def empty_dir(path: str | Path, keep_files: list[str] | None = None):
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
from reflex.components.base.fragment import Fragment
|
||||
from reflex.components.component import Component
|
||||
from reflex.ivars.base import ImmutableVar
|
||||
from reflex.vars.base import Var
|
||||
|
||||
|
||||
class AppWrap(Fragment):
|
||||
@ -15,4 +15,4 @@ class AppWrap(Fragment):
|
||||
Returns:
|
||||
A new AppWrap component containing {children}.
|
||||
"""
|
||||
return super().create(ImmutableVar.create("children"))
|
||||
return super().create(Var(_js_expr="children"))
|
||||
|
@ -3,12 +3,12 @@
|
||||
# ------------------- DO NOT EDIT ----------------------
|
||||
# This file was generated by `reflex/utils/pyi_generator.py`!
|
||||
# ------------------------------------------------------
|
||||
from typing import Any, Callable, Dict, Optional, Union, overload
|
||||
from typing import Any, Dict, Optional, Union, overload
|
||||
|
||||
from reflex.components.base.fragment import Fragment
|
||||
from reflex.event import EventHandler, EventSpec
|
||||
from reflex.ivars.base import ImmutableVar
|
||||
from reflex.event import EventType
|
||||
from reflex.style import Style
|
||||
from reflex.vars.base import Var
|
||||
|
||||
class AppWrap(Fragment):
|
||||
@overload
|
||||
@ -21,52 +21,22 @@ class AppWrap(Fragment):
|
||||
id: Optional[Any] = None,
|
||||
class_name: Optional[Any] = None,
|
||||
autofocus: Optional[bool] = None,
|
||||
custom_attrs: Optional[Dict[str, Union[ImmutableVar, str]]] = None,
|
||||
on_blur: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_context_menu: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_double_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_focus: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_down: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_enter: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_leave: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_move: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_out: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_over: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_up: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_scroll: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_unmount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = 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,
|
||||
) -> "AppWrap":
|
||||
"""Create a new AppWrap component.
|
||||
|
@ -4,11 +4,11 @@ from __future__ import annotations
|
||||
|
||||
from typing import Any, Iterator
|
||||
|
||||
from reflex.components.component import Component
|
||||
from reflex.components.component import Component, LiteralComponentVar
|
||||
from reflex.components.tags import Tag
|
||||
from reflex.components.tags.tagless import Tagless
|
||||
from reflex.ivars.base import ImmutableVar
|
||||
from reflex.vars import Var
|
||||
from reflex.utils.imports import ParsedImportDict
|
||||
from reflex.vars import BooleanVar, ObjectVar, Var
|
||||
|
||||
|
||||
class Bare(Component):
|
||||
@ -26,18 +26,88 @@ class Bare(Component):
|
||||
Returns:
|
||||
The component.
|
||||
"""
|
||||
if isinstance(contents, ImmutableVar):
|
||||
if isinstance(contents, Var):
|
||||
return cls(contents=contents)
|
||||
else:
|
||||
contents = str(contents) if contents is not None else ""
|
||||
return cls(contents=contents) # type: ignore
|
||||
|
||||
def _get_all_hooks_internal(self) -> dict[str, None]:
|
||||
"""Include the hooks for the component.
|
||||
|
||||
Returns:
|
||||
The hooks for the component.
|
||||
"""
|
||||
hooks = super()._get_all_hooks_internal()
|
||||
if isinstance(self.contents, LiteralComponentVar):
|
||||
hooks |= self.contents._var_value._get_all_hooks_internal()
|
||||
return hooks
|
||||
|
||||
def _get_all_hooks(self) -> dict[str, None]:
|
||||
"""Include the hooks for the component.
|
||||
|
||||
Returns:
|
||||
The hooks for the component.
|
||||
"""
|
||||
hooks = super()._get_all_hooks()
|
||||
if isinstance(self.contents, LiteralComponentVar):
|
||||
hooks |= self.contents._var_value._get_all_hooks()
|
||||
return hooks
|
||||
|
||||
def _get_all_imports(self) -> ParsedImportDict:
|
||||
"""Include the imports for the component.
|
||||
|
||||
Returns:
|
||||
The imports for the component.
|
||||
"""
|
||||
imports = super()._get_all_imports()
|
||||
if isinstance(self.contents, LiteralComponentVar):
|
||||
var_data = self.contents._get_all_var_data()
|
||||
if var_data:
|
||||
imports |= {k: list(v) for k, v in var_data.imports}
|
||||
return imports
|
||||
|
||||
def _get_all_dynamic_imports(self) -> set[str]:
|
||||
"""Get dynamic imports for the component.
|
||||
|
||||
Returns:
|
||||
The dynamic imports.
|
||||
"""
|
||||
dynamic_imports = super()._get_all_dynamic_imports()
|
||||
if isinstance(self.contents, LiteralComponentVar):
|
||||
dynamic_imports |= self.contents._var_value._get_all_dynamic_imports()
|
||||
return dynamic_imports
|
||||
|
||||
def _get_all_custom_code(self) -> set[str]:
|
||||
"""Get custom code for the component.
|
||||
|
||||
Returns:
|
||||
The custom code.
|
||||
"""
|
||||
custom_code = super()._get_all_custom_code()
|
||||
if isinstance(self.contents, LiteralComponentVar):
|
||||
custom_code |= self.contents._var_value._get_all_custom_code()
|
||||
return custom_code
|
||||
|
||||
def _get_all_refs(self) -> set[str]:
|
||||
"""Get the refs for the children of the component.
|
||||
|
||||
Returns:
|
||||
The refs for the children.
|
||||
"""
|
||||
refs = super()._get_all_refs()
|
||||
if isinstance(self.contents, LiteralComponentVar):
|
||||
refs |= self.contents._var_value._get_all_refs()
|
||||
return refs
|
||||
|
||||
def _render(self) -> Tag:
|
||||
if isinstance(self.contents, ImmutableVar):
|
||||
if isinstance(self.contents, Var):
|
||||
if isinstance(self.contents, (BooleanVar, ObjectVar)):
|
||||
return Tagless(contents=f"{{{str(self.contents.to_string())}}}")
|
||||
return Tagless(contents=f"{{{str(self.contents)}}}")
|
||||
return Tagless(contents=str(self.contents))
|
||||
|
||||
def _get_vars(self, include_children: bool = False) -> Iterator[ImmutableVar]:
|
||||
def _get_vars(self, include_children: bool = False) -> Iterator[Var]:
|
||||
"""Walk all Vars used in this component.
|
||||
|
||||
Args:
|
||||
|
@ -3,12 +3,12 @@
|
||||
# ------------------- DO NOT EDIT ----------------------
|
||||
# This file was generated by `reflex/utils/pyi_generator.py`!
|
||||
# ------------------------------------------------------
|
||||
from typing import Any, Callable, Dict, Optional, Union, overload
|
||||
from typing import Any, Dict, Optional, Union, overload
|
||||
|
||||
from reflex.components.component import Component
|
||||
from reflex.event import EventHandler, EventSpec
|
||||
from reflex.ivars.base import ImmutableVar
|
||||
from reflex.event import EventType
|
||||
from reflex.style import Style
|
||||
from reflex.vars.base import Var
|
||||
|
||||
class Body(Component):
|
||||
@overload
|
||||
@ -21,52 +21,22 @@ class Body(Component):
|
||||
id: Optional[Any] = None,
|
||||
class_name: Optional[Any] = None,
|
||||
autofocus: Optional[bool] = None,
|
||||
custom_attrs: Optional[Dict[str, Union[ImmutableVar, str]]] = None,
|
||||
on_blur: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_context_menu: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_double_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_focus: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_down: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_enter: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_leave: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_move: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_out: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_over: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_up: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_scroll: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_unmount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = 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,
|
||||
) -> "Body":
|
||||
"""Create the component.
|
||||
|
@ -3,12 +3,12 @@
|
||||
# ------------------- DO NOT EDIT ----------------------
|
||||
# This file was generated by `reflex/utils/pyi_generator.py`!
|
||||
# ------------------------------------------------------
|
||||
from typing import Any, Callable, Dict, Optional, Union, overload
|
||||
from typing import Any, Dict, Optional, Union, overload
|
||||
|
||||
from reflex.components.component import Component
|
||||
from reflex.event import EventHandler, EventSpec
|
||||
from reflex.ivars.base import ImmutableVar
|
||||
from reflex.event import EventType
|
||||
from reflex.style import Style
|
||||
from reflex.vars.base import Var
|
||||
|
||||
class NextDocumentLib(Component):
|
||||
@overload
|
||||
@ -21,52 +21,22 @@ class NextDocumentLib(Component):
|
||||
id: Optional[Any] = None,
|
||||
class_name: Optional[Any] = None,
|
||||
autofocus: Optional[bool] = None,
|
||||
custom_attrs: Optional[Dict[str, Union[ImmutableVar, str]]] = None,
|
||||
on_blur: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_context_menu: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_double_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_focus: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_down: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_enter: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_leave: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_move: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_out: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_over: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_up: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_scroll: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_unmount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = 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,
|
||||
) -> "NextDocumentLib":
|
||||
"""Create the component.
|
||||
@ -98,52 +68,22 @@ class Html(NextDocumentLib):
|
||||
id: Optional[Any] = None,
|
||||
class_name: Optional[Any] = None,
|
||||
autofocus: Optional[bool] = None,
|
||||
custom_attrs: Optional[Dict[str, Union[ImmutableVar, str]]] = None,
|
||||
on_blur: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_context_menu: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_double_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_focus: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_down: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_enter: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_leave: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_move: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_out: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_over: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_up: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_scroll: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_unmount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = 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,
|
||||
) -> "Html":
|
||||
"""Create the component.
|
||||
@ -174,52 +114,22 @@ class DocumentHead(NextDocumentLib):
|
||||
id: Optional[Any] = None,
|
||||
class_name: Optional[Any] = None,
|
||||
autofocus: Optional[bool] = None,
|
||||
custom_attrs: Optional[Dict[str, Union[ImmutableVar, str]]] = None,
|
||||
on_blur: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_context_menu: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_double_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_focus: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_down: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_enter: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_leave: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_move: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_out: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_over: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_up: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_scroll: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_unmount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = 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,
|
||||
) -> "DocumentHead":
|
||||
"""Create the component.
|
||||
@ -250,52 +160,22 @@ class Main(NextDocumentLib):
|
||||
id: Optional[Any] = None,
|
||||
class_name: Optional[Any] = None,
|
||||
autofocus: Optional[bool] = None,
|
||||
custom_attrs: Optional[Dict[str, Union[ImmutableVar, str]]] = None,
|
||||
on_blur: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_context_menu: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_double_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_focus: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_down: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_enter: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_leave: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_move: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_out: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_over: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_up: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_scroll: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_unmount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = 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,
|
||||
) -> "Main":
|
||||
"""Create the component.
|
||||
@ -326,52 +206,22 @@ class NextScript(NextDocumentLib):
|
||||
id: Optional[Any] = None,
|
||||
class_name: Optional[Any] = None,
|
||||
autofocus: Optional[bool] = None,
|
||||
custom_attrs: Optional[Dict[str, Union[ImmutableVar, str]]] = None,
|
||||
on_blur: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_context_menu: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_double_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_focus: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_down: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_enter: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_leave: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_move: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_out: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_over: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_up: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_scroll: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_unmount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = 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,
|
||||
) -> "NextScript":
|
||||
"""Create the component.
|
||||
|
@ -2,17 +2,32 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import List
|
||||
from typing import Dict, List, Tuple
|
||||
|
||||
from reflex.compiler.compiler import _compile_component
|
||||
from reflex.components.component import Component
|
||||
from reflex.components.el import div, p
|
||||
from reflex.constants import Hooks, Imports
|
||||
from reflex.event import EventChain, EventHandler
|
||||
from reflex.ivars.base import ImmutableVar
|
||||
from reflex.ivars.function import FunctionVar
|
||||
from reflex.utils.imports import ImportVar
|
||||
from reflex.vars import Var
|
||||
from reflex.event import EventHandler
|
||||
from reflex.state import FrontendEventExceptionState
|
||||
from reflex.vars.base import Var
|
||||
|
||||
|
||||
def on_error_spec(
|
||||
error: Var[Dict[str, str]], info: Var[Dict[str, str]]
|
||||
) -> Tuple[Var[str], Var[str]]:
|
||||
"""The spec for the on_error event handler.
|
||||
|
||||
Args:
|
||||
error: The error message.
|
||||
info: Additional information about the error.
|
||||
|
||||
Returns:
|
||||
The arguments for the event handler.
|
||||
"""
|
||||
return (
|
||||
error.stack,
|
||||
info.componentStack,
|
||||
)
|
||||
|
||||
|
||||
class ErrorBoundary(Component):
|
||||
@ -22,31 +37,13 @@ class ErrorBoundary(Component):
|
||||
tag = "ErrorBoundary"
|
||||
|
||||
# Fired when the boundary catches an error.
|
||||
on_error: EventHandler[lambda error, info: [error, info]] = ImmutableVar( # type: ignore
|
||||
"logFrontendError"
|
||||
).to(FunctionVar, EventChain)
|
||||
on_error: EventHandler[on_error_spec]
|
||||
|
||||
# Rendered instead of the children when an error is caught.
|
||||
Fallback_component: Var[Component] = ImmutableVar.create_safe("Fallback")._replace(
|
||||
Fallback_component: Var[Component] = Var(_js_expr="Fallback")._replace(
|
||||
_var_type=Component
|
||||
)
|
||||
|
||||
def add_imports(self) -> dict[str, list[ImportVar]]:
|
||||
"""Add imports for the component.
|
||||
|
||||
Returns:
|
||||
The imports to add.
|
||||
"""
|
||||
return Imports.EVENTS
|
||||
|
||||
def add_hooks(self) -> List[str | ImmutableVar]:
|
||||
"""Add hooks for the component.
|
||||
|
||||
Returns:
|
||||
The hooks to add.
|
||||
"""
|
||||
return [Hooks.EVENTS, Hooks.FRONTEND_ERRORS]
|
||||
|
||||
def add_custom_code(self) -> List[str]:
|
||||
"""Add custom Javascript code into the page that contains this component.
|
||||
|
||||
@ -58,7 +55,7 @@ class ErrorBoundary(Component):
|
||||
fallback_container = div(
|
||||
p("Ooops...Unknown Reflex error has occured:"),
|
||||
p(
|
||||
ImmutableVar.create("error.message"),
|
||||
Var(_js_expr="error.message"),
|
||||
color="red",
|
||||
),
|
||||
p("Please contact the support."),
|
||||
@ -76,5 +73,20 @@ class ErrorBoundary(Component):
|
||||
"""
|
||||
]
|
||||
|
||||
@classmethod
|
||||
def create(cls, *children, **props):
|
||||
"""Create an ErrorBoundary component.
|
||||
|
||||
Args:
|
||||
*children: The children of the component.
|
||||
**props: The props of the component.
|
||||
|
||||
Returns:
|
||||
The ErrorBoundary component.
|
||||
"""
|
||||
if "on_error" not in props:
|
||||
props["on_error"] = FrontendEventExceptionState.handle_frontend_exception
|
||||
return super().create(*children, **props)
|
||||
|
||||
|
||||
error_boundary = ErrorBoundary.create
|
||||
|
@ -3,85 +3,54 @@
|
||||
# ------------------- DO NOT EDIT ----------------------
|
||||
# This file was generated by `reflex/utils/pyi_generator.py`!
|
||||
# ------------------------------------------------------
|
||||
from typing import Any, Callable, Dict, List, Optional, Union, overload
|
||||
from typing import Any, Dict, List, Optional, Tuple, Union, overload
|
||||
|
||||
from reflex.components.component import Component
|
||||
from reflex.event import EventHandler, EventSpec
|
||||
from reflex.ivars.base import ImmutableVar
|
||||
from reflex.event import EventType
|
||||
from reflex.style import Style
|
||||
from reflex.utils.imports import ImportVar
|
||||
from reflex.vars import Var
|
||||
from reflex.vars.base import Var
|
||||
|
||||
def on_error_spec(
|
||||
error: Var[Dict[str, str]], info: Var[Dict[str, str]]
|
||||
) -> Tuple[Var[str], Var[str]]: ...
|
||||
|
||||
class ErrorBoundary(Component):
|
||||
def add_imports(self) -> dict[str, list[ImportVar]]: ...
|
||||
def add_hooks(self) -> List[str | ImmutableVar]: ...
|
||||
def add_custom_code(self) -> List[str]: ...
|
||||
@overload
|
||||
@classmethod
|
||||
def create( # type: ignore
|
||||
cls,
|
||||
*children,
|
||||
Fallback_component: Optional[Union[Var[Component], Component]] = None,
|
||||
Fallback_component: Optional[Union[Component, Var[Component]]] = 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[ImmutableVar, str]]] = None,
|
||||
on_blur: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_context_menu: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_double_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_error: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_focus: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_down: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_enter: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_leave: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_move: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_out: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_over: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_up: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_scroll: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_unmount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = 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_error: Optional[EventType[str, str]] = 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,
|
||||
) -> "ErrorBoundary":
|
||||
"""Create the component.
|
||||
"""Create an ErrorBoundary component.
|
||||
|
||||
Args:
|
||||
*children: The children of the component.
|
||||
on_error: Fired when the boundary catches an error.
|
||||
Fallback_component: Rendered instead of the children when an error is caught.
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
@ -92,7 +61,7 @@ class ErrorBoundary(Component):
|
||||
**props: The props of the component.
|
||||
|
||||
Returns:
|
||||
The component.
|
||||
The ErrorBoundary component.
|
||||
"""
|
||||
...
|
||||
|
||||
|
@ -3,12 +3,12 @@
|
||||
# ------------------- DO NOT EDIT ----------------------
|
||||
# This file was generated by `reflex/utils/pyi_generator.py`!
|
||||
# ------------------------------------------------------
|
||||
from typing import Any, Callable, Dict, Optional, Union, overload
|
||||
from typing import Any, Dict, Optional, Union, overload
|
||||
|
||||
from reflex.components.component import Component
|
||||
from reflex.event import EventHandler, EventSpec
|
||||
from reflex.ivars.base import ImmutableVar
|
||||
from reflex.event import EventType
|
||||
from reflex.style import Style
|
||||
from reflex.vars.base import Var
|
||||
|
||||
class Fragment(Component):
|
||||
@overload
|
||||
@ -21,52 +21,22 @@ class Fragment(Component):
|
||||
id: Optional[Any] = None,
|
||||
class_name: Optional[Any] = None,
|
||||
autofocus: Optional[bool] = None,
|
||||
custom_attrs: Optional[Dict[str, Union[ImmutableVar, str]]] = None,
|
||||
on_blur: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_context_menu: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_double_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_focus: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_down: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_enter: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_leave: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_move: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_out: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_over: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_up: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_scroll: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_unmount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = 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,
|
||||
) -> "Fragment":
|
||||
"""Create the component.
|
||||
|
@ -3,12 +3,12 @@
|
||||
# ------------------- DO NOT EDIT ----------------------
|
||||
# This file was generated by `reflex/utils/pyi_generator.py`!
|
||||
# ------------------------------------------------------
|
||||
from typing import Any, Callable, Dict, Optional, Union, overload
|
||||
from typing import Any, Dict, Optional, Union, overload
|
||||
|
||||
from reflex.components.component import Component, MemoizationLeaf
|
||||
from reflex.event import EventHandler, EventSpec
|
||||
from reflex.ivars.base import ImmutableVar
|
||||
from reflex.event import EventType
|
||||
from reflex.style import Style
|
||||
from reflex.vars.base import Var
|
||||
|
||||
class NextHeadLib(Component):
|
||||
@overload
|
||||
@ -21,52 +21,22 @@ class NextHeadLib(Component):
|
||||
id: Optional[Any] = None,
|
||||
class_name: Optional[Any] = None,
|
||||
autofocus: Optional[bool] = None,
|
||||
custom_attrs: Optional[Dict[str, Union[ImmutableVar, str]]] = None,
|
||||
on_blur: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_context_menu: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_double_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_focus: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_down: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_enter: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_leave: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_move: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_out: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_over: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_up: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_scroll: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_unmount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = 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,
|
||||
) -> "NextHeadLib":
|
||||
"""Create the component.
|
||||
@ -97,52 +67,22 @@ class Head(NextHeadLib, MemoizationLeaf):
|
||||
id: Optional[Any] = None,
|
||||
class_name: Optional[Any] = None,
|
||||
autofocus: Optional[bool] = None,
|
||||
custom_attrs: Optional[Dict[str, Union[ImmutableVar, str]]] = None,
|
||||
on_blur: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_context_menu: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_double_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_focus: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_down: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_enter: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_leave: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_move: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_out: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_over: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_up: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_scroll: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_unmount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = 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,
|
||||
) -> "Head":
|
||||
"""Create a new memoization leaf component.
|
||||
|
@ -1,7 +1,7 @@
|
||||
"""Display the title of the current page."""
|
||||
|
||||
from reflex.components.component import Component
|
||||
from reflex.vars import Var
|
||||
from reflex.vars.base import Var
|
||||
|
||||
|
||||
class RawLink(Component):
|
||||
|
@ -3,13 +3,12 @@
|
||||
# ------------------- DO NOT EDIT ----------------------
|
||||
# This file was generated by `reflex/utils/pyi_generator.py`!
|
||||
# ------------------------------------------------------
|
||||
from typing import Any, Callable, Dict, Optional, Union, overload
|
||||
from typing import Any, Dict, Optional, Union, overload
|
||||
|
||||
from reflex.components.component import Component
|
||||
from reflex.event import EventHandler, EventSpec
|
||||
from reflex.ivars.base import ImmutableVar
|
||||
from reflex.event import EventType
|
||||
from reflex.style import Style
|
||||
from reflex.vars import Var
|
||||
from reflex.vars.base import Var
|
||||
|
||||
class RawLink(Component):
|
||||
@overload
|
||||
@ -24,52 +23,22 @@ class RawLink(Component):
|
||||
id: Optional[Any] = None,
|
||||
class_name: Optional[Any] = None,
|
||||
autofocus: Optional[bool] = None,
|
||||
custom_attrs: Optional[Dict[str, Union[ImmutableVar, str]]] = None,
|
||||
on_blur: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_context_menu: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_double_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_focus: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_down: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_enter: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_leave: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_move: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_out: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_over: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_up: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_scroll: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_unmount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = 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,
|
||||
) -> "RawLink":
|
||||
"""Create the component.
|
||||
@ -109,52 +78,22 @@ class ScriptTag(Component):
|
||||
id: Optional[Any] = None,
|
||||
class_name: Optional[Any] = None,
|
||||
autofocus: Optional[bool] = None,
|
||||
custom_attrs: Optional[Dict[str, Union[ImmutableVar, str]]] = None,
|
||||
on_blur: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_context_menu: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_double_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_focus: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_down: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_enter: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_leave: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_move: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_out: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_over: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_up: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_scroll: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_unmount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = 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,
|
||||
) -> "ScriptTag":
|
||||
"""Create the component.
|
||||
|
@ -16,13 +16,15 @@ class Title(Component):
|
||||
def render(self) -> dict:
|
||||
"""Render the title component.
|
||||
|
||||
Raises:
|
||||
ValueError: If the title is not a single string.
|
||||
|
||||
Returns:
|
||||
The rendered title component.
|
||||
"""
|
||||
# Make sure the title is a single string.
|
||||
assert len(self.children) == 1 and isinstance(
|
||||
self.children[0], Bare
|
||||
), "Title must be a single string."
|
||||
if len(self.children) != 1 or not isinstance(self.children[0], Bare):
|
||||
raise ValueError("Title must be a single string.")
|
||||
return super().render()
|
||||
|
||||
|
||||
|
@ -3,12 +3,12 @@
|
||||
# ------------------- DO NOT EDIT ----------------------
|
||||
# This file was generated by `reflex/utils/pyi_generator.py`!
|
||||
# ------------------------------------------------------
|
||||
from typing import Any, Callable, Dict, Optional, Union, overload
|
||||
from typing import Any, Dict, Optional, Union, overload
|
||||
|
||||
from reflex.components.component import Component
|
||||
from reflex.event import EventHandler, EventSpec
|
||||
from reflex.ivars.base import ImmutableVar
|
||||
from reflex.event import EventType
|
||||
from reflex.style import Style
|
||||
from reflex.vars.base import Var
|
||||
|
||||
class Title(Component):
|
||||
def render(self) -> dict: ...
|
||||
@ -22,52 +22,22 @@ class Title(Component):
|
||||
id: Optional[Any] = None,
|
||||
class_name: Optional[Any] = None,
|
||||
autofocus: Optional[bool] = None,
|
||||
custom_attrs: Optional[Dict[str, Union[ImmutableVar, str]]] = None,
|
||||
on_blur: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_context_menu: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_double_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_focus: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_down: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_enter: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_leave: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_move: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_out: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_over: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_up: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_scroll: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_unmount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = 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,
|
||||
) -> "Title":
|
||||
"""Create the component.
|
||||
@ -103,52 +73,22 @@ class Meta(Component):
|
||||
id: Optional[Any] = None,
|
||||
class_name: Optional[Any] = None,
|
||||
autofocus: Optional[bool] = None,
|
||||
custom_attrs: Optional[Dict[str, Union[ImmutableVar, str]]] = None,
|
||||
on_blur: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_context_menu: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_double_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_focus: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_down: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_enter: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_leave: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_move: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_out: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_over: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_up: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_scroll: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_unmount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = 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,
|
||||
) -> "Meta":
|
||||
"""Create the component.
|
||||
@ -189,52 +129,22 @@ class Description(Meta):
|
||||
id: Optional[Any] = None,
|
||||
class_name: Optional[Any] = None,
|
||||
autofocus: Optional[bool] = None,
|
||||
custom_attrs: Optional[Dict[str, Union[ImmutableVar, str]]] = None,
|
||||
on_blur: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_context_menu: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_double_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_focus: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_down: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_enter: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_leave: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_move: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_out: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_over: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_up: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_scroll: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_unmount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = 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,
|
||||
) -> "Description":
|
||||
"""Create the component.
|
||||
@ -275,52 +185,22 @@ class Image(Meta):
|
||||
id: Optional[Any] = None,
|
||||
class_name: Optional[Any] = None,
|
||||
autofocus: Optional[bool] = None,
|
||||
custom_attrs: Optional[Dict[str, Union[ImmutableVar, str]]] = None,
|
||||
on_blur: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_context_menu: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_double_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_focus: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_down: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_enter: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_leave: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_move: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_out: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_over: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_up: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_scroll: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_unmount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = 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,
|
||||
) -> "Image":
|
||||
"""Create the component.
|
||||
|
@ -8,9 +8,8 @@ from __future__ import annotations
|
||||
from typing import Literal
|
||||
|
||||
from reflex.components.component import Component
|
||||
from reflex.event import EventHandler
|
||||
from reflex.ivars.base import LiteralVar
|
||||
from reflex.vars import Var
|
||||
from reflex.event import EventHandler, empty_event
|
||||
from reflex.vars.base import LiteralVar, Var
|
||||
|
||||
|
||||
class Script(Component):
|
||||
@ -36,13 +35,13 @@ class Script(Component):
|
||||
)
|
||||
|
||||
# Triggered when the script is loading
|
||||
on_load: EventHandler[lambda: []]
|
||||
on_load: EventHandler[empty_event]
|
||||
|
||||
# Triggered when the script has loaded
|
||||
on_ready: EventHandler[lambda: []]
|
||||
on_ready: EventHandler[empty_event]
|
||||
|
||||
# Triggered when the script has errored
|
||||
on_error: EventHandler[lambda: []]
|
||||
on_error: EventHandler[empty_event]
|
||||
|
||||
@classmethod
|
||||
def create(cls, *children, **props) -> Component:
|
||||
|
@ -3,13 +3,12 @@
|
||||
# ------------------- DO NOT EDIT ----------------------
|
||||
# This file was generated by `reflex/utils/pyi_generator.py`!
|
||||
# ------------------------------------------------------
|
||||
from typing import Any, Callable, Dict, Literal, Optional, Union, overload
|
||||
from typing import Any, Dict, Literal, Optional, Union, overload
|
||||
|
||||
from reflex.components.component import Component
|
||||
from reflex.event import EventHandler, EventSpec
|
||||
from reflex.ivars.base import ImmutableVar
|
||||
from reflex.event import EventType
|
||||
from reflex.style import Style
|
||||
from reflex.vars import Var
|
||||
from reflex.vars.base import Var
|
||||
|
||||
class Script(Component):
|
||||
@overload
|
||||
@ -20,8 +19,8 @@ class Script(Component):
|
||||
src: Optional[Union[Var[str], str]] = None,
|
||||
strategy: Optional[
|
||||
Union[
|
||||
Var[Literal["afterInteractive", "beforeInteractive", "lazyOnload"]],
|
||||
Literal["afterInteractive", "beforeInteractive", "lazyOnload"],
|
||||
Var[Literal["afterInteractive", "beforeInteractive", "lazyOnload"]],
|
||||
]
|
||||
] = None,
|
||||
style: Optional[Style] = None,
|
||||
@ -29,61 +28,25 @@ class Script(Component):
|
||||
id: Optional[Any] = None,
|
||||
class_name: Optional[Any] = None,
|
||||
autofocus: Optional[bool] = None,
|
||||
custom_attrs: Optional[Dict[str, Union[ImmutableVar, str]]] = None,
|
||||
on_blur: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_context_menu: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_double_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_error: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_focus: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_load: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_down: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_enter: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_leave: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_move: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_out: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_over: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_up: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_ready: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_scroll: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_unmount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = 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_error: Optional[EventType[[]]] = None,
|
||||
on_focus: Optional[EventType[[]]] = None,
|
||||
on_load: 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_ready: Optional[EventType[[]]] = None,
|
||||
on_scroll: Optional[EventType[[]]] = None,
|
||||
on_unmount: Optional[EventType[[]]] = None,
|
||||
**props,
|
||||
) -> "Script":
|
||||
"""Create an inline or user-defined script.
|
||||
@ -102,6 +65,9 @@ class Script(Component):
|
||||
*children: The children of the component.
|
||||
src: Required unless inline script is used
|
||||
strategy: When the script will execute: afterInteractive (defer-like behavior) | beforeInteractive | lazyOnload (async-like behavior)
|
||||
on_load: Triggered when the script is loading
|
||||
on_ready: Triggered when the script has loaded
|
||||
on_error: Triggered when the script has errored
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
|
@ -3,6 +3,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import copy
|
||||
import dataclasses
|
||||
import typing
|
||||
from abc import ABC, abstractmethod
|
||||
from functools import lru_cache, wraps
|
||||
@ -25,6 +26,7 @@ import reflex.state
|
||||
from reflex.base import Base
|
||||
from reflex.compiler.templates import STATEFUL_COMPONENT
|
||||
from reflex.components.core.breakpoints import Breakpoints
|
||||
from reflex.components.dynamic import load_dynamic_serializer
|
||||
from reflex.components.tags import Tag
|
||||
from reflex.constants import (
|
||||
Dirs,
|
||||
@ -35,15 +37,19 @@ from reflex.constants import (
|
||||
MemoizationMode,
|
||||
PageNames,
|
||||
)
|
||||
from reflex.constants.compiler import SpecialAttributes
|
||||
from reflex.event import (
|
||||
EventCallback,
|
||||
EventChain,
|
||||
EventChainVar,
|
||||
EventHandler,
|
||||
EventSpec,
|
||||
EventVar,
|
||||
call_event_fn,
|
||||
call_event_handler,
|
||||
empty_event,
|
||||
get_handler_args,
|
||||
)
|
||||
from reflex.ivars.base import ImmutableVar, LiteralVar
|
||||
from reflex.style import Style, format_as_emotion
|
||||
from reflex.utils import format, imports, types
|
||||
from reflex.utils.imports import (
|
||||
@ -53,8 +59,17 @@ from reflex.utils.imports import (
|
||||
ParsedImportDict,
|
||||
parse_imports,
|
||||
)
|
||||
from reflex.utils.serializers import serializer
|
||||
from reflex.vars import Var, VarData
|
||||
from reflex.vars import VarData
|
||||
from reflex.vars.base import (
|
||||
CachedVarOperation,
|
||||
LiteralVar,
|
||||
Var,
|
||||
cached_property_no_lock,
|
||||
)
|
||||
from reflex.vars.function import ArgsFunctionOperation, FunctionStringVar
|
||||
from reflex.vars.number import ternary_operation
|
||||
from reflex.vars.object import ObjectVar
|
||||
from reflex.vars.sequence import LiteralArrayVar
|
||||
|
||||
|
||||
class BaseComponent(Base, ABC):
|
||||
@ -177,7 +192,7 @@ class Component(BaseComponent, ABC):
|
||||
style: Style = Style()
|
||||
|
||||
# A mapping from event triggers to event chains.
|
||||
event_triggers: Dict[str, Union[EventChain, ImmutableVar]] = {}
|
||||
event_triggers: Dict[str, Union[EventChain, Var]] = {}
|
||||
|
||||
# The alias for the tag.
|
||||
alias: Optional[str] = None
|
||||
@ -195,7 +210,7 @@ class Component(BaseComponent, ABC):
|
||||
class_name: Any = None
|
||||
|
||||
# Special component props.
|
||||
special_props: Set[ImmutableVar] = set()
|
||||
special_props: List[Var] = []
|
||||
|
||||
# Whether the component should take the focus once the page is loaded
|
||||
autofocus: bool = False
|
||||
@ -213,7 +228,7 @@ class Component(BaseComponent, ABC):
|
||||
_rename_props: Dict[str, str] = {}
|
||||
|
||||
# custom attribute
|
||||
custom_attrs: Dict[str, Union[ImmutableVar, str]] = {}
|
||||
custom_attrs: Dict[str, Union[Var, str]] = {}
|
||||
|
||||
# When to memoize this component and its children.
|
||||
_memoization_mode: MemoizationMode = MemoizationMode()
|
||||
@ -249,7 +264,7 @@ class Component(BaseComponent, ABC):
|
||||
"""
|
||||
return {}
|
||||
|
||||
def add_hooks(self) -> list[str | ImmutableVar]:
|
||||
def add_hooks(self) -> list[str | Var]:
|
||||
"""Add hooks inside the component function.
|
||||
|
||||
Hooks are pieces of literal Javascript code that is inserted inside the
|
||||
@ -404,7 +419,7 @@ class Component(BaseComponent, ABC):
|
||||
passed_types = None
|
||||
try:
|
||||
# Try to create a var from the value.
|
||||
if isinstance(value, ImmutableVar):
|
||||
if isinstance(value, Var):
|
||||
kwargs[key] = value
|
||||
else:
|
||||
kwargs[key] = LiteralVar.create(value)
|
||||
@ -447,11 +462,17 @@ class Component(BaseComponent, ABC):
|
||||
not passed_types
|
||||
and not types._issubclass(passed_type, expected_type, value)
|
||||
):
|
||||
value_name = (
|
||||
value._var_name if isinstance(value, ImmutableVar) else value
|
||||
value_name = value._js_expr if isinstance(value, Var) else value
|
||||
|
||||
additional_info = (
|
||||
" You can call `.bool()` on the value to convert it to a boolean."
|
||||
if expected_type is bool and isinstance(value, Var)
|
||||
else ""
|
||||
)
|
||||
|
||||
raise TypeError(
|
||||
f"Invalid var passed for prop {type(self).__name__}.{key}, expected type {expected_type}, got value {value_name} of type {passed_types or passed_type}."
|
||||
f"Invalid var passed for prop {type(self).__name__}.{key}, expected type {expected_type}, got value {value_name} of type {passed_type}."
|
||||
+ additional_info
|
||||
)
|
||||
# Check if the key is an event trigger.
|
||||
if key in component_specific_triggers:
|
||||
@ -459,19 +480,31 @@ class Component(BaseComponent, ABC):
|
||||
kwargs["event_triggers"][key] = self._create_event_chain(
|
||||
value=value, # type: ignore
|
||||
args_spec=component_specific_triggers[key],
|
||||
key=key,
|
||||
)
|
||||
|
||||
# Remove any keys that were added as events.
|
||||
for key in kwargs["event_triggers"]:
|
||||
del kwargs[key]
|
||||
|
||||
# Place data_ and aria_ attributes into custom_attrs
|
||||
special_attributes = tuple(
|
||||
key
|
||||
for key in kwargs
|
||||
if key not in fields and SpecialAttributes.is_special(key)
|
||||
)
|
||||
if special_attributes:
|
||||
custom_attrs = kwargs.setdefault("custom_attrs", {})
|
||||
for key in special_attributes:
|
||||
custom_attrs[format.to_kebab_case(key)] = kwargs.pop(key)
|
||||
|
||||
# Add style props to the component.
|
||||
style = kwargs.get("style", {})
|
||||
if isinstance(style, List):
|
||||
# Merge styles, the later ones overriding keys in the earlier ones.
|
||||
style = {k: v for style_dict in style for k, v in style_dict.items()}
|
||||
|
||||
if isinstance(style, Breakpoints):
|
||||
if isinstance(style, (Breakpoints, Var)):
|
||||
style = {
|
||||
# Assign the Breakpoints to the self-referential selector to avoid squashing down to a regular dict.
|
||||
"&": style,
|
||||
@ -484,13 +517,16 @@ class Component(BaseComponent, ABC):
|
||||
**{attr: value for attr, value in kwargs.items() if attr not in fields},
|
||||
}
|
||||
)
|
||||
if "custom_attrs" not in kwargs:
|
||||
kwargs["custom_attrs"] = {}
|
||||
|
||||
# Convert class_name to str if it's list
|
||||
class_name = kwargs.get("class_name", "")
|
||||
if isinstance(class_name, (List, tuple)):
|
||||
kwargs["class_name"] = " ".join(class_name)
|
||||
if any(isinstance(c, Var) for c in class_name):
|
||||
kwargs["class_name"] = LiteralArrayVar.create(
|
||||
class_name, _var_type=List[str]
|
||||
).join(" ")
|
||||
else:
|
||||
kwargs["class_name"] = " ".join(class_name)
|
||||
|
||||
# Construct the component.
|
||||
super().__init__(*args, **kwargs)
|
||||
@ -499,14 +535,20 @@ class Component(BaseComponent, ABC):
|
||||
self,
|
||||
args_spec: Any,
|
||||
value: Union[
|
||||
Var, EventHandler, EventSpec, List[Union[EventHandler, EventSpec]], Callable
|
||||
Var,
|
||||
EventHandler,
|
||||
EventSpec,
|
||||
List[Union[EventHandler, EventSpec, EventVar]],
|
||||
Callable,
|
||||
],
|
||||
) -> Union[EventChain, ImmutableVar]:
|
||||
key: Optional[str] = None,
|
||||
) -> Union[EventChain, Var]:
|
||||
"""Create an event chain from a variety of input types.
|
||||
|
||||
Args:
|
||||
args_spec: The args_spec of the event trigger being bound.
|
||||
value: The value to create the event chain from.
|
||||
key: The key of the event trigger being bound.
|
||||
|
||||
Returns:
|
||||
The event chain.
|
||||
@ -515,12 +557,17 @@ class Component(BaseComponent, ABC):
|
||||
ValueError: If the value is not a valid event chain.
|
||||
"""
|
||||
# If it's an event chain var, return it.
|
||||
if isinstance(value, ImmutableVar):
|
||||
if value._var_type is not EventChain:
|
||||
if isinstance(value, Var):
|
||||
if isinstance(value, EventChainVar):
|
||||
return value
|
||||
elif isinstance(value, EventVar):
|
||||
value = [value]
|
||||
elif issubclass(value._var_type, (EventChain, EventSpec)):
|
||||
return self._create_event_chain(args_spec, value.guess_type(), key=key)
|
||||
else:
|
||||
raise ValueError(
|
||||
f"Invalid event chain: {repr(value)} of type {type(value)}"
|
||||
f"Invalid event chain: {str(value)} of type {value._var_type}"
|
||||
)
|
||||
return value
|
||||
elif isinstance(value, EventChain):
|
||||
# Trust that the caller knows what they're doing passing an EventChain directly
|
||||
return value
|
||||
@ -531,55 +578,55 @@ class Component(BaseComponent, ABC):
|
||||
|
||||
# If the input is a list of event handlers, create an event chain.
|
||||
if isinstance(value, List):
|
||||
events: list[EventSpec] = []
|
||||
events: List[Union[EventSpec, EventVar]] = []
|
||||
for v in value:
|
||||
if isinstance(v, (EventHandler, EventSpec)):
|
||||
# Call the event handler to get the event.
|
||||
events.append(call_event_handler(v, args_spec))
|
||||
events.append(call_event_handler(v, args_spec, key=key))
|
||||
elif isinstance(v, Callable):
|
||||
# Call the lambda to get the event chain.
|
||||
result = call_event_fn(v, args_spec)
|
||||
if isinstance(result, ImmutableVar):
|
||||
result = call_event_fn(v, args_spec, key=key)
|
||||
if isinstance(result, Var):
|
||||
raise ValueError(
|
||||
f"Invalid event chain: {v}. Cannot use a Var-returning "
|
||||
"lambda inside an EventChain list."
|
||||
)
|
||||
events.extend(result)
|
||||
elif isinstance(v, EventVar):
|
||||
events.append(v)
|
||||
else:
|
||||
raise ValueError(f"Invalid event: {v}")
|
||||
|
||||
# If the input is a callable, create an event chain.
|
||||
elif isinstance(value, Callable):
|
||||
result = call_event_fn(value, args_spec)
|
||||
if isinstance(result, ImmutableVar):
|
||||
if isinstance(result, Var):
|
||||
# Recursively call this function if the lambda returned an EventChain Var.
|
||||
return self._create_event_chain(args_spec, result)
|
||||
events = result
|
||||
return self._create_event_chain(args_spec, result, key=key)
|
||||
events = [*result]
|
||||
|
||||
# Otherwise, raise an error.
|
||||
else:
|
||||
raise ValueError(f"Invalid event chain: {value}")
|
||||
|
||||
# Add args to the event specs if necessary.
|
||||
events = [e.with_args(get_handler_args(e)) for e in events]
|
||||
|
||||
# Collect event_actions from each spec
|
||||
event_actions = {}
|
||||
for e in events:
|
||||
event_actions.update(e.event_actions)
|
||||
events = [
|
||||
(e.with_args(get_handler_args(e)) if isinstance(e, EventSpec) else e)
|
||||
for e in events
|
||||
]
|
||||
|
||||
# Return the event chain.
|
||||
if isinstance(args_spec, ImmutableVar):
|
||||
if isinstance(args_spec, Var):
|
||||
return EventChain(
|
||||
events=events,
|
||||
args_spec=None,
|
||||
event_actions=event_actions,
|
||||
event_actions={},
|
||||
)
|
||||
else:
|
||||
return EventChain(
|
||||
events=events,
|
||||
args_spec=args_spec,
|
||||
event_actions=event_actions,
|
||||
event_actions={},
|
||||
)
|
||||
|
||||
def get_event_triggers(self) -> Dict[str, Any]:
|
||||
@ -590,32 +637,32 @@ class Component(BaseComponent, ABC):
|
||||
|
||||
"""
|
||||
default_triggers = {
|
||||
EventTriggers.ON_FOCUS: lambda: [],
|
||||
EventTriggers.ON_BLUR: lambda: [],
|
||||
EventTriggers.ON_CLICK: lambda: [],
|
||||
EventTriggers.ON_CONTEXT_MENU: lambda: [],
|
||||
EventTriggers.ON_DOUBLE_CLICK: lambda: [],
|
||||
EventTriggers.ON_MOUSE_DOWN: lambda: [],
|
||||
EventTriggers.ON_MOUSE_ENTER: lambda: [],
|
||||
EventTriggers.ON_MOUSE_LEAVE: lambda: [],
|
||||
EventTriggers.ON_MOUSE_MOVE: lambda: [],
|
||||
EventTriggers.ON_MOUSE_OUT: lambda: [],
|
||||
EventTriggers.ON_MOUSE_OVER: lambda: [],
|
||||
EventTriggers.ON_MOUSE_UP: lambda: [],
|
||||
EventTriggers.ON_SCROLL: lambda: [],
|
||||
EventTriggers.ON_MOUNT: lambda: [],
|
||||
EventTriggers.ON_UNMOUNT: lambda: [],
|
||||
EventTriggers.ON_FOCUS: empty_event,
|
||||
EventTriggers.ON_BLUR: empty_event,
|
||||
EventTriggers.ON_CLICK: empty_event,
|
||||
EventTriggers.ON_CONTEXT_MENU: empty_event,
|
||||
EventTriggers.ON_DOUBLE_CLICK: empty_event,
|
||||
EventTriggers.ON_MOUSE_DOWN: empty_event,
|
||||
EventTriggers.ON_MOUSE_ENTER: empty_event,
|
||||
EventTriggers.ON_MOUSE_LEAVE: empty_event,
|
||||
EventTriggers.ON_MOUSE_MOVE: empty_event,
|
||||
EventTriggers.ON_MOUSE_OUT: empty_event,
|
||||
EventTriggers.ON_MOUSE_OVER: empty_event,
|
||||
EventTriggers.ON_MOUSE_UP: empty_event,
|
||||
EventTriggers.ON_SCROLL: empty_event,
|
||||
EventTriggers.ON_MOUNT: empty_event,
|
||||
EventTriggers.ON_UNMOUNT: empty_event,
|
||||
}
|
||||
|
||||
# Look for component specific triggers,
|
||||
# e.g. variable declared as EventHandler types.
|
||||
for field in self.get_fields().values():
|
||||
if types._issubclass(field.type_, EventHandler):
|
||||
if types._issubclass(field.outer_type_, EventHandler):
|
||||
args_spec = None
|
||||
annotation = field.annotation
|
||||
if hasattr(annotation, "__metadata__"):
|
||||
args_spec = annotation.__metadata__[0]
|
||||
default_triggers[field.name] = args_spec or (lambda: [])
|
||||
if (metadata := getattr(annotation, "__metadata__", None)) is not None:
|
||||
args_spec = metadata[0]
|
||||
default_triggers[field.name] = args_spec or (empty_event) # type: ignore
|
||||
return default_triggers
|
||||
|
||||
def __repr__(self) -> str:
|
||||
@ -655,7 +702,7 @@ class Component(BaseComponent, ABC):
|
||||
"""
|
||||
# Create the base tag.
|
||||
tag = Tag(
|
||||
name=self.tag if not self.alias else self.alias,
|
||||
name=(self.tag if not self.alias else self.alias) or "",
|
||||
special_props=self.special_props,
|
||||
)
|
||||
|
||||
@ -669,7 +716,7 @@ class Component(BaseComponent, ABC):
|
||||
# Add ref to element if `id` is not None.
|
||||
ref = self.get_ref()
|
||||
if ref is not None:
|
||||
props["ref"] = ImmutableVar.create(ref)
|
||||
props["ref"] = Var(_js_expr=ref)
|
||||
else:
|
||||
props = props.copy()
|
||||
|
||||
@ -882,7 +929,7 @@ class Component(BaseComponent, ABC):
|
||||
Returns:
|
||||
The dictionary of the component style as value and the style notation as key.
|
||||
"""
|
||||
if isinstance(self.style, ImmutableVar):
|
||||
if isinstance(self.style, Var):
|
||||
return {"css": self.style}
|
||||
emotion_style = format_as_emotion(self.style)
|
||||
return (
|
||||
@ -998,8 +1045,8 @@ class Component(BaseComponent, ABC):
|
||||
|
||||
@staticmethod
|
||||
def _get_vars_from_event_triggers(
|
||||
event_triggers: dict[str, EventChain | ImmutableVar],
|
||||
) -> Iterator[tuple[str, list[ImmutableVar]]]:
|
||||
event_triggers: dict[str, EventChain | Var],
|
||||
) -> Iterator[tuple[str, list[Var]]]:
|
||||
"""Get the Vars associated with each event trigger.
|
||||
|
||||
Args:
|
||||
@ -1009,16 +1056,19 @@ class Component(BaseComponent, ABC):
|
||||
tuple of (event_name, event_vars)
|
||||
"""
|
||||
for event_trigger, event in event_triggers.items():
|
||||
if isinstance(event, ImmutableVar):
|
||||
if isinstance(event, Var):
|
||||
yield event_trigger, [event]
|
||||
elif isinstance(event, EventChain):
|
||||
event_args = []
|
||||
for spec in event.events:
|
||||
for args in spec.args:
|
||||
event_args.extend(args)
|
||||
if isinstance(spec, EventSpec):
|
||||
for args in spec.args:
|
||||
event_args.extend(args)
|
||||
else:
|
||||
event_args.append(spec)
|
||||
yield event_trigger, event_args
|
||||
|
||||
def _get_vars(self, include_children: bool = False) -> list[ImmutableVar]:
|
||||
def _get_vars(self, include_children: bool = False) -> list[Var]:
|
||||
"""Walk all Vars used in this component.
|
||||
|
||||
Args:
|
||||
@ -1038,18 +1088,14 @@ class Component(BaseComponent, ABC):
|
||||
# Get Vars associated with component props.
|
||||
for prop in self.get_props():
|
||||
prop_var = getattr(self, prop)
|
||||
if isinstance(prop_var, ImmutableVar):
|
||||
if isinstance(prop_var, Var):
|
||||
vars.append(prop_var)
|
||||
|
||||
# Style keeps track of its own VarData instance, so embed in a temp Var that is yielded.
|
||||
if (
|
||||
isinstance(self.style, dict)
|
||||
and self.style
|
||||
or isinstance(self.style, ImmutableVar)
|
||||
):
|
||||
if isinstance(self.style, dict) and self.style or isinstance(self.style, Var):
|
||||
vars.append(
|
||||
ImmutableVar(
|
||||
_var_name="style",
|
||||
Var(
|
||||
_js_expr="style",
|
||||
_var_type=str,
|
||||
_var_data=VarData.merge(self.style._var_data),
|
||||
)
|
||||
@ -1066,7 +1112,7 @@ class Component(BaseComponent, ABC):
|
||||
self.autofocus,
|
||||
*self.custom_attrs.values(),
|
||||
):
|
||||
if isinstance(comp_prop, ImmutableVar):
|
||||
if isinstance(comp_prop, Var):
|
||||
vars.append(comp_prop)
|
||||
elif isinstance(comp_prop, str):
|
||||
# Collapse VarData encoded in f-strings.
|
||||
@ -1093,9 +1139,15 @@ class Component(BaseComponent, ABC):
|
||||
for trigger in self.event_triggers.values():
|
||||
if isinstance(trigger, EventChain):
|
||||
for event in trigger.events:
|
||||
if event.handler.state_full_name:
|
||||
return True
|
||||
elif isinstance(trigger, ImmutableVar) and trigger._var_state:
|
||||
if isinstance(event, EventCallback):
|
||||
continue
|
||||
if isinstance(event, EventSpec):
|
||||
if event.handler.state_full_name:
|
||||
return True
|
||||
else:
|
||||
if event._var_state:
|
||||
return True
|
||||
elif isinstance(trigger, Var) and trigger._var_state:
|
||||
return True
|
||||
return False
|
||||
|
||||
@ -1268,7 +1320,9 @@ class Component(BaseComponent, ABC):
|
||||
if self._get_ref_hook():
|
||||
# Handle hooks needed for attaching react refs to DOM nodes.
|
||||
_imports.setdefault("react", set()).add(ImportVar(tag="useRef"))
|
||||
_imports.setdefault(f"/{Dirs.STATE_PATH}", set()).add(ImportVar(tag="refs"))
|
||||
_imports.setdefault(f"$/{Dirs.STATE_PATH}", set()).add(
|
||||
ImportVar(tag="refs")
|
||||
)
|
||||
|
||||
if self._get_mount_lifecycle_hook():
|
||||
# Handle hooks for `on_mount` / `on_unmount`.
|
||||
@ -1287,7 +1341,7 @@ class Component(BaseComponent, ABC):
|
||||
user_hooks = self._get_hooks()
|
||||
user_hooks_data = (
|
||||
VarData.merge(user_hooks._get_all_var_data())
|
||||
if user_hooks is not None and isinstance(user_hooks, ImmutableVar)
|
||||
if user_hooks is not None and isinstance(user_hooks, Var)
|
||||
else None
|
||||
)
|
||||
if user_hooks_data is not None:
|
||||
@ -1390,7 +1444,7 @@ class Component(BaseComponent, ABC):
|
||||
"""
|
||||
ref = self.get_ref()
|
||||
if ref is not None:
|
||||
return f"const {ref} = useRef(null); {str(ImmutableVar.create_safe(ref).as_ref())} = {ref};"
|
||||
return f"const {ref} = useRef(null); {str(Var(_js_expr=ref).as_ref())} = {ref};"
|
||||
|
||||
def _get_vars_hooks(self) -> dict[str, None]:
|
||||
"""Get the hooks required by vars referenced in this component.
|
||||
@ -1453,7 +1507,7 @@ class Component(BaseComponent, ABC):
|
||||
"""
|
||||
code = {}
|
||||
|
||||
def extract_var_hooks(hook: ImmutableVar):
|
||||
def extract_var_hooks(hook: Var):
|
||||
_imports = {}
|
||||
var_data = VarData.merge(hook._get_all_var_data())
|
||||
if var_data is not None:
|
||||
@ -1470,7 +1524,7 @@ class Component(BaseComponent, ABC):
|
||||
# the order of the hooks in the final output)
|
||||
for clz in reversed(tuple(self._iter_parent_classes_with_method("add_hooks"))):
|
||||
for hook in clz.add_hooks(self):
|
||||
if isinstance(hook, ImmutableVar):
|
||||
if isinstance(hook, Var):
|
||||
extract_var_hooks(hook)
|
||||
else:
|
||||
code[hook] = {}
|
||||
@ -1531,7 +1585,7 @@ class Component(BaseComponent, ABC):
|
||||
The ref name.
|
||||
"""
|
||||
# do not create a ref if the id is dynamic or unspecified
|
||||
if self.id is None or isinstance(self.id, ImmutableVar):
|
||||
if self.id is None or isinstance(self.id, Var):
|
||||
return None
|
||||
return format.format_ref(self.id)
|
||||
|
||||
@ -1625,7 +1679,7 @@ class CustomComponent(Component):
|
||||
"""A custom user-defined component."""
|
||||
|
||||
# Use the components library.
|
||||
library = f"/{Dirs.COMPONENTS_PATH}"
|
||||
library = f"$/{Dirs.COMPONENTS_PATH}"
|
||||
|
||||
# The function that creates the component.
|
||||
component_fn: Callable[..., Component] = Component.create
|
||||
@ -1669,8 +1723,9 @@ class CustomComponent(Component):
|
||||
value = self._create_event_chain(
|
||||
value=value,
|
||||
args_spec=event_triggers_in_component_declaration.get(
|
||||
key, lambda: []
|
||||
key, empty_event
|
||||
),
|
||||
key=key,
|
||||
)
|
||||
self.props[format.to_camel_case(key)] = value
|
||||
continue
|
||||
@ -1732,10 +1787,14 @@ class CustomComponent(Component):
|
||||
Args:
|
||||
seen: The tags of the components that have already been seen.
|
||||
|
||||
Raises:
|
||||
ValueError: If the tag is not set.
|
||||
|
||||
Returns:
|
||||
The set of custom components.
|
||||
"""
|
||||
assert self.tag is not None, "The tag must be set."
|
||||
if self.tag is None:
|
||||
raise ValueError("The tag must be set.")
|
||||
|
||||
# Store the seen components in a set to avoid infinite recursion.
|
||||
if seen is None:
|
||||
@ -1770,15 +1829,15 @@ class CustomComponent(Component):
|
||||
"""
|
||||
return super()._render(props=self.props)
|
||||
|
||||
def get_prop_vars(self) -> List[ImmutableVar]:
|
||||
def get_prop_vars(self) -> List[Var]:
|
||||
"""Get the prop vars.
|
||||
|
||||
Returns:
|
||||
The prop vars.
|
||||
"""
|
||||
return [
|
||||
ImmutableVar(
|
||||
_var_name=name,
|
||||
Var(
|
||||
_js_expr=name,
|
||||
_var_type=(
|
||||
prop._var_type if types._isinstance(prop, Var) else type(prop)
|
||||
),
|
||||
@ -1786,7 +1845,7 @@ class CustomComponent(Component):
|
||||
for name, prop in self.props.items()
|
||||
]
|
||||
|
||||
def _get_vars(self, include_children: bool = False) -> list[ImmutableVar]:
|
||||
def _get_vars(self, include_children: bool = False) -> list[Var]:
|
||||
"""Walk all Vars used in this component.
|
||||
|
||||
Args:
|
||||
@ -1797,7 +1856,7 @@ class CustomComponent(Component):
|
||||
"""
|
||||
return (
|
||||
super()._get_vars(include_children=include_children)
|
||||
+ [prop for prop in self.props.values() if isinstance(prop, ImmutableVar)]
|
||||
+ [prop for prop in self.props.values() if isinstance(prop, Var)]
|
||||
+ self.get_component(self)._get_vars(include_children=include_children)
|
||||
)
|
||||
|
||||
@ -1884,19 +1943,6 @@ class NoSSRComponent(Component):
|
||||
return "".join((library_import, mod_import, opts_fragment))
|
||||
|
||||
|
||||
@serializer
|
||||
def serialize_component(comp: Component):
|
||||
"""Serialize a component.
|
||||
|
||||
Args:
|
||||
comp: The component to serialize.
|
||||
|
||||
Returns:
|
||||
The serialized component.
|
||||
"""
|
||||
return str(comp)
|
||||
|
||||
|
||||
class StatefulComponent(BaseComponent):
|
||||
"""A component that depends on state and is rendered outside of the page component.
|
||||
|
||||
@ -1968,7 +2014,7 @@ class StatefulComponent(BaseComponent):
|
||||
should_memoize = True
|
||||
break
|
||||
child = cls._child_var(child)
|
||||
if isinstance(child, ImmutableVar) and child._get_all_var_data():
|
||||
if isinstance(child, Var) and child._get_all_var_data():
|
||||
should_memoize = True
|
||||
break
|
||||
|
||||
@ -2124,7 +2170,7 @@ class StatefulComponent(BaseComponent):
|
||||
def _get_memoized_event_triggers(
|
||||
cls,
|
||||
component: Component,
|
||||
) -> dict[str, tuple[ImmutableVar, str]]:
|
||||
) -> dict[str, tuple[Var, str]]:
|
||||
"""Memoize event handler functions with useCallback to avoid unnecessary re-renders.
|
||||
|
||||
Args:
|
||||
@ -2171,7 +2217,7 @@ class StatefulComponent(BaseComponent):
|
||||
|
||||
# Store the memoized function name and hook code for this event trigger.
|
||||
trigger_memo[event_trigger] = (
|
||||
ImmutableVar.create_safe(memo_name)._replace(
|
||||
Var(_js_expr=memo_name)._replace(
|
||||
_var_type=EventChain, merge_var_data=memo_var_data
|
||||
),
|
||||
f"const {memo_name} = useCallback({rendered_chain}, [{', '.join(var_deps)}])",
|
||||
@ -2202,7 +2248,7 @@ class StatefulComponent(BaseComponent):
|
||||
"""
|
||||
if self.rendered_as_shared:
|
||||
return {
|
||||
f"/{Dirs.UTILS}/{PageNames.STATEFUL_COMPONENTS}": [
|
||||
f"$/{Dirs.UTILS}/{PageNames.STATEFUL_COMPONENTS}": [
|
||||
ImportVar(tag=self.tag)
|
||||
]
|
||||
}
|
||||
@ -2244,7 +2290,7 @@ class StatefulComponent(BaseComponent):
|
||||
Returns:
|
||||
The tag to render.
|
||||
"""
|
||||
return dict(Tag(name=self.tag))
|
||||
return dict(Tag(name=self.tag or ""))
|
||||
|
||||
def __str__(self) -> str:
|
||||
"""Represent the component in React.
|
||||
@ -2309,3 +2355,206 @@ class MemoizationLeaf(Component):
|
||||
update={"disposition": MemoizationDisposition.ALWAYS}
|
||||
)
|
||||
return comp
|
||||
|
||||
|
||||
load_dynamic_serializer()
|
||||
|
||||
|
||||
class ComponentVar(Var[Component], python_types=BaseComponent):
|
||||
"""A Var that represents a Component."""
|
||||
|
||||
|
||||
def empty_component() -> Component:
|
||||
"""Create an empty component.
|
||||
|
||||
Returns:
|
||||
An empty component.
|
||||
"""
|
||||
from reflex.components.base.bare import Bare
|
||||
|
||||
return Bare.create("")
|
||||
|
||||
|
||||
def render_dict_to_var(tag: dict | Component | str, imported_names: set[str]) -> Var:
|
||||
"""Convert a render dict to a Var.
|
||||
|
||||
Args:
|
||||
tag: The render dict.
|
||||
imported_names: The names of the imported components.
|
||||
|
||||
Returns:
|
||||
The Var.
|
||||
"""
|
||||
if not isinstance(tag, dict):
|
||||
if isinstance(tag, Component):
|
||||
return render_dict_to_var(tag.render(), imported_names)
|
||||
return Var.create(tag)
|
||||
|
||||
if "iterable" in tag:
|
||||
function_return = Var.create(
|
||||
[
|
||||
render_dict_to_var(child.render(), imported_names)
|
||||
for child in tag["children"]
|
||||
]
|
||||
)
|
||||
|
||||
func = ArgsFunctionOperation.create(
|
||||
(tag["arg_var_name"], tag["index_var_name"]),
|
||||
function_return,
|
||||
)
|
||||
|
||||
return FunctionStringVar.create("Array.prototype.map.call").call(
|
||||
tag["iterable"]
|
||||
if not isinstance(tag["iterable"], ObjectVar)
|
||||
else tag["iterable"].items(),
|
||||
func,
|
||||
)
|
||||
|
||||
if tag["name"] == "match":
|
||||
element = tag["cond"]
|
||||
|
||||
conditionals = tag["default"]
|
||||
|
||||
for case in tag["match_cases"][::-1]:
|
||||
condition = case[0].to_string() == element.to_string()
|
||||
for pattern in case[1:-1]:
|
||||
condition = condition | (pattern.to_string() == element.to_string())
|
||||
|
||||
conditionals = ternary_operation(
|
||||
condition,
|
||||
case[-1],
|
||||
conditionals,
|
||||
)
|
||||
|
||||
return conditionals
|
||||
|
||||
if "cond" in tag:
|
||||
return ternary_operation(
|
||||
tag["cond"],
|
||||
render_dict_to_var(tag["true_value"], imported_names),
|
||||
render_dict_to_var(tag["false_value"], imported_names)
|
||||
if tag["false_value"] is not None
|
||||
else Var.create(None),
|
||||
)
|
||||
|
||||
props = {}
|
||||
|
||||
special_props = []
|
||||
|
||||
for prop_str in tag["props"]:
|
||||
if "=" not in prop_str:
|
||||
special_props.append(Var(prop_str).to(ObjectVar))
|
||||
continue
|
||||
prop = prop_str.index("=")
|
||||
key = prop_str[:prop]
|
||||
value = prop_str[prop + 2 : -1]
|
||||
props[key] = value
|
||||
|
||||
props = Var.create({Var.create(k): Var(v) for k, v in props.items()})
|
||||
|
||||
for prop in special_props:
|
||||
props = props.merge(prop)
|
||||
|
||||
contents = tag["contents"][1:-1] if tag["contents"] else None
|
||||
|
||||
raw_tag_name = tag.get("name")
|
||||
tag_name = Var(raw_tag_name or "Fragment")
|
||||
|
||||
tag_name = (
|
||||
Var.create(raw_tag_name)
|
||||
if raw_tag_name
|
||||
and raw_tag_name.split(".")[0] not in imported_names
|
||||
and raw_tag_name.lower() == raw_tag_name
|
||||
else tag_name
|
||||
)
|
||||
|
||||
return FunctionStringVar.create(
|
||||
"jsx",
|
||||
).call(
|
||||
tag_name,
|
||||
props,
|
||||
*([Var(contents)] if contents is not None else []),
|
||||
*[render_dict_to_var(child, imported_names) for child in tag["children"]],
|
||||
)
|
||||
|
||||
|
||||
@dataclasses.dataclass(
|
||||
eq=False,
|
||||
frozen=True,
|
||||
)
|
||||
class LiteralComponentVar(CachedVarOperation, LiteralVar, ComponentVar):
|
||||
"""A Var that represents a Component."""
|
||||
|
||||
_var_value: BaseComponent = dataclasses.field(default_factory=empty_component)
|
||||
|
||||
@cached_property_no_lock
|
||||
def _cached_var_name(self) -> str:
|
||||
"""Get the name of the var.
|
||||
|
||||
Returns:
|
||||
The name of the var.
|
||||
"""
|
||||
var_data = self._get_all_var_data()
|
||||
if var_data is not None:
|
||||
# flatten imports
|
||||
imported_names = {j.alias or j.name for i in var_data.imports for j in i[1]}
|
||||
else:
|
||||
imported_names = set()
|
||||
return str(render_dict_to_var(self._var_value.render(), imported_names))
|
||||
|
||||
@cached_property_no_lock
|
||||
def _cached_get_all_var_data(self) -> VarData | None:
|
||||
"""Get the VarData for the var.
|
||||
|
||||
Returns:
|
||||
The VarData for the var.
|
||||
"""
|
||||
return VarData.merge(
|
||||
VarData(
|
||||
imports={
|
||||
"@emotion/react": [
|
||||
ImportVar(tag="jsx"),
|
||||
],
|
||||
}
|
||||
),
|
||||
VarData(
|
||||
imports=self._var_value._get_all_imports(),
|
||||
),
|
||||
VarData(
|
||||
imports={
|
||||
"react": [
|
||||
ImportVar(tag="Fragment"),
|
||||
],
|
||||
}
|
||||
),
|
||||
)
|
||||
|
||||
def __hash__(self) -> int:
|
||||
"""Get the hash of the var.
|
||||
|
||||
Returns:
|
||||
The hash of the var.
|
||||
"""
|
||||
return hash((self.__class__.__name__, self._js_expr))
|
||||
|
||||
@classmethod
|
||||
def create(
|
||||
cls,
|
||||
value: Component,
|
||||
_var_data: VarData | None = None,
|
||||
):
|
||||
"""Create a var from a value.
|
||||
|
||||
Args:
|
||||
value: The value of the var.
|
||||
_var_data: Additional hooks and imports associated with the Var.
|
||||
|
||||
Returns:
|
||||
The var.
|
||||
"""
|
||||
return LiteralComponentVar(
|
||||
_js_expr="",
|
||||
_var_type=type(value),
|
||||
_var_data=_var_data,
|
||||
_var_value=value,
|
||||
)
|
||||
|
@ -18,60 +18,56 @@ from reflex.components.radix.themes.typography.text import Text
|
||||
from reflex.components.sonner.toast import Toaster, ToastProps
|
||||
from reflex.constants import Dirs, Hooks, Imports
|
||||
from reflex.constants.compiler import CompileVars
|
||||
from reflex.ivars.base import ImmutableVar, LiteralVar
|
||||
from reflex.ivars.function import FunctionStringVar
|
||||
from reflex.ivars.number import BooleanVar
|
||||
from reflex.ivars.sequence import LiteralArrayVar
|
||||
from reflex.utils.imports import ImportVar
|
||||
from reflex.vars import Var, VarData
|
||||
from reflex.vars import VarData
|
||||
from reflex.vars.base import LiteralVar, Var
|
||||
from reflex.vars.function import FunctionStringVar
|
||||
from reflex.vars.number import BooleanVar
|
||||
from reflex.vars.sequence import LiteralArrayVar
|
||||
|
||||
connect_error_var_data: VarData = VarData( # type: ignore
|
||||
imports=Imports.EVENTS,
|
||||
hooks={Hooks.EVENTS: None},
|
||||
)
|
||||
|
||||
connect_errors: Var = ImmutableVar.create_safe(
|
||||
value=CompileVars.CONNECT_ERROR,
|
||||
connect_errors = Var(
|
||||
_js_expr=CompileVars.CONNECT_ERROR, _var_data=connect_error_var_data
|
||||
)
|
||||
|
||||
connection_error = Var(
|
||||
_js_expr="((connectErrors.length > 0) ? connectErrors[connectErrors.length - 1].message : '')",
|
||||
_var_data=connect_error_var_data,
|
||||
)
|
||||
|
||||
connection_error: Var = ImmutableVar.create_safe(
|
||||
value="((connectErrors.length > 0) ? connectErrors[connectErrors.length - 1].message : '')",
|
||||
_var_data=connect_error_var_data,
|
||||
connection_errors_count = Var(
|
||||
_js_expr="connectErrors.length", _var_data=connect_error_var_data
|
||||
)
|
||||
|
||||
connection_errors_count: Var = ImmutableVar.create_safe(
|
||||
value="connectErrors.length",
|
||||
_var_data=connect_error_var_data,
|
||||
)
|
||||
|
||||
has_connection_errors: Var = ImmutableVar.create_safe(
|
||||
value="(connectErrors.length > 0)",
|
||||
_var_data=connect_error_var_data,
|
||||
has_connection_errors = Var(
|
||||
_js_expr="(connectErrors.length > 0)", _var_data=connect_error_var_data
|
||||
).to(BooleanVar)
|
||||
|
||||
has_too_many_connection_errors: Var = ImmutableVar.create_safe(
|
||||
value="(connectErrors.length >= 2)",
|
||||
_var_data=connect_error_var_data,
|
||||
has_too_many_connection_errors = Var(
|
||||
_js_expr="(connectErrors.length >= 2)", _var_data=connect_error_var_data
|
||||
).to(BooleanVar)
|
||||
|
||||
|
||||
class WebsocketTargetURL(ImmutableVar):
|
||||
class WebsocketTargetURL(Var):
|
||||
"""A component that renders the websocket target URL."""
|
||||
|
||||
@classmethod
|
||||
def create(cls) -> ImmutableVar:
|
||||
def create(cls) -> Var:
|
||||
"""Create a websocket target URL component.
|
||||
|
||||
Returns:
|
||||
The websocket target URL component.
|
||||
"""
|
||||
return ImmutableVar(
|
||||
_var_name="getBackendURL(env.EVENT).href",
|
||||
return Var(
|
||||
_js_expr="getBackendURL(env.EVENT).href",
|
||||
_var_data=VarData(
|
||||
imports={
|
||||
"/env.json": [ImportVar(tag="env", is_default=True)],
|
||||
f"/{Dirs.STATE_PATH}": [ImportVar(tag="getBackendURL")],
|
||||
"$/env.json": [ImportVar(tag="env", is_default=True)],
|
||||
f"$/{Dirs.STATE_PATH}": [ImportVar(tag="getBackendURL")],
|
||||
},
|
||||
),
|
||||
_var_type=WebsocketTargetURL,
|
||||
@ -95,7 +91,7 @@ def default_connection_error() -> list[str | Var | Component]:
|
||||
class ConnectionToaster(Toaster):
|
||||
"""A connection toaster component."""
|
||||
|
||||
def add_hooks(self) -> list[str | ImmutableVar]:
|
||||
def add_hooks(self) -> list[str | Var]:
|
||||
"""Add the hooks for the connection toaster.
|
||||
|
||||
Returns:
|
||||
@ -125,8 +121,8 @@ class ConnectionToaster(Toaster):
|
||||
),
|
||||
).call(
|
||||
# TODO: This breaks the assumption that Vars are JS expressions
|
||||
ImmutableVar.create_safe(
|
||||
f"""
|
||||
Var(
|
||||
_js_expr=f"""
|
||||
() => {{
|
||||
if ({str(has_too_many_connection_errors)}) {{
|
||||
if (!userDismissed) {{
|
||||
@ -238,7 +234,7 @@ class WifiOffPulse(Icon):
|
||||
Returns:
|
||||
The icon component with default props applied.
|
||||
"""
|
||||
pulse_var = ImmutableVar.create("pulse")
|
||||
pulse_var = Var(_js_expr="pulse")
|
||||
return super().create(
|
||||
"wifi_off",
|
||||
color=props.pop("color", "crimson"),
|
||||
|
@ -3,33 +3,46 @@
|
||||
# ------------------- DO NOT EDIT ----------------------
|
||||
# This file was generated by `reflex/utils/pyi_generator.py`!
|
||||
# ------------------------------------------------------
|
||||
from typing import Any, Callable, Dict, Literal, Optional, Union, overload
|
||||
from typing import Any, Dict, Literal, Optional, Union, overload
|
||||
|
||||
from reflex.components.component import Component
|
||||
from reflex.components.el.elements.typography import Div
|
||||
from reflex.components.lucide.icon import Icon
|
||||
from reflex.components.sonner.toast import Toaster, ToastProps
|
||||
from reflex.event import EventHandler, EventSpec
|
||||
from reflex.ivars.base import ImmutableVar
|
||||
from reflex.constants.compiler import CompileVars
|
||||
from reflex.event import EventType
|
||||
from reflex.style import Style
|
||||
from reflex.utils.imports import ImportVar
|
||||
from reflex.vars import Var, VarData
|
||||
from reflex.vars import VarData
|
||||
from reflex.vars.base import Var
|
||||
from reflex.vars.number import BooleanVar
|
||||
|
||||
connect_error_var_data: VarData
|
||||
connect_errors: Var
|
||||
connection_error: Var
|
||||
connection_errors_count: Var
|
||||
has_connection_errors: Var
|
||||
has_too_many_connection_errors: Var
|
||||
connect_errors = Var(
|
||||
_js_expr=CompileVars.CONNECT_ERROR, _var_data=connect_error_var_data
|
||||
)
|
||||
connection_error = Var(
|
||||
_js_expr="((connectErrors.length > 0) ? connectErrors[connectErrors.length - 1].message : '')",
|
||||
_var_data=connect_error_var_data,
|
||||
)
|
||||
connection_errors_count = Var(
|
||||
_js_expr="connectErrors.length", _var_data=connect_error_var_data
|
||||
)
|
||||
has_connection_errors = Var(
|
||||
_js_expr="(connectErrors.length > 0)", _var_data=connect_error_var_data
|
||||
).to(BooleanVar)
|
||||
has_too_many_connection_errors = Var(
|
||||
_js_expr="(connectErrors.length >= 2)", _var_data=connect_error_var_data
|
||||
).to(BooleanVar)
|
||||
|
||||
class WebsocketTargetURL(ImmutableVar):
|
||||
class WebsocketTargetURL(Var):
|
||||
@classmethod
|
||||
def create(cls) -> ImmutableVar: ... # type: ignore
|
||||
def create(cls) -> Var: ... # type: ignore
|
||||
|
||||
def default_connection_error() -> list[str | Var | Component]: ...
|
||||
|
||||
class ConnectionToaster(Toaster):
|
||||
def add_hooks(self) -> list[str | ImmutableVar]: ...
|
||||
def add_hooks(self) -> list[str | Var]: ...
|
||||
@overload
|
||||
@classmethod
|
||||
def create( # type: ignore
|
||||
@ -41,24 +54,24 @@ class ConnectionToaster(Toaster):
|
||||
visible_toasts: Optional[Union[Var[int], int]] = None,
|
||||
position: Optional[
|
||||
Union[
|
||||
Literal[
|
||||
"bottom-center",
|
||||
"bottom-left",
|
||||
"bottom-right",
|
||||
"top-center",
|
||||
"top-left",
|
||||
"top-right",
|
||||
],
|
||||
Var[
|
||||
Literal[
|
||||
"top-left",
|
||||
"top-center",
|
||||
"top-right",
|
||||
"bottom-left",
|
||||
"bottom-center",
|
||||
"bottom-left",
|
||||
"bottom-right",
|
||||
"top-center",
|
||||
"top-left",
|
||||
"top-right",
|
||||
]
|
||||
],
|
||||
Literal[
|
||||
"top-left",
|
||||
"top-center",
|
||||
"top-right",
|
||||
"bottom-left",
|
||||
"bottom-center",
|
||||
"bottom-right",
|
||||
],
|
||||
]
|
||||
] = None,
|
||||
close_button: Optional[Union[Var[bool], bool]] = None,
|
||||
@ -66,61 +79,31 @@ class ConnectionToaster(Toaster):
|
||||
dir: Optional[Union[Var[str], str]] = None,
|
||||
hotkey: Optional[Union[Var[str], str]] = None,
|
||||
invert: Optional[Union[Var[bool], bool]] = None,
|
||||
toast_options: Optional[Union[Var[ToastProps], ToastProps]] = None,
|
||||
toast_options: Optional[Union[ToastProps, Var[ToastProps]]] = None,
|
||||
gap: Optional[Union[Var[int], int]] = None,
|
||||
loading_icon: Optional[Union[Var[Icon], Icon]] = None,
|
||||
loading_icon: Optional[Union[Icon, Var[Icon]]] = None,
|
||||
pause_when_page_is_hidden: Optional[Union[Var[bool], bool]] = 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[ImmutableVar, str]]] = None,
|
||||
on_blur: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_context_menu: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_double_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_focus: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_down: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_enter: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_leave: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_move: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_out: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_over: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_up: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_scroll: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_unmount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = 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,
|
||||
) -> "ConnectionToaster":
|
||||
"""Create a connection toaster component.
|
||||
@ -165,52 +148,22 @@ class ConnectionBanner(Component):
|
||||
id: Optional[Any] = None,
|
||||
class_name: Optional[Any] = None,
|
||||
autofocus: Optional[bool] = None,
|
||||
custom_attrs: Optional[Dict[str, Union[ImmutableVar, str]]] = None,
|
||||
on_blur: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_context_menu: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_double_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_focus: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_down: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_enter: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_leave: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_move: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_out: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_over: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_up: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_scroll: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_unmount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = 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,
|
||||
) -> "ConnectionBanner":
|
||||
"""Create a connection banner component.
|
||||
@ -234,52 +187,22 @@ class ConnectionModal(Component):
|
||||
id: Optional[Any] = None,
|
||||
class_name: Optional[Any] = None,
|
||||
autofocus: Optional[bool] = None,
|
||||
custom_attrs: Optional[Dict[str, Union[ImmutableVar, str]]] = None,
|
||||
on_blur: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_context_menu: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_double_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_focus: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_down: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_enter: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_leave: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_move: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_out: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_over: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_up: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_scroll: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_unmount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = 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,
|
||||
) -> "ConnectionModal":
|
||||
"""Create a connection banner component.
|
||||
@ -304,52 +227,22 @@ class WifiOffPulse(Icon):
|
||||
id: Optional[Any] = None,
|
||||
class_name: Optional[Any] = None,
|
||||
autofocus: Optional[bool] = None,
|
||||
custom_attrs: Optional[Dict[str, Union[ImmutableVar, str]]] = None,
|
||||
on_blur: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_context_menu: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_double_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_focus: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_down: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_enter: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_leave: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_move: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_out: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_over: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_up: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_scroll: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_unmount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = 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,
|
||||
) -> "WifiOffPulse":
|
||||
"""Create a wifi_off icon with an animated opacity pulse.
|
||||
@ -378,81 +271,51 @@ class ConnectionPulser(Div):
|
||||
def create( # type: ignore
|
||||
cls,
|
||||
*children,
|
||||
access_key: Optional[Union[Var[Union[bool, int, str]], str, int, bool]] = None,
|
||||
access_key: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
auto_capitalize: Optional[
|
||||
Union[Var[Union[bool, int, str]], str, int, bool]
|
||||
Union[Var[Union[bool, int, str]], bool, int, str]
|
||||
] = None,
|
||||
content_editable: Optional[
|
||||
Union[Var[Union[bool, int, str]], str, int, bool]
|
||||
Union[Var[Union[bool, int, str]], bool, int, str]
|
||||
] = None,
|
||||
context_menu: Optional[
|
||||
Union[Var[Union[bool, int, str]], str, int, bool]
|
||||
Union[Var[Union[bool, int, str]], bool, int, str]
|
||||
] = None,
|
||||
dir: Optional[Union[Var[Union[bool, int, str]], str, int, bool]] = None,
|
||||
draggable: Optional[Union[Var[Union[bool, int, str]], str, int, bool]] = None,
|
||||
dir: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
draggable: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
enter_key_hint: Optional[
|
||||
Union[Var[Union[bool, int, str]], str, int, bool]
|
||||
Union[Var[Union[bool, int, str]], bool, int, str]
|
||||
] = None,
|
||||
hidden: Optional[Union[Var[Union[bool, int, str]], str, int, bool]] = None,
|
||||
input_mode: Optional[Union[Var[Union[bool, int, str]], str, int, bool]] = None,
|
||||
item_prop: Optional[Union[Var[Union[bool, int, str]], str, int, bool]] = None,
|
||||
lang: Optional[Union[Var[Union[bool, int, str]], str, int, bool]] = None,
|
||||
role: Optional[Union[Var[Union[bool, int, str]], str, int, bool]] = None,
|
||||
slot: Optional[Union[Var[Union[bool, int, str]], str, int, bool]] = None,
|
||||
spell_check: Optional[Union[Var[Union[bool, int, str]], str, int, bool]] = None,
|
||||
tab_index: Optional[Union[Var[Union[bool, int, str]], str, int, bool]] = None,
|
||||
title: Optional[Union[Var[Union[bool, int, str]], str, int, bool]] = None,
|
||||
hidden: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
input_mode: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
item_prop: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
lang: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
role: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
slot: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
spell_check: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
tab_index: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
title: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = 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[ImmutableVar, str]]] = None,
|
||||
on_blur: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_context_menu: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_double_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_focus: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_down: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_enter: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_leave: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_move: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_out: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_over: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_up: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_scroll: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_unmount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = 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,
|
||||
) -> "ConnectionPulser":
|
||||
"""Create a connection pulser component.
|
||||
|
@ -13,16 +13,15 @@ from __future__ import annotations
|
||||
from reflex import constants
|
||||
from reflex.components.component import Component
|
||||
from reflex.components.core.cond import cond
|
||||
from reflex.ivars.base import ImmutableVar
|
||||
from reflex.vars import Var
|
||||
from reflex.vars.base import Var
|
||||
|
||||
route_not_found: Var = ImmutableVar.create_safe(constants.ROUTE_NOT_FOUND)
|
||||
route_not_found: Var = Var(_js_expr=constants.ROUTE_NOT_FOUND)
|
||||
|
||||
|
||||
class ClientSideRouting(Component):
|
||||
"""The client-side routing component."""
|
||||
|
||||
library = "/utils/client_side_routing"
|
||||
library = "$/utils/client_side_routing"
|
||||
tag = "useClientSideRouting"
|
||||
|
||||
def add_hooks(self) -> list[str]:
|
||||
|
@ -3,13 +3,12 @@
|
||||
# ------------------- DO NOT EDIT ----------------------
|
||||
# This file was generated by `reflex/utils/pyi_generator.py`!
|
||||
# ------------------------------------------------------
|
||||
from typing import Any, Callable, Dict, Optional, Union, overload
|
||||
from typing import Any, Dict, Optional, Union, overload
|
||||
|
||||
from reflex.components.component import Component
|
||||
from reflex.event import EventHandler, EventSpec
|
||||
from reflex.ivars.base import ImmutableVar
|
||||
from reflex.event import EventType
|
||||
from reflex.style import Style
|
||||
from reflex.vars import Var
|
||||
from reflex.vars.base import Var
|
||||
|
||||
route_not_found: Var
|
||||
|
||||
@ -26,52 +25,22 @@ class ClientSideRouting(Component):
|
||||
id: Optional[Any] = None,
|
||||
class_name: Optional[Any] = None,
|
||||
autofocus: Optional[bool] = None,
|
||||
custom_attrs: Optional[Dict[str, Union[ImmutableVar, str]]] = None,
|
||||
on_blur: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_context_menu: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_double_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_focus: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_down: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_enter: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_leave: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_move: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_out: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_over: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_up: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_scroll: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_unmount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = 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,
|
||||
) -> "ClientSideRouting":
|
||||
"""Create the component.
|
||||
@ -105,52 +74,22 @@ class Default404Page(Component):
|
||||
id: Optional[Any] = None,
|
||||
class_name: Optional[Any] = None,
|
||||
autofocus: Optional[bool] = None,
|
||||
custom_attrs: Optional[Dict[str, Union[ImmutableVar, str]]] = None,
|
||||
on_blur: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_context_menu: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_double_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_focus: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_down: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_enter: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_leave: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_move: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_out: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_over: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_up: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_scroll: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_unmount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = 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,
|
||||
) -> "Default404Page":
|
||||
"""Create the component.
|
||||
|
@ -2,14 +2,15 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Dict, List, Union
|
||||
from typing import Dict, List, Tuple, Union
|
||||
|
||||
from reflex.components.base.fragment import Fragment
|
||||
from reflex.components.tags.tag import Tag
|
||||
from reflex.event import EventChain, EventHandler
|
||||
from reflex.event import EventChain, EventHandler, identity_event
|
||||
from reflex.utils.format import format_prop, wrap
|
||||
from reflex.utils.imports import ImportVar
|
||||
from reflex.vars import Var, get_unique_variable_name
|
||||
from reflex.vars import get_unique_variable_name
|
||||
from reflex.vars.base import Var
|
||||
|
||||
|
||||
class Clipboard(Fragment):
|
||||
@ -19,7 +20,7 @@ class Clipboard(Fragment):
|
||||
targets: Var[List[str]]
|
||||
|
||||
# Called when the user pastes data into the document. Data is a list of tuples of (mime_type, data). Binary types will be base64 encoded as a data uri.
|
||||
on_paste: EventHandler[lambda data: [data]]
|
||||
on_paste: EventHandler[identity_event(List[Tuple[str, str]])]
|
||||
|
||||
# Save the original event actions for the on_paste event.
|
||||
on_paste_event_actions: Var[Dict[str, Union[bool, int]]]
|
||||
@ -66,7 +67,7 @@ class Clipboard(Fragment):
|
||||
The import dict for the component.
|
||||
"""
|
||||
return {
|
||||
"/utils/helpers/paste.js": ImportVar(
|
||||
"$/utils/helpers/paste.js": ImportVar(
|
||||
tag="usePasteHandler", is_default=True
|
||||
),
|
||||
}
|
||||
|
@ -3,14 +3,13 @@
|
||||
# ------------------- DO NOT EDIT ----------------------
|
||||
# This file was generated by `reflex/utils/pyi_generator.py`!
|
||||
# ------------------------------------------------------
|
||||
from typing import Any, Callable, Dict, List, Optional, Union, overload
|
||||
from typing import Any, Dict, List, Optional, Union, overload
|
||||
|
||||
from reflex.components.base.fragment import Fragment
|
||||
from reflex.event import EventHandler, EventSpec
|
||||
from reflex.ivars.base import ImmutableVar
|
||||
from reflex.event import EventType
|
||||
from reflex.style import Style
|
||||
from reflex.utils.imports import ImportVar
|
||||
from reflex.vars import Var
|
||||
from reflex.vars.base import Var
|
||||
|
||||
class Clipboard(Fragment):
|
||||
@overload
|
||||
@ -18,64 +17,32 @@ class Clipboard(Fragment):
|
||||
def create( # type: ignore
|
||||
cls,
|
||||
*children,
|
||||
targets: Optional[Union[Var[List[str]], List[str]]] = None,
|
||||
targets: Optional[Union[List[str], Var[List[str]]]] = None,
|
||||
on_paste_event_actions: Optional[
|
||||
Union[Var[Dict[str, Union[bool, int]]], Dict[str, Union[bool, int]]]
|
||||
Union[Dict[str, Union[bool, int]], Var[Dict[str, Union[bool, int]]]]
|
||||
] = 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[ImmutableVar, str]]] = None,
|
||||
on_blur: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_context_menu: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_double_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_focus: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_down: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_enter: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_leave: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_move: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_out: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_over: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_up: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_paste: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_scroll: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_unmount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = 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_paste: Optional[EventType[list[tuple[str, str]]]] = None,
|
||||
on_scroll: Optional[EventType[[]]] = None,
|
||||
on_unmount: Optional[EventType[[]]] = None,
|
||||
**props,
|
||||
) -> "Clipboard":
|
||||
"""Create a Clipboard component.
|
||||
@ -83,6 +50,7 @@ class Clipboard(Fragment):
|
||||
Args:
|
||||
*children: The children of the component.
|
||||
targets: The element ids to attach the event listener to. Defaults to all child components or the document.
|
||||
on_paste: Called when the user pastes data into the document. Data is a list of tuples of (mime_type, data). Binary types will be base64 encoded as a data uri.
|
||||
on_paste_event_actions: Save the original event actions for the on_paste event.
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
|
@ -8,14 +8,14 @@ from reflex.components.base.fragment import Fragment
|
||||
from reflex.components.component import BaseComponent, Component, MemoizationLeaf
|
||||
from reflex.components.tags import CondTag, Tag
|
||||
from reflex.constants import Dirs
|
||||
from reflex.ivars.base import ImmutableVar, LiteralVar
|
||||
from reflex.ivars.number import ternary_operation
|
||||
from reflex.style import LIGHT_COLOR_MODE, resolved_color_mode
|
||||
from reflex.utils.imports import ImportDict, ImportVar
|
||||
from reflex.vars import Var, VarData
|
||||
from reflex.vars import VarData
|
||||
from reflex.vars.base import LiteralVar, Var
|
||||
from reflex.vars.number import ternary_operation
|
||||
|
||||
_IS_TRUE_IMPORT: ImportDict = {
|
||||
f"/{Dirs.STATE_PATH}": [ImportVar(tag="isTrue")],
|
||||
f"$/{Dirs.STATE_PATH}": [ImportVar(tag="isTrue")],
|
||||
}
|
||||
|
||||
|
||||
@ -119,10 +119,10 @@ def cond(condition: Any, c1: Component) -> Component: ...
|
||||
|
||||
|
||||
@overload
|
||||
def cond(condition: Any, c1: Any, c2: Any) -> ImmutableVar: ...
|
||||
def cond(condition: Any, c1: Any, c2: Any) -> Var: ...
|
||||
|
||||
|
||||
def cond(condition: Any, c1: Any, c2: Any = None) -> Component | ImmutableVar:
|
||||
def cond(condition: Any, c1: Any, c2: Any = None) -> Component | Var:
|
||||
"""Create a conditional component or Prop.
|
||||
|
||||
Args:
|
||||
@ -138,13 +138,13 @@ def cond(condition: Any, c1: Any, c2: Any = None) -> Component | ImmutableVar:
|
||||
"""
|
||||
# Convert the condition to a Var.
|
||||
cond_var = LiteralVar.create(condition)
|
||||
assert cond_var is not None, "The condition must be set."
|
||||
if cond_var is None:
|
||||
raise ValueError("The condition must be set.")
|
||||
|
||||
# If the first component is a component, create a Cond component.
|
||||
if isinstance(c1, BaseComponent):
|
||||
assert c2 is None or isinstance(
|
||||
c2, BaseComponent
|
||||
), "Both arguments must be components."
|
||||
if c2 is not None and not isinstance(c2, BaseComponent):
|
||||
raise ValueError("Both arguments must be components.")
|
||||
return Cond.create(cond_var, c1, c2)
|
||||
|
||||
# Otherwise, create a conditional Var.
|
||||
|
@ -6,9 +6,9 @@ from typing import Any, Type, Union
|
||||
|
||||
from reflex.components.component import Component
|
||||
from reflex.constants import EventTriggers
|
||||
from reflex.event import EventHandler
|
||||
from reflex.ivars.base import ImmutableVar
|
||||
from reflex.vars import Var, VarData
|
||||
from reflex.event import EventHandler, empty_event
|
||||
from reflex.vars import VarData
|
||||
from reflex.vars.base import Var
|
||||
|
||||
DEFAULT_DEBOUNCE_TIMEOUT = 300
|
||||
|
||||
@ -46,7 +46,7 @@ class DebounceInput(Component):
|
||||
element: Var[Type[Component]]
|
||||
|
||||
# Fired when the input value changes
|
||||
on_change: EventHandler[lambda e0: [e0.value]]
|
||||
on_change: EventHandler[empty_event]
|
||||
|
||||
@classmethod
|
||||
def create(cls, *children: Component, **props: Any) -> Component:
|
||||
@ -107,18 +107,18 @@ class DebounceInput(Component):
|
||||
props[field] = getattr(child, field)
|
||||
child_ref = child.get_ref()
|
||||
if props.get("input_ref") is None and child_ref:
|
||||
props["input_ref"] = ImmutableVar.create_safe(child_ref)
|
||||
props["input_ref"] = Var(_js_expr=child_ref, _var_type=str)
|
||||
props["id"] = child.id
|
||||
|
||||
# Set the child element to wrap, including any imports/hooks from the child.
|
||||
props.setdefault(
|
||||
"element",
|
||||
ImmutableVar(
|
||||
_var_name=str(child.alias or child.tag),
|
||||
Var(
|
||||
_js_expr=str(child.alias or child.tag),
|
||||
_var_type=Type[Component],
|
||||
_var_data=VarData(
|
||||
imports=child._get_imports(),
|
||||
hooks=child._get_hooks_internal(),
|
||||
hooks=child._get_all_hooks(),
|
||||
),
|
||||
),
|
||||
)
|
||||
@ -128,6 +128,10 @@ class DebounceInput(Component):
|
||||
component.event_triggers.update(child.event_triggers)
|
||||
component.children = child.children
|
||||
component._rename_props = child._rename_props
|
||||
outer_get_all_custom_code = component._get_all_custom_code
|
||||
component._get_all_custom_code = lambda: outer_get_all_custom_code().union(
|
||||
child._get_all_custom_code()
|
||||
)
|
||||
return component
|
||||
|
||||
def _render(self):
|
||||
|
@ -3,13 +3,12 @@
|
||||
# ------------------- DO NOT EDIT ----------------------
|
||||
# This file was generated by `reflex/utils/pyi_generator.py`!
|
||||
# ------------------------------------------------------
|
||||
from typing import Any, Callable, Dict, Optional, Type, Union, overload
|
||||
from typing import Any, Dict, Optional, Type, Union, overload
|
||||
|
||||
from reflex.components.component import Component
|
||||
from reflex.event import EventHandler, EventSpec
|
||||
from reflex.ivars.base import ImmutableVar
|
||||
from reflex.event import EventType
|
||||
from reflex.style import Style
|
||||
from reflex.vars import Var
|
||||
from reflex.vars.base import Var
|
||||
|
||||
DEFAULT_DEBOUNCE_TIMEOUT = 300
|
||||
|
||||
@ -23,63 +22,31 @@ class DebounceInput(Component):
|
||||
debounce_timeout: Optional[Union[Var[int], int]] = None,
|
||||
force_notify_by_enter: Optional[Union[Var[bool], bool]] = None,
|
||||
force_notify_on_blur: Optional[Union[Var[bool], bool]] = None,
|
||||
value: Optional[Union[Var[Union[float, int, str]], str, int, float]] = None,
|
||||
value: Optional[Union[Var[Union[float, int, str]], float, int, str]] = None,
|
||||
input_ref: Optional[Union[Var[str], str]] = None,
|
||||
element: Optional[Union[Var[Type[Component]], Type[Component]]] = None,
|
||||
element: Optional[Union[Type[Component], Var[Type[Component]]]] = 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[ImmutableVar, str]]] = None,
|
||||
on_blur: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_change: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_context_menu: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_double_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_focus: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_down: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_enter: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_leave: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_move: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_out: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_over: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_up: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_scroll: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_unmount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
custom_attrs: Optional[Dict[str, Union[Var, str]]] = None,
|
||||
on_blur: Optional[EventType[[]]] = None,
|
||||
on_change: 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,
|
||||
) -> "DebounceInput":
|
||||
"""Create a DebounceInput component.
|
||||
|
@ -9,9 +9,8 @@ from reflex.components.base.fragment import Fragment
|
||||
from reflex.components.component import Component
|
||||
from reflex.components.tags import IterTag
|
||||
from reflex.constants import MemoizationMode
|
||||
from reflex.ivars.base import ImmutableVar
|
||||
from reflex.state import ComponentState
|
||||
from reflex.vars import Var
|
||||
from reflex.vars.base import LiteralVar, Var
|
||||
|
||||
|
||||
class ForeachVarError(TypeError):
|
||||
@ -52,7 +51,7 @@ class Foreach(Component):
|
||||
ForeachVarError: If the iterable is of type Any.
|
||||
TypeError: If the render function is a ComponentState.
|
||||
"""
|
||||
iterable = ImmutableVar.create_safe(iterable)
|
||||
iterable = LiteralVar.create(iterable)
|
||||
if iterable._var_type == Any:
|
||||
raise ForeachVarError(
|
||||
f"Could not foreach over var `{str(iterable)}` of type Any. "
|
||||
@ -130,7 +129,7 @@ class Foreach(Component):
|
||||
iterable_state=str(tag.iterable),
|
||||
arg_name=tag.arg_var_name,
|
||||
arg_index=tag.get_index_var_arg(),
|
||||
iterable_type=tag.iterable.upcast()._var_type.mro()[0].__name__,
|
||||
iterable_type=tag.iterable._var_type.mro()[0].__name__,
|
||||
)
|
||||
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
from typing import Dict
|
||||
|
||||
from reflex.components.el.elements.typography import Div
|
||||
from reflex.vars import Var
|
||||
from reflex.vars.base import Var
|
||||
|
||||
|
||||
class Html(Div):
|
||||
|
@ -3,13 +3,12 @@
|
||||
# ------------------- DO NOT EDIT ----------------------
|
||||
# This file was generated by `reflex/utils/pyi_generator.py`!
|
||||
# ------------------------------------------------------
|
||||
from typing import Any, Callable, Dict, Optional, Union, overload
|
||||
from typing import Any, Dict, Optional, Union, overload
|
||||
|
||||
from reflex.components.el.elements.typography import Div
|
||||
from reflex.event import EventHandler, EventSpec
|
||||
from reflex.ivars.base import ImmutableVar
|
||||
from reflex.event import EventType
|
||||
from reflex.style import Style
|
||||
from reflex.vars import Var
|
||||
from reflex.vars.base import Var
|
||||
|
||||
class Html(Div):
|
||||
@overload
|
||||
@ -18,83 +17,53 @@ class Html(Div):
|
||||
cls,
|
||||
*children,
|
||||
dangerouslySetInnerHTML: Optional[
|
||||
Union[Var[Dict[str, str]], Dict[str, str]]
|
||||
Union[Dict[str, str], Var[Dict[str, str]]]
|
||||
] = None,
|
||||
access_key: Optional[Union[Var[Union[bool, int, str]], str, int, bool]] = None,
|
||||
access_key: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
auto_capitalize: Optional[
|
||||
Union[Var[Union[bool, int, str]], str, int, bool]
|
||||
Union[Var[Union[bool, int, str]], bool, int, str]
|
||||
] = None,
|
||||
content_editable: Optional[
|
||||
Union[Var[Union[bool, int, str]], str, int, bool]
|
||||
Union[Var[Union[bool, int, str]], bool, int, str]
|
||||
] = None,
|
||||
context_menu: Optional[
|
||||
Union[Var[Union[bool, int, str]], str, int, bool]
|
||||
Union[Var[Union[bool, int, str]], bool, int, str]
|
||||
] = None,
|
||||
dir: Optional[Union[Var[Union[bool, int, str]], str, int, bool]] = None,
|
||||
draggable: Optional[Union[Var[Union[bool, int, str]], str, int, bool]] = None,
|
||||
dir: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
draggable: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
enter_key_hint: Optional[
|
||||
Union[Var[Union[bool, int, str]], str, int, bool]
|
||||
Union[Var[Union[bool, int, str]], bool, int, str]
|
||||
] = None,
|
||||
hidden: Optional[Union[Var[Union[bool, int, str]], str, int, bool]] = None,
|
||||
input_mode: Optional[Union[Var[Union[bool, int, str]], str, int, bool]] = None,
|
||||
item_prop: Optional[Union[Var[Union[bool, int, str]], str, int, bool]] = None,
|
||||
lang: Optional[Union[Var[Union[bool, int, str]], str, int, bool]] = None,
|
||||
role: Optional[Union[Var[Union[bool, int, str]], str, int, bool]] = None,
|
||||
slot: Optional[Union[Var[Union[bool, int, str]], str, int, bool]] = None,
|
||||
spell_check: Optional[Union[Var[Union[bool, int, str]], str, int, bool]] = None,
|
||||
tab_index: Optional[Union[Var[Union[bool, int, str]], str, int, bool]] = None,
|
||||
title: Optional[Union[Var[Union[bool, int, str]], str, int, bool]] = None,
|
||||
hidden: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
input_mode: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
item_prop: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
lang: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
role: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
slot: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
spell_check: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
tab_index: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
title: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = 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[ImmutableVar, str]]] = None,
|
||||
on_blur: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_context_menu: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_double_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_focus: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_down: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_enter: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_leave: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_move: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_out: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_over: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_up: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_scroll: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_unmount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = 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,
|
||||
) -> "Html":
|
||||
"""Create a html component.
|
||||
|
@ -6,12 +6,12 @@ from typing import Any, Dict, List, Optional, Tuple, Union
|
||||
from reflex.components.base import Fragment
|
||||
from reflex.components.component import BaseComponent, Component, MemoizationLeaf
|
||||
from reflex.components.tags import MatchTag, Tag
|
||||
from reflex.ivars.base import ImmutableVar, LiteralVar
|
||||
from reflex.style import Style
|
||||
from reflex.utils import format, types
|
||||
from reflex.utils.exceptions import MatchTypeError
|
||||
from reflex.utils.imports import ImportDict
|
||||
from reflex.vars import Var, VarData
|
||||
from reflex.vars import VarData
|
||||
from reflex.vars.base import LiteralVar, Var
|
||||
|
||||
|
||||
class Match(MemoizationLeaf):
|
||||
@ -27,7 +27,7 @@ class Match(MemoizationLeaf):
|
||||
default: Any
|
||||
|
||||
@classmethod
|
||||
def create(cls, cond: Any, *cases) -> Union[Component, ImmutableVar]:
|
||||
def create(cls, cond: Any, *cases) -> Union[Component, Var]:
|
||||
"""Create a Match Component.
|
||||
|
||||
Args:
|
||||
@ -56,7 +56,7 @@ class Match(MemoizationLeaf):
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def _create_condition_var(cls, cond: Any) -> ImmutableVar:
|
||||
def _create_condition_var(cls, cond: Any) -> Var:
|
||||
"""Convert the condition to a Var.
|
||||
|
||||
Args:
|
||||
@ -77,7 +77,7 @@ class Match(MemoizationLeaf):
|
||||
@classmethod
|
||||
def _process_cases(
|
||||
cls, cases: List
|
||||
) -> Tuple[List, Optional[Union[ImmutableVar, BaseComponent]]]:
|
||||
) -> Tuple[List, Optional[Union[Var, BaseComponent]]]:
|
||||
"""Process the list of match cases and the catchall default case.
|
||||
|
||||
Args:
|
||||
@ -125,7 +125,7 @@ class Match(MemoizationLeaf):
|
||||
return case_element
|
||||
|
||||
@classmethod
|
||||
def _process_match_cases(cls, cases: List) -> List[List[ImmutableVar]]:
|
||||
def _process_match_cases(cls, cases: List) -> List[List[Var]]:
|
||||
"""Process the individual match cases.
|
||||
|
||||
Args:
|
||||
@ -157,7 +157,7 @@ class Match(MemoizationLeaf):
|
||||
if not isinstance(element, BaseComponent)
|
||||
else element
|
||||
)
|
||||
if not isinstance(el, (ImmutableVar, BaseComponent)):
|
||||
if not isinstance(el, (Var, BaseComponent)):
|
||||
raise ValueError("Case element must be a var or component")
|
||||
case_list.append(el)
|
||||
|
||||
@ -166,7 +166,7 @@ class Match(MemoizationLeaf):
|
||||
return match_cases
|
||||
|
||||
@classmethod
|
||||
def _validate_return_types(cls, match_cases: List[List[ImmutableVar]]) -> None:
|
||||
def _validate_return_types(cls, match_cases: List[List[Var]]) -> None:
|
||||
"""Validate that match cases have the same return types.
|
||||
|
||||
Args:
|
||||
@ -180,24 +180,24 @@ class Match(MemoizationLeaf):
|
||||
|
||||
if types._isinstance(first_case_return, BaseComponent):
|
||||
return_type = BaseComponent
|
||||
elif types._isinstance(first_case_return, ImmutableVar):
|
||||
return_type = ImmutableVar
|
||||
elif types._isinstance(first_case_return, Var):
|
||||
return_type = Var
|
||||
|
||||
for index, case in enumerate(match_cases):
|
||||
if not types._issubclass(type(case[-1]), return_type):
|
||||
raise MatchTypeError(
|
||||
f"Match cases should have the same return types. Case {index} with return "
|
||||
f"value `{case[-1]._var_name if isinstance(case[-1], ImmutableVar) else textwrap.shorten(str(case[-1]), width=250)}`"
|
||||
f"value `{case[-1]._js_expr if isinstance(case[-1], Var) else textwrap.shorten(str(case[-1]), width=250)}`"
|
||||
f" of type {type(case[-1])!r} is not {return_type}"
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def _create_match_cond_var_or_component(
|
||||
cls,
|
||||
match_cond_var: ImmutableVar,
|
||||
match_cases: List[List[ImmutableVar]],
|
||||
default: Optional[Union[ImmutableVar, BaseComponent]],
|
||||
) -> Union[Component, ImmutableVar]:
|
||||
match_cond_var: Var,
|
||||
match_cases: List[List[Var]],
|
||||
default: Optional[Union[Var, BaseComponent]],
|
||||
) -> Union[Component, Var]:
|
||||
"""Create and return the match condition var or component.
|
||||
|
||||
Args:
|
||||
@ -232,8 +232,8 @@ class Match(MemoizationLeaf):
|
||||
) or not types._isinstance(default, Var):
|
||||
raise ValueError("Return types of match cases should be Vars.")
|
||||
|
||||
return ImmutableVar(
|
||||
_var_name=format.format_match(
|
||||
return Var(
|
||||
_js_expr=format.format_match(
|
||||
cond=str(match_cond_var),
|
||||
match_cases=match_cases,
|
||||
default=default, # type: ignore
|
||||
|
@ -2,14 +2,20 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
from pathlib import Path
|
||||
from typing import Callable, ClassVar, Dict, List, Optional
|
||||
from typing import Any, Callable, ClassVar, Dict, List, Optional, Tuple
|
||||
|
||||
from reflex.components.component import Component, ComponentNamespace, MemoizationLeaf
|
||||
from reflex.components.component import (
|
||||
Component,
|
||||
ComponentNamespace,
|
||||
MemoizationLeaf,
|
||||
StatefulComponent,
|
||||
)
|
||||
from reflex.components.el.elements.forms import Input
|
||||
from reflex.components.radix.themes.layout.box import Box
|
||||
from reflex.config import environment
|
||||
from reflex.constants import Dirs
|
||||
from reflex.constants.compiler import Imports
|
||||
from reflex.event import (
|
||||
CallableEventSpec,
|
||||
EventChain,
|
||||
@ -19,17 +25,18 @@ from reflex.event import (
|
||||
call_script,
|
||||
parse_args_spec,
|
||||
)
|
||||
from reflex.ivars.base import ImmutableCallableVar, ImmutableVar, LiteralVar
|
||||
from reflex.ivars.sequence import LiteralStringVar
|
||||
from reflex.utils import format
|
||||
from reflex.utils.imports import ImportVar
|
||||
from reflex.vars import Var, VarData
|
||||
from reflex.vars import VarData
|
||||
from reflex.vars.base import CallableVar, LiteralVar, Var, get_unique_variable_name
|
||||
from reflex.vars.sequence import LiteralStringVar
|
||||
|
||||
DEFAULT_UPLOAD_ID: str = "default"
|
||||
|
||||
upload_files_context_var_data: VarData = VarData(
|
||||
imports={
|
||||
"react": "useContext",
|
||||
f"/{Dirs.CONTEXTS_PATH}": "UploadFilesContext",
|
||||
f"$/{Dirs.CONTEXTS_PATH}": "UploadFilesContext",
|
||||
},
|
||||
hooks={
|
||||
"const [filesById, setFilesById] = useContext(UploadFilesContext);": None,
|
||||
@ -37,8 +44,8 @@ upload_files_context_var_data: VarData = VarData(
|
||||
)
|
||||
|
||||
|
||||
@ImmutableCallableVar
|
||||
def upload_file(id_: str = DEFAULT_UPLOAD_ID) -> ImmutableVar:
|
||||
@CallableVar
|
||||
def upload_file(id_: str = DEFAULT_UPLOAD_ID) -> Var:
|
||||
"""Get the file upload drop trigger.
|
||||
|
||||
This var is passed to the dropzone component to update the file list when a
|
||||
@ -58,8 +65,8 @@ def upload_file(id_: str = DEFAULT_UPLOAD_ID) -> ImmutableVar:
|
||||
}})
|
||||
"""
|
||||
|
||||
return ImmutableVar(
|
||||
_var_name=var_name,
|
||||
return Var(
|
||||
_js_expr=var_name,
|
||||
_var_type=EventChain,
|
||||
_var_data=VarData.merge(
|
||||
upload_files_context_var_data, id_var._get_all_var_data()
|
||||
@ -67,8 +74,8 @@ def upload_file(id_: str = DEFAULT_UPLOAD_ID) -> ImmutableVar:
|
||||
)
|
||||
|
||||
|
||||
@ImmutableCallableVar
|
||||
def selected_files(id_: str = DEFAULT_UPLOAD_ID) -> ImmutableVar:
|
||||
@CallableVar
|
||||
def selected_files(id_: str = DEFAULT_UPLOAD_ID) -> Var:
|
||||
"""Get the list of selected files.
|
||||
|
||||
Args:
|
||||
@ -78,8 +85,8 @@ def selected_files(id_: str = DEFAULT_UPLOAD_ID) -> ImmutableVar:
|
||||
A var referencing the list of selected file paths.
|
||||
"""
|
||||
id_var = LiteralStringVar.create(id_)
|
||||
return ImmutableVar(
|
||||
_var_name=f"(filesById[{str(id_var)}] ? filesById[{str(id_var)}].map((f) => (f.path || f.name)) : [])",
|
||||
return Var(
|
||||
_js_expr=f"(filesById[{str(id_var)}] ? filesById[{str(id_var)}].map((f) => (f.path || f.name)) : [])",
|
||||
_var_type=List[str],
|
||||
_var_data=VarData.merge(
|
||||
upload_files_context_var_data, id_var._get_all_var_data()
|
||||
@ -125,19 +132,17 @@ def get_upload_dir() -> Path:
|
||||
"""
|
||||
Upload.is_used = True
|
||||
|
||||
uploaded_files_dir = Path(
|
||||
os.environ.get("REFLEX_UPLOADED_FILES_DIR", "./uploaded_files")
|
||||
)
|
||||
uploaded_files_dir = environment.REFLEX_UPLOADED_FILES_DIR
|
||||
uploaded_files_dir.mkdir(parents=True, exist_ok=True)
|
||||
return uploaded_files_dir
|
||||
|
||||
|
||||
uploaded_files_url_prefix = ImmutableVar(
|
||||
_var_name="getBackendURL(env.UPLOAD)",
|
||||
uploaded_files_url_prefix = Var(
|
||||
_js_expr="getBackendURL(env.UPLOAD)",
|
||||
_var_data=VarData(
|
||||
imports={
|
||||
f"/{Dirs.STATE_PATH}": "getBackendURL",
|
||||
"/env.json": ImportVar(tag="env", is_default=True),
|
||||
f"$/{Dirs.STATE_PATH}": "getBackendURL",
|
||||
"$/env.json": ImportVar(tag="env", is_default=True),
|
||||
}
|
||||
),
|
||||
).to(str)
|
||||
@ -157,7 +162,7 @@ def get_upload_url(file_path: str) -> Var[str]:
|
||||
return uploaded_files_url_prefix + "/" + file_path
|
||||
|
||||
|
||||
def _on_drop_spec(files: Var):
|
||||
def _on_drop_spec(files: Var) -> Tuple[Var[Any]]:
|
||||
"""Args spec for the on_drop event trigger.
|
||||
|
||||
Args:
|
||||
@ -166,24 +171,22 @@ def _on_drop_spec(files: Var):
|
||||
Returns:
|
||||
Signature for on_drop handler including the files to upload.
|
||||
"""
|
||||
return [files]
|
||||
return (files,)
|
||||
|
||||
|
||||
class UploadFilesProvider(Component):
|
||||
"""AppWrap component that provides a dict of selected files by ID via useContext."""
|
||||
|
||||
library = f"/{Dirs.CONTEXTS_PATH}"
|
||||
library = f"$/{Dirs.CONTEXTS_PATH}"
|
||||
tag = "UploadFilesProvider"
|
||||
|
||||
|
||||
class Upload(MemoizationLeaf):
|
||||
"""A file upload component."""
|
||||
|
||||
library = "react-dropzone@14.2.3"
|
||||
library = "react-dropzone@14.2.10"
|
||||
|
||||
tag = "ReactDropzone"
|
||||
|
||||
is_default = True
|
||||
tag = ""
|
||||
|
||||
# The list of accepted file types. This should be a dictionary of MIME types as keys and array of file formats as
|
||||
# values.
|
||||
@ -203,7 +206,7 @@ class Upload(MemoizationLeaf):
|
||||
min_size: Var[int]
|
||||
|
||||
# Whether to allow multiple files to be uploaded.
|
||||
multiple: Var[bool] = True # type: ignore
|
||||
multiple: Var[bool]
|
||||
|
||||
# Whether to disable click to upload.
|
||||
no_click: Var[bool]
|
||||
@ -234,6 +237,8 @@ class Upload(MemoizationLeaf):
|
||||
# Mark the Upload component as used in the app.
|
||||
cls.is_used = True
|
||||
|
||||
props.setdefault("multiple", True)
|
||||
|
||||
# Apply the default classname
|
||||
given_class_name = props.pop("class_name", [])
|
||||
if isinstance(given_class_name, str):
|
||||
@ -245,21 +250,6 @@ class Upload(MemoizationLeaf):
|
||||
upload_props = {
|
||||
key: value for key, value in props.items() if key in supported_props
|
||||
}
|
||||
# The file input to use.
|
||||
upload = Input.create(type="file")
|
||||
upload.special_props = {
|
||||
ImmutableVar(_var_name="{...getInputProps()}", _var_type=None)
|
||||
}
|
||||
|
||||
# The dropzone to use.
|
||||
zone = Box.create(
|
||||
upload,
|
||||
*children,
|
||||
**{k: v for k, v in props.items() if k not in supported_props},
|
||||
)
|
||||
zone.special_props = {
|
||||
ImmutableVar(_var_name="{...getRootProps()}", _var_type=None)
|
||||
}
|
||||
|
||||
# Create the component.
|
||||
upload_props["id"] = props.get("id", DEFAULT_UPLOAD_ID)
|
||||
@ -281,15 +271,78 @@ class Upload(MemoizationLeaf):
|
||||
),
|
||||
)
|
||||
upload_props["on_drop"] = on_drop
|
||||
|
||||
input_props_unique_name = get_unique_variable_name()
|
||||
root_props_unique_name = get_unique_variable_name()
|
||||
|
||||
event_var, callback_str = StatefulComponent._get_memoized_event_triggers(
|
||||
Box.create(on_click=upload_props["on_drop"]) # type: ignore
|
||||
)["on_click"]
|
||||
|
||||
upload_props["on_drop"] = event_var
|
||||
|
||||
upload_props = {
|
||||
format.to_camel_case(key): value for key, value in upload_props.items()
|
||||
}
|
||||
|
||||
use_dropzone_arguements = {
|
||||
"onDrop": event_var,
|
||||
**upload_props,
|
||||
}
|
||||
|
||||
left_side = f"const {{getRootProps: {root_props_unique_name}, getInputProps: {input_props_unique_name}}} "
|
||||
right_side = f"useDropzone({str(Var.create(use_dropzone_arguements))})"
|
||||
|
||||
var_data = VarData.merge(
|
||||
VarData(
|
||||
imports=Imports.EVENTS,
|
||||
hooks={
|
||||
"const [addEvents, connectError] = useContext(EventLoopContext);": None
|
||||
},
|
||||
),
|
||||
event_var._get_all_var_data(),
|
||||
VarData(
|
||||
hooks={
|
||||
callback_str: None,
|
||||
f"{left_side} = {right_side};": None,
|
||||
},
|
||||
imports={
|
||||
"react-dropzone": "useDropzone",
|
||||
**Imports.EVENTS,
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
# The file input to use.
|
||||
upload = Input.create(type="file")
|
||||
upload.special_props = [
|
||||
Var(
|
||||
_js_expr=f"{{...{input_props_unique_name}()}}",
|
||||
_var_type=None,
|
||||
_var_data=var_data,
|
||||
)
|
||||
]
|
||||
|
||||
# The dropzone to use.
|
||||
zone = Box.create(
|
||||
upload,
|
||||
*children,
|
||||
**{k: v for k, v in props.items() if k not in supported_props},
|
||||
)
|
||||
zone.special_props = [
|
||||
Var(
|
||||
_js_expr=f"{{...{root_props_unique_name}()}}",
|
||||
_var_type=None,
|
||||
_var_data=var_data,
|
||||
)
|
||||
]
|
||||
|
||||
return super().create(
|
||||
zone,
|
||||
**upload_props,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def _update_arg_tuple_for_on_drop(
|
||||
cls, arg_value: tuple[ImmutableVar, ImmutableVar]
|
||||
):
|
||||
def _update_arg_tuple_for_on_drop(cls, arg_value: tuple[Var, Var]):
|
||||
"""Helper to update caller-provided EventSpec args for direct use with on_drop.
|
||||
|
||||
Args:
|
||||
@ -298,16 +351,11 @@ class Upload(MemoizationLeaf):
|
||||
Returns:
|
||||
The updated arg_value tuple when arg is "files", otherwise the original arg_value.
|
||||
"""
|
||||
if arg_value[0]._var_name == "files":
|
||||
if arg_value[0]._js_expr == "files":
|
||||
placeholder = parse_args_spec(_on_drop_spec)[0]
|
||||
return (arg_value[0], placeholder)
|
||||
return arg_value
|
||||
|
||||
def _render(self):
|
||||
out = super()._render()
|
||||
out.args = ("getRootProps", "getInputProps")
|
||||
return out
|
||||
|
||||
@staticmethod
|
||||
def _get_app_wrap_components() -> dict[tuple[int, str], Component]:
|
||||
return {
|
||||
|
@ -4,38 +4,42 @@
|
||||
# This file was generated by `reflex/utils/pyi_generator.py`!
|
||||
# ------------------------------------------------------
|
||||
from pathlib import Path
|
||||
from typing import Any, Callable, ClassVar, Dict, List, Optional, Union, overload
|
||||
from typing import Any, ClassVar, Dict, List, Optional, Union, overload
|
||||
|
||||
from reflex.components.component import Component, ComponentNamespace, MemoizationLeaf
|
||||
from reflex.components.component import (
|
||||
Component,
|
||||
ComponentNamespace,
|
||||
MemoizationLeaf,
|
||||
)
|
||||
from reflex.constants import Dirs
|
||||
from reflex.event import (
|
||||
CallableEventSpec,
|
||||
EventHandler,
|
||||
EventSpec,
|
||||
EventType,
|
||||
)
|
||||
from reflex.ivars.base import ImmutableCallableVar, ImmutableVar
|
||||
from reflex.style import Style
|
||||
from reflex.utils.imports import ImportVar
|
||||
from reflex.vars import Var, VarData
|
||||
from reflex.vars import VarData
|
||||
from reflex.vars.base import CallableVar, Var
|
||||
|
||||
DEFAULT_UPLOAD_ID: str
|
||||
upload_files_context_var_data: VarData
|
||||
|
||||
@ImmutableCallableVar
|
||||
def upload_file(id_: str = DEFAULT_UPLOAD_ID) -> ImmutableVar: ...
|
||||
@ImmutableCallableVar
|
||||
def selected_files(id_: str = DEFAULT_UPLOAD_ID) -> ImmutableVar: ...
|
||||
@CallableVar
|
||||
def upload_file(id_: str = DEFAULT_UPLOAD_ID) -> Var: ...
|
||||
@CallableVar
|
||||
def selected_files(id_: str = DEFAULT_UPLOAD_ID) -> Var: ...
|
||||
@CallableEventSpec
|
||||
def clear_selected_files(id_: str = DEFAULT_UPLOAD_ID) -> EventSpec: ...
|
||||
def cancel_upload(upload_id: str) -> EventSpec: ...
|
||||
def get_upload_dir() -> Path: ...
|
||||
|
||||
uploaded_files_url_prefix = ImmutableVar(
|
||||
_var_name="getBackendURL(env.UPLOAD)",
|
||||
uploaded_files_url_prefix = Var(
|
||||
_js_expr="getBackendURL(env.UPLOAD)",
|
||||
_var_data=VarData(
|
||||
imports={
|
||||
f"/{Dirs.STATE_PATH}": "getBackendURL",
|
||||
"/env.json": ImportVar(tag="env", is_default=True),
|
||||
f"$/{Dirs.STATE_PATH}": "getBackendURL",
|
||||
"$/env.json": ImportVar(tag="env", is_default=True),
|
||||
}
|
||||
),
|
||||
).to(str)
|
||||
@ -53,52 +57,22 @@ class UploadFilesProvider(Component):
|
||||
id: Optional[Any] = None,
|
||||
class_name: Optional[Any] = None,
|
||||
autofocus: Optional[bool] = None,
|
||||
custom_attrs: Optional[Dict[str, Union[ImmutableVar, str]]] = None,
|
||||
on_blur: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_context_menu: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_double_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_focus: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_down: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_enter: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_leave: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_move: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_out: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_over: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_up: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_scroll: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_unmount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = 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,
|
||||
) -> "UploadFilesProvider":
|
||||
"""Create the component.
|
||||
@ -126,7 +100,7 @@ class Upload(MemoizationLeaf):
|
||||
def create( # type: ignore
|
||||
cls,
|
||||
*children,
|
||||
accept: Optional[Union[Var[Optional[Dict[str, List]]], Dict[str, List]]] = None,
|
||||
accept: Optional[Union[Dict[str, List], Var[Optional[Dict[str, List]]]]] = None,
|
||||
disabled: Optional[Union[Var[bool], bool]] = None,
|
||||
max_files: Optional[Union[Var[int], int]] = None,
|
||||
max_size: Optional[Union[Var[int], int]] = None,
|
||||
@ -140,55 +114,23 @@ class Upload(MemoizationLeaf):
|
||||
id: Optional[Any] = None,
|
||||
class_name: Optional[Any] = None,
|
||||
autofocus: Optional[bool] = None,
|
||||
custom_attrs: Optional[Dict[str, Union[ImmutableVar, str]]] = None,
|
||||
on_blur: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_context_menu: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_double_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_drop: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_focus: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_down: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_enter: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_leave: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_move: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_out: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_over: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_up: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_scroll: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_unmount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = 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_drop: Optional[EventType[Any]] = 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,
|
||||
) -> "Upload":
|
||||
"""Create an upload component.
|
||||
@ -204,6 +146,7 @@ class Upload(MemoizationLeaf):
|
||||
no_click: Whether to disable click to upload.
|
||||
no_drag: Whether to disable drag and drop.
|
||||
no_keyboard: Whether to disable using the space/enter keys to upload.
|
||||
on_drop: Fired when files are dropped.
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
@ -223,7 +166,7 @@ class StyledUpload(Upload):
|
||||
def create( # type: ignore
|
||||
cls,
|
||||
*children,
|
||||
accept: Optional[Union[Var[Optional[Dict[str, List]]], Dict[str, List]]] = None,
|
||||
accept: Optional[Union[Dict[str, List], Var[Optional[Dict[str, List]]]]] = None,
|
||||
disabled: Optional[Union[Var[bool], bool]] = None,
|
||||
max_files: Optional[Union[Var[int], int]] = None,
|
||||
max_size: Optional[Union[Var[int], int]] = None,
|
||||
@ -237,55 +180,23 @@ class StyledUpload(Upload):
|
||||
id: Optional[Any] = None,
|
||||
class_name: Optional[Any] = None,
|
||||
autofocus: Optional[bool] = None,
|
||||
custom_attrs: Optional[Dict[str, Union[ImmutableVar, str]]] = None,
|
||||
on_blur: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_context_menu: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_double_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_drop: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_focus: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_down: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_enter: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_leave: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_move: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_out: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_over: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_up: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_scroll: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_unmount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = 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_drop: Optional[EventType[Any]] = 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,
|
||||
) -> "StyledUpload":
|
||||
"""Create the styled upload component.
|
||||
@ -301,6 +212,7 @@ class StyledUpload(Upload):
|
||||
no_click: Whether to disable click to upload.
|
||||
no_drag: Whether to disable drag and drop.
|
||||
no_keyboard: Whether to disable using the space/enter keys to upload.
|
||||
on_drop: Fired when files are dropped.
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
@ -320,7 +232,7 @@ class UploadNamespace(ComponentNamespace):
|
||||
@staticmethod
|
||||
def __call__(
|
||||
*children,
|
||||
accept: Optional[Union[Var[Optional[Dict[str, List]]], Dict[str, List]]] = None,
|
||||
accept: Optional[Union[Dict[str, List], Var[Optional[Dict[str, List]]]]] = None,
|
||||
disabled: Optional[Union[Var[bool], bool]] = None,
|
||||
max_files: Optional[Union[Var[int], int]] = None,
|
||||
max_size: Optional[Union[Var[int], int]] = None,
|
||||
@ -334,55 +246,23 @@ class UploadNamespace(ComponentNamespace):
|
||||
id: Optional[Any] = None,
|
||||
class_name: Optional[Any] = None,
|
||||
autofocus: Optional[bool] = None,
|
||||
custom_attrs: Optional[Dict[str, Union[ImmutableVar, str]]] = None,
|
||||
on_blur: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_context_menu: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_double_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_drop: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_focus: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_down: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_enter: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_leave: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_move: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_out: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_over: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_up: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_scroll: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_unmount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = 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_drop: Optional[EventType[Any]] = 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,
|
||||
) -> "StyledUpload":
|
||||
"""Create the styled upload component.
|
||||
@ -398,6 +278,7 @@ class UploadNamespace(ComponentNamespace):
|
||||
no_click: Whether to disable click to upload.
|
||||
no_drag: Whether to disable drag and drop.
|
||||
no_keyboard: Whether to disable using the space/enter keys to upload.
|
||||
on_drop: Fired when files are dropped.
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
|
@ -8,7 +8,6 @@ _SUBMOD_ATTRS: dict[str, list[str]] = {
|
||||
"code": [
|
||||
"CodeBlock",
|
||||
"code_block",
|
||||
"LiteralCodeBlockTheme",
|
||||
"LiteralCodeLanguage",
|
||||
],
|
||||
"dataeditor": ["data_editor", "data_editor_theme", "DataEditorTheme"],
|
||||
|
@ -4,7 +4,6 @@
|
||||
# ------------------------------------------------------
|
||||
|
||||
from .code import CodeBlock as CodeBlock
|
||||
from .code import LiteralCodeBlockTheme as LiteralCodeBlockTheme
|
||||
from .code import LiteralCodeLanguage as LiteralCodeLanguage
|
||||
from .code import code_block as code_block
|
||||
from .dataeditor import DataEditorTheme as DataEditorTheme
|
||||
|
@ -2,71 +2,20 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Dict, Literal, Optional, Union
|
||||
import dataclasses
|
||||
from typing import ClassVar, Dict, Literal, Optional, Union
|
||||
|
||||
from typing_extensions import get_args
|
||||
|
||||
from reflex.components.component import Component
|
||||
from reflex.components.component import Component, ComponentNamespace
|
||||
from reflex.components.core.cond import color_mode_cond
|
||||
from reflex.components.lucide.icon import Icon
|
||||
from reflex.components.radix.themes.components.button import Button
|
||||
from reflex.components.radix.themes.layout.box import Box
|
||||
from reflex.constants.colors import Color
|
||||
from reflex.event import set_clipboard
|
||||
from reflex.ivars.base import ImmutableVar, LiteralVar
|
||||
from reflex.style import Style
|
||||
from reflex.utils import format
|
||||
from reflex.utils import console, format
|
||||
from reflex.utils.imports import ImportDict, ImportVar
|
||||
from reflex.vars import Var
|
||||
|
||||
LiteralCodeBlockTheme = Literal[
|
||||
"a11y-dark",
|
||||
"atom-dark",
|
||||
"cb",
|
||||
"coldark-cold",
|
||||
"coldark-dark",
|
||||
"coy",
|
||||
"coy-without-shadows",
|
||||
"darcula",
|
||||
"dark",
|
||||
"dracula",
|
||||
"duotone-dark",
|
||||
"duotone-earth",
|
||||
"duotone-forest",
|
||||
"duotone-light",
|
||||
"duotone-sea",
|
||||
"duotone-space",
|
||||
"funky",
|
||||
"ghcolors",
|
||||
"gruvbox-dark",
|
||||
"gruvbox-light",
|
||||
"holi-theme",
|
||||
"hopscotch",
|
||||
"light", # not present in react-syntax-highlighter styles
|
||||
"lucario",
|
||||
"material-dark",
|
||||
"material-light",
|
||||
"material-oceanic",
|
||||
"night-owl",
|
||||
"nord",
|
||||
"okaidia",
|
||||
"one-dark",
|
||||
"one-light",
|
||||
"pojoaque",
|
||||
"prism",
|
||||
"shades-of-purple",
|
||||
"solarized-dark-atom",
|
||||
"solarizedlight",
|
||||
"synthwave84",
|
||||
"tomorrow",
|
||||
"twilight",
|
||||
"vs",
|
||||
"vs-dark",
|
||||
"vsc-dark-plus",
|
||||
"xonokai",
|
||||
"z-touch",
|
||||
]
|
||||
|
||||
from reflex.vars.base import LiteralVar, Var, VarData
|
||||
|
||||
LiteralCodeLanguage = Literal[
|
||||
"abap",
|
||||
@ -351,34 +300,98 @@ LiteralCodeLanguage = Literal[
|
||||
]
|
||||
|
||||
|
||||
def replace_quotes_with_camel_case(value: str) -> str:
|
||||
"""Replaces quotes in the given string with camel case format.
|
||||
def construct_theme_var(theme: str) -> Var[Theme]:
|
||||
"""Construct a theme var.
|
||||
|
||||
Args:
|
||||
value (str): The string to be processed.
|
||||
theme: The theme to construct.
|
||||
|
||||
Returns:
|
||||
str: The processed string with quotes replaced by camel case.
|
||||
The constructed theme var.
|
||||
"""
|
||||
for theme in get_args(LiteralCodeBlockTheme):
|
||||
value = value.replace(f'"{theme}"', format.to_camel_case(theme))
|
||||
return value
|
||||
return Var(
|
||||
theme,
|
||||
_var_data=VarData(
|
||||
imports={
|
||||
f"react-syntax-highlighter/dist/cjs/styles/prism/{format.to_kebab_case(theme)}": [
|
||||
ImportVar(tag=theme, is_default=True, install=False)
|
||||
]
|
||||
}
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@dataclasses.dataclass(init=False)
|
||||
class Theme:
|
||||
"""Themes for the CodeBlock component."""
|
||||
|
||||
a11y_dark: ClassVar[Var[Theme]] = construct_theme_var("a11yDark")
|
||||
atom_dark: ClassVar[Var[Theme]] = construct_theme_var("atomDark")
|
||||
cb: ClassVar[Var[Theme]] = construct_theme_var("cb")
|
||||
coldark_cold: ClassVar[Var[Theme]] = construct_theme_var("coldarkCold")
|
||||
coldark_dark: ClassVar[Var[Theme]] = construct_theme_var("coldarkDark")
|
||||
coy: ClassVar[Var[Theme]] = construct_theme_var("coy")
|
||||
coy_without_shadows: ClassVar[Var[Theme]] = construct_theme_var("coyWithoutShadows")
|
||||
darcula: ClassVar[Var[Theme]] = construct_theme_var("darcula")
|
||||
dark: ClassVar[Var[Theme]] = construct_theme_var("oneDark")
|
||||
dracula: ClassVar[Var[Theme]] = construct_theme_var("dracula")
|
||||
duotone_dark: ClassVar[Var[Theme]] = construct_theme_var("duotoneDark")
|
||||
duotone_earth: ClassVar[Var[Theme]] = construct_theme_var("duotoneEarth")
|
||||
duotone_forest: ClassVar[Var[Theme]] = construct_theme_var("duotoneForest")
|
||||
duotone_light: ClassVar[Var[Theme]] = construct_theme_var("duotoneLight")
|
||||
duotone_sea: ClassVar[Var[Theme]] = construct_theme_var("duotoneSea")
|
||||
duotone_space: ClassVar[Var[Theme]] = construct_theme_var("duotoneSpace")
|
||||
funky: ClassVar[Var[Theme]] = construct_theme_var("funky")
|
||||
ghcolors: ClassVar[Var[Theme]] = construct_theme_var("ghcolors")
|
||||
gruvbox_dark: ClassVar[Var[Theme]] = construct_theme_var("gruvboxDark")
|
||||
gruvbox_light: ClassVar[Var[Theme]] = construct_theme_var("gruvboxLight")
|
||||
holi_theme: ClassVar[Var[Theme]] = construct_theme_var("holiTheme")
|
||||
hopscotch: ClassVar[Var[Theme]] = construct_theme_var("hopscotch")
|
||||
light: ClassVar[Var[Theme]] = construct_theme_var("oneLight")
|
||||
lucario: ClassVar[Var[Theme]] = construct_theme_var("lucario")
|
||||
material_dark: ClassVar[Var[Theme]] = construct_theme_var("materialDark")
|
||||
material_light: ClassVar[Var[Theme]] = construct_theme_var("materialLight")
|
||||
material_oceanic: ClassVar[Var[Theme]] = construct_theme_var("materialOceanic")
|
||||
night_owl: ClassVar[Var[Theme]] = construct_theme_var("nightOwl")
|
||||
nord: ClassVar[Var[Theme]] = construct_theme_var("nord")
|
||||
okaidia: ClassVar[Var[Theme]] = construct_theme_var("okaidia")
|
||||
one_dark: ClassVar[Var[Theme]] = construct_theme_var("oneDark")
|
||||
one_light: ClassVar[Var[Theme]] = construct_theme_var("oneLight")
|
||||
pojoaque: ClassVar[Var[Theme]] = construct_theme_var("pojoaque")
|
||||
prism: ClassVar[Var[Theme]] = construct_theme_var("prism")
|
||||
shades_of_purple: ClassVar[Var[Theme]] = construct_theme_var("shadesOfPurple")
|
||||
solarized_dark_atom: ClassVar[Var[Theme]] = construct_theme_var("solarizedDarkAtom")
|
||||
solarizedlight: ClassVar[Var[Theme]] = construct_theme_var("solarizedlight")
|
||||
synthwave84: ClassVar[Var[Theme]] = construct_theme_var("synthwave84")
|
||||
tomorrow: ClassVar[Var[Theme]] = construct_theme_var("tomorrow")
|
||||
twilight: ClassVar[Var[Theme]] = construct_theme_var("twilight")
|
||||
vs: ClassVar[Var[Theme]] = construct_theme_var("vs")
|
||||
vs_dark: ClassVar[Var[Theme]] = construct_theme_var("vsDark")
|
||||
vsc_dark_plus: ClassVar[Var[Theme]] = construct_theme_var("vscDarkPlus")
|
||||
xonokai: ClassVar[Var[Theme]] = construct_theme_var("xonokai")
|
||||
z_touch: ClassVar[Var[Theme]] = construct_theme_var("zTouch")
|
||||
|
||||
|
||||
for theme_name in dir(Theme):
|
||||
if theme_name.startswith("_"):
|
||||
continue
|
||||
setattr(Theme, theme_name, getattr(Theme, theme_name)._replace(_var_type=Theme))
|
||||
|
||||
|
||||
class CodeBlock(Component):
|
||||
"""A code block."""
|
||||
|
||||
library = "react-syntax-highlighter@15.5.0"
|
||||
library = "react-syntax-highlighter@15.6.1"
|
||||
|
||||
tag = "PrismAsyncLight"
|
||||
|
||||
alias = "SyntaxHighlighter"
|
||||
|
||||
# The theme to use ("light" or "dark").
|
||||
theme: Var[LiteralCodeBlockTheme] = "one-light" # type: ignore
|
||||
theme: Var[Union[Theme, str]] = Theme.one_light
|
||||
|
||||
# The language to use.
|
||||
language: Var[LiteralCodeLanguage] = "python" # type: ignore
|
||||
language: Var[LiteralCodeLanguage] = Var.create("python")
|
||||
|
||||
# The code to display.
|
||||
code: Var[str]
|
||||
@ -398,6 +411,12 @@ class CodeBlock(Component):
|
||||
# Props passed down to the code tag.
|
||||
code_tag_props: Var[Dict[str, str]]
|
||||
|
||||
# Whether a copy button should appear.
|
||||
can_copy: Optional[bool] = False
|
||||
|
||||
# A custom copy button to override the default one.
|
||||
copy_button: Optional[Union[bool, Component]] = None
|
||||
|
||||
def add_imports(self) -> ImportDict:
|
||||
"""Add imports for the CodeBlock component.
|
||||
|
||||
@ -406,31 +425,6 @@ class CodeBlock(Component):
|
||||
"""
|
||||
imports_: ImportDict = {}
|
||||
|
||||
themeString = str(self.theme)
|
||||
|
||||
selected_themes = []
|
||||
|
||||
for possibleTheme in get_args(LiteralCodeBlockTheme):
|
||||
if format.to_camel_case(possibleTheme) in themeString:
|
||||
selected_themes.append(possibleTheme)
|
||||
if possibleTheme in themeString:
|
||||
selected_themes.append(possibleTheme)
|
||||
|
||||
selected_themes = sorted(set(map(self.convert_theme_name, selected_themes)))
|
||||
|
||||
imports_.update(
|
||||
{
|
||||
f"react-syntax-highlighter/dist/cjs/styles/prism/{theme}": [
|
||||
ImportVar(
|
||||
tag=format.to_camel_case(theme),
|
||||
is_default=True,
|
||||
install=False,
|
||||
)
|
||||
]
|
||||
for theme in selected_themes
|
||||
}
|
||||
)
|
||||
|
||||
if (
|
||||
self.language is not None
|
||||
and (language_without_quotes := str(self.language).replace('"', ""))
|
||||
@ -460,16 +454,12 @@ class CodeBlock(Component):
|
||||
def create(
|
||||
cls,
|
||||
*children,
|
||||
can_copy: Optional[bool] = False,
|
||||
copy_button: Optional[Union[bool, Component]] = None,
|
||||
**props,
|
||||
):
|
||||
"""Create a text component.
|
||||
|
||||
Args:
|
||||
*children: The children of the component.
|
||||
can_copy: Whether a copy button should appears.
|
||||
copy_button: A custom copy button to override the default one.
|
||||
**props: The props to pass to the component.
|
||||
|
||||
Returns:
|
||||
@ -477,18 +467,26 @@ class CodeBlock(Component):
|
||||
"""
|
||||
# This component handles style in a special prop.
|
||||
custom_style = props.pop("custom_style", {})
|
||||
can_copy = props.pop("can_copy", False)
|
||||
copy_button = props.pop("copy_button", None)
|
||||
|
||||
if "theme" not in props:
|
||||
# Default color scheme responds to global color mode.
|
||||
props["theme"] = color_mode_cond(
|
||||
light=ImmutableVar.create_safe("oneLight"),
|
||||
dark=ImmutableVar.create_safe("oneDark"),
|
||||
light=Theme.one_light,
|
||||
dark=Theme.one_dark,
|
||||
)
|
||||
|
||||
# react-syntax-highlighter doesnt have an explicit "light" or "dark" theme so we use one-light and one-dark
|
||||
# themes respectively to ensure code compatibility.
|
||||
if "theme" in props and not isinstance(props["theme"], ImmutableVar):
|
||||
props["theme"] = cls.convert_theme_name(props["theme"])
|
||||
if "theme" in props and not isinstance(props["theme"], Var):
|
||||
props["theme"] = getattr(Theme, format.to_snake_case(props["theme"])) # type: ignore
|
||||
console.deprecate(
|
||||
feature_name="theme prop as string",
|
||||
reason="Use code_block.themes instead.",
|
||||
deprecation_version="0.6.0",
|
||||
removal_version="0.7.0",
|
||||
)
|
||||
|
||||
if can_copy:
|
||||
code = children[0]
|
||||
@ -513,7 +511,7 @@ class CodeBlock(Component):
|
||||
# Carry the children (code) via props
|
||||
if children:
|
||||
props["code"] = children[0]
|
||||
if not isinstance(props["code"], ImmutableVar):
|
||||
if not isinstance(props["code"], Var):
|
||||
props["code"] = LiteralVar.create(props["code"])
|
||||
|
||||
# Create the component.
|
||||
@ -534,9 +532,7 @@ class CodeBlock(Component):
|
||||
def _render(self):
|
||||
out = super()._render()
|
||||
|
||||
theme = self.theme.upcast()._replace(
|
||||
_var_name=replace_quotes_with_camel_case(str(self.theme))
|
||||
)
|
||||
theme = self.theme
|
||||
|
||||
out.add_props(style=theme).remove_props("theme", "code").add_props(
|
||||
children=self.code
|
||||
@ -544,19 +540,16 @@ class CodeBlock(Component):
|
||||
|
||||
return out
|
||||
|
||||
@staticmethod
|
||||
def convert_theme_name(theme) -> str:
|
||||
"""Convert theme names to appropriate names.
|
||||
|
||||
Args:
|
||||
theme: The theme name.
|
||||
|
||||
Returns:
|
||||
The right theme name.
|
||||
"""
|
||||
if theme in ["light", "dark"]:
|
||||
return f"one-{theme}"
|
||||
return theme
|
||||
def _exclude_props(self) -> list[str]:
|
||||
return ["can_copy", "copy_button"]
|
||||
|
||||
|
||||
code_block = CodeBlock.create
|
||||
class CodeblockNamespace(ComponentNamespace):
|
||||
"""Namespace for the CodeBlock component."""
|
||||
|
||||
themes = Theme
|
||||
|
||||
__call__ = CodeBlock.create
|
||||
|
||||
|
||||
code_block = CodeblockNamespace()
|
||||
|
@ -3,63 +3,16 @@
|
||||
# ------------------- DO NOT EDIT ----------------------
|
||||
# This file was generated by `reflex/utils/pyi_generator.py`!
|
||||
# ------------------------------------------------------
|
||||
from typing import Any, Callable, Dict, Literal, Optional, Union, overload
|
||||
import dataclasses
|
||||
from typing import Any, ClassVar, Dict, Literal, Optional, Union, overload
|
||||
|
||||
from reflex.components.component import Component
|
||||
from reflex.components.component import Component, ComponentNamespace
|
||||
from reflex.constants.colors import Color
|
||||
from reflex.event import EventHandler, EventSpec
|
||||
from reflex.ivars.base import ImmutableVar
|
||||
from reflex.event import EventType
|
||||
from reflex.style import Style
|
||||
from reflex.utils.imports import ImportDict
|
||||
from reflex.vars import Var
|
||||
from reflex.vars.base import Var
|
||||
|
||||
LiteralCodeBlockTheme = Literal[
|
||||
"a11y-dark",
|
||||
"atom-dark",
|
||||
"cb",
|
||||
"coldark-cold",
|
||||
"coldark-dark",
|
||||
"coy",
|
||||
"coy-without-shadows",
|
||||
"darcula",
|
||||
"dark",
|
||||
"dracula",
|
||||
"duotone-dark",
|
||||
"duotone-earth",
|
||||
"duotone-forest",
|
||||
"duotone-light",
|
||||
"duotone-sea",
|
||||
"duotone-space",
|
||||
"funky",
|
||||
"ghcolors",
|
||||
"gruvbox-dark",
|
||||
"gruvbox-light",
|
||||
"holi-theme",
|
||||
"hopscotch",
|
||||
"light",
|
||||
"lucario",
|
||||
"material-dark",
|
||||
"material-light",
|
||||
"material-oceanic",
|
||||
"night-owl",
|
||||
"nord",
|
||||
"okaidia",
|
||||
"one-dark",
|
||||
"one-light",
|
||||
"pojoaque",
|
||||
"prism",
|
||||
"shades-of-purple",
|
||||
"solarized-dark-atom",
|
||||
"solarizedlight",
|
||||
"synthwave84",
|
||||
"tomorrow",
|
||||
"twilight",
|
||||
"vs",
|
||||
"vs-dark",
|
||||
"vsc-dark-plus",
|
||||
"xonokai",
|
||||
"z-touch",
|
||||
]
|
||||
LiteralCodeLanguage = Literal[
|
||||
"abap",
|
||||
"abnf",
|
||||
@ -342,7 +295,59 @@ LiteralCodeLanguage = Literal[
|
||||
"zig",
|
||||
]
|
||||
|
||||
def replace_quotes_with_camel_case(value: str) -> str: ...
|
||||
def construct_theme_var(theme: str) -> Var[Theme]: ...
|
||||
@dataclasses.dataclass(init=False)
|
||||
class Theme:
|
||||
a11y_dark: ClassVar[Var[Theme]] = construct_theme_var("a11yDark")
|
||||
atom_dark: ClassVar[Var[Theme]] = construct_theme_var("atomDark")
|
||||
cb: ClassVar[Var[Theme]] = construct_theme_var("cb")
|
||||
coldark_cold: ClassVar[Var[Theme]] = construct_theme_var("coldarkCold")
|
||||
coldark_dark: ClassVar[Var[Theme]] = construct_theme_var("coldarkDark")
|
||||
coy: ClassVar[Var[Theme]] = construct_theme_var("coy")
|
||||
coy_without_shadows: ClassVar[Var[Theme]] = construct_theme_var("coyWithoutShadows")
|
||||
darcula: ClassVar[Var[Theme]] = construct_theme_var("darcula")
|
||||
dark: ClassVar[Var[Theme]] = construct_theme_var("oneDark")
|
||||
dracula: ClassVar[Var[Theme]] = construct_theme_var("dracula")
|
||||
duotone_dark: ClassVar[Var[Theme]] = construct_theme_var("duotoneDark")
|
||||
duotone_earth: ClassVar[Var[Theme]] = construct_theme_var("duotoneEarth")
|
||||
duotone_forest: ClassVar[Var[Theme]] = construct_theme_var("duotoneForest")
|
||||
duotone_light: ClassVar[Var[Theme]] = construct_theme_var("duotoneLight")
|
||||
duotone_sea: ClassVar[Var[Theme]] = construct_theme_var("duotoneSea")
|
||||
duotone_space: ClassVar[Var[Theme]] = construct_theme_var("duotoneSpace")
|
||||
funky: ClassVar[Var[Theme]] = construct_theme_var("funky")
|
||||
ghcolors: ClassVar[Var[Theme]] = construct_theme_var("ghcolors")
|
||||
gruvbox_dark: ClassVar[Var[Theme]] = construct_theme_var("gruvboxDark")
|
||||
gruvbox_light: ClassVar[Var[Theme]] = construct_theme_var("gruvboxLight")
|
||||
holi_theme: ClassVar[Var[Theme]] = construct_theme_var("holiTheme")
|
||||
hopscotch: ClassVar[Var[Theme]] = construct_theme_var("hopscotch")
|
||||
light: ClassVar[Var[Theme]] = construct_theme_var("oneLight")
|
||||
lucario: ClassVar[Var[Theme]] = construct_theme_var("lucario")
|
||||
material_dark: ClassVar[Var[Theme]] = construct_theme_var("materialDark")
|
||||
material_light: ClassVar[Var[Theme]] = construct_theme_var("materialLight")
|
||||
material_oceanic: ClassVar[Var[Theme]] = construct_theme_var("materialOceanic")
|
||||
night_owl: ClassVar[Var[Theme]] = construct_theme_var("nightOwl")
|
||||
nord: ClassVar[Var[Theme]] = construct_theme_var("nord")
|
||||
okaidia: ClassVar[Var[Theme]] = construct_theme_var("okaidia")
|
||||
one_dark: ClassVar[Var[Theme]] = construct_theme_var("oneDark")
|
||||
one_light: ClassVar[Var[Theme]] = construct_theme_var("oneLight")
|
||||
pojoaque: ClassVar[Var[Theme]] = construct_theme_var("pojoaque")
|
||||
prism: ClassVar[Var[Theme]] = construct_theme_var("prism")
|
||||
shades_of_purple: ClassVar[Var[Theme]] = construct_theme_var("shadesOfPurple")
|
||||
solarized_dark_atom: ClassVar[Var[Theme]] = construct_theme_var("solarizedDarkAtom")
|
||||
solarizedlight: ClassVar[Var[Theme]] = construct_theme_var("solarizedlight")
|
||||
synthwave84: ClassVar[Var[Theme]] = construct_theme_var("synthwave84")
|
||||
tomorrow: ClassVar[Var[Theme]] = construct_theme_var("tomorrow")
|
||||
twilight: ClassVar[Var[Theme]] = construct_theme_var("twilight")
|
||||
vs: ClassVar[Var[Theme]] = construct_theme_var("vs")
|
||||
vs_dark: ClassVar[Var[Theme]] = construct_theme_var("vsDark")
|
||||
vsc_dark_plus: ClassVar[Var[Theme]] = construct_theme_var("vscDarkPlus")
|
||||
xonokai: ClassVar[Var[Theme]] = construct_theme_var("xonokai")
|
||||
z_touch: ClassVar[Var[Theme]] = construct_theme_var("zTouch")
|
||||
|
||||
for theme_name in dir(Theme):
|
||||
if theme_name.startswith("_"):
|
||||
continue
|
||||
setattr(Theme, theme_name, getattr(Theme, theme_name)._replace(_var_type=Theme))
|
||||
|
||||
class CodeBlock(Component):
|
||||
def add_imports(self) -> ImportDict: ...
|
||||
@ -351,110 +356,290 @@ class CodeBlock(Component):
|
||||
def create( # type: ignore
|
||||
cls,
|
||||
*children,
|
||||
can_copy: Optional[bool] = False,
|
||||
copy_button: Optional[Union[Component, bool]] = None,
|
||||
theme: Optional[
|
||||
Union[
|
||||
Var[
|
||||
Literal[
|
||||
"a11y-dark",
|
||||
"atom-dark",
|
||||
"cb",
|
||||
"coldark-cold",
|
||||
"coldark-dark",
|
||||
"coy",
|
||||
"coy-without-shadows",
|
||||
"darcula",
|
||||
"dark",
|
||||
"dracula",
|
||||
"duotone-dark",
|
||||
"duotone-earth",
|
||||
"duotone-forest",
|
||||
"duotone-light",
|
||||
"duotone-sea",
|
||||
"duotone-space",
|
||||
"funky",
|
||||
"ghcolors",
|
||||
"gruvbox-dark",
|
||||
"gruvbox-light",
|
||||
"holi-theme",
|
||||
"hopscotch",
|
||||
"light",
|
||||
"lucario",
|
||||
"material-dark",
|
||||
"material-light",
|
||||
"material-oceanic",
|
||||
"night-owl",
|
||||
"nord",
|
||||
"okaidia",
|
||||
"one-dark",
|
||||
"one-light",
|
||||
"pojoaque",
|
||||
"prism",
|
||||
"shades-of-purple",
|
||||
"solarized-dark-atom",
|
||||
"solarizedlight",
|
||||
"synthwave84",
|
||||
"tomorrow",
|
||||
"twilight",
|
||||
"vs",
|
||||
"vs-dark",
|
||||
"vsc-dark-plus",
|
||||
"xonokai",
|
||||
"z-touch",
|
||||
]
|
||||
],
|
||||
Literal[
|
||||
"a11y-dark",
|
||||
"atom-dark",
|
||||
"cb",
|
||||
"coldark-cold",
|
||||
"coldark-dark",
|
||||
"coy",
|
||||
"coy-without-shadows",
|
||||
"darcula",
|
||||
"dark",
|
||||
"dracula",
|
||||
"duotone-dark",
|
||||
"duotone-earth",
|
||||
"duotone-forest",
|
||||
"duotone-light",
|
||||
"duotone-sea",
|
||||
"duotone-space",
|
||||
"funky",
|
||||
"ghcolors",
|
||||
"gruvbox-dark",
|
||||
"gruvbox-light",
|
||||
"holi-theme",
|
||||
"hopscotch",
|
||||
"light",
|
||||
"lucario",
|
||||
"material-dark",
|
||||
"material-light",
|
||||
"material-oceanic",
|
||||
"night-owl",
|
||||
"nord",
|
||||
"okaidia",
|
||||
"one-dark",
|
||||
"one-light",
|
||||
"pojoaque",
|
||||
"prism",
|
||||
"shades-of-purple",
|
||||
"solarized-dark-atom",
|
||||
"solarizedlight",
|
||||
"synthwave84",
|
||||
"tomorrow",
|
||||
"twilight",
|
||||
"vs",
|
||||
"vs-dark",
|
||||
"vsc-dark-plus",
|
||||
"xonokai",
|
||||
"z-touch",
|
||||
],
|
||||
]
|
||||
] = None,
|
||||
theme: Optional[Union[Theme, Var[Union[Theme, str]], str]] = None,
|
||||
language: Optional[
|
||||
Union[
|
||||
Literal[
|
||||
"abap",
|
||||
"abnf",
|
||||
"actionscript",
|
||||
"ada",
|
||||
"agda",
|
||||
"al",
|
||||
"antlr4",
|
||||
"apacheconf",
|
||||
"apex",
|
||||
"apl",
|
||||
"applescript",
|
||||
"aql",
|
||||
"arduino",
|
||||
"arff",
|
||||
"asciidoc",
|
||||
"asm6502",
|
||||
"asmatmel",
|
||||
"aspnet",
|
||||
"autohotkey",
|
||||
"autoit",
|
||||
"avisynth",
|
||||
"avro-idl",
|
||||
"bash",
|
||||
"basic",
|
||||
"batch",
|
||||
"bbcode",
|
||||
"bicep",
|
||||
"birb",
|
||||
"bison",
|
||||
"bnf",
|
||||
"brainfuck",
|
||||
"brightscript",
|
||||
"bro",
|
||||
"bsl",
|
||||
"c",
|
||||
"cfscript",
|
||||
"chaiscript",
|
||||
"cil",
|
||||
"clike",
|
||||
"clojure",
|
||||
"cmake",
|
||||
"cobol",
|
||||
"coffeescript",
|
||||
"concurnas",
|
||||
"coq",
|
||||
"core",
|
||||
"cpp",
|
||||
"crystal",
|
||||
"csharp",
|
||||
"cshtml",
|
||||
"csp",
|
||||
"css",
|
||||
"css-extras",
|
||||
"csv",
|
||||
"cypher",
|
||||
"d",
|
||||
"dart",
|
||||
"dataweave",
|
||||
"dax",
|
||||
"dhall",
|
||||
"diff",
|
||||
"django",
|
||||
"dns-zone-file",
|
||||
"docker",
|
||||
"dot",
|
||||
"ebnf",
|
||||
"editorconfig",
|
||||
"eiffel",
|
||||
"ejs",
|
||||
"elixir",
|
||||
"elm",
|
||||
"erb",
|
||||
"erlang",
|
||||
"etlua",
|
||||
"excel-formula",
|
||||
"factor",
|
||||
"false",
|
||||
"firestore-security-rules",
|
||||
"flow",
|
||||
"fortran",
|
||||
"fsharp",
|
||||
"ftl",
|
||||
"gap",
|
||||
"gcode",
|
||||
"gdscript",
|
||||
"gedcom",
|
||||
"gherkin",
|
||||
"git",
|
||||
"glsl",
|
||||
"gml",
|
||||
"gn",
|
||||
"go",
|
||||
"go-module",
|
||||
"graphql",
|
||||
"groovy",
|
||||
"haml",
|
||||
"handlebars",
|
||||
"haskell",
|
||||
"haxe",
|
||||
"hcl",
|
||||
"hlsl",
|
||||
"hoon",
|
||||
"hpkp",
|
||||
"hsts",
|
||||
"http",
|
||||
"ichigojam",
|
||||
"icon",
|
||||
"icu-message-format",
|
||||
"idris",
|
||||
"iecst",
|
||||
"ignore",
|
||||
"index",
|
||||
"inform7",
|
||||
"ini",
|
||||
"io",
|
||||
"j",
|
||||
"java",
|
||||
"javadoc",
|
||||
"javadoclike",
|
||||
"javascript",
|
||||
"javastacktrace",
|
||||
"jexl",
|
||||
"jolie",
|
||||
"jq",
|
||||
"js-extras",
|
||||
"js-templates",
|
||||
"jsdoc",
|
||||
"json",
|
||||
"json5",
|
||||
"jsonp",
|
||||
"jsstacktrace",
|
||||
"jsx",
|
||||
"julia",
|
||||
"keepalived",
|
||||
"keyman",
|
||||
"kotlin",
|
||||
"kumir",
|
||||
"kusto",
|
||||
"latex",
|
||||
"latte",
|
||||
"less",
|
||||
"lilypond",
|
||||
"liquid",
|
||||
"lisp",
|
||||
"livescript",
|
||||
"llvm",
|
||||
"log",
|
||||
"lolcode",
|
||||
"lua",
|
||||
"magma",
|
||||
"makefile",
|
||||
"markdown",
|
||||
"markup",
|
||||
"markup-templating",
|
||||
"matlab",
|
||||
"maxscript",
|
||||
"mel",
|
||||
"mermaid",
|
||||
"mizar",
|
||||
"mongodb",
|
||||
"monkey",
|
||||
"moonscript",
|
||||
"n1ql",
|
||||
"n4js",
|
||||
"nand2tetris-hdl",
|
||||
"naniscript",
|
||||
"nasm",
|
||||
"neon",
|
||||
"nevod",
|
||||
"nginx",
|
||||
"nim",
|
||||
"nix",
|
||||
"nsis",
|
||||
"objectivec",
|
||||
"ocaml",
|
||||
"opencl",
|
||||
"openqasm",
|
||||
"oz",
|
||||
"parigp",
|
||||
"parser",
|
||||
"pascal",
|
||||
"pascaligo",
|
||||
"pcaxis",
|
||||
"peoplecode",
|
||||
"perl",
|
||||
"php",
|
||||
"php-extras",
|
||||
"phpdoc",
|
||||
"plsql",
|
||||
"powerquery",
|
||||
"powershell",
|
||||
"processing",
|
||||
"prolog",
|
||||
"promql",
|
||||
"properties",
|
||||
"protobuf",
|
||||
"psl",
|
||||
"pug",
|
||||
"puppet",
|
||||
"pure",
|
||||
"purebasic",
|
||||
"purescript",
|
||||
"python",
|
||||
"q",
|
||||
"qml",
|
||||
"qore",
|
||||
"qsharp",
|
||||
"r",
|
||||
"racket",
|
||||
"reason",
|
||||
"regex",
|
||||
"rego",
|
||||
"renpy",
|
||||
"rest",
|
||||
"rip",
|
||||
"roboconf",
|
||||
"robotframework",
|
||||
"ruby",
|
||||
"rust",
|
||||
"sas",
|
||||
"sass",
|
||||
"scala",
|
||||
"scheme",
|
||||
"scss",
|
||||
"shell-session",
|
||||
"smali",
|
||||
"smalltalk",
|
||||
"smarty",
|
||||
"sml",
|
||||
"solidity",
|
||||
"solution-file",
|
||||
"soy",
|
||||
"sparql",
|
||||
"splunk-spl",
|
||||
"sqf",
|
||||
"sql",
|
||||
"squirrel",
|
||||
"stan",
|
||||
"stylus",
|
||||
"swift",
|
||||
"systemd",
|
||||
"t4-cs",
|
||||
"t4-templating",
|
||||
"t4-vb",
|
||||
"tap",
|
||||
"tcl",
|
||||
"textile",
|
||||
"toml",
|
||||
"tremor",
|
||||
"tsx",
|
||||
"tt2",
|
||||
"turtle",
|
||||
"twig",
|
||||
"typescript",
|
||||
"typoscript",
|
||||
"unrealscript",
|
||||
"uorazor",
|
||||
"uri",
|
||||
"v",
|
||||
"vala",
|
||||
"vbnet",
|
||||
"velocity",
|
||||
"verilog",
|
||||
"vhdl",
|
||||
"vim",
|
||||
"visual-basic",
|
||||
"warpscript",
|
||||
"wasm",
|
||||
"web-idl",
|
||||
"wiki",
|
||||
"wolfram",
|
||||
"wren",
|
||||
"xeora",
|
||||
"xml-doc",
|
||||
"xojo",
|
||||
"xquery",
|
||||
"yaml",
|
||||
"yang",
|
||||
"zig",
|
||||
],
|
||||
Var[
|
||||
Literal[
|
||||
"abap",
|
||||
@ -738,6 +923,77 @@ class CodeBlock(Component):
|
||||
"zig",
|
||||
]
|
||||
],
|
||||
]
|
||||
] = None,
|
||||
code: Optional[Union[Var[str], str]] = None,
|
||||
show_line_numbers: Optional[Union[Var[bool], bool]] = None,
|
||||
starting_line_number: Optional[Union[Var[int], int]] = None,
|
||||
wrap_long_lines: Optional[Union[Var[bool], bool]] = None,
|
||||
custom_style: Optional[Dict[str, Union[str, Var, Color]]] = None,
|
||||
code_tag_props: Optional[Union[Dict[str, str], Var[Dict[str, str]]]] = None,
|
||||
can_copy: Optional[bool] = None,
|
||||
copy_button: Optional[Union[Component, bool]] = 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,
|
||||
) -> "CodeBlock":
|
||||
"""Create a text component.
|
||||
|
||||
Args:
|
||||
*children: The children of the component.
|
||||
theme: The theme to use ("light" or "dark").
|
||||
language: The language to use.
|
||||
code: The code to display.
|
||||
show_line_numbers: If this is enabled line numbers will be shown next to the code block.
|
||||
starting_line_number: The starting line number to use.
|
||||
wrap_long_lines: Whether to wrap long lines.
|
||||
custom_style: A custom style for the code block.
|
||||
code_tag_props: Props passed down to the code tag.
|
||||
can_copy: Whether a copy button should appear.
|
||||
copy_button: A custom copy button to override the default one.
|
||||
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 text component.
|
||||
"""
|
||||
...
|
||||
|
||||
def add_style(self): ...
|
||||
|
||||
class CodeblockNamespace(ComponentNamespace):
|
||||
themes = Theme
|
||||
|
||||
@staticmethod
|
||||
def __call__(
|
||||
*children,
|
||||
theme: Optional[Union[Theme, Var[Union[Theme, str]], str]] = None,
|
||||
language: Optional[
|
||||
Union[
|
||||
Literal[
|
||||
"abap",
|
||||
"abnf",
|
||||
@ -1019,6 +1275,289 @@ class CodeBlock(Component):
|
||||
"yang",
|
||||
"zig",
|
||||
],
|
||||
Var[
|
||||
Literal[
|
||||
"abap",
|
||||
"abnf",
|
||||
"actionscript",
|
||||
"ada",
|
||||
"agda",
|
||||
"al",
|
||||
"antlr4",
|
||||
"apacheconf",
|
||||
"apex",
|
||||
"apl",
|
||||
"applescript",
|
||||
"aql",
|
||||
"arduino",
|
||||
"arff",
|
||||
"asciidoc",
|
||||
"asm6502",
|
||||
"asmatmel",
|
||||
"aspnet",
|
||||
"autohotkey",
|
||||
"autoit",
|
||||
"avisynth",
|
||||
"avro-idl",
|
||||
"bash",
|
||||
"basic",
|
||||
"batch",
|
||||
"bbcode",
|
||||
"bicep",
|
||||
"birb",
|
||||
"bison",
|
||||
"bnf",
|
||||
"brainfuck",
|
||||
"brightscript",
|
||||
"bro",
|
||||
"bsl",
|
||||
"c",
|
||||
"cfscript",
|
||||
"chaiscript",
|
||||
"cil",
|
||||
"clike",
|
||||
"clojure",
|
||||
"cmake",
|
||||
"cobol",
|
||||
"coffeescript",
|
||||
"concurnas",
|
||||
"coq",
|
||||
"core",
|
||||
"cpp",
|
||||
"crystal",
|
||||
"csharp",
|
||||
"cshtml",
|
||||
"csp",
|
||||
"css",
|
||||
"css-extras",
|
||||
"csv",
|
||||
"cypher",
|
||||
"d",
|
||||
"dart",
|
||||
"dataweave",
|
||||
"dax",
|
||||
"dhall",
|
||||
"diff",
|
||||
"django",
|
||||
"dns-zone-file",
|
||||
"docker",
|
||||
"dot",
|
||||
"ebnf",
|
||||
"editorconfig",
|
||||
"eiffel",
|
||||
"ejs",
|
||||
"elixir",
|
||||
"elm",
|
||||
"erb",
|
||||
"erlang",
|
||||
"etlua",
|
||||
"excel-formula",
|
||||
"factor",
|
||||
"false",
|
||||
"firestore-security-rules",
|
||||
"flow",
|
||||
"fortran",
|
||||
"fsharp",
|
||||
"ftl",
|
||||
"gap",
|
||||
"gcode",
|
||||
"gdscript",
|
||||
"gedcom",
|
||||
"gherkin",
|
||||
"git",
|
||||
"glsl",
|
||||
"gml",
|
||||
"gn",
|
||||
"go",
|
||||
"go-module",
|
||||
"graphql",
|
||||
"groovy",
|
||||
"haml",
|
||||
"handlebars",
|
||||
"haskell",
|
||||
"haxe",
|
||||
"hcl",
|
||||
"hlsl",
|
||||
"hoon",
|
||||
"hpkp",
|
||||
"hsts",
|
||||
"http",
|
||||
"ichigojam",
|
||||
"icon",
|
||||
"icu-message-format",
|
||||
"idris",
|
||||
"iecst",
|
||||
"ignore",
|
||||
"index",
|
||||
"inform7",
|
||||
"ini",
|
||||
"io",
|
||||
"j",
|
||||
"java",
|
||||
"javadoc",
|
||||
"javadoclike",
|
||||
"javascript",
|
||||
"javastacktrace",
|
||||
"jexl",
|
||||
"jolie",
|
||||
"jq",
|
||||
"js-extras",
|
||||
"js-templates",
|
||||
"jsdoc",
|
||||
"json",
|
||||
"json5",
|
||||
"jsonp",
|
||||
"jsstacktrace",
|
||||
"jsx",
|
||||
"julia",
|
||||
"keepalived",
|
||||
"keyman",
|
||||
"kotlin",
|
||||
"kumir",
|
||||
"kusto",
|
||||
"latex",
|
||||
"latte",
|
||||
"less",
|
||||
"lilypond",
|
||||
"liquid",
|
||||
"lisp",
|
||||
"livescript",
|
||||
"llvm",
|
||||
"log",
|
||||
"lolcode",
|
||||
"lua",
|
||||
"magma",
|
||||
"makefile",
|
||||
"markdown",
|
||||
"markup",
|
||||
"markup-templating",
|
||||
"matlab",
|
||||
"maxscript",
|
||||
"mel",
|
||||
"mermaid",
|
||||
"mizar",
|
||||
"mongodb",
|
||||
"monkey",
|
||||
"moonscript",
|
||||
"n1ql",
|
||||
"n4js",
|
||||
"nand2tetris-hdl",
|
||||
"naniscript",
|
||||
"nasm",
|
||||
"neon",
|
||||
"nevod",
|
||||
"nginx",
|
||||
"nim",
|
||||
"nix",
|
||||
"nsis",
|
||||
"objectivec",
|
||||
"ocaml",
|
||||
"opencl",
|
||||
"openqasm",
|
||||
"oz",
|
||||
"parigp",
|
||||
"parser",
|
||||
"pascal",
|
||||
"pascaligo",
|
||||
"pcaxis",
|
||||
"peoplecode",
|
||||
"perl",
|
||||
"php",
|
||||
"php-extras",
|
||||
"phpdoc",
|
||||
"plsql",
|
||||
"powerquery",
|
||||
"powershell",
|
||||
"processing",
|
||||
"prolog",
|
||||
"promql",
|
||||
"properties",
|
||||
"protobuf",
|
||||
"psl",
|
||||
"pug",
|
||||
"puppet",
|
||||
"pure",
|
||||
"purebasic",
|
||||
"purescript",
|
||||
"python",
|
||||
"q",
|
||||
"qml",
|
||||
"qore",
|
||||
"qsharp",
|
||||
"r",
|
||||
"racket",
|
||||
"reason",
|
||||
"regex",
|
||||
"rego",
|
||||
"renpy",
|
||||
"rest",
|
||||
"rip",
|
||||
"roboconf",
|
||||
"robotframework",
|
||||
"ruby",
|
||||
"rust",
|
||||
"sas",
|
||||
"sass",
|
||||
"scala",
|
||||
"scheme",
|
||||
"scss",
|
||||
"shell-session",
|
||||
"smali",
|
||||
"smalltalk",
|
||||
"smarty",
|
||||
"sml",
|
||||
"solidity",
|
||||
"solution-file",
|
||||
"soy",
|
||||
"sparql",
|
||||
"splunk-spl",
|
||||
"sqf",
|
||||
"sql",
|
||||
"squirrel",
|
||||
"stan",
|
||||
"stylus",
|
||||
"swift",
|
||||
"systemd",
|
||||
"t4-cs",
|
||||
"t4-templating",
|
||||
"t4-vb",
|
||||
"tap",
|
||||
"tcl",
|
||||
"textile",
|
||||
"toml",
|
||||
"tremor",
|
||||
"tsx",
|
||||
"tt2",
|
||||
"turtle",
|
||||
"twig",
|
||||
"typescript",
|
||||
"typoscript",
|
||||
"unrealscript",
|
||||
"uorazor",
|
||||
"uri",
|
||||
"v",
|
||||
"vala",
|
||||
"vbnet",
|
||||
"velocity",
|
||||
"verilog",
|
||||
"vhdl",
|
||||
"vim",
|
||||
"visual-basic",
|
||||
"warpscript",
|
||||
"wasm",
|
||||
"web-idl",
|
||||
"wiki",
|
||||
"wolfram",
|
||||
"wren",
|
||||
"xeora",
|
||||
"xml-doc",
|
||||
"xojo",
|
||||
"xquery",
|
||||
"yaml",
|
||||
"yang",
|
||||
"zig",
|
||||
]
|
||||
],
|
||||
]
|
||||
] = None,
|
||||
code: Optional[Union[Var[str], str]] = None,
|
||||
@ -1026,66 +1565,36 @@ class CodeBlock(Component):
|
||||
starting_line_number: Optional[Union[Var[int], int]] = None,
|
||||
wrap_long_lines: Optional[Union[Var[bool], bool]] = None,
|
||||
custom_style: Optional[Dict[str, Union[str, Var, Color]]] = None,
|
||||
code_tag_props: Optional[Union[Var[Dict[str, str]], Dict[str, str]]] = None,
|
||||
code_tag_props: Optional[Union[Dict[str, str], Var[Dict[str, str]]]] = None,
|
||||
can_copy: Optional[bool] = None,
|
||||
copy_button: Optional[Union[Component, bool]] = 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[ImmutableVar, str]]] = None,
|
||||
on_blur: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_context_menu: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_double_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_focus: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_down: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_enter: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_leave: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_move: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_out: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_over: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_up: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_scroll: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_unmount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = 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,
|
||||
) -> "CodeBlock":
|
||||
"""Create a text component.
|
||||
|
||||
Args:
|
||||
*children: The children of the component.
|
||||
can_copy: Whether a copy button should appears.
|
||||
copy_button: A custom copy button to override the default one.
|
||||
theme: The theme to use ("light" or "dark").
|
||||
language: The language to use.
|
||||
code: The code to display.
|
||||
@ -1094,6 +1603,8 @@ class CodeBlock(Component):
|
||||
wrap_long_lines: Whether to wrap long lines.
|
||||
custom_style: A custom style for the code block.
|
||||
code_tag_props: Props passed down to the code tag.
|
||||
can_copy: Whether a copy button should appear.
|
||||
copy_button: A custom copy button to override the default one.
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
@ -1107,8 +1618,4 @@ class CodeBlock(Component):
|
||||
"""
|
||||
...
|
||||
|
||||
def add_style(self): ...
|
||||
@staticmethod
|
||||
def convert_theme_name(theme) -> str: ...
|
||||
|
||||
code_block = CodeBlock.create
|
||||
code_block = CodeblockNamespace()
|
||||
|
@ -3,18 +3,20 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from enum import Enum
|
||||
from typing import Any, Dict, List, Literal, Optional, Union
|
||||
from typing import Any, Dict, List, Literal, Optional, Tuple, Union
|
||||
|
||||
from typing_extensions import TypedDict
|
||||
|
||||
from reflex.base import Base
|
||||
from reflex.components.component import Component, NoSSRComponent
|
||||
from reflex.components.literals import LiteralRowMarker
|
||||
from reflex.event import EventHandler
|
||||
from reflex.ivars.base import ImmutableVar
|
||||
from reflex.ivars.sequence import ArrayVar
|
||||
from reflex.event import EventHandler, empty_event, identity_event
|
||||
from reflex.utils import console, format, types
|
||||
from reflex.utils.imports import ImportDict, ImportVar
|
||||
from reflex.utils.serializers import serializer
|
||||
from reflex.vars import Var, get_unique_variable_name
|
||||
from reflex.vars import get_unique_variable_name
|
||||
from reflex.vars.base import Var
|
||||
from reflex.vars.sequence import ArrayVar
|
||||
|
||||
|
||||
# TODO: Fix the serialization issue for custom types.
|
||||
@ -107,17 +109,76 @@ class DataEditorTheme(Base):
|
||||
text_medium: Optional[str] = None
|
||||
|
||||
|
||||
def on_edit_spec(pos, data: dict[str, Any]):
|
||||
"""The on edit spec function.
|
||||
class Bounds(TypedDict):
|
||||
"""The bounds of the group header."""
|
||||
|
||||
Args:
|
||||
pos: The position of the edit event.
|
||||
data: The data of the edit event.
|
||||
x: int
|
||||
y: int
|
||||
width: int
|
||||
height: int
|
||||
|
||||
Returns:
|
||||
The position and data.
|
||||
"""
|
||||
return [pos, data]
|
||||
|
||||
class CompatSelection(TypedDict):
|
||||
"""The selection."""
|
||||
|
||||
items: list
|
||||
|
||||
|
||||
class Rectangle(TypedDict):
|
||||
"""The bounds of the group header."""
|
||||
|
||||
x: int
|
||||
y: int
|
||||
width: int
|
||||
height: int
|
||||
|
||||
|
||||
class GridSelectionCurrent(TypedDict):
|
||||
"""The current selection."""
|
||||
|
||||
cell: tuple[int, int]
|
||||
range: Rectangle
|
||||
rangeStack: list[Rectangle]
|
||||
|
||||
|
||||
class GridSelection(TypedDict):
|
||||
"""The grid selection."""
|
||||
|
||||
current: Optional[GridSelectionCurrent]
|
||||
columns: CompatSelection
|
||||
rows: CompatSelection
|
||||
|
||||
|
||||
class GroupHeaderClickedEventArgs(TypedDict):
|
||||
"""The arguments for the group header clicked event."""
|
||||
|
||||
kind: str
|
||||
group: str
|
||||
location: tuple[int, int]
|
||||
bounds: Bounds
|
||||
isEdge: bool
|
||||
shiftKey: bool
|
||||
ctrlKey: bool
|
||||
metaKey: bool
|
||||
isTouch: bool
|
||||
localEventX: int
|
||||
localEventY: int
|
||||
button: int
|
||||
buttons: int
|
||||
scrollEdge: tuple[int, int]
|
||||
|
||||
|
||||
class GridCell(TypedDict):
|
||||
"""The grid cell."""
|
||||
|
||||
span: Optional[List[int]]
|
||||
|
||||
|
||||
class GridColumn(TypedDict):
|
||||
"""The grid column."""
|
||||
|
||||
title: str
|
||||
group: Optional[str]
|
||||
|
||||
|
||||
class DataEditor(NoSSRComponent):
|
||||
@ -125,10 +186,10 @@ class DataEditor(NoSSRComponent):
|
||||
|
||||
tag = "DataEditor"
|
||||
is_default = True
|
||||
library: str = "@glideapps/glide-data-grid@^5.3.0"
|
||||
library: str = "@glideapps/glide-data-grid@^6.0.3"
|
||||
lib_dependencies: List[str] = [
|
||||
"lodash@^4.17.21",
|
||||
"marked@^4.0.10",
|
||||
"marked@^14.1.2",
|
||||
"react-responsive-carousel@^3.2.7",
|
||||
]
|
||||
|
||||
@ -145,7 +206,7 @@ class DataEditor(NoSSRComponent):
|
||||
get_cell_content: Var[str]
|
||||
|
||||
# Allow selection for copying.
|
||||
get_cell_for_selection: Var[bool]
|
||||
get_cells_for_selection: Var[bool]
|
||||
|
||||
# Allow paste.
|
||||
on_paste: Var[bool]
|
||||
@ -223,52 +284,56 @@ class DataEditor(NoSSRComponent):
|
||||
theme: Var[Union[DataEditorTheme, Dict]]
|
||||
|
||||
# Fired when a cell is activated.
|
||||
on_cell_activated: EventHandler[lambda pos: [pos]]
|
||||
on_cell_activated: EventHandler[identity_event(Tuple[int, int])]
|
||||
|
||||
# Fired when a cell is clicked.
|
||||
on_cell_clicked: EventHandler[lambda pos: [pos]]
|
||||
on_cell_clicked: EventHandler[identity_event(Tuple[int, int])]
|
||||
|
||||
# Fired when a cell is right-clicked.
|
||||
on_cell_context_menu: EventHandler[lambda pos: [pos]]
|
||||
on_cell_context_menu: EventHandler[identity_event(Tuple[int, int])]
|
||||
|
||||
# Fired when a cell is edited.
|
||||
on_cell_edited: EventHandler[on_edit_spec]
|
||||
on_cell_edited: EventHandler[identity_event(Tuple[int, int], GridCell)]
|
||||
|
||||
# Fired when a group header is clicked.
|
||||
on_group_header_clicked: EventHandler[on_edit_spec]
|
||||
on_group_header_clicked: EventHandler[identity_event(Tuple[int, int], GridCell)]
|
||||
|
||||
# Fired when a group header is right-clicked.
|
||||
on_group_header_context_menu: EventHandler[lambda grp_idx, data: [grp_idx, data]]
|
||||
on_group_header_context_menu: EventHandler[
|
||||
identity_event(int, GroupHeaderClickedEventArgs)
|
||||
]
|
||||
|
||||
# Fired when a group header is renamed.
|
||||
on_group_header_renamed: EventHandler[lambda idx, val: [idx, val]]
|
||||
on_group_header_renamed: EventHandler[identity_event(str, str)]
|
||||
|
||||
# Fired when a header is clicked.
|
||||
on_header_clicked: EventHandler[lambda pos: [pos]]
|
||||
on_header_clicked: EventHandler[identity_event(Tuple[int, int])]
|
||||
|
||||
# Fired when a header is right-clicked.
|
||||
on_header_context_menu: EventHandler[lambda pos: [pos]]
|
||||
on_header_context_menu: EventHandler[identity_event(Tuple[int, int])]
|
||||
|
||||
# Fired when a header menu item is clicked.
|
||||
on_header_menu_click: EventHandler[lambda col, pos: [col, pos]]
|
||||
on_header_menu_click: EventHandler[identity_event(int, Rectangle)]
|
||||
|
||||
# Fired when an item is hovered.
|
||||
on_item_hovered: EventHandler[lambda pos: [pos]]
|
||||
on_item_hovered: EventHandler[identity_event(Tuple[int, int])]
|
||||
|
||||
# Fired when a selection is deleted.
|
||||
on_delete: EventHandler[lambda selection: [selection]]
|
||||
on_delete: EventHandler[identity_event(GridSelection)]
|
||||
|
||||
# Fired when editing is finished.
|
||||
on_finished_editing: EventHandler[lambda new_value, movement: [new_value, movement]]
|
||||
on_finished_editing: EventHandler[
|
||||
identity_event(Union[GridCell, None], tuple[int, int])
|
||||
]
|
||||
|
||||
# Fired when a row is appended.
|
||||
on_row_appended: EventHandler[lambda: []]
|
||||
on_row_appended: EventHandler[empty_event]
|
||||
|
||||
# Fired when the selection is cleared.
|
||||
on_selection_cleared: EventHandler[lambda: []]
|
||||
on_selection_cleared: EventHandler[empty_event]
|
||||
|
||||
# Fired when a column is resized.
|
||||
on_column_resize: EventHandler[lambda col, width: [col, width]]
|
||||
on_column_resize: EventHandler[identity_event(GridColumn, int)]
|
||||
|
||||
def add_imports(self) -> ImportDict:
|
||||
"""Add imports for the component.
|
||||
@ -279,7 +344,7 @@ class DataEditor(NoSSRComponent):
|
||||
return {
|
||||
"": f"{format.format_library_name(self.library)}/dist/index.css",
|
||||
self.library: "GridCellKind",
|
||||
"/utils/helpers/dataeditor.js": ImportVar(
|
||||
"$/utils/helpers/dataeditor.js": ImportVar(
|
||||
tag="formatDataEditorCells", is_default=False, install=False
|
||||
),
|
||||
}
|
||||
@ -295,7 +360,7 @@ class DataEditor(NoSSRComponent):
|
||||
|
||||
# Define the name of the getData callback associated with this component and assign to get_cell_content.
|
||||
data_callback = f"getData_{editor_id}"
|
||||
self.get_cell_content = ImmutableVar.create(data_callback) # type: ignore
|
||||
self.get_cell_content = Var(_js_expr=data_callback) # type: ignore
|
||||
|
||||
code = [f"function {data_callback}([col, row])" "{"]
|
||||
|
||||
@ -329,22 +394,20 @@ class DataEditor(NoSSRComponent):
|
||||
|
||||
columns = props.get("columns", [])
|
||||
data = props.get("data", [])
|
||||
rows = props.get("rows", None)
|
||||
rows = props.get("rows")
|
||||
|
||||
# If rows is not provided, determine from data.
|
||||
if rows is None:
|
||||
if isinstance(data, ImmutableVar) and not isinstance(data, ArrayVar):
|
||||
if isinstance(data, Var) and not isinstance(data, ArrayVar):
|
||||
raise ValueError(
|
||||
"DataEditor data must be an ArrayVar if rows is not provided."
|
||||
)
|
||||
props["rows"] = (
|
||||
data.length() if isinstance(data, ImmutableVar) else len(data)
|
||||
)
|
||||
props["rows"] = data.length() if isinstance(data, Var) else len(data)
|
||||
|
||||
if not isinstance(columns, ImmutableVar) and len(columns):
|
||||
if not isinstance(columns, Var) and len(columns):
|
||||
if (
|
||||
types.is_dataframe(type(data))
|
||||
or isinstance(data, ImmutableVar)
|
||||
or isinstance(data, Var)
|
||||
and types.is_dataframe(data._var_type)
|
||||
):
|
||||
raise ValueError(
|
||||
@ -361,7 +424,7 @@ class DataEditor(NoSSRComponent):
|
||||
props["theme"] = DataEditorTheme(**theme)
|
||||
|
||||
# Allow by default to select a region of cells in the grid.
|
||||
props.setdefault("get_cell_for_selection", True)
|
||||
props.setdefault("get_cells_for_selection", True)
|
||||
|
||||
# Disable on_paste by default if not provided.
|
||||
props.setdefault("on_paste", False)
|
||||
|
@ -4,16 +4,17 @@
|
||||
# This file was generated by `reflex/utils/pyi_generator.py`!
|
||||
# ------------------------------------------------------
|
||||
from enum import Enum
|
||||
from typing import Any, Callable, Dict, List, Literal, Optional, Union, overload
|
||||
from typing import Any, Dict, List, Literal, Optional, Union, overload
|
||||
|
||||
from typing_extensions import TypedDict
|
||||
|
||||
from reflex.base import Base
|
||||
from reflex.components.component import NoSSRComponent
|
||||
from reflex.event import EventHandler, EventSpec
|
||||
from reflex.ivars.base import ImmutableVar
|
||||
from reflex.event import EventType
|
||||
from reflex.style import Style
|
||||
from reflex.utils.imports import ImportDict
|
||||
from reflex.utils.serializers import serializer
|
||||
from reflex.vars import Var
|
||||
from reflex.vars.base import Var
|
||||
|
||||
class GridColumnIcons(Enum):
|
||||
Array = "array"
|
||||
@ -77,7 +78,53 @@ class DataEditorTheme(Base):
|
||||
text_light: Optional[str]
|
||||
text_medium: Optional[str]
|
||||
|
||||
def on_edit_spec(pos, data: dict[str, Any]): ...
|
||||
class Bounds(TypedDict):
|
||||
x: int
|
||||
y: int
|
||||
width: int
|
||||
height: int
|
||||
|
||||
class CompatSelection(TypedDict):
|
||||
items: list
|
||||
|
||||
class Rectangle(TypedDict):
|
||||
x: int
|
||||
y: int
|
||||
width: int
|
||||
height: int
|
||||
|
||||
class GridSelectionCurrent(TypedDict):
|
||||
cell: tuple[int, int]
|
||||
range: Rectangle
|
||||
rangeStack: list[Rectangle]
|
||||
|
||||
class GridSelection(TypedDict):
|
||||
current: Optional[GridSelectionCurrent]
|
||||
columns: CompatSelection
|
||||
rows: CompatSelection
|
||||
|
||||
class GroupHeaderClickedEventArgs(TypedDict):
|
||||
kind: str
|
||||
group: str
|
||||
location: tuple[int, int]
|
||||
bounds: Bounds
|
||||
isEdge: bool
|
||||
shiftKey: bool
|
||||
ctrlKey: bool
|
||||
metaKey: bool
|
||||
isTouch: bool
|
||||
localEventX: int
|
||||
localEventY: int
|
||||
button: int
|
||||
buttons: int
|
||||
scrollEdge: tuple[int, int]
|
||||
|
||||
class GridCell(TypedDict):
|
||||
span: Optional[List[int]]
|
||||
|
||||
class GridColumn(TypedDict):
|
||||
title: str
|
||||
group: Optional[str]
|
||||
|
||||
class DataEditor(NoSSRComponent):
|
||||
def add_imports(self) -> ImportDict: ...
|
||||
@ -89,11 +136,11 @@ class DataEditor(NoSSRComponent):
|
||||
*children,
|
||||
rows: Optional[Union[Var[int], int]] = None,
|
||||
columns: Optional[
|
||||
Union[Var[List[Dict[str, Any]]], List[Dict[str, Any]]]
|
||||
Union[List[Dict[str, Any]], Var[List[Dict[str, Any]]]]
|
||||
] = None,
|
||||
data: Optional[Union[Var[List[List[Any]]], List[List[Any]]]] = None,
|
||||
data: Optional[Union[List[List[Any]], Var[List[List[Any]]]]] = None,
|
||||
get_cell_content: Optional[Union[Var[str], str]] = None,
|
||||
get_cell_for_selection: Optional[Union[Var[bool], bool]] = None,
|
||||
get_cells_for_selection: Optional[Union[Var[bool], bool]] = None,
|
||||
on_paste: Optional[Union[Var[bool], bool]] = None,
|
||||
draw_focus_ring: Optional[Union[Var[bool], bool]] = None,
|
||||
fixed_shadow_x: Optional[Union[Var[bool], bool]] = None,
|
||||
@ -107,8 +154,8 @@ class DataEditor(NoSSRComponent):
|
||||
row_height: Optional[Union[Var[int], int]] = None,
|
||||
row_markers: Optional[
|
||||
Union[
|
||||
Var[Literal["none", "number", "checkbox", "both", "clickable-number"]],
|
||||
Literal["none", "number", "checkbox", "both", "clickable-number"],
|
||||
Literal["both", "checkbox", "clickable-number", "none", "number"],
|
||||
Var[Literal["both", "checkbox", "clickable-number", "none", "number"]],
|
||||
]
|
||||
] = None,
|
||||
row_marker_start_index: Optional[Union[Var[int], int]] = None,
|
||||
@ -118,8 +165,8 @@ class DataEditor(NoSSRComponent):
|
||||
vertical_border: Optional[Union[Var[bool], bool]] = None,
|
||||
column_select: Optional[
|
||||
Union[
|
||||
Var[Literal["none", "single", "multi"]],
|
||||
Literal["none", "single", "multi"],
|
||||
Literal["multi", "none", "single"],
|
||||
Var[Literal["multi", "none", "single"]],
|
||||
]
|
||||
] = None,
|
||||
prevent_diagonal_scrolling: Optional[Union[Var[bool], bool]] = None,
|
||||
@ -128,107 +175,49 @@ class DataEditor(NoSSRComponent):
|
||||
scroll_offset_x: Optional[Union[Var[int], int]] = None,
|
||||
scroll_offset_y: Optional[Union[Var[int], int]] = None,
|
||||
theme: Optional[
|
||||
Union[Var[Union[DataEditorTheme, Dict]], DataEditorTheme, Dict]
|
||||
Union[DataEditorTheme, Dict, Var[Union[DataEditorTheme, Dict]]]
|
||||
] = 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[ImmutableVar, str]]] = None,
|
||||
on_blur: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_cell_activated: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_cell_clicked: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_cell_context_menu: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_cell_edited: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_column_resize: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_context_menu: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_delete: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_double_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
custom_attrs: Optional[Dict[str, Union[Var, str]]] = None,
|
||||
on_blur: Optional[EventType[[]]] = None,
|
||||
on_cell_activated: Optional[EventType[tuple[int, int]]] = None,
|
||||
on_cell_clicked: Optional[EventType[tuple[int, int]]] = None,
|
||||
on_cell_context_menu: Optional[EventType[tuple[int, int]]] = None,
|
||||
on_cell_edited: Optional[EventType[tuple[int, int], GridCell]] = None,
|
||||
on_click: Optional[EventType[[]]] = None,
|
||||
on_column_resize: Optional[EventType[GridColumn, int]] = None,
|
||||
on_context_menu: Optional[EventType[[]]] = None,
|
||||
on_delete: Optional[EventType[GridSelection]] = None,
|
||||
on_double_click: Optional[EventType[[]]] = None,
|
||||
on_finished_editing: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_focus: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_group_header_clicked: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
EventType[Union[GridCell, None], tuple[int, int]]
|
||||
] = None,
|
||||
on_focus: Optional[EventType[[]]] = None,
|
||||
on_group_header_clicked: Optional[EventType[tuple[int, int], GridCell]] = None,
|
||||
on_group_header_context_menu: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_group_header_renamed: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_header_clicked: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_header_context_menu: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_header_menu_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_item_hovered: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_down: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_enter: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_leave: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_move: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_out: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_over: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_up: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_row_appended: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_scroll: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_selection_cleared: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_unmount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
EventType[int, GroupHeaderClickedEventArgs]
|
||||
] = None,
|
||||
on_group_header_renamed: Optional[EventType[str, str]] = None,
|
||||
on_header_clicked: Optional[EventType[tuple[int, int]]] = None,
|
||||
on_header_context_menu: Optional[EventType[tuple[int, int]]] = None,
|
||||
on_header_menu_click: Optional[EventType[int, Rectangle]] = None,
|
||||
on_item_hovered: Optional[EventType[tuple[int, int]]] = 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_row_appended: Optional[EventType[[]]] = None,
|
||||
on_scroll: Optional[EventType[[]]] = None,
|
||||
on_selection_cleared: Optional[EventType[[]]] = None,
|
||||
on_unmount: Optional[EventType[[]]] = None,
|
||||
**props,
|
||||
) -> "DataEditor":
|
||||
"""Create the DataEditor component.
|
||||
@ -239,7 +228,7 @@ class DataEditor(NoSSRComponent):
|
||||
columns: Headers of the columns for the data grid.
|
||||
data: The data.
|
||||
get_cell_content: The name of the callback used to find the data to display.
|
||||
get_cell_for_selection: Allow selection for copying.
|
||||
get_cells_for_selection: Allow selection for copying.
|
||||
on_paste: Allow paste.
|
||||
draw_focus_ring: Controls the drawing of the focus ring.
|
||||
fixed_shadow_x: Enables or disables the overlay shadow when scrolling horizontally.
|
||||
@ -264,6 +253,22 @@ class DataEditor(NoSSRComponent):
|
||||
scroll_offset_x: Initial scroll offset on the horizontal axis.
|
||||
scroll_offset_y: Initial scroll offset on the vertical axis.
|
||||
theme: global theme
|
||||
on_cell_activated: Fired when a cell is activated.
|
||||
on_cell_clicked: Fired when a cell is clicked.
|
||||
on_cell_context_menu: Fired when a cell is right-clicked.
|
||||
on_cell_edited: Fired when a cell is edited.
|
||||
on_group_header_clicked: Fired when a group header is clicked.
|
||||
on_group_header_context_menu: Fired when a group header is right-clicked.
|
||||
on_group_header_renamed: Fired when a group header is renamed.
|
||||
on_header_clicked: Fired when a header is clicked.
|
||||
on_header_context_menu: Fired when a header is right-clicked.
|
||||
on_header_menu_click: Fired when a header menu item is clicked.
|
||||
on_item_hovered: Fired when an item is hovered.
|
||||
on_delete: Fired when a selection is deleted.
|
||||
on_finished_editing: Fired when editing is finished.
|
||||
on_row_appended: Fired when a row is appended.
|
||||
on_selection_cleared: Fired when the selection is cleared.
|
||||
on_column_resize: Fired when a column is resized.
|
||||
style: The style of the component.
|
||||
key: A unique key for the component.
|
||||
id: The id for the component.
|
||||
|
@ -12,31 +12,33 @@ def logo(**props):
|
||||
Returns:
|
||||
The logo component.
|
||||
"""
|
||||
light_mode_logo = """<svg width="56" height="12" viewBox="0 0 56 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M0 11.6V0.400024H8.96V4.88002H6.72V2.64002H2.24V4.88002H6.72V7.12002H2.24V11.6H0ZM6.72 11.6V7.12002H8.96V11.6H6.72Z" fill="#110F1F"/>
|
||||
<path d="M11.2 11.6V0.400024H17.92V2.64002H13.44V4.88002H17.92V7.12002H13.44V9.36002H17.92V11.6H11.2Z" fill="#110F1F"/>
|
||||
<path d="M20.16 11.6V0.400024H26.88V2.64002H22.4V4.88002H26.88V7.12002H22.4V11.6H20.16Z" fill="#110F1F"/>
|
||||
<path d="M29.12 11.6V0.400024H31.36V9.36002H35.84V11.6H29.12Z" fill="#110F1F"/>
|
||||
<path d="M38.08 11.6V0.400024H44.8V2.64002H40.32V4.88002H44.8V7.12002H40.32V9.36002H44.8V11.6H38.08Z" fill="#110F1F"/>
|
||||
<path d="M47.04 4.88002V0.400024H49.28V4.88002H47.04ZM53.76 4.88002V0.400024H56V4.88002H53.76ZM49.28 7.12002V4.88002H53.76V7.12002H49.28ZM47.04 11.6V7.12002H49.28V11.6H47.04ZM53.76 11.6V7.12002H56V11.6H53.76Z" fill="#110F1F"/>
|
||||
</svg>"""
|
||||
|
||||
dark_mode_logo = """<svg width="56" height="12" viewBox="0 0 56 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M0 11.5999V0.399902H8.96V4.8799H6.72V2.6399H2.24V4.8799H6.72V7.1199H2.24V11.5999H0ZM6.72 11.5999V7.1199H8.96V11.5999H6.72Z" fill="white"/>
|
||||
<path d="M11.2 11.5999V0.399902H17.92V2.6399H13.44V4.8799H17.92V7.1199H13.44V9.3599H17.92V11.5999H11.2Z" fill="white"/>
|
||||
<path d="M20.16 11.5999V0.399902H26.88V2.6399H22.4V4.8799H26.88V7.1199H22.4V11.5999H20.16Z" fill="white"/>
|
||||
<path d="M29.12 11.5999V0.399902H31.36V9.3599H35.84V11.5999H29.12Z" fill="white"/>
|
||||
<path d="M38.08 11.5999V0.399902H44.8V2.6399H40.32V4.8799H44.8V7.1199H40.32V9.3599H44.8V11.5999H38.08Z" fill="white"/>
|
||||
<path d="M47.04 4.8799V0.399902H49.28V4.8799H47.04ZM53.76 4.8799V0.399902H56V4.8799H53.76ZM49.28 7.1199V4.8799H53.76V7.1199H49.28ZM47.04 11.5999V7.1199H49.28V11.5999H47.04ZM53.76 11.5999V7.1199H56V11.5999H53.76Z" fill="white"/>
|
||||
</svg>"""
|
||||
def logo_path(d):
|
||||
return rx.el.svg.path(
|
||||
d=d,
|
||||
fill=rx.color_mode_cond("#110F1F", "white"),
|
||||
)
|
||||
|
||||
paths = [
|
||||
"M0 11.5999V0.399902H8.96V4.8799H6.72V2.6399H2.24V4.8799H6.72V7.1199H2.24V11.5999H0ZM6.72 11.5999V7.1199H8.96V11.5999H6.72Z",
|
||||
"M11.2 11.5999V0.399902H17.92V2.6399H13.44V4.8799H17.92V7.1199H13.44V9.3599H17.92V11.5999H11.2Z",
|
||||
"M20.16 11.5999V0.399902H26.88V2.6399H22.4V4.8799H26.88V7.1199H22.4V11.5999H20.16Z",
|
||||
"M29.12 11.5999V0.399902H31.36V9.3599H35.84V11.5999H29.12Z",
|
||||
"M38.08 11.5999V0.399902H44.8V2.6399H40.32V4.8799H44.8V7.1199H40.32V9.3599H44.8V11.5999H38.08Z",
|
||||
"M47.04 4.8799V0.399902H49.28V4.8799H47.04ZM53.76 4.8799V0.399902H56V4.8799H53.76ZM49.28 7.1199V4.8799H53.76V7.1199H49.28ZM47.04 11.5999V7.1199H49.28V11.5999H47.04ZM53.76 11.5999V7.1199H56V11.5999H53.76Z",
|
||||
]
|
||||
|
||||
return rx.center(
|
||||
rx.link(
|
||||
rx.hstack(
|
||||
"Built with ",
|
||||
rx.color_mode_cond(
|
||||
rx.html(light_mode_logo),
|
||||
rx.html(dark_mode_logo),
|
||||
rx.el.svg(
|
||||
*[logo_path(d) for d in paths],
|
||||
width="56",
|
||||
height="12",
|
||||
viewBox="0 0 56 12",
|
||||
fill="none",
|
||||
xmlns="http://www.w3.org/2000/svg",
|
||||
),
|
||||
text_align="center",
|
||||
align="center",
|
||||
|
846
reflex/components/datadisplay/shiki_code_block.py
Normal file
846
reflex/components/datadisplay/shiki_code_block.py
Normal file
@ -0,0 +1,846 @@
|
||||
"""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.props import NoExtrasAllowedProps
|
||||
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 button (parent element)
|
||||
const parent = event.target.closest('button');
|
||||
// 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 = '<polyline points="20 6 9 17 4 12"></polyline>'; // 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",
|
||||
"plain",
|
||||
"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",
|
||||
"plastic",
|
||||
"poimandres",
|
||||
"red",
|
||||
# rose-pine themes dont work with the current version of shikijs transformers
|
||||
# https://github.com/shikijs/shiki/issues/730
|
||||
"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 Position(NoExtrasAllowedProps):
|
||||
"""Position of the decoration."""
|
||||
|
||||
line: int
|
||||
character: int
|
||||
|
||||
|
||||
class ShikiDecorations(NoExtrasAllowedProps):
|
||||
"""Decorations for the code block."""
|
||||
|
||||
start: Union[int, Position]
|
||||
end: Union[int, Position]
|
||||
tag_name: str = "span"
|
||||
properties: dict[str, Any] = {}
|
||||
always_wrap: bool = False
|
||||
|
||||
|
||||
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(
|
||||
[]
|
||||
)
|
||||
|
||||
# The decorations to use for the syntax highlighter.
|
||||
decorations: Var[list[ShikiDecorations]] = 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 = {}
|
||||
decorations = props.pop("decorations", [])
|
||||
|
||||
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
|
||||
)
|
||||
|
||||
# cast decorations into ShikiDecorations.
|
||||
decorations = [
|
||||
ShikiDecorations(**decoration)
|
||||
if not isinstance(decoration, ShikiDecorations)
|
||||
else decoration
|
||||
for decoration in decorations
|
||||
]
|
||||
code_block_props["decorations"] = decorations
|
||||
|
||||
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: bool = False
|
||||
|
||||
# copy_button: A custom copy button to override the default one.
|
||||
copy_button: Optional[Union[Component, bool]] = 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()
|
2231
reflex/components/datadisplay/shiki_code_block.pyi
Normal file
2231
reflex/components/datadisplay/shiki_code_block.pyi
Normal file
File diff suppressed because it is too large
Load Diff
190
reflex/components/dynamic.py
Normal file
190
reflex/components/dynamic.py
Normal file
@ -0,0 +1,190 @@
|
||||
"""Components that are dynamically generated on the backend."""
|
||||
|
||||
from typing import TYPE_CHECKING, Union
|
||||
|
||||
from reflex import constants
|
||||
from reflex.utils import imports
|
||||
from reflex.utils.exceptions import DynamicComponentMissingLibrary
|
||||
from reflex.utils.format import format_library_name
|
||||
from reflex.utils.serializers import serializer
|
||||
from reflex.vars import Var, get_unique_variable_name
|
||||
from reflex.vars.base import VarData, transform
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from reflex.components.component import Component
|
||||
|
||||
|
||||
def get_cdn_url(lib: str) -> str:
|
||||
"""Get the CDN URL for a library.
|
||||
|
||||
Args:
|
||||
lib: The library to get the CDN URL for.
|
||||
|
||||
Returns:
|
||||
The CDN URL for the library.
|
||||
"""
|
||||
return f"https://cdn.jsdelivr.net/npm/{lib}" + "/+esm"
|
||||
|
||||
|
||||
bundled_libraries = {"react", "@radix-ui/themes", "@emotion/react", "next/link"}
|
||||
|
||||
|
||||
def bundle_library(component: Union["Component", str]):
|
||||
"""Bundle a library with the component.
|
||||
|
||||
Args:
|
||||
component: The component to bundle the library with.
|
||||
|
||||
Raises:
|
||||
DynamicComponentMissingLibrary: Raised when a dynamic component is missing a library.
|
||||
"""
|
||||
if isinstance(component, str):
|
||||
bundled_libraries.add(component)
|
||||
return
|
||||
if component.library is None:
|
||||
raise DynamicComponentMissingLibrary("Component must have a library to bundle.")
|
||||
bundled_libraries.add(format_library_name(component.library))
|
||||
|
||||
|
||||
def load_dynamic_serializer():
|
||||
"""Load the serializer for dynamic components."""
|
||||
# Causes a circular import, so we import here.
|
||||
from reflex.components.component import Component
|
||||
|
||||
@serializer
|
||||
def make_component(component: Component) -> str:
|
||||
"""Generate the code for a dynamic component.
|
||||
|
||||
Args:
|
||||
component: The component to generate code for.
|
||||
|
||||
Returns:
|
||||
The generated code
|
||||
"""
|
||||
# Causes a circular import, so we import here.
|
||||
from reflex.compiler import templates, utils
|
||||
from reflex.components.base.bare import Bare
|
||||
|
||||
component = Bare.create(Var.create(component))
|
||||
|
||||
rendered_components = {}
|
||||
# Include dynamic imports in the shared component.
|
||||
if dynamic_imports := component._get_all_dynamic_imports():
|
||||
rendered_components.update(
|
||||
{dynamic_import: None for dynamic_import in dynamic_imports}
|
||||
)
|
||||
|
||||
# Include custom code in the shared component.
|
||||
rendered_components.update(
|
||||
{code: None for code in component._get_all_custom_code()},
|
||||
)
|
||||
|
||||
rendered_components[
|
||||
templates.STATEFUL_COMPONENT.render(
|
||||
tag_name="MySSRComponent",
|
||||
memo_trigger_hooks=[],
|
||||
component=component,
|
||||
)
|
||||
] = None
|
||||
|
||||
libs_in_window = bundled_libraries
|
||||
|
||||
imports = {}
|
||||
for lib, names in component._get_all_imports().items():
|
||||
formatted_lib_name = format_library_name(lib)
|
||||
if (
|
||||
not lib.startswith((".", "/", "$/"))
|
||||
and not lib.startswith("http")
|
||||
and formatted_lib_name not in libs_in_window
|
||||
):
|
||||
imports[get_cdn_url(lib)] = names
|
||||
else:
|
||||
imports[lib] = names
|
||||
|
||||
module_code_lines = templates.STATEFUL_COMPONENTS.render(
|
||||
imports=utils.compile_imports(imports),
|
||||
memoized_code="\n".join(rendered_components),
|
||||
).splitlines()[1:]
|
||||
|
||||
# Rewrite imports from `/` to destructure from window
|
||||
for ix, line in enumerate(module_code_lines[:]):
|
||||
if line.startswith("import "):
|
||||
if 'from "$/' in line or 'from "/' in line:
|
||||
module_code_lines[ix] = (
|
||||
line.replace("import ", "const ", 1).replace(
|
||||
" from ", " = window['__reflex'][", 1
|
||||
)
|
||||
+ "]"
|
||||
)
|
||||
else:
|
||||
for lib in libs_in_window:
|
||||
if f'from "{lib}"' in line:
|
||||
module_code_lines[ix] = (
|
||||
line.replace("import ", "const ", 1)
|
||||
.replace(
|
||||
f' from "{lib}"', f" = window.__reflex['{lib}']", 1
|
||||
)
|
||||
.replace(" as ", ": ")
|
||||
)
|
||||
if line.startswith("export function"):
|
||||
module_code_lines[ix] = line.replace(
|
||||
"export function", "export default function", 1
|
||||
)
|
||||
line_stripped = line.strip()
|
||||
if line_stripped.startswith("{") and line_stripped.endswith("}"):
|
||||
module_code_lines[ix] = line_stripped[1:-1]
|
||||
|
||||
module_code_lines.insert(0, "const React = window.__reflex.react;")
|
||||
|
||||
return "\n".join(
|
||||
[
|
||||
"//__reflex_evaluate",
|
||||
*module_code_lines,
|
||||
]
|
||||
)
|
||||
|
||||
@transform
|
||||
def evaluate_component(js_string: Var[str]) -> Var[Component]:
|
||||
"""Evaluate a component.
|
||||
|
||||
Args:
|
||||
js_string: The JavaScript string to evaluate.
|
||||
|
||||
Returns:
|
||||
The evaluated JavaScript string.
|
||||
"""
|
||||
unique_var_name = get_unique_variable_name()
|
||||
|
||||
return js_string._replace(
|
||||
_js_expr=unique_var_name,
|
||||
_var_type=Component,
|
||||
merge_var_data=VarData.merge(
|
||||
VarData(
|
||||
imports={
|
||||
f"$/{constants.Dirs.STATE_PATH}": [
|
||||
imports.ImportVar(tag="evalReactComponent"),
|
||||
],
|
||||
"react": [
|
||||
imports.ImportVar(tag="useState"),
|
||||
imports.ImportVar(tag="useEffect"),
|
||||
],
|
||||
},
|
||||
hooks={
|
||||
f"const [{unique_var_name}, set_{unique_var_name}] = useState(null);": None,
|
||||
"useEffect(() => {"
|
||||
"let isMounted = true;"
|
||||
f"evalReactComponent({str(js_string)})"
|
||||
".then((component) => {"
|
||||
"if (isMounted) {"
|
||||
f"set_{unique_var_name}(component);"
|
||||
"}"
|
||||
"});"
|
||||
"return () => {"
|
||||
"isMounted = false;"
|
||||
"};"
|
||||
"}"
|
||||
f", [{str(js_string)}]);": None,
|
||||
},
|
||||
),
|
||||
),
|
||||
)
|
@ -3,6 +3,7 @@
|
||||
# This file was generated by `reflex/utils/pyi_generator.py`!
|
||||
# ------------------------------------------------------
|
||||
|
||||
from . import elements as elements
|
||||
from .elements.forms import Button as Button
|
||||
from .elements.forms import Fieldset as Fieldset
|
||||
from .elements.forms import Form as Form
|
||||
|
@ -3,12 +3,12 @@
|
||||
# ------------------- DO NOT EDIT ----------------------
|
||||
# This file was generated by `reflex/utils/pyi_generator.py`!
|
||||
# ------------------------------------------------------
|
||||
from typing import Any, Callable, Dict, Optional, Union, overload
|
||||
from typing import Any, Dict, Optional, Union, overload
|
||||
|
||||
from reflex.components.component import Component
|
||||
from reflex.event import EventHandler, EventSpec
|
||||
from reflex.ivars.base import ImmutableVar
|
||||
from reflex.event import EventType
|
||||
from reflex.style import Style
|
||||
from reflex.vars.base import Var
|
||||
|
||||
class Element(Component):
|
||||
@overload
|
||||
@ -21,52 +21,22 @@ class Element(Component):
|
||||
id: Optional[Any] = None,
|
||||
class_name: Optional[Any] = None,
|
||||
autofocus: Optional[bool] = None,
|
||||
custom_attrs: Optional[Dict[str, Union[ImmutableVar, str]]] = None,
|
||||
on_blur: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_context_menu: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_double_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_focus: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_down: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_enter: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_leave: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_move: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_out: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_over: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_up: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_scroll: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_unmount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = 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,
|
||||
) -> "Element":
|
||||
"""Create the component.
|
||||
|
@ -3,7 +3,7 @@
|
||||
from typing import Union
|
||||
|
||||
from reflex.components.el.element import Element
|
||||
from reflex.vars import Var as Var
|
||||
from reflex.vars.base import Var
|
||||
|
||||
|
||||
class BaseHTML(Element):
|
||||
|
@ -3,13 +3,12 @@
|
||||
# ------------------- DO NOT EDIT ----------------------
|
||||
# This file was generated by `reflex/utils/pyi_generator.py`!
|
||||
# ------------------------------------------------------
|
||||
from typing import Any, Callable, Dict, Optional, Union, overload
|
||||
from typing import Any, Dict, Optional, Union, overload
|
||||
|
||||
from reflex.components.el.element import Element
|
||||
from reflex.event import EventHandler, EventSpec
|
||||
from reflex.ivars.base import ImmutableVar
|
||||
from reflex.event import EventType
|
||||
from reflex.style import Style
|
||||
from reflex.vars import Var
|
||||
from reflex.vars.base import Var
|
||||
|
||||
class BaseHTML(Element):
|
||||
@overload
|
||||
@ -17,81 +16,51 @@ class BaseHTML(Element):
|
||||
def create( # type: ignore
|
||||
cls,
|
||||
*children,
|
||||
access_key: Optional[Union[Var[Union[bool, int, str]], str, int, bool]] = None,
|
||||
access_key: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
auto_capitalize: Optional[
|
||||
Union[Var[Union[bool, int, str]], str, int, bool]
|
||||
Union[Var[Union[bool, int, str]], bool, int, str]
|
||||
] = None,
|
||||
content_editable: Optional[
|
||||
Union[Var[Union[bool, int, str]], str, int, bool]
|
||||
Union[Var[Union[bool, int, str]], bool, int, str]
|
||||
] = None,
|
||||
context_menu: Optional[
|
||||
Union[Var[Union[bool, int, str]], str, int, bool]
|
||||
Union[Var[Union[bool, int, str]], bool, int, str]
|
||||
] = None,
|
||||
dir: Optional[Union[Var[Union[bool, int, str]], str, int, bool]] = None,
|
||||
draggable: Optional[Union[Var[Union[bool, int, str]], str, int, bool]] = None,
|
||||
dir: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
draggable: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
enter_key_hint: Optional[
|
||||
Union[Var[Union[bool, int, str]], str, int, bool]
|
||||
Union[Var[Union[bool, int, str]], bool, int, str]
|
||||
] = None,
|
||||
hidden: Optional[Union[Var[Union[bool, int, str]], str, int, bool]] = None,
|
||||
input_mode: Optional[Union[Var[Union[bool, int, str]], str, int, bool]] = None,
|
||||
item_prop: Optional[Union[Var[Union[bool, int, str]], str, int, bool]] = None,
|
||||
lang: Optional[Union[Var[Union[bool, int, str]], str, int, bool]] = None,
|
||||
role: Optional[Union[Var[Union[bool, int, str]], str, int, bool]] = None,
|
||||
slot: Optional[Union[Var[Union[bool, int, str]], str, int, bool]] = None,
|
||||
spell_check: Optional[Union[Var[Union[bool, int, str]], str, int, bool]] = None,
|
||||
tab_index: Optional[Union[Var[Union[bool, int, str]], str, int, bool]] = None,
|
||||
title: Optional[Union[Var[Union[bool, int, str]], str, int, bool]] = None,
|
||||
hidden: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
input_mode: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
item_prop: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
lang: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
role: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
slot: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
spell_check: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
tab_index: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = None,
|
||||
title: Optional[Union[Var[Union[bool, int, str]], bool, int, str]] = 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[ImmutableVar, str]]] = None,
|
||||
on_blur: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_context_menu: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_double_click: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_focus: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_down: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_enter: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_leave: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_move: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_out: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_over: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_mouse_up: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_scroll: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = None,
|
||||
on_unmount: Optional[
|
||||
Union[EventHandler, EventSpec, list, Callable, ImmutableVar]
|
||||
] = 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,
|
||||
) -> "BaseHTML":
|
||||
"""Create the component.
|
||||
|
@ -3,21 +3,27 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from hashlib import md5
|
||||
from typing import Any, Dict, Iterator, Set, Union
|
||||
from typing import Any, Dict, Iterator, Set, Tuple, Union
|
||||
|
||||
from jinja2 import Environment
|
||||
|
||||
from reflex.components.el.element import Element
|
||||
from reflex.components.tags.tag import Tag
|
||||
from reflex.constants import Dirs, EventTriggers
|
||||
from reflex.event import EventChain, EventHandler
|
||||
from reflex.ivars.base import ImmutableVar, LiteralVar
|
||||
from reflex.event import (
|
||||
EventChain,
|
||||
EventHandler,
|
||||
input_event,
|
||||
key_event,
|
||||
prevent_default,
|
||||
)
|
||||
from reflex.utils.imports import ImportDict
|
||||
from reflex.vars import Var, VarData
|
||||
from reflex.vars import VarData
|
||||
from reflex.vars.base import LiteralVar, Var
|
||||
|
||||
from .base import BaseHTML
|
||||
|
||||
FORM_DATA = ImmutableVar.create("form_data")
|
||||
FORM_DATA = Var(_js_expr="form_data")
|
||||
HANDLE_SUBMIT_JS_JINJA2 = Environment().from_string(
|
||||
"""
|
||||
const handleSubmit_{{ handle_submit_unique_name }} = useCallback((ev) => {
|
||||
@ -96,6 +102,24 @@ class Fieldset(Element):
|
||||
name: Var[Union[str, int, bool]]
|
||||
|
||||
|
||||
def on_submit_event_spec() -> Tuple[Var[Dict[str, Any]]]:
|
||||
"""Event handler spec for the on_submit event.
|
||||
|
||||
Returns:
|
||||
The event handler spec.
|
||||
"""
|
||||
return (FORM_DATA,)
|
||||
|
||||
|
||||
def on_submit_string_event_spec() -> Tuple[Var[Dict[str, str]]]:
|
||||
"""Event handler spec for the on_submit event.
|
||||
|
||||
Returns:
|
||||
The event handler spec.
|
||||
"""
|
||||
return (FORM_DATA,)
|
||||
|
||||
|
||||
class Form(BaseHTML):
|
||||
"""Display the form element."""
|
||||
|
||||
@ -135,7 +159,7 @@ class Form(BaseHTML):
|
||||
handle_submit_unique_name: Var[str]
|
||||
|
||||
# Fired when the form is submitted
|
||||
on_submit: EventHandler[lambda e0: [FORM_DATA]]
|
||||
on_submit: EventHandler[on_submit_event_spec, on_submit_string_event_spec]
|
||||
|
||||
@classmethod
|
||||
def create(cls, *children, **props):
|
||||
@ -148,6 +172,9 @@ class Form(BaseHTML):
|
||||
Returns:
|
||||
The form component.
|
||||
"""
|
||||
if "on_submit" not in props:
|
||||
props["on_submit"] = prevent_default
|
||||
|
||||
if "handle_submit_unique_name" in props:
|
||||
return super().create(*children, **props)
|
||||
|
||||
@ -169,7 +196,7 @@ class Form(BaseHTML):
|
||||
"""
|
||||
return {
|
||||
"react": "useCallback",
|
||||
f"/{Dirs.STATE_PATH}": ["getRefValue", "getRefValues"],
|
||||
f"$/{Dirs.STATE_PATH}": ["getRefValue", "getRefValues"],
|
||||
}
|
||||
|
||||
def add_hooks(self) -> list[str]:
|
||||
@ -197,8 +224,8 @@ class Form(BaseHTML):
|
||||
if EventTriggers.ON_SUBMIT in self.event_triggers:
|
||||
render_tag.add_props(
|
||||
**{
|
||||
EventTriggers.ON_SUBMIT: ImmutableVar(
|
||||
_var_name=f"handleSubmit_{self.handle_submit_unique_name}",
|
||||
EventTriggers.ON_SUBMIT: Var(
|
||||
_js_expr=f"handleSubmit_{self.handle_submit_unique_name}",
|
||||
_var_type=EventChain,
|
||||
)
|
||||
}
|
||||
@ -212,21 +239,21 @@ class Form(BaseHTML):
|
||||
# when ref start with refs_ it's an array of refs, so we need different method
|
||||
# to collect data
|
||||
if ref.startswith("refs_"):
|
||||
ref_var = ImmutableVar.create_safe(ref[:-3]).as_ref()
|
||||
form_refs[ref[len("refs_") : -3]] = ImmutableVar.create_safe(
|
||||
f"getRefValues({str(ref_var)})",
|
||||
ref_var = Var(_js_expr=ref[:-3]).as_ref()
|
||||
form_refs[ref[len("refs_") : -3]] = Var(
|
||||
_js_expr=f"getRefValues({str(ref_var)})",
|
||||
_var_data=VarData.merge(ref_var._get_all_var_data()),
|
||||
)
|
||||
else:
|
||||
ref_var = ImmutableVar.create_safe(ref).as_ref()
|
||||
form_refs[ref[4:]] = ImmutableVar.create_safe(
|
||||
f"getRefValue({str(ref_var)})",
|
||||
ref_var = Var(_js_expr=ref).as_ref()
|
||||
form_refs[ref[4:]] = Var(
|
||||
_js_expr=f"getRefValue({str(ref_var)})",
|
||||
_var_data=VarData.merge(ref_var._get_all_var_data()),
|
||||
)
|
||||
# print(repr(form_refs))
|
||||
return form_refs
|
||||
|
||||
def _get_vars(self, include_children: bool = True) -> Iterator[ImmutableVar]:
|
||||
def _get_vars(self, include_children: bool = True) -> Iterator[Var]:
|
||||
yield from super()._get_vars(include_children=include_children)
|
||||
yield from self._get_form_refs().values()
|
||||
|
||||
@ -342,19 +369,19 @@ class Input(BaseHTML):
|
||||
value: Var[Union[str, int, float]]
|
||||
|
||||
# Fired when the input value changes
|
||||
on_change: EventHandler[lambda e0: [e0.target.value]]
|
||||
on_change: EventHandler[input_event]
|
||||
|
||||
# Fired when the input gains focus
|
||||
on_focus: EventHandler[lambda e0: [e0.target.value]]
|
||||
on_focus: EventHandler[input_event]
|
||||
|
||||
# Fired when the input loses focus
|
||||
on_blur: EventHandler[lambda e0: [e0.target.value]]
|
||||
on_blur: EventHandler[input_event]
|
||||
|
||||
# Fired when a key is pressed down
|
||||
on_key_down: EventHandler[lambda e0: [e0.key]]
|
||||
on_key_down: EventHandler[key_event]
|
||||
|
||||
# Fired when a key is released
|
||||
on_key_up: EventHandler[lambda e0: [e0.key]]
|
||||
on_key_up: EventHandler[key_event]
|
||||
|
||||
|
||||
class Label(BaseHTML):
|
||||
@ -493,7 +520,7 @@ class Select(BaseHTML):
|
||||
size: Var[Union[str, int, bool]]
|
||||
|
||||
# Fired when the select value changes
|
||||
on_change: EventHandler[lambda e0: [e0.target.value]]
|
||||
on_change: EventHandler[input_event]
|
||||
|
||||
|
||||
AUTO_HEIGHT_JS = """
|
||||
@ -583,19 +610,55 @@ class Textarea(BaseHTML):
|
||||
wrap: Var[Union[str, int, bool]]
|
||||
|
||||
# Fired when the input value changes
|
||||
on_change: EventHandler[lambda e0: [e0.target.value]]
|
||||
on_change: EventHandler[input_event]
|
||||
|
||||
# Fired when the input gains focus
|
||||
on_focus: EventHandler[lambda e0: [e0.target.value]]
|
||||
on_focus: EventHandler[input_event]
|
||||
|
||||
# Fired when the input loses focus
|
||||
on_blur: EventHandler[lambda e0: [e0.target.value]]
|
||||
on_blur: EventHandler[input_event]
|
||||
|
||||
# Fired when a key is pressed down
|
||||
on_key_down: EventHandler[lambda e0: [e0.key]]
|
||||
on_key_down: EventHandler[key_event]
|
||||
|
||||
# Fired when a key is released
|
||||
on_key_up: EventHandler[lambda e0: [e0.key]]
|
||||
on_key_up: EventHandler[key_event]
|
||||
|
||||
@classmethod
|
||||
def create(cls, *children, **props):
|
||||
"""Create a textarea component.
|
||||
|
||||
Args:
|
||||
*children: The children of the textarea.
|
||||
**props: The properties of the textarea.
|
||||
|
||||
Returns:
|
||||
The textarea component.
|
||||
|
||||
Raises:
|
||||
ValueError: when `enter_key_submit` is combined with `on_key_down`.
|
||||
"""
|
||||
enter_key_submit = props.get("enter_key_submit")
|
||||
auto_height = props.get("auto_height")
|
||||
custom_attrs = props.setdefault("custom_attrs", {})
|
||||
|
||||
if enter_key_submit is not None:
|
||||
enter_key_submit = Var.create(enter_key_submit)
|
||||
if "on_key_down" in props:
|
||||
raise ValueError(
|
||||
"Cannot combine `enter_key_submit` with `on_key_down`.",
|
||||
)
|
||||
custom_attrs["on_key_down"] = Var(
|
||||
_js_expr=f"(e) => enterKeySubmitOnKeyDown(e, {str(enter_key_submit)})",
|
||||
_var_data=VarData.merge(enter_key_submit._get_all_var_data()),
|
||||
)
|
||||
if auto_height is not None:
|
||||
auto_height = Var.create(auto_height)
|
||||
custom_attrs["on_input"] = Var(
|
||||
_js_expr=f"(e) => autoHeightOnInput(e, {str(auto_height)})",
|
||||
_var_data=VarData.merge(auto_height._get_all_var_data()),
|
||||
)
|
||||
return super().create(*children, **props)
|
||||
|
||||
def _exclude_props(self) -> list[str]:
|
||||
return super()._exclude_props() + [
|
||||
@ -616,28 +679,6 @@ class Textarea(BaseHTML):
|
||||
custom_code.add(ENTER_KEY_SUBMIT_JS)
|
||||
return custom_code
|
||||
|
||||
def _render(self) -> Tag:
|
||||
tag = super()._render()
|
||||
if self.enter_key_submit is not None:
|
||||
if "on_key_down" in self.event_triggers:
|
||||
raise ValueError(
|
||||
"Cannot combine `enter_key_submit` with `on_key_down`.",
|
||||
)
|
||||
tag.add_props(
|
||||
on_key_down=ImmutableVar.create_safe(
|
||||
f"(e) => enterKeySubmitOnKeyDown(e, {str(self.enter_key_submit)})",
|
||||
_var_data=VarData.merge(self.enter_key_submit._get_all_var_data()),
|
||||
)
|
||||
)
|
||||
if self.auto_height is not None:
|
||||
tag.add_props(
|
||||
on_input=ImmutableVar.create_safe(
|
||||
f"(e) => autoHeightOnInput(e, {str(self.auto_height)})",
|
||||
_var_data=VarData.merge(self.auto_height._get_all_var_data()),
|
||||
)
|
||||
)
|
||||
return tag
|
||||
|
||||
|
||||
button = Button.create
|
||||
fieldset = Fieldset.create
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user