Decorator-based routing with view stacking for Flet applications
Project description
flet-stack
Component-based routing with automatic view stacking for Flet applications.
Features
- 🎯 Decorator-based routing - Clean, intuitive
@view()decorator for route definitions - 🔄 Observable state management - Built-in state management using
@ft.observabledataclasses - ⚡ Async support - Handle async data loading with automatic loading indicators
- 🎨 URL parameters - Extract parameters from routes like
/user/{id} - 🧩 Component-based architecture - Uses Flet's modern
@ft.componentpattern - 🚀 Simple setup - Just call
page.render_views(FletStack)in your app - 🔐 Custom initial routes - Start your app at any route
Requirements
- Python 3.9+
- Flet >= 0.70.0.dev6281
Installation
From PyPI
pip install flet-stack
From GitHub
pip install git+https://github.com/fasilwdr/flet-stack.git
Install Specific Version
pip install git+https://github.com/fasilwdr/flet-stack.git@v0.2.2
From Source
git clone https://github.com/fasilwdr/flet-stack.git
cd flet-stack
pip install .
Quick Start
import flet as ft
from flet_stack import view, FletStack
import asyncio
# Define your routes with the @view decorator
@view("/")
@ft.component
def home_view():
return [
ft.Text("Home Page", size=30),
ft.Button(
"Go to Profile",
on_click=lambda _: asyncio.create_task(
ft.context.page.push_route("/profile")
)
),
]
@view("/profile", appbar=ft.AppBar())
@ft.component
def profile_view():
return [
ft.Text("Profile Page", size=30),
]
# Run your app
ft.run(lambda page: page.render_views(FletStack))
That's it! The routing is automatically handled by FletStack.
Advanced Usage
URL Parameters
Extract parameters from your routes:
@view("/user/{user_id}")
@ft.component
def user_view(user_id):
return [
ft.Text(f"User Profile: {user_id}", size=30),
]
State Management
Use observable dataclasses to manage component state:
from dataclasses import dataclass
@ft.observable
@dataclass
class CounterState:
count: int = 0
def increment(self, e):
self.count += 1
def decrement(self, e):
self.count -= 1
@view("/counter", state_class=CounterState, appbar=ft.AppBar())
@ft.component
def counter_view(state):
return [
ft.Text(f"Count: {state.count}", size=30),
ft.Row([
ft.Button("Decrement", on_click=state.decrement),
ft.Button("Increment", on_click=state.increment),
]),
]
Async Data Loading
Load data asynchronously before showing your view:
@ft.observable
@dataclass
class UserState:
user_data: dict = None
async def load_user_data(state, user_id):
# Simulate API call
await asyncio.sleep(1)
state.user_data = {
"id": user_id,
"name": f"User {user_id}",
"email": f"user{user_id}@example.com"
}
@view("/user/{user_id}", state_class=UserState, on_load=load_user_data)
@ft.component
def user_detail_view(state, user_id):
return [
ft.Text(f"Name: {state.user_data['name']}", size=20),
ft.Text(f"Email: {state.user_data['email']}", size=16),
ft.Text(f"ID: {state.user_data['id']}", size=16),
]
While loading, a progress indicator is automatically displayed.
Sync Data Loading
You can also use synchronous loading functions:
def load_item_info(state, category, item_id, page):
"""Sync data loading with access to page object"""
state.info = {
"category": category.capitalize(),
"item_id": item_id,
"name": f"{category.capitalize()} Item #{item_id}",
"price": f"${int(item_id) * 10}.99"
}
@view(
"/category/{category}/item/{item_id}",
state_class=ItemState,
on_load=load_item_info
)
@ft.component
def item_view(state, category, item_id):
return [
ft.Text(f"{state.info['name']}", size=20),
ft.Text(f"Price: {state.info['price']}", size=18),
]
View Configuration
Pass additional Flet view properties:
@view(
"/settings",
appbar=ft.AppBar(title=ft.Text("Settings")),
bgcolor=ft.Colors.BLUE_GREY_50,
padding=20,
horizontal_alignment=ft.CrossAxisAlignment.CENTER,
vertical_alignment=ft.MainAxisAlignment.CENTER,
)
@ft.component
def settings_view():
return [ft.Text("Settings", size=30)]
Multiple URL Parameters
Handle routes with multiple parameters:
@view("/category/{category}/item/{item_id}")
@ft.component
def item_view(category, item_id):
return [
ft.Text(f"Category: {category}", size=20),
ft.Text(f"Item ID: {item_id}", size=20),
]
Setting Initial Route
You can start your app at any route instead of the default /:
def main(page: ft.Page):
page.title = "My App"
page.route = "/login" # Start at login page
page.render_views(FletStack)
ft.run(main)
API Reference
@view Decorator
@view(route: str, state_class: Type = None, on_load: Optional[Callable] = None, **view_kwargs)
- route: The route path for this view (e.g.,
/,/user/{user_id}) - state_class: Optional dataclass decorated with
@ft.observablefor state management - on_load: Optional function to call before rendering (can be async)
- Can accept parameters:
state,page, and any URL parameters
- Can accept parameters:
- view_kwargs: Additional kwargs passed to
ft.View(e.g.,appbar,bgcolor,padding)
FletStack Component
Main component that manages the routing stack and renders views.
# Option 1: Direct render
ft.run(lambda page: page.render_views(FletStack))
# Option 2: In main function
def main(page: ft.Page):
page.title = "My App"
page.route = "/login" # Optional: Set initial route
page.render_views(FletStack)
ft.run(main)
Navigation
Use asyncio.create_task with ft.context.page.push_route:
# Navigate to a route
asyncio.create_task(ft.context.page.push_route("/profile"))
# In button click handler
ft.Button(
"Go to Profile",
on_click=lambda _: asyncio.create_task(
ft.context.page.push_route("/profile")
)
)
Examples
Check the examples/ directory for more detailed examples:
basic_example.py- Simple routing and navigationadvanced_example.py- State management, async loading, and URL parameters
How It Works
flet-stack provides a FletStack component that:
- Registers all
@viewdecorated functions - Manages a navigation stack for route changes
- Handles state management with observable dataclasses
- Manages async/sync loading with automatic progress indicators
- Renders views with proper navigation support
- Supports custom initial routes via
page.route
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Acknowledgments
Built on top of the amazing Flet framework by Feodor Fitsner.
Support
If you encounter any issues or have questions:
- Open an issue on GitHub
- Check the examples directory
- Read the Flet documentation
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file flet_stack-0.2.2.tar.gz.
File metadata
- Download URL: flet_stack-0.2.2.tar.gz
- Upload date:
- Size: 10.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7656e8451c78c9035a39833ed22e92cfee920919b82732ac3307a3963001d832
|
|
| MD5 |
0edc2e5fa833c9e920811d0c3ab2b7eb
|
|
| BLAKE2b-256 |
a5fe4b114a70407851faa8d6347e21ea4f1adcd98aecc90eb1b43ccc6c786c50
|
File details
Details for the file flet_stack-0.2.2-py3-none-any.whl.
File metadata
- Download URL: flet_stack-0.2.2-py3-none-any.whl
- Upload date:
- Size: 8.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d648cd6c3e82bdfa02304ce9a62c7c00a44f717aff33530d0e2ff1078195845d
|
|
| MD5 |
e13682049055bac8c5db7ae2f50408c2
|
|
| BLAKE2b-256 |
07cf8c087edec6008e7e163c7dd0cd34076c19653b43a0c470810e8b839c2c1e
|