From 987038d922ad71af1e487a2356025f444209337d Mon Sep 17 00:00:00 2001
From: Suyash sahu <142486268+7uyash@users.noreply.github.com>
Date: Fri, 10 Oct 2025 12:27:04 +0530
Subject: [PATCH 1/2] feat(docs): overhaul FletX docs with progressive
Architecture guide, SVG diagrams, a11y captions, tips, and cross-links
---
docs/assets/diagrams/di.svg | 31 +++
docs/assets/diagrams/reactivity.svg | 32 +++
docs/assets/diagrams/routing.svg | 36 +++
docs/getting-started/architecture.md | 295 ++++++++++++++---------
docs/getting-started/routing.md | 10 +-
docs/getting-started/state-management.md | 10 +
6 files changed, 301 insertions(+), 113 deletions(-)
create mode 100644 docs/assets/diagrams/di.svg
create mode 100644 docs/assets/diagrams/reactivity.svg
create mode 100644 docs/assets/diagrams/routing.svg
diff --git a/docs/assets/diagrams/di.svg b/docs/assets/diagrams/di.svg
new file mode 100644
index 0000000..3cb69b0
--- /dev/null
+++ b/docs/assets/diagrams/di.svg
@@ -0,0 +1,31 @@
+
+
diff --git a/docs/assets/diagrams/reactivity.svg b/docs/assets/diagrams/reactivity.svg
new file mode 100644
index 0000000..ef180d4
--- /dev/null
+++ b/docs/assets/diagrams/reactivity.svg
@@ -0,0 +1,32 @@
+
+
diff --git a/docs/assets/diagrams/routing.svg b/docs/assets/diagrams/routing.svg
new file mode 100644
index 0000000..ba16436
--- /dev/null
+++ b/docs/assets/diagrams/routing.svg
@@ -0,0 +1,36 @@
+
+
diff --git a/docs/getting-started/architecture.md b/docs/getting-started/architecture.md
index f50f15d..3e4e5b5 100644
--- a/docs/getting-started/architecture.md
+++ b/docs/getting-started/architecture.md
@@ -1,163 +1,252 @@
-# ποΈ FletX Architecture
+# ποΈ FletX Architecture (Progressive Guide)
-FletX is built on a **modular and reactive architecture** designed to help developers structure Flet applications in a clean, maintainable, and scalable way. It is inspired by principles like separation of concerns and dependency injection.
+FletX is a **modular, reactive application layer** for [Flet](https://flet.dev). Think of it as the scaffolding that helps your UI, logic, and navigation work together cleanly.
+
+This guide builds up from the big picture to the details, with diagrams and tiny examples you can copy and adapt.
---
-## π Overview
+## πΊοΈ Big Picture
-FletX architecture revolves around three **core components**:
+Analogy: FletX is like a theater production.
-1. **Pages (`FletXPage`)** β declarative, reactive UI components.
-2. **Controllers (`FletXController`)** β business logic and state management.
-3. **Services (optional)** β reusable utilities for API calls, database access, etc.
+- The **Page** is the stage where the scene is rendered.
+- The **Controller** is the director that decides what happens next.
+- **Reactive state (Rx)** is the script prompts: when a line changes, actors (widgets) immediately react.
+- **Services** are backstage crews (API, storage, utilities).
+- The **Router** is the stage manager who swaps scenes.
----
+High-level flow:
+
+```text
+User action β Controller updates reactive state β Widgets re-render
+```
-### π Typical Flow
+
+
+ Reactivity flow: events update reactive state; bound widgets re-render automatically.
+
-A typical user interaction flows like this:
+Navigation flow:
-```plaintext
-User Action β Controller Logic β State Update β UI Re-render
+```text
+Route change β Page created β Controller available β build() renders UI
```
-When routing/navigation happens, it flows like this:
+
+
+ Routing flow: router matches URL, creates the page, attaches its controller, then renders.
+
-```plaintext
-Routing β Page Instantiation β Controller Injection β Build UI
-```
+!!! tip "How to read these diagrams"
+
+ - Boxes represent **components** (Page, Controller, Service, etc.).
+ - Arrows indicate **direction of flow** (events β state β UI).
+ - Bold labels are the **key step** in each stage.
+ - White diagram backgrounds ensure legibility in **dark mode**; use the ASCII diagrams alongside if you prefer text.
---
-## π§± Core Building Blocks
+## π§± Core Pieces (at a glance)
-### 1. FletXPage
+- Page (`FletXPage`): builds UI in `build()` and accesses its controller via `self.ctrl`.
+- Controller (`FletXController`): holds logic and reactive state (e.g., `RxInt`, `RxStr`).
+- Services (optional): reusable dependencies resolved via DI (dependency injection).
+- Router (`router_config`): maps paths to pages; supports dynamic params and guards.
-A **FletXPage** is a class that represents a visual page (screen) in your app. It inherits from `FletXPage` and defines a `build()` method that returns a reactive Flet UI.
+Simple data flow:
-#### Example:
+```text
+[Widget event] βββΆ [Controller method] βββΆ [Rx value changes] βββΆ [UI auto-updates]
+```
+
+---
+
+## β First Contact: 30βsecond example
```python
-class HomePage(FletXPage):
- ctrl = HomeController()
+import flet as ft
+from fletx.core import FletXPage, FletXController, RxInt
+
+class CounterController(FletXController):
+ def __init__(self):
+ self.count = RxInt(0)
+ super().__init__()
+
+class CounterPage(FletXPage):
+ ctrl = CounterController()
def build(self):
return ft.Column([
- ft.Text(lambda: str(self.ctrl.counter()), size=40),
- ft.ElevatedButton("Increment", on_click=lambda e: self.ctrl.counter.increment())
+ ft.Text(lambda: f"Count: {self.ctrl.count.value}", size=40),
+ ft.ElevatedButton("+1", on_click=lambda e: self.ctrl.count.increment())
])
```
+What to notice:
+
+- The `Text` uses a `lambda:` so it re-renders when `count` changes.
+- The button calls a controller method that mutates reactive state.
+
---
-### 2. FletXController
+## π Reactivity (how updates propagate)
+
+```text
+ increment()
+ β
+ βΌ
+ [RxInt.count] ββ change detected βββΆ widgets depending on it re-render
+```
+
+Key ideas:
-A **FletXController** handles **business logic**, manages **reactive state**, and is tied to a specific page. It uses observable values to trigger UI updates automatically.
+- Use `Rx*` types (`RxInt`, `RxStr`, `RxList`, `RxDict`, β¦) for observable state.
+- Bind widgets with `lambda:` or reactive decorators so they update automatically.
+- Keep computations inside the controller; keep the page mostly declarative.
-#### Example:
+Tiny example:
```python
-class HomeController(FletXController):
+from fletx.core import FletXController, RxStr
+
+class HelloController(FletXController):
def __init__(self):
- self.counter = RxInt(0)
+ self.name = RxStr("World")
super().__init__()
+
+ def set_name(self, value: str):
+ self.name.value = value.strip() or "World"
```
-`RxInt` is a reactive object provided by FletX. Updating it automatically refreshes all widgets that depend on it.
+```python
+import flet as ft
+from fletx.core import FletXPage
+
+class HelloPage(FletXPage):
+ ctrl = HelloController()
+
+ def build(self):
+ return ft.Column([
+ ft.Text(lambda: f"Hello, {self.ctrl.name.value}!"),
+ ft.TextField(on_change=lambda e: self.ctrl.set_name(e.control.value))
+ ])
+```
---
-## π Navigation & Routing
+## π§ Routing (moving between pages)
-FletX provides a centralized router configuration (`router_config`) for managing navigation across your app:
+Basic setup:
```python
-router_config.add_route("/", HomePage)
-router_config.add_route("/about", AboutPage)
+from fletx.app import FletXApp
+from fletx.navigation import router_config
-# Or register a list of routes
router_config.add_routes([
{"path": "/", "component": HomePage},
- {"path": "/settings", "component": SettingsPage}
+ {"path": "/user/:id", "component": UserPage},
])
+
+app = FletXApp(title="My App", initial_route="/")
+app.run()
```
-> You can define dynamic routes like:
+Access dynamic params inside a page:
```python
-router_config.add_route("/user/:id", UserPage)
-router_config.add_route("/user/*category", CategoryPage)
+class UserPage(FletXPage):
+ ctrl = UserController()
+
+ def build(self):
+ user_id = self.route_info.params["id"]
+ # render with user_id
```
-In your page:
+Diagram:
-```python
-def build(self):
- user_id = self.route_info.params["id"]
+```text
+URL change β match route β create Page β attach Controller β build() β UI
```
----
+Learn more: see `Getting Started β Routing System` and `Pages (views)`.
-## π§ Reactive State Management
+---
-FletX provides **reactive variables**: `RxInt`, `RxStr`, `RxList`, etc., which track their values and trigger UI updates when modified.
+## π§© Dependency Injection (Services and reuse)
-#### Example:
+Analogy: DI is a tool bench. Controllers donβt build the tools; they pick them up.
```python
-class CounterController(FletXController):
+class UserService:
+ def fetch_user(self, user_id: str) -> dict:
+ return {"id": user_id, "name": "Jane"}
+
+class UserController(FletXController):
def __init__(self):
- self.count = RxInt(0)
+ from fletx.core import FletX
+ self.user_service = FletX.find(UserService)
+ self.user = RxDict({})
super().__init__()
-class CounterPage(FletXPage):
- ctrl = CounterController()
+ def load_user(self, user_id: str):
+ self.user.value = self.user_service.fetch_user(user_id)
+```
- def build(self):
- return MyReactiveText(rx_text=self.ctrl.count, size=200, weight="bold"),
+DI flow:
+
+```text
+[Controller] ββasksβββΆ [DI container] ββreturnsβββΆ [Service instance]
```
-> `lambda:` makes the widget reactive β it will re-render automatically when the value changes.
+
+
+ Dependency Injection: controllers ask the container for services instead of constructing them.
+
----
+Learn more: see `Getting Started β Dependency Injection` and `Services`.
-## π§© Services (Optional)
+---
-**Services** are reusable, testable classes used for accessing APIs, databases, or any shared logic. They can be injected into controllers.
+## π£ EndβtoβEnd Mini Walkthrough
-#### Example:
+Goal: Tap a button on `CounterPage` to increment a number.
-```python
-class UserService:
- def fetch_user(self, user_id):
- return {"id": user_id, "name": "John Doe"}
-```
+1) Router maps `/` β `CounterPage`.
+2) `CounterPage` is created with `ctrl = CounterController()`.
+3) UI shows a `Text(lambda: ...)` bound to `ctrl.count`.
+4) Button calls `ctrl.count.increment()`.
+5) `RxInt` notifies dependents β `Text` re-renders with the new value.
-Used in a controller:
+---
-```python
-class UserController(FletXController):
- def __init__(self):
- self.user_service = FletX.find(UserService)
- self.user = RxDict({})
- super().__init__()
+## π§° Common Patterns
- def load_user(self, user_id):
- self.user.value = self.user_service.fetch_user(user_id)
-```
+- Keep pages thin; put logic in controllers.
+- Use services for I/O and reuse (API, storage, computation helpers).
+- Prefer small, focused controllers per page/feature.
+- Derive view state from a few reactive primitives to avoid duplication.
+- Use route params to load data in `on_init`/first build.
---
-## π§ͺ Minimal Architecture Example
+## β
Best Practices
+
+- Name reactive variables by intent (e.g., `isLoading`, `selectedUserId`).
+- Avoid mutating raw data in pages; call controller methods instead.
+- Keep `build()` pure; it should read state and declare UI, not perform side-effects.
+- Debounce or throttle controller methods that respond to rapid UI events.
+- Centralize navigation in controller methods for testability.
+- Guard your routes when needed (auth, permissions).
+
+---
-Hereβs a minimal FletX app putting all the pieces together:
+## π§ͺ Minimal App Template
```python
# main.py
from fletx.app import FletXApp
from fletx.navigation import router_config
-from .pages.counter import CounterPage
router_config.add_route("/", CounterPage)
@@ -167,47 +256,38 @@ app.run()
```python
# pages/counter.py
-from fletx.core import FletXPage
-from .controllers.counter import CounterController
-from .components.reactive_text import MyReactiveText
import flet as ft
+from fletx.core import FletXPage, FletXController, RxInt
+
+class CounterController(FletXController):
+ def __init__(self):
+ self.count = RxInt(0)
+ super().__init__()
class CounterPage(FletXPage):
ctrl = CounterController()
def build(self):
return ft.Column([
- MyReactiveText(rx_text=self.ctrl.count, size=40, weight="bold"),
- ft.ElevatedButton("Increment", on_click=lambda e: self.ctrl.count.increment())
+ ft.Text(lambda: f"{self.ctrl.count.value}", size=40),
+ ft.ElevatedButton("Increment", on_click=lambda e: self.ctrl.count.increment()),
])
```
-```python
-# components/reactive_text.py
-import flet as ft
-from fletx.decorators import simple_reactive
-
-@simple_reactive(bindings={'value': 'text'})
-class MyReactiveText(ft.Text):
+---
- def __init__(self, rx_text: RxStr, **kwargs):
- self.text: RxStr = rx_text
- super().__init__(**kwargs)
-```
+## π Where to go next
-```python
-# controllers/counter.py
-from fletx.core import FletXController, RxInt
-
-class CounterController(FletXController):
- def __init__(self):
- self.count = RxInt(0)
- super().__init__()
-```
+- Getting Started β `Pages (views)`
+- Getting Started β `Controllers`
+- Getting Started β `Routing System`
+- Getting Started β `State Management`
+- Getting Started β `Dependency Injection`
+- Sample project: `Getting Started β Sample Project`
---
-## β
Summary Table
+## π Reference Cheatsheet
| Component | Responsibility |
| ----------------- | ---------------------------------------- |
@@ -215,13 +295,4 @@ class CounterController(FletXController):
| `FletXController` | Holds business logic and reactive state |
| `Rx*` objects | Reactive state (trigger UI rebuilds) |
| `router_config` | Defines app navigation routes |
-| Services | Shared utilities for APIs, storage, etc. |
-
-
----
-
-## π§ Next Steps
-
-* Explore [reactive UI binding](ui/reactivity.md)
-* Learn about the [Architecture](architecture.md)
-* Dive into [dependency injection](guides/dependency-injection.md)
\ No newline at end of file
+| Services | Shared utilities for APIs, storage, etc. |
\ No newline at end of file
diff --git a/docs/getting-started/routing.md b/docs/getting-started/routing.md
index 44c0d6c..5f498e5 100644
--- a/docs/getting-started/routing.md
+++ b/docs/getting-started/routing.md
@@ -6,6 +6,14 @@ FletX also provides utility functions for programmatic navigation, such as `navi
---
+!!! tip "How to read routing diagrams"
+
+ - Boxes represent **router steps** or **components**.
+ - Arrows indicate **navigation flow** (URL β match β page β controller β UI).
+ - Prefer using the Architecture guideβs diagrams as a quick mental model.
+
+[β Back to Architecture](architecture.md)
+
## π§ Basic Routing
Use the global `router_config` to define your app's navigation structure:
@@ -268,5 +276,5 @@ go_back()
## π§ Next Steps
* Dive into [dependency injection](dependency-injection.md)
-* Explore the [sevices](services.md)
+* Explore the [services](services.md)
* Learn about the [Architecture](architecture.md)
\ No newline at end of file
diff --git a/docs/getting-started/state-management.md b/docs/getting-started/state-management.md
index e121965..cb4ee6c 100644
--- a/docs/getting-started/state-management.md
+++ b/docs/getting-started/state-management.md
@@ -4,6 +4,16 @@
---
+!!! tip "How to read reactivity diagrams"
+
+ - Boxes are **state holders** (Rx) or **consumers** (widgets/controllers).
+
+ - Arrows show **state change propagation**.
+
+ - Use the Architecture guideβs reactivity figure as a companion visual.
+
+[β Back to Architecture](architecture.md)
+
### π Why reactivity matters
In most frameworks, when a value changes (e.g. a user logs in), you need to manually update the UI, synchronize the state, or refresh components.
From 1aa4c87505d0a62da25d5150ba555101d285ebef Mon Sep 17 00:00:00 2001
From: Suyash sahu <142486268+7uyash@users.noreply.github.com>
Date: Sat, 11 Oct 2025 00:45:54 +0530
Subject: [PATCH 2/2] UI updates using the @obx
---
docs/assets/diagrams/di.svg | 1 +
docs/assets/diagrams/reactivity.svg | 1 +
docs/assets/diagrams/routing.svg | 1 +
docs/getting-started/architecture.md | 36 +++++++++++++++++++++-------
4 files changed, 31 insertions(+), 8 deletions(-)
diff --git a/docs/assets/diagrams/di.svg b/docs/assets/diagrams/di.svg
index 3cb69b0..c3349cb 100644
--- a/docs/assets/diagrams/di.svg
+++ b/docs/assets/diagrams/di.svg
@@ -29,3 +29,4 @@
+
diff --git a/docs/assets/diagrams/reactivity.svg b/docs/assets/diagrams/reactivity.svg
index ef180d4..f1800b3 100644
--- a/docs/assets/diagrams/reactivity.svg
+++ b/docs/assets/diagrams/reactivity.svg
@@ -30,3 +30,4 @@
+
diff --git a/docs/assets/diagrams/routing.svg b/docs/assets/diagrams/routing.svg
index ba16436..862e519 100644
--- a/docs/assets/diagrams/routing.svg
+++ b/docs/assets/diagrams/routing.svg
@@ -34,3 +34,4 @@
+
diff --git a/docs/getting-started/architecture.md b/docs/getting-started/architecture.md
index 3e4e5b5..1f806e9 100644
--- a/docs/getting-started/architecture.md
+++ b/docs/getting-started/architecture.md
@@ -49,7 +49,7 @@ Route change β Page created β Controller available β build() renders UI
## π§± Core Pieces (at a glance)
-- Page (`FletXPage`): builds UI in `build()` and accesses its controller via `self.ctrl`.
+- Page (`FletXPage`): builds UI in `build()` and accesses its controller via `self.ctrl` (or any variable name you choose).
- Controller (`FletXController`): holds logic and reactive state (e.g., `RxInt`, `RxStr`).
- Services (optional): reusable dependencies resolved via DI (dependency injection).
- Router (`router_config`): maps paths to pages; supports dynamic params and guards.
@@ -67,6 +67,7 @@ Simple data flow:
```python
import flet as ft
from fletx.core import FletXPage, FletXController, RxInt
+from fletx.decorators import obx
class CounterController(FletXController):
def __init__(self):
@@ -74,19 +75,24 @@ class CounterController(FletXController):
super().__init__()
class CounterPage(FletXPage):
- ctrl = CounterController()
+ ctrl = CounterController() # 'ctrl' is a convention; you can name it anything
+
+ @obx
+ def counter_text(self):
+ return ft.Text(f"Count: {self.ctrl.count.value}", size=40)
def build(self):
return ft.Column([
- ft.Text(lambda: f"Count: {self.ctrl.count.value}", size=40),
+ self.counter_text(),
ft.ElevatedButton("+1", on_click=lambda e: self.ctrl.count.increment())
])
```
What to notice:
-- The `Text` uses a `lambda:` so it re-renders when `count` changes.
+- The `@obx` decorator makes the method reactive β it re-renders when `count` changes.
- The button calls a controller method that mutates reactive state.
+- `ctrl` is just a variable name; you can use any name you prefer.
---
@@ -102,7 +108,7 @@ What to notice:
Key ideas:
- Use `Rx*` types (`RxInt`, `RxStr`, `RxList`, `RxDict`, β¦) for observable state.
-- Bind widgets with `lambda:` or reactive decorators so they update automatically.
+- Use `@obx` decorator or reactive decorators so widgets update automatically.
- Keep computations inside the controller; keep the page mostly declarative.
Tiny example:
@@ -122,13 +128,18 @@ class HelloController(FletXController):
```python
import flet as ft
from fletx.core import FletXPage
+from fletx.decorators import obx
class HelloPage(FletXPage):
ctrl = HelloController()
+ @obx
+ def greeting(self):
+ return ft.Text(f"Hello, {self.ctrl.name.value}!")
+
def build(self):
return ft.Column([
- ft.Text(lambda: f"Hello, {self.ctrl.name.value}!"),
+ self.greeting(),
ft.TextField(on_change=lambda e: self.ctrl.set_name(e.control.value))
])
```
@@ -182,9 +193,12 @@ class UserService:
def fetch_user(self, user_id: str) -> dict:
return {"id": user_id, "name": "Jane"}
+# Register the service with DI container (typically in main.py or app setup)
+from fletx.core import FletX
+FletX.put(UserService) # Register as singleton
+
class UserController(FletXController):
def __init__(self):
- from fletx.core import FletX
self.user_service = FletX.find(UserService)
self.user = RxDict({})
super().__init__()
@@ -258,6 +272,7 @@ app.run()
# pages/counter.py
import flet as ft
from fletx.core import FletXPage, FletXController, RxInt
+from fletx.decorators import obx
class CounterController(FletXController):
def __init__(self):
@@ -267,9 +282,13 @@ class CounterController(FletXController):
class CounterPage(FletXPage):
ctrl = CounterController()
+ @obx
+ def count_display(self):
+ return ft.Text(f"{self.ctrl.count.value}", size=40)
+
def build(self):
return ft.Column([
- ft.Text(lambda: f"{self.ctrl.count.value}", size=40),
+ self.count_display(),
ft.ElevatedButton("Increment", on_click=lambda e: self.ctrl.count.increment()),
])
```
@@ -284,6 +303,7 @@ class CounterPage(FletXPage):
- Getting Started β `State Management`
- Getting Started β `Dependency Injection`
- Sample project: `Getting Started β Sample Project`
+- Real-world example: [Fake Shop E-commerce App](https://github.com/AllDotPy/fake-shop)
---