| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent a529834 commit 3bd87de
32 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -100,10 +100,14 @@ Recommended scopes (choose the smallest, most accurate unit; prefer module/direc | |||
| 100 | 100 | - `cli` – CLI tool and `pn` command (`src/pythonnative/cli/`) | |
| 101 | 101 | - `components` – declarative element-creating functions (`components.py`) | |
| 102 | 102 | - `element` – Element descriptor class (`element.py`) | |
| 103 | + - `hooks` – function components and hooks (`hooks.py`) | ||
| 104 | + - `hot_reload` – file watcher and module reloader (`hot_reload.py`) | ||
| 105 | + - `native_modules` – native API modules for device capabilities (`native_modules/`) | ||
| 103 | 106 | - `native_views` – platform-specific native view creation and updates (`native_views.py`) | |
| 104 | 107 | - `package` – `src/pythonnative/__init__.py` exports and package boundary | |
| 105 | 108 | - `page` – Page component, lifecycle, and reactive state (`page.py`) | |
| 106 | 109 | - `reconciler` – virtual view tree diffing and reconciliation (`reconciler.py`) | |
| 110 | + - `style` – StyleSheet and theming (`style.py`) | ||
| 107 | 111 | - `utils` – shared utilities (`utils.py`) | |
| 108 | 112 | ||
| 109 | 113 | - Other scopes: | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -2,6 +2,19 @@ | |||
| 2 | 2 | ||
| 3 | 3 | All style and behaviour properties are passed as keyword arguments to element functions. | |
| 4 | 4 | ||
| 5 | + ## Common layout properties | ||
| 6 | + | ||
| 7 | + All components accept these layout properties: | ||
| 8 | + | ||
| 9 | + - `width` — fixed width in dp (Android) / pt (iOS) | ||
| 10 | + - `height` — fixed height | ||
| 11 | + - `flex` — flex grow factor within Column/Row | ||
| 12 | + - `margin` — outer spacing (int, float, or dict with `horizontal`, `vertical`, `left`, `top`, `right`, `bottom`) | ||
| 13 | + - `min_width`, `max_width` — width constraints | ||
| 14 | + - `min_height`, `max_height` — height constraints | ||
| 15 | + - `align_self` — override parent alignment (`"fill"`, `"center"`, etc.) | ||
| 16 | + - `key` — stable identity for reconciliation | ||
| 17 | + | ||
| 5 | 18 | ## Text | |
| 6 | 19 | ||
| 7 | 20 | ```python | |
@@ -42,6 +55,22 @@ pn.Row(*children, spacing=0, padding=None, alignment=None, background_color=None | |||
| 42 | 55 | - `alignment` — cross-axis: `"fill"`, `"center"`, `"leading"`, `"trailing"`, `"start"`, `"end"`, `"top"`, `"bottom"` | |
| 43 | 56 | - `background_color` — container background | |
| 44 | 57 | ||
| 58 | + ## View | ||
| 59 | + | ||
| 60 | + ```python | ||
| 61 | + pn.View(*children, background_color=None, padding=None) | ||
| 62 | + ``` | ||
| 63 | + | ||
| 64 | + Generic container (UIView / FrameLayout). Supports all layout properties. | ||
| 65 | + | ||
| 66 | + ## SafeAreaView | ||
| 67 | + | ||
| 68 | + ```python | ||
| 69 | + pn.SafeAreaView(*children, background_color=None, padding=None) | ||
| 70 | + ``` | ||
| 71 | + | ||
| 72 | + Container that respects safe area insets (notch, status bar). | ||
| 73 | + | ||
| 45 | 74 | ## ScrollView | |
| 46 | 75 | ||
| 47 | 76 | ```python | |
@@ -63,6 +92,9 @@ pn.TextInput(value="", placeholder="", on_change=None, secure=False, | |||
| 63 | 92 | pn.Image(source="", width=None, height=None, scale_type=None, background_color=None) | |
| 64 | 93 | ``` | |
| 65 | 94 | ||
| 95 | + - `source` — image URL (`http://...` / `https://...`) or local resource name | ||
| 96 | + - `scale_type` — `"cover"`, `"contain"`, `"stretch"`, `"center"` | ||
| 97 | + | ||
| 66 | 98 | ## Switch | |
| 67 | 99 | ||
| 68 | 100 | ```python | |
@@ -71,6 +103,14 @@ pn.Switch(value=False, on_change=None) | |||
| 71 | 103 | ||
| 72 | 104 | - `on_change` — callback `(bool) -> None` | |
| 73 | 105 | ||
| 106 | + ## Slider | ||
| 107 | + | ||
| 108 | + ```python | ||
| 109 | + pn.Slider(value=0.0, min_value=0.0, max_value=1.0, on_change=None) | ||
| 110 | + ``` | ||
| 111 | + | ||
| 112 | + - `on_change` — callback `(float) -> None` | ||
| 113 | + | ||
| 74 | 114 | ## ProgressBar | |
| 75 | 115 | ||
| 76 | 116 | ```python | |
@@ -94,7 +134,36 @@ pn.WebView(url="") | |||
| 94 | 134 | ## Spacer | |
| 95 | 135 | ||
| 96 | 136 | ```python | |
| 97 | - pn.Spacer(size=None) | ||
| 137 | + pn.Spacer(size=None, flex=None) | ||
| 98 | 138 | ``` | |
| 99 | 139 | ||
| 100 | 140 | - `size` — fixed dimension in dp / pt | |
| 141 | + - `flex` — flex grow factor | ||
| 142 | + | ||
| 143 | + ## Pressable | ||
| 144 | + | ||
| 145 | + ```python | ||
| 146 | + pn.Pressable(child, on_press=None, on_long_press=None) | ||
| 147 | + ``` | ||
| 148 | + | ||
| 149 | + Wraps any child element with tap/long-press handling. | ||
| 150 | + | ||
| 151 | + ## Modal | ||
| 152 | + | ||
| 153 | + ```python | ||
| 154 | + pn.Modal(*children, visible=False, on_dismiss=None, title=None, background_color=None) | ||
| 155 | + ``` | ||
| 156 | + | ||
| 157 | + Overlay dialog shown when `visible=True`. | ||
| 158 | + | ||
| 159 | + ## FlatList | ||
| 160 | + | ||
| 161 | + ```python | ||
| 162 | + pn.FlatList(data=None, render_item=None, key_extractor=None, | ||
| 163 | + separator_height=0, background_color=None) | ||
| 164 | + ``` | ||
| 165 | + | ||
| 166 | + - `data` — list of items | ||
| 167 | + - `render_item` — `(item, index) -> Element` function | ||
| 168 | + - `key_extractor` — `(item, index) -> str` for stable keys | ||
| 169 | + - `separator_height` — spacing between items | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -9,24 +9,56 @@ | |||
| 9 | 9 | ### Element functions | |
| 10 | 10 | ||
| 11 | 11 | - `pythonnative.Text`, `Button`, `Column`, `Row`, `ScrollView`, `TextInput`, `Image`, `Switch`, `ProgressBar`, `ActivityIndicator`, `WebView`, `Spacer` | |
| 12 | + - `pythonnative.View`, `SafeAreaView`, `Modal`, `Slider`, `Pressable`, `FlatList` | ||
| 12 | 13 | ||
| 13 | 14 | Each returns an `Element` descriptor. See the Component Property Reference for full signatures. | |
| 14 | 15 | ||
| 15 | 16 | ### Element | |
| 16 | 17 | ||
| 17 | 18 | `pythonnative.Element` — the descriptor type returned by element functions. You generally don't create these directly. | |
| 18 | 19 | ||
| 20 | + ### Hooks | ||
| 21 | + | ||
| 22 | + Function component primitives: | ||
| 23 | + | ||
| 24 | + - `pythonnative.component` — decorator to create a function component | ||
| 25 | + - `pythonnative.use_state(initial)` — local component state | ||
| 26 | + - `pythonnative.use_effect(effect, deps)` — side effects | ||
| 27 | + - `pythonnative.use_memo(factory, deps)` — memoised values | ||
| 28 | + - `pythonnative.use_callback(fn, deps)` — stable function references | ||
| 29 | + - `pythonnative.use_ref(initial)` — mutable ref object | ||
| 30 | + - `pythonnative.use_context(context)` — read from context | ||
| 31 | + - `pythonnative.create_context(default)` — create a new context | ||
| 32 | + - `pythonnative.Provider(context, value, child)` — provide a context value | ||
| 33 | + | ||
| 34 | + ### Styling | ||
| 35 | + | ||
| 36 | + - `pythonnative.StyleSheet` — utility for creating and composing style dicts | ||
| 37 | + - `pythonnative.ThemeContext` — built-in theme context (defaults to light theme) | ||
| 38 | + | ||
| 39 | + ## Native API modules | ||
| 40 | + | ||
| 41 | + - `pythonnative.native_modules.Camera` — photo capture and gallery picking | ||
| 42 | + - `pythonnative.native_modules.Location` — GPS / location services | ||
| 43 | + - `pythonnative.native_modules.FileSystem` — app-scoped file I/O | ||
| 44 | + - `pythonnative.native_modules.Notifications` — local push notifications | ||
| 45 | + | ||
| 19 | 46 | ## Internal helpers | |
| 20 | 47 | ||
| 21 | 48 | - `pythonnative.utils.IS_ANDROID` — platform flag with robust detection for Chaquopy/Android. | |
| 22 | 49 | - `pythonnative.utils.get_android_context()` — returns the current Android `Activity`/`Context` when running on Android. | |
| 23 | 50 | - `pythonnative.utils.set_android_context(ctx)` — set by `Page` on Android; you generally don't call this directly. | |
| 24 | 51 | - `pythonnative.utils.get_android_fragment_container()` — returns the current Fragment container `ViewGroup` used for page rendering. | |
| 25 | - - `pythonnative.utils.set_android_fragment_container(viewGroup)` — set by the host `PageFragment`; you generally don't call this directly. | ||
| 26 | 52 | ||
| 27 | 53 | ## Reconciler | |
| 28 | 54 | ||
| 29 | - `pythonnative.reconciler.Reconciler` — diffs element trees and applies minimal native mutations. Used internally by `Page`. | ||
| 55 | + `pythonnative.reconciler.Reconciler` — diffs element trees and applies minimal native mutations. Supports key-based child reconciliation, function components, and context providers. Used internally by `Page`. | ||
| 56 | + | ||
| 57 | + ## Hot reload | ||
| 58 | + | ||
| 59 | + `pythonnative.hot_reload.FileWatcher` — watches a directory for file changes and triggers a callback. Used by `pn run --hot-reload`. | ||
| 60 | + | ||
| 61 | + `pythonnative.hot_reload.ModuleReloader` — reloads changed Python modules on the device and triggers page re-rendering. | ||
| 30 | 62 | ||
| 31 | 63 | ## Native view registry | |
| 32 | 64 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -5,27 +5,58 @@ PythonNative combines **direct native bindings** with a **declarative reconciler | |||
| 5 | 5 | ## High-level model | |
| 6 | 6 | ||
| 7 | 7 | 1. **Declarative element tree:** Your `Page.render()` method returns a tree of `Element` descriptors (similar to React elements / virtual DOM nodes). | |
| 8 | - 2. **Reconciler:** On first render, the reconciler walks the tree and creates real native views via the platform backend. On subsequent renders (triggered by `set_state`), it diffs the new tree against the old one and applies the minimal set of native mutations. | ||
| 9 | - 3. **Direct bindings:** Under the hood, native views are created and updated through direct platform calls: | ||
| 8 | + 2. **Function components and hooks:** Reusable components with independent state via `@pn.component`, `use_state`, `use_effect`, etc. — inspired by React hooks but designed for Python. | ||
| 9 | + 3. **Reconciler:** On first render, the reconciler walks the tree and creates real native views via the platform backend. On subsequent renders (triggered by `set_state` or hook state changes), it diffs the new tree against the old one and applies the minimal set of native mutations. | ||
| 10 | + 4. **Key-based reconciliation:** Children can be assigned stable `key` values to preserve identity across re-renders — critical for lists and dynamic content. | ||
| 11 | + 5. **Direct bindings:** Under the hood, native views are created and updated through direct platform calls: | ||
| 10 | 12 | - **iOS:** rubicon-objc exposes Objective-C/Swift classes (`UILabel`, `UIButton`, `UIStackView`, etc.). | |
| 11 | 13 | - **Android:** Chaquopy exposes Java classes (`android.widget.TextView`, `android.widget.Button`, etc.) via the JNI bridge. | |
| 12 | - 4. **Thin native bootstrap:** The host app remains native (Android `Activity` or iOS `UIViewController`). It passes a live instance/pointer into Python, and Python drives the UI through the reconciler. | ||
| 14 | + 6. **Thin native bootstrap:** The host app remains native (Android `Activity` or iOS `UIViewController`). It passes a live instance/pointer into Python, and Python drives the UI through the reconciler. | ||
| 13 | 15 | ||
| 14 | 16 | ## How it works | |
| 15 | 17 | ||
| 16 | 18 | ``` | |
| 17 | 19 | Page.render() → Element tree → Reconciler → Native views | |
| 18 | 20 | ↑ | |
| 19 | 21 | Page.set_state() → re-render → diff → patch native views | |
| 22 | + Hook set_state() → re-render → diff → patch native views | ||
| 20 | 23 | ``` | |
| 21 | 24 | ||
| 22 | - The reconciler uses **positional diffing** (comparing children by index). When a child at a given position has the same element type, its props are updated in-place on the native view. When the type changes, the old native view is destroyed and a new one is created. | ||
| 25 | + The reconciler uses **key-based diffing** (matching children by key first, then by position). When a child with the same key/type is found, its props are updated in-place on the native view. When the type changes, the old native view is destroyed and a new one is created. | ||
| 26 | + | ||
| 27 | + ## Component model | ||
| 28 | + | ||
| 29 | + PythonNative supports two kinds of components: | ||
| 30 | + | ||
| 31 | + ### Page classes (screens) | ||
| 32 | + | ||
| 33 | + Each screen is a `Page` subclass that bridges native lifecycle events to Python. Pages have `render()`, `set_state()`, navigation (`push`/`pop`), and lifecycle hooks (`on_create`, `on_resume`, etc.). | ||
| 34 | + | ||
| 35 | + ### Function components (reusable UI) | ||
| 36 | + | ||
| 37 | + Decorated with `@pn.component`, these are Python functions that return `Element` trees and can use hooks for state, effects, memoisation, and context. Each call site creates an independent instance with its own hook state. | ||
| 38 | + | ||
| 39 | + ```python | ||
| 40 | + @pn.component | ||
| 41 | + def counter(initial: int = 0) -> pn.Element: | ||
| 42 | + count, set_count = pn.use_state(initial) | ||
| 43 | + return pn.Text(f"Count: {count}") | ||
| 44 | + ``` | ||
| 45 | + | ||
| 46 | + ## Styling | ||
| 47 | + | ||
| 48 | + - **Inline styles:** Pass props directly to components (`font_size=24`, `color="#333"`). | ||
| 49 | + - **StyleSheet:** Create reusable named style dictionaries with `pn.StyleSheet.create(...)`. | ||
| 50 | + - **Theming:** Use `pn.ThemeContext` with `pn.Provider` and `pn.use_context` to propagate theme values through the tree. | ||
| 51 | + | ||
| 52 | + ## Layout | ||
| 53 | + | ||
| 54 | + All components support layout properties: `width`, `height`, `flex`, `margin`, `min_width`, `max_width`, `min_height`, `max_height`, `align_self`. Containers (`Column`, `Row`) support `spacing`, `padding`, and `alignment`. | ||
| 23 | 55 | ||
| 24 | 56 | ## Comparison | |
| 25 | 57 | ||
| 26 | 58 | - **Versus React Native:** RN uses JSX + a JavaScript bridge + Yoga layout. PythonNative uses Python + direct native calls + platform layout managers. No JS bridge, no serialisation overhead. | |
| 27 | - - **Versus NativeScript:** Similar philosophy (direct, synchronous native access), but PythonNative adds a declarative reconciler layer that NativeScript does not have by default. | ||
| 28 | - - **Versus the old imperative API:** The previous PythonNative API required manual `add_view()` calls and explicit setter methods. The new declarative model handles view lifecycle automatically. | ||
| 59 | + - **Versus NativeScript:** Similar philosophy (direct, synchronous native access), but PythonNative adds a declarative reconciler layer and React-like hooks that NativeScript does not have by default. | ||
| 29 | 60 | ||
| 30 | 61 | ## iOS flow (Rubicon-ObjC) | |
| 31 | 62 | ||
@@ -39,6 +70,19 @@ The reconciler uses **positional diffing** (comparing children by index). When a | |||
| 39 | 70 | - `PageFragment` calls `on_create()` on the Python `Page`, which renders and attaches views to the fragment container. | |
| 40 | 71 | - State changes trigger re-render; the reconciler patches Android views in-place. | |
| 41 | 72 | ||
| 73 | + ## Hot reload | ||
| 74 | + | ||
| 75 | + During development, `pn run --hot-reload` watches `app/` for file changes and pushes updated Python files to the running app, enabling near-instant UI updates without full rebuilds. | ||
| 76 | + | ||
| 77 | + ## Native API modules | ||
| 78 | + | ||
| 79 | + PythonNative provides cross-platform modules for common device APIs: | ||
| 80 | + | ||
| 81 | + - `pythonnative.native_modules.Camera` — photo capture and gallery | ||
| 82 | + - `pythonnative.native_modules.Location` — GPS / location services | ||
| 83 | + - `pythonnative.native_modules.FileSystem` — app-scoped file I/O | ||
| 84 | + - `pythonnative.native_modules.Notifications` — local push notifications | ||
| 85 | + | ||
| 42 | 86 | ## Navigation model overview | |
| 43 | 87 | ||
| 44 | 88 | - See the Navigation guide for full details. | |
| Back | FazBrowse Home | New Git URL |
0 commit comments