pythonnative 0.23.0__py3-none-any.whl → 0.24.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pythonnative/__init__.py +29 -50
- pythonnative/animated.py +1 -1
- pythonnative/cli/pn.py +3 -3
- pythonnative/components.py +250 -513
- pythonnative/diagnostics.py +214 -0
- pythonnative/element.py +5 -2
- pythonnative/events.py +13 -8
- pythonnative/hooks.py +413 -49
- pythonnative/hot_reload.py +9 -1
- pythonnative/native_views/android.py +78 -1
- pythonnative/native_views/desktop.py +38 -1
- pythonnative/native_views/ios.py +241 -7
- pythonnative/navigation.py +41 -17
- pythonnative/preview.py +43 -7
- pythonnative/reconciler.py +863 -441
- pythonnative/screen.py +324 -27
- pythonnative/storage.py +3 -3
- pythonnative/style.py +83 -0
- pythonnative/templates/android_template/app/src/main/java/com/pythonnative/android_template/ScreenFragment.kt +22 -0
- {pythonnative-0.23.0.dist-info → pythonnative-0.24.0.dist-info}/METADATA +5 -4
- {pythonnative-0.23.0.dist-info → pythonnative-0.24.0.dist-info}/RECORD +25 -24
- {pythonnative-0.23.0.dist-info → pythonnative-0.24.0.dist-info}/WHEEL +0 -0
- {pythonnative-0.23.0.dist-info → pythonnative-0.24.0.dist-info}/entry_points.txt +0 -0
- {pythonnative-0.23.0.dist-info → pythonnative-0.24.0.dist-info}/licenses/LICENSE +0 -0
- {pythonnative-0.23.0.dist-info → pythonnative-0.24.0.dist-info}/top_level.txt +0 -0
pythonnative/components.py
CHANGED
|
@@ -1,16 +1,12 @@
|
|
|
1
|
-
"""Built-in element factories
|
|
1
|
+
"""Built-in element factories.
|
|
2
2
|
|
|
3
|
-
Each
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
The same Props dataclasses are used by the `pythonnative.sdk` surface
|
|
12
|
-
for third-party components, so the built-in API and the extension API
|
|
13
|
-
speak the same shape.
|
|
3
|
+
Each factory function (``Text``, ``Button``, …) is a fully-typed thin
|
|
4
|
+
wrapper that builds an [`Element`][pythonnative.Element] through the
|
|
5
|
+
shared :func:`_make_element` helper, so style resolution, ``ref``
|
|
6
|
+
attachment, ``None``-default dropping, and forced overrides (e.g.
|
|
7
|
+
``Column``'s fixed ``flex_direction``) live in exactly one place. The
|
|
8
|
+
factory signatures themselves are the canonical prop schemas: editors
|
|
9
|
+
and type checkers validate calls directly against them.
|
|
14
10
|
|
|
15
11
|
Example:
|
|
16
12
|
```python
|
|
@@ -18,27 +14,27 @@ Example:
|
|
|
18
14
|
|
|
19
15
|
pn.Column(
|
|
20
16
|
pn.Text("Hello", style=pn.style(font_size=18)),
|
|
21
|
-
pn.Button("Tap",
|
|
17
|
+
pn.Button("Tap", on_press=lambda: print("tapped")),
|
|
22
18
|
style=pn.style(spacing=12, padding=16),
|
|
23
19
|
)
|
|
24
20
|
```
|
|
25
21
|
"""
|
|
26
22
|
|
|
27
23
|
import bisect
|
|
28
|
-
from dataclasses import dataclass, field
|
|
29
24
|
from typing import Any, Callable, Dict, List, Literal, Optional, Tuple, Union
|
|
30
25
|
|
|
31
26
|
from .element import Element
|
|
32
27
|
from .hooks import (
|
|
28
|
+
Ref,
|
|
33
29
|
component,
|
|
34
|
-
|
|
30
|
+
use_imperative_handle,
|
|
35
31
|
use_keyboard_height,
|
|
36
32
|
use_ref,
|
|
37
33
|
use_safe_area_insets,
|
|
38
34
|
use_state,
|
|
39
35
|
)
|
|
40
|
-
from .sdk import Props
|
|
41
36
|
from .style import (
|
|
37
|
+
AccessibilityState,
|
|
42
38
|
AutoCapitalize,
|
|
43
39
|
Color,
|
|
44
40
|
KeyboardType,
|
|
@@ -46,6 +42,7 @@ from .style import (
|
|
|
46
42
|
ScaleType,
|
|
47
43
|
StyleProp,
|
|
48
44
|
resolve_style,
|
|
45
|
+
validate_style_keys,
|
|
49
46
|
)
|
|
50
47
|
|
|
51
48
|
# ======================================================================
|
|
@@ -57,7 +54,7 @@ def _make_element(
|
|
|
57
54
|
name: str,
|
|
58
55
|
*children: Element,
|
|
59
56
|
style: StyleProp = None,
|
|
60
|
-
ref: Optional[
|
|
57
|
+
ref: Optional[Ref] = None,
|
|
61
58
|
key: Optional[str] = None,
|
|
62
59
|
_defaults: Optional[Dict[str, Any]] = None,
|
|
63
60
|
_forced: Optional[Dict[str, Any]] = None,
|
|
@@ -85,8 +82,9 @@ def _make_element(
|
|
|
85
82
|
name: Element type name (e.g. ``"Text"``).
|
|
86
83
|
*children: Child elements.
|
|
87
84
|
style: Style dict, list of dicts, or ``None``.
|
|
88
|
-
ref: Optional ``use_ref()
|
|
89
|
-
``ref
|
|
85
|
+
ref: Optional [`Ref`][pythonnative.Ref] from ``use_ref()``; the
|
|
86
|
+
reconciler populates ``ref.current`` with the underlying
|
|
87
|
+
native view.
|
|
90
88
|
key: Stable identity for keyed reconciliation.
|
|
91
89
|
_defaults: Internal: fill-only-if-missing prop defaults.
|
|
92
90
|
_forced: Internal: prop overrides applied last.
|
|
@@ -96,6 +94,8 @@ def _make_element(
|
|
|
96
94
|
A fresh [`Element`][pythonnative.Element].
|
|
97
95
|
"""
|
|
98
96
|
out: Dict[str, Any] = dict(resolve_style(style))
|
|
97
|
+
if out:
|
|
98
|
+
validate_style_keys(out, owner=name)
|
|
99
99
|
if _defaults:
|
|
100
100
|
for k, v in _defaults.items():
|
|
101
101
|
out.setdefault(k, v)
|
|
@@ -109,352 +109,6 @@ def _make_element(
|
|
|
109
109
|
return Element(name, out, list(children), key=key)
|
|
110
110
|
|
|
111
111
|
|
|
112
|
-
# ======================================================================
|
|
113
|
-
# Props dataclasses
|
|
114
|
-
# ======================================================================
|
|
115
|
-
#
|
|
116
|
-
# These are the canonical schemas for every built-in component. They
|
|
117
|
-
# subclass the SDK's ``Props`` base, so the same shape works for both
|
|
118
|
-
# the built-in factory functions and the third-party
|
|
119
|
-
# [`element_factory`][pythonnative.element_factory] API.
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
@dataclass(frozen=True)
|
|
123
|
-
class TextProps(Props):
|
|
124
|
-
"""Props for [`Text`][pythonnative.Text]."""
|
|
125
|
-
|
|
126
|
-
text: str = ""
|
|
127
|
-
spans: Optional[List[Dict[str, Any]]] = None
|
|
128
|
-
accessibility_label: Optional[str] = None
|
|
129
|
-
accessibility_hint: Optional[str] = None
|
|
130
|
-
accessibility_role: Optional[str] = None
|
|
131
|
-
accessible: Optional[bool] = None
|
|
132
|
-
accessibility_state: Optional[Dict[str, Any]] = None
|
|
133
|
-
accessibility_live_region: Optional[Literal["none", "polite", "assertive"]] = None
|
|
134
|
-
test_id: Optional[str] = None
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
@dataclass(frozen=True)
|
|
138
|
-
class ButtonProps(Props):
|
|
139
|
-
"""Props for [`Button`][pythonnative.Button]."""
|
|
140
|
-
|
|
141
|
-
title: str = ""
|
|
142
|
-
on_click: Optional[Callable[[], None]] = None
|
|
143
|
-
enabled: bool = True
|
|
144
|
-
accessibility_label: Optional[str] = None
|
|
145
|
-
accessibility_hint: Optional[str] = None
|
|
146
|
-
accessibility_role: Optional[str] = None
|
|
147
|
-
accessible: Optional[bool] = None
|
|
148
|
-
accessibility_state: Optional[Dict[str, Any]] = None
|
|
149
|
-
accessibility_live_region: Optional[Literal["none", "polite", "assertive"]] = None
|
|
150
|
-
test_id: Optional[str] = None
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
@dataclass(frozen=True)
|
|
154
|
-
class TextInputProps(Props):
|
|
155
|
-
"""Props for [`TextInput`][pythonnative.TextInput]."""
|
|
156
|
-
|
|
157
|
-
value: str = ""
|
|
158
|
-
placeholder: Optional[str] = None
|
|
159
|
-
on_change: Optional[Callable[[str], None]] = None
|
|
160
|
-
on_submit: Optional[Callable[[str], None]] = None
|
|
161
|
-
secure: bool = False
|
|
162
|
-
multiline: bool = False
|
|
163
|
-
keyboard_type: Optional[KeyboardType] = None
|
|
164
|
-
auto_capitalize: Optional[AutoCapitalize] = None
|
|
165
|
-
auto_correct: Optional[bool] = None
|
|
166
|
-
auto_focus: bool = False
|
|
167
|
-
return_key_type: Optional[ReturnKeyType] = None
|
|
168
|
-
max_length: Optional[int] = None
|
|
169
|
-
placeholder_color: Optional[Color] = None
|
|
170
|
-
editable: bool = True
|
|
171
|
-
clear_button: bool = False
|
|
172
|
-
on_focus: Optional[Callable[[], None]] = None
|
|
173
|
-
on_blur: Optional[Callable[[], None]] = None
|
|
174
|
-
selection_color: Optional[Color] = None
|
|
175
|
-
text_content_type: Optional[str] = None
|
|
176
|
-
accessibility_label: Optional[str] = None
|
|
177
|
-
accessibility_hint: Optional[str] = None
|
|
178
|
-
accessible: Optional[bool] = None
|
|
179
|
-
accessibility_state: Optional[Dict[str, Any]] = None
|
|
180
|
-
accessibility_live_region: Optional[Literal["none", "polite", "assertive"]] = None
|
|
181
|
-
test_id: Optional[str] = None
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
@dataclass(frozen=True)
|
|
185
|
-
class ImageProps(Props):
|
|
186
|
-
"""Props for [`Image`][pythonnative.Image]."""
|
|
187
|
-
|
|
188
|
-
source: Optional[str] = None
|
|
189
|
-
scale_type: Optional[ScaleType] = None
|
|
190
|
-
tint_color: Optional[Color] = None
|
|
191
|
-
placeholder_color: Optional[Color] = None
|
|
192
|
-
on_load: Optional[Callable[[], None]] = None
|
|
193
|
-
on_error: Optional[Callable[[str], None]] = None
|
|
194
|
-
accessibility_label: Optional[str] = None
|
|
195
|
-
accessibility_role: Optional[str] = None
|
|
196
|
-
accessible: Optional[bool] = None
|
|
197
|
-
accessibility_state: Optional[Dict[str, Any]] = None
|
|
198
|
-
accessibility_live_region: Optional[Literal["none", "polite", "assertive"]] = None
|
|
199
|
-
test_id: Optional[str] = None
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
@dataclass(frozen=True)
|
|
203
|
-
class SwitchProps(Props):
|
|
204
|
-
"""Props for [`Switch`][pythonnative.Switch]."""
|
|
205
|
-
|
|
206
|
-
value: bool = False
|
|
207
|
-
on_change: Optional[Callable[[bool], None]] = None
|
|
208
|
-
accessibility_label: Optional[str] = None
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
@dataclass(frozen=True)
|
|
212
|
-
class ProgressBarProps(Props):
|
|
213
|
-
"""Props for [`ProgressBar`][pythonnative.ProgressBar]."""
|
|
214
|
-
|
|
215
|
-
value: float = 0.0
|
|
216
|
-
color: Optional[Color] = None
|
|
217
|
-
track_color: Optional[Color] = None
|
|
218
|
-
indeterminate: bool = False
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
@dataclass(frozen=True)
|
|
222
|
-
class ActivityIndicatorProps(Props):
|
|
223
|
-
"""Props for [`ActivityIndicator`][pythonnative.ActivityIndicator]."""
|
|
224
|
-
|
|
225
|
-
animating: bool = True
|
|
226
|
-
color: Optional[Color] = None
|
|
227
|
-
size: Literal["small", "large"] = "small"
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
@dataclass(frozen=True)
|
|
231
|
-
class WebViewProps(Props):
|
|
232
|
-
"""Props for [`WebView`][pythonnative.WebView]."""
|
|
233
|
-
|
|
234
|
-
url: Optional[str] = None
|
|
235
|
-
html: Optional[str] = None
|
|
236
|
-
on_load: Optional[Callable[[str], None]] = None
|
|
237
|
-
on_message: Optional[Callable[[str], None]] = None
|
|
238
|
-
on_navigation_state_change: Optional[Callable[[str], None]] = None
|
|
239
|
-
inject_javascript: Optional[str] = None
|
|
240
|
-
scroll_enabled: bool = True
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
@dataclass(frozen=True)
|
|
244
|
-
class SpacerProps(Props):
|
|
245
|
-
"""Props for [`Spacer`][pythonnative.Spacer]."""
|
|
246
|
-
|
|
247
|
-
size: Optional[float] = None
|
|
248
|
-
flex: Optional[float] = None
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
@dataclass(frozen=True)
|
|
252
|
-
class SliderProps(Props):
|
|
253
|
-
"""Props for [`Slider`][pythonnative.Slider]."""
|
|
254
|
-
|
|
255
|
-
value: float = 0.0
|
|
256
|
-
min_value: float = 0.0
|
|
257
|
-
max_value: float = 1.0
|
|
258
|
-
on_change: Optional[Callable[[float], None]] = None
|
|
259
|
-
accessibility_label: Optional[str] = None
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
@dataclass(frozen=True)
|
|
263
|
-
class ViewProps(Props):
|
|
264
|
-
"""Props for [`View`][pythonnative.View], [`Column`][pythonnative.Column], and [`Row`][pythonnative.Row]."""
|
|
265
|
-
|
|
266
|
-
gestures: Optional[List[Any]] = None
|
|
267
|
-
accessibility_label: Optional[str] = None
|
|
268
|
-
accessibility_hint: Optional[str] = None
|
|
269
|
-
accessibility_role: Optional[str] = None
|
|
270
|
-
accessible: Optional[bool] = None
|
|
271
|
-
accessibility_state: Optional[Dict[str, Any]] = None
|
|
272
|
-
accessibility_live_region: Optional[Literal["none", "polite", "assertive"]] = None
|
|
273
|
-
test_id: Optional[str] = None
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
@dataclass(frozen=True)
|
|
277
|
-
class ScrollViewProps(Props):
|
|
278
|
-
"""Props for [`ScrollView`][pythonnative.ScrollView].
|
|
279
|
-
|
|
280
|
-
``on_scroll`` receives a single payload dict with ``"x"`` and
|
|
281
|
-
``"y"`` content offsets in points.
|
|
282
|
-
"""
|
|
283
|
-
|
|
284
|
-
refresh_control: Optional[Dict[str, Any]] = None
|
|
285
|
-
scroll_axis: Optional[Literal["vertical", "horizontal"]] = None
|
|
286
|
-
on_scroll: Optional[Callable[[Dict[str, float]], None]] = None
|
|
287
|
-
shows_scroll_indicator: bool = True
|
|
288
|
-
paging_enabled: bool = False
|
|
289
|
-
bounces: bool = True
|
|
290
|
-
content_container_style: StyleProp = None
|
|
291
|
-
keyboard_dismiss_mode: Optional[Literal["none", "on_drag", "interactive"]] = None
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
@dataclass(frozen=True)
|
|
295
|
-
class SafeAreaViewProps(Props):
|
|
296
|
-
"""Props for [`SafeAreaView`][pythonnative.SafeAreaView]."""
|
|
297
|
-
|
|
298
|
-
edges: Optional[Tuple[Literal["top", "left", "bottom", "right"], ...]] = None
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
@dataclass(frozen=True)
|
|
302
|
-
class ModalProps(Props):
|
|
303
|
-
"""Props for [`Modal`][pythonnative.Modal]."""
|
|
304
|
-
|
|
305
|
-
visible: bool = False
|
|
306
|
-
on_dismiss: Optional[Callable[[], None]] = None
|
|
307
|
-
on_show: Optional[Callable[[], None]] = None
|
|
308
|
-
title: Optional[str] = None
|
|
309
|
-
animation_type: Literal["slide", "fade", "none"] = "slide"
|
|
310
|
-
transparent: bool = False
|
|
311
|
-
presentation_style: Literal["page_sheet", "form_sheet", "full_screen", "overlay"] = "page_sheet"
|
|
312
|
-
dismiss_on_backdrop: bool = True
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
@dataclass(frozen=True)
|
|
316
|
-
class PressableProps(Props):
|
|
317
|
-
"""Props for [`Pressable`][pythonnative.Pressable]."""
|
|
318
|
-
|
|
319
|
-
on_press: Optional[Callable[[], None]] = None
|
|
320
|
-
on_long_press: Optional[Callable[[], None]] = None
|
|
321
|
-
on_press_in: Optional[Callable[[], None]] = None
|
|
322
|
-
on_press_out: Optional[Callable[[], None]] = None
|
|
323
|
-
pressed_opacity: float = 0.6
|
|
324
|
-
gestures: Optional[List[Any]] = None
|
|
325
|
-
accessibility_label: Optional[str] = None
|
|
326
|
-
accessibility_hint: Optional[str] = None
|
|
327
|
-
accessibility_role: Optional[str] = None
|
|
328
|
-
accessible: Optional[bool] = None
|
|
329
|
-
accessibility_state: Optional[Dict[str, Any]] = None
|
|
330
|
-
accessibility_live_region: Optional[Literal["none", "polite", "assertive"]] = None
|
|
331
|
-
test_id: Optional[str] = None
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
@dataclass(frozen=True)
|
|
335
|
-
class StatusBarProps(Props):
|
|
336
|
-
"""Props for [`StatusBar`][pythonnative.StatusBar]."""
|
|
337
|
-
|
|
338
|
-
bar_style: Optional[Literal["light", "dark", "default"]] = None
|
|
339
|
-
background_color: Optional[Color] = None
|
|
340
|
-
hidden: Optional[bool] = None
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
@dataclass(frozen=True)
|
|
344
|
-
class KeyboardAvoidingViewProps(Props):
|
|
345
|
-
"""Props for [`KeyboardAvoidingView`][pythonnative.KeyboardAvoidingView]."""
|
|
346
|
-
|
|
347
|
-
behavior: Literal["padding", "position"] = "padding"
|
|
348
|
-
keyboard_vertical_offset: float = 0.0
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
@dataclass(frozen=True)
|
|
352
|
-
class PickerProps(Props):
|
|
353
|
-
"""Props for [`Picker`][pythonnative.Picker].
|
|
354
|
-
|
|
355
|
-
``items`` is an ordered list of ``{"value": Any, "label": str}``
|
|
356
|
-
entries. ``value`` is matched against ``items[i]["value"]`` to
|
|
357
|
-
determine the currently selected row.
|
|
358
|
-
"""
|
|
359
|
-
|
|
360
|
-
value: Any = None
|
|
361
|
-
items: List[Dict[str, Any]] = field(default_factory=list)
|
|
362
|
-
on_change: Optional[Callable[[Any], None]] = None
|
|
363
|
-
placeholder: str = "Select…"
|
|
364
|
-
accessibility_label: Optional[str] = None
|
|
365
|
-
accessibility_hint: Optional[str] = None
|
|
366
|
-
accessible: Optional[bool] = None
|
|
367
|
-
accessibility_state: Optional[Dict[str, Any]] = None
|
|
368
|
-
accessibility_live_region: Optional[Literal["none", "polite", "assertive"]] = None
|
|
369
|
-
test_id: Optional[str] = None
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
@dataclass(frozen=True)
|
|
373
|
-
class TouchableOpacityProps(Props):
|
|
374
|
-
"""Props for [`TouchableOpacity`][pythonnative.TouchableOpacity]."""
|
|
375
|
-
|
|
376
|
-
on_press: Optional[Callable[[], None]] = None
|
|
377
|
-
on_long_press: Optional[Callable[[], None]] = None
|
|
378
|
-
active_opacity: float = 0.2
|
|
379
|
-
disabled: bool = False
|
|
380
|
-
accessibility_label: Optional[str] = None
|
|
381
|
-
accessibility_hint: Optional[str] = None
|
|
382
|
-
accessibility_role: Optional[str] = None
|
|
383
|
-
accessible: Optional[bool] = None
|
|
384
|
-
accessibility_state: Optional[Dict[str, Any]] = None
|
|
385
|
-
accessibility_live_region: Optional[Literal["none", "polite", "assertive"]] = None
|
|
386
|
-
test_id: Optional[str] = None
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
@dataclass(frozen=True)
|
|
390
|
-
class ImageBackgroundProps(Props):
|
|
391
|
-
"""Props for [`ImageBackground`][pythonnative.ImageBackground]."""
|
|
392
|
-
|
|
393
|
-
source: Optional[str] = None
|
|
394
|
-
scale_type: Optional[ScaleType] = None
|
|
395
|
-
accessibility_label: Optional[str] = None
|
|
396
|
-
accessible: Optional[bool] = None
|
|
397
|
-
accessibility_state: Optional[Dict[str, Any]] = None
|
|
398
|
-
accessibility_live_region: Optional[Literal["none", "polite", "assertive"]] = None
|
|
399
|
-
test_id: Optional[str] = None
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
@dataclass(frozen=True)
|
|
403
|
-
class CheckboxProps(Props):
|
|
404
|
-
"""Props for [`Checkbox`][pythonnative.Checkbox]."""
|
|
405
|
-
|
|
406
|
-
value: bool = False
|
|
407
|
-
on_change: Optional[Callable[[bool], None]] = None
|
|
408
|
-
label: Optional[str] = None
|
|
409
|
-
disabled: bool = False
|
|
410
|
-
color: Optional[Color] = None
|
|
411
|
-
accessibility_label: Optional[str] = None
|
|
412
|
-
accessibility_hint: Optional[str] = None
|
|
413
|
-
accessible: Optional[bool] = None
|
|
414
|
-
accessibility_state: Optional[Dict[str, Any]] = None
|
|
415
|
-
accessibility_live_region: Optional[Literal["none", "polite", "assertive"]] = None
|
|
416
|
-
test_id: Optional[str] = None
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
@dataclass(frozen=True)
|
|
420
|
-
class SegmentedControlProps(Props):
|
|
421
|
-
"""Props for [`SegmentedControl`][pythonnative.SegmentedControl]."""
|
|
422
|
-
|
|
423
|
-
segments: List[str] = field(default_factory=list)
|
|
424
|
-
selected_index: int = 0
|
|
425
|
-
on_change: Optional[Callable[[int], None]] = None
|
|
426
|
-
enabled: bool = True
|
|
427
|
-
tint_color: Optional[Color] = None
|
|
428
|
-
accessibility_label: Optional[str] = None
|
|
429
|
-
accessible: Optional[bool] = None
|
|
430
|
-
accessibility_state: Optional[Dict[str, Any]] = None
|
|
431
|
-
accessibility_live_region: Optional[Literal["none", "polite", "assertive"]] = None
|
|
432
|
-
test_id: Optional[str] = None
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
@dataclass(frozen=True)
|
|
436
|
-
class DatePickerProps(Props):
|
|
437
|
-
"""Props for [`DatePicker`][pythonnative.DatePicker].
|
|
438
|
-
|
|
439
|
-
``value`` and the value passed to ``on_change`` are ISO-8601
|
|
440
|
-
strings (``"2026-05-31"`` for ``mode="date"``, ``"14:30"`` for
|
|
441
|
-
``mode="time"``, ``"2026-05-31T14:30"`` for ``mode="datetime"``),
|
|
442
|
-
so the schema stays JSON-serializable and platform-agnostic.
|
|
443
|
-
"""
|
|
444
|
-
|
|
445
|
-
value: Optional[str] = None
|
|
446
|
-
mode: Literal["date", "time", "datetime"] = "date"
|
|
447
|
-
on_change: Optional[Callable[[str], None]] = None
|
|
448
|
-
minimum: Optional[str] = None
|
|
449
|
-
maximum: Optional[str] = None
|
|
450
|
-
enabled: bool = True
|
|
451
|
-
accessibility_label: Optional[str] = None
|
|
452
|
-
accessible: Optional[bool] = None
|
|
453
|
-
accessibility_state: Optional[Dict[str, Any]] = None
|
|
454
|
-
accessibility_live_region: Optional[Literal["none", "polite", "assertive"]] = None
|
|
455
|
-
test_id: Optional[str] = None
|
|
456
|
-
|
|
457
|
-
|
|
458
112
|
# ======================================================================
|
|
459
113
|
# Leaf factories
|
|
460
114
|
# ======================================================================
|
|
@@ -518,10 +172,10 @@ def Text(
|
|
|
518
172
|
accessibility_hint: Optional[str] = None,
|
|
519
173
|
accessibility_role: Optional[str] = None,
|
|
520
174
|
accessible: Optional[bool] = None,
|
|
521
|
-
accessibility_state: Optional[
|
|
175
|
+
accessibility_state: Optional[AccessibilityState] = None,
|
|
522
176
|
accessibility_live_region: Optional[Literal["none", "polite", "assertive"]] = None,
|
|
523
177
|
test_id: Optional[str] = None,
|
|
524
|
-
ref: Optional[
|
|
178
|
+
ref: Optional[Ref] = None,
|
|
525
179
|
key: Optional[str] = None,
|
|
526
180
|
) -> Element:
|
|
527
181
|
"""Display a string of text, optionally with styled nested spans.
|
|
@@ -571,7 +225,7 @@ def Text(
|
|
|
571
225
|
test_id: Stable identifier for UI tests; exposed as
|
|
572
226
|
``resource-id`` on Android and ``accessibilityIdentifier``
|
|
573
227
|
on iOS.
|
|
574
|
-
ref: Optional ``use_ref()
|
|
228
|
+
ref: Optional [`Ref`][pythonnative.Ref] from ``use_ref()``.
|
|
575
229
|
key: Stable identity for keyed reconciliation.
|
|
576
230
|
|
|
577
231
|
Returns:
|
|
@@ -604,17 +258,17 @@ def Text(
|
|
|
604
258
|
def Button(
|
|
605
259
|
title: str = "",
|
|
606
260
|
*,
|
|
607
|
-
|
|
261
|
+
on_press: Optional[Callable[[], None]] = None,
|
|
608
262
|
enabled: bool = True,
|
|
609
263
|
style: StyleProp = None,
|
|
610
264
|
accessibility_label: Optional[str] = None,
|
|
611
265
|
accessibility_hint: Optional[str] = None,
|
|
612
266
|
accessibility_role: Optional[str] = None,
|
|
613
267
|
accessible: Optional[bool] = None,
|
|
614
|
-
accessibility_state: Optional[
|
|
268
|
+
accessibility_state: Optional[AccessibilityState] = None,
|
|
615
269
|
accessibility_live_region: Optional[Literal["none", "polite", "assertive"]] = None,
|
|
616
270
|
test_id: Optional[str] = None,
|
|
617
|
-
ref: Optional[
|
|
271
|
+
ref: Optional[Ref] = None,
|
|
618
272
|
key: Optional[str] = None,
|
|
619
273
|
) -> Element:
|
|
620
274
|
"""Display a tappable button.
|
|
@@ -627,7 +281,7 @@ def Button(
|
|
|
627
281
|
|
|
628
282
|
Args:
|
|
629
283
|
title: Button label.
|
|
630
|
-
|
|
284
|
+
on_press: Callback invoked when the user taps the button.
|
|
631
285
|
enabled: When ``False``, the button is disabled and cannot be
|
|
632
286
|
tapped.
|
|
633
287
|
style: Style dict (or list of dicts).
|
|
@@ -645,7 +299,7 @@ def Button(
|
|
|
645
299
|
test_id: Stable identifier for UI tests; exposed as
|
|
646
300
|
``resource-id`` on Android and ``accessibilityIdentifier``
|
|
647
301
|
on iOS.
|
|
648
|
-
ref: Optional ``use_ref()
|
|
302
|
+
ref: Optional [`Ref`][pythonnative.Ref] from ``use_ref()``.
|
|
649
303
|
key: Stable identity for keyed reconciliation.
|
|
650
304
|
|
|
651
305
|
Returns:
|
|
@@ -657,7 +311,7 @@ def Button(
|
|
|
657
311
|
ref=ref,
|
|
658
312
|
key=key,
|
|
659
313
|
title=title,
|
|
660
|
-
|
|
314
|
+
on_press=on_press,
|
|
661
315
|
enabled=enabled,
|
|
662
316
|
accessibility_label=accessibility_label,
|
|
663
317
|
accessibility_hint=accessibility_hint,
|
|
@@ -695,10 +349,10 @@ def TextInput(
|
|
|
695
349
|
accessibility_label: Optional[str] = None,
|
|
696
350
|
accessibility_hint: Optional[str] = None,
|
|
697
351
|
accessible: Optional[bool] = None,
|
|
698
|
-
accessibility_state: Optional[
|
|
352
|
+
accessibility_state: Optional[AccessibilityState] = None,
|
|
699
353
|
accessibility_live_region: Optional[Literal["none", "polite", "assertive"]] = None,
|
|
700
354
|
test_id: Optional[str] = None,
|
|
701
|
-
ref: Optional[
|
|
355
|
+
ref: Optional[Ref] = None,
|
|
702
356
|
key: Optional[str] = None,
|
|
703
357
|
) -> Element:
|
|
704
358
|
"""Display a text-entry field (single-line by default, or ``multiline``).
|
|
@@ -748,7 +402,7 @@ def TextInput(
|
|
|
748
402
|
test_id: Stable identifier for UI tests; exposed as
|
|
749
403
|
``resource-id`` on Android and ``accessibilityIdentifier``
|
|
750
404
|
on iOS.
|
|
751
|
-
ref: Optional ``use_ref()
|
|
405
|
+
ref: Optional [`Ref`][pythonnative.Ref] from ``use_ref()``.
|
|
752
406
|
key: Stable identity for keyed reconciliation.
|
|
753
407
|
|
|
754
408
|
Returns:
|
|
@@ -799,10 +453,10 @@ def Image(
|
|
|
799
453
|
accessibility_label: Optional[str] = None,
|
|
800
454
|
accessibility_role: Optional[str] = None,
|
|
801
455
|
accessible: Optional[bool] = None,
|
|
802
|
-
accessibility_state: Optional[
|
|
456
|
+
accessibility_state: Optional[AccessibilityState] = None,
|
|
803
457
|
accessibility_live_region: Optional[Literal["none", "polite", "assertive"]] = None,
|
|
804
458
|
test_id: Optional[str] = None,
|
|
805
|
-
ref: Optional[
|
|
459
|
+
ref: Optional[Ref] = None,
|
|
806
460
|
key: Optional[str] = None,
|
|
807
461
|
) -> Element:
|
|
808
462
|
"""Display an image from a resource path or URL.
|
|
@@ -842,7 +496,7 @@ def Image(
|
|
|
842
496
|
test_id: Stable identifier for UI tests; exposed as
|
|
843
497
|
``resource-id`` on Android and ``accessibilityIdentifier``
|
|
844
498
|
on iOS.
|
|
845
|
-
ref: Optional ``use_ref()
|
|
499
|
+
ref: Optional [`Ref`][pythonnative.Ref] from ``use_ref()``.
|
|
846
500
|
key: Stable identity for keyed reconciliation.
|
|
847
501
|
|
|
848
502
|
Returns:
|
|
@@ -1105,10 +759,10 @@ def View(
|
|
|
1105
759
|
accessibility_hint: Optional[str] = None,
|
|
1106
760
|
accessibility_role: Optional[str] = None,
|
|
1107
761
|
accessible: Optional[bool] = None,
|
|
1108
|
-
accessibility_state: Optional[
|
|
762
|
+
accessibility_state: Optional[AccessibilityState] = None,
|
|
1109
763
|
accessibility_live_region: Optional[Literal["none", "polite", "assertive"]] = None,
|
|
1110
764
|
test_id: Optional[str] = None,
|
|
1111
|
-
ref: Optional[
|
|
765
|
+
ref: Optional[Ref] = None,
|
|
1112
766
|
key: Optional[str] = None,
|
|
1113
767
|
) -> Element:
|
|
1114
768
|
"""Universal flex container (like React Native's ``View``).
|
|
@@ -1157,7 +811,7 @@ def View(
|
|
|
1157
811
|
test_id: Stable identifier for UI tests; exposed as
|
|
1158
812
|
``resource-id`` on Android and ``accessibilityIdentifier``
|
|
1159
813
|
on iOS.
|
|
1160
|
-
ref: Optional ``use_ref()
|
|
814
|
+
ref: Optional [`Ref`][pythonnative.Ref] from ``use_ref()``.
|
|
1161
815
|
key: Stable identity for keyed reconciliation.
|
|
1162
816
|
|
|
1163
817
|
Returns:
|
|
@@ -1184,7 +838,7 @@ def View(
|
|
|
1184
838
|
def Column(
|
|
1185
839
|
*children: Element,
|
|
1186
840
|
style: StyleProp = None,
|
|
1187
|
-
ref: Optional[
|
|
841
|
+
ref: Optional[Ref] = None,
|
|
1188
842
|
key: Optional[str] = None,
|
|
1189
843
|
) -> Element:
|
|
1190
844
|
"""Arrange children vertically.
|
|
@@ -1196,7 +850,7 @@ def Column(
|
|
|
1196
850
|
Args:
|
|
1197
851
|
*children: Child elements stacked top to bottom.
|
|
1198
852
|
style: Style dict (or list of dicts).
|
|
1199
|
-
ref: Optional
|
|
853
|
+
ref: Optional [`Ref`][pythonnative.Ref] for native-view access.
|
|
1200
854
|
key: Stable identity for keyed reconciliation.
|
|
1201
855
|
|
|
1202
856
|
Returns:
|
|
@@ -1215,7 +869,7 @@ def Column(
|
|
|
1215
869
|
def Row(
|
|
1216
870
|
*children: Element,
|
|
1217
871
|
style: StyleProp = None,
|
|
1218
|
-
ref: Optional[
|
|
872
|
+
ref: Optional[Ref] = None,
|
|
1219
873
|
key: Optional[str] = None,
|
|
1220
874
|
) -> Element:
|
|
1221
875
|
"""Arrange children horizontally.
|
|
@@ -1227,7 +881,7 @@ def Row(
|
|
|
1227
881
|
Args:
|
|
1228
882
|
*children: Child elements arranged left to right.
|
|
1229
883
|
style: Style dict (or list of dicts).
|
|
1230
|
-
ref: Optional
|
|
884
|
+
ref: Optional [`Ref`][pythonnative.Ref] for native-view access.
|
|
1231
885
|
key: Stable identity for keyed reconciliation.
|
|
1232
886
|
|
|
1233
887
|
Returns:
|
|
@@ -1254,7 +908,7 @@ def ScrollView(
|
|
|
1254
908
|
content_container_style: StyleProp = None,
|
|
1255
909
|
keyboard_dismiss_mode: Optional[Literal["none", "on_drag", "interactive"]] = None,
|
|
1256
910
|
style: StyleProp = None,
|
|
1257
|
-
ref: Optional[
|
|
911
|
+
ref: Optional[Ref] = None,
|
|
1258
912
|
key: Optional[str] = None,
|
|
1259
913
|
) -> Element:
|
|
1260
914
|
"""Wrap children in a scrollable container.
|
|
@@ -1285,7 +939,7 @@ def ScrollView(
|
|
|
1285
939
|
``"interactive"``. Controls whether scrolling dismisses
|
|
1286
940
|
the keyboard.
|
|
1287
941
|
style: Style dict (or list of dicts).
|
|
1288
|
-
ref: Optional ``use_ref()
|
|
942
|
+
ref: Optional [`Ref`][pythonnative.Ref] from ``use_ref()``.
|
|
1289
943
|
key: Stable identity for keyed reconciliation.
|
|
1290
944
|
|
|
1291
945
|
Returns:
|
|
@@ -1495,10 +1149,10 @@ def Pressable(
|
|
|
1495
1149
|
accessibility_hint: Optional[str] = None,
|
|
1496
1150
|
accessibility_role: Optional[str] = None,
|
|
1497
1151
|
accessible: Optional[bool] = None,
|
|
1498
|
-
accessibility_state: Optional[
|
|
1152
|
+
accessibility_state: Optional[AccessibilityState] = None,
|
|
1499
1153
|
accessibility_live_region: Optional[Literal["none", "polite", "assertive"]] = None,
|
|
1500
1154
|
test_id: Optional[str] = None,
|
|
1501
|
-
ref: Optional[
|
|
1155
|
+
ref: Optional[Ref] = None,
|
|
1502
1156
|
key: Optional[str] = None,
|
|
1503
1157
|
) -> Element:
|
|
1504
1158
|
"""Wrap children with tap / long-press / gesture handlers.
|
|
@@ -1547,7 +1201,7 @@ def Pressable(
|
|
|
1547
1201
|
test_id: Stable identifier for UI tests; exposed as
|
|
1548
1202
|
``resource-id`` on Android and ``accessibilityIdentifier``
|
|
1549
1203
|
on iOS.
|
|
1550
|
-
ref: Optional ``use_ref()
|
|
1204
|
+
ref: Optional [`Ref`][pythonnative.Ref] from ``use_ref()``.
|
|
1551
1205
|
key: Stable identity for keyed reconciliation.
|
|
1552
1206
|
|
|
1553
1207
|
Returns:
|
|
@@ -1613,7 +1267,7 @@ def TouchableOpacity(
|
|
|
1613
1267
|
accessibility_hint: Optional[str] = None,
|
|
1614
1268
|
accessibility_role: Optional[str] = None,
|
|
1615
1269
|
accessible: Optional[bool] = None,
|
|
1616
|
-
accessibility_state: Optional[
|
|
1270
|
+
accessibility_state: Optional[AccessibilityState] = None,
|
|
1617
1271
|
accessibility_live_region: Optional[Literal["none", "polite", "assertive"]] = None,
|
|
1618
1272
|
test_id: Optional[str] = None,
|
|
1619
1273
|
key: Optional[str] = None,
|
|
@@ -1683,7 +1337,7 @@ def ImageBackground(
|
|
|
1683
1337
|
style: StyleProp = None,
|
|
1684
1338
|
accessibility_label: Optional[str] = None,
|
|
1685
1339
|
accessible: Optional[bool] = None,
|
|
1686
|
-
accessibility_state: Optional[
|
|
1340
|
+
accessibility_state: Optional[AccessibilityState] = None,
|
|
1687
1341
|
accessibility_live_region: Optional[Literal["none", "polite", "assertive"]] = None,
|
|
1688
1342
|
test_id: Optional[str] = None,
|
|
1689
1343
|
key: Optional[str] = None,
|
|
@@ -1751,7 +1405,7 @@ def Checkbox(
|
|
|
1751
1405
|
accessibility_label: Optional[str] = None,
|
|
1752
1406
|
accessibility_hint: Optional[str] = None,
|
|
1753
1407
|
accessible: Optional[bool] = None,
|
|
1754
|
-
accessibility_state: Optional[
|
|
1408
|
+
accessibility_state: Optional[AccessibilityState] = None,
|
|
1755
1409
|
accessibility_live_region: Optional[Literal["none", "polite", "assertive"]] = None,
|
|
1756
1410
|
test_id: Optional[str] = None,
|
|
1757
1411
|
key: Optional[str] = None,
|
|
@@ -1816,7 +1470,7 @@ def SegmentedControl(
|
|
|
1816
1470
|
style: StyleProp = None,
|
|
1817
1471
|
accessibility_label: Optional[str] = None,
|
|
1818
1472
|
accessible: Optional[bool] = None,
|
|
1819
|
-
accessibility_state: Optional[
|
|
1473
|
+
accessibility_state: Optional[AccessibilityState] = None,
|
|
1820
1474
|
accessibility_live_region: Optional[Literal["none", "polite", "assertive"]] = None,
|
|
1821
1475
|
test_id: Optional[str] = None,
|
|
1822
1476
|
key: Optional[str] = None,
|
|
@@ -1879,7 +1533,7 @@ def DatePicker(
|
|
|
1879
1533
|
style: StyleProp = None,
|
|
1880
1534
|
accessibility_label: Optional[str] = None,
|
|
1881
1535
|
accessible: Optional[bool] = None,
|
|
1882
|
-
accessibility_state: Optional[
|
|
1536
|
+
accessibility_state: Optional[AccessibilityState] = None,
|
|
1883
1537
|
accessibility_live_region: Optional[Literal["none", "polite", "assertive"]] = None,
|
|
1884
1538
|
test_id: Optional[str] = None,
|
|
1885
1539
|
key: Optional[str] = None,
|
|
@@ -1889,7 +1543,10 @@ def DatePicker(
|
|
|
1889
1543
|
Backed by ``UIDatePicker`` on iOS and a trigger button that opens
|
|
1890
1544
|
the platform ``DatePickerDialog`` / ``TimePickerDialog`` on
|
|
1891
1545
|
Android. ``value`` and the value reported to ``on_change`` are
|
|
1892
|
-
ISO-8601 strings (
|
|
1546
|
+
ISO-8601 strings (``"2026-05-31"`` for ``mode="date"``, ``"14:30"``
|
|
1547
|
+
for ``mode="time"``, ``"2026-05-31T14:30"`` for
|
|
1548
|
+
``mode="datetime"``), so values stay JSON-serializable and
|
|
1549
|
+
platform-agnostic.
|
|
1893
1550
|
|
|
1894
1551
|
Args:
|
|
1895
1552
|
value: Currently selected value as an ISO-8601 string.
|
|
@@ -1943,14 +1600,12 @@ def DatePicker(
|
|
|
1943
1600
|
def Fragment(*children: Optional[Element], key: Optional[str] = None) -> Element:
|
|
1944
1601
|
"""Group children without adding a wrapping native view.
|
|
1945
1602
|
|
|
1946
|
-
Like React's ``<></>``:
|
|
1947
|
-
|
|
1948
|
-
Fragment
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
[`memo`][pythonnative.memo] / conditional logic when grouping
|
|
1953
|
-
siblings inside another component's child list:
|
|
1603
|
+
Like React's ``<></>``: groups elements without introducing an
|
|
1604
|
+
extra container. Each child mounts as a direct sibling of the
|
|
1605
|
+
Fragment's position in the parent's child list. Components may
|
|
1606
|
+
also simply return a plain ``list`` of elements; ``Fragment``
|
|
1607
|
+
exists for when the group needs a ``key`` (e.g. rendering a list
|
|
1608
|
+
of pairs) or when a single expression reads better.
|
|
1954
1609
|
|
|
1955
1610
|
```python
|
|
1956
1611
|
pn.Column(
|
|
@@ -1964,24 +1619,54 @@ def Fragment(*children: Optional[Element], key: Optional[str] = None) -> Element
|
|
|
1964
1619
|
```
|
|
1965
1620
|
|
|
1966
1621
|
Args:
|
|
1967
|
-
*children: Child elements to expose at the parent level.
|
|
1968
|
-
children are dropped, which makes
|
|
1969
|
-
``cond and pn.Text(...)``
|
|
1970
|
-
|
|
1971
|
-
|
|
1622
|
+
*children: Child elements to expose at the parent level.
|
|
1623
|
+
``None`` and ``False`` children are dropped, which makes
|
|
1624
|
+
conditional rendering with ``cond and pn.Text(...)``
|
|
1625
|
+
ergonomic.
|
|
1626
|
+
key: Stable identity for keyed reconciliation. A keyed
|
|
1627
|
+
Fragment moves all of its children as one unit and
|
|
1628
|
+
preserves their state across reorders.
|
|
1972
1629
|
|
|
1973
1630
|
Returns:
|
|
1974
1631
|
An [`Element`][pythonnative.Element] of type ``"__Fragment__"``.
|
|
1632
|
+
"""
|
|
1633
|
+
kept = [c for c in children if c is not None and c is not False]
|
|
1634
|
+
return Element("__Fragment__", {}, kept, key=key)
|
|
1635
|
+
|
|
1636
|
+
|
|
1637
|
+
def Portal(*children: Element, key: Optional[str] = None) -> Element:
|
|
1638
|
+
"""Render ``children`` into a full-screen overlay above everything else.
|
|
1639
|
+
|
|
1640
|
+
Like React DOM's ``createPortal``: the children stay part of this
|
|
1641
|
+
component's tree for state, context, and events, but their native
|
|
1642
|
+
views mount in a transparent overlay attached to the window (above
|
|
1643
|
+
the screen's content) instead of inside the surrounding parent.
|
|
1644
|
+
Use it for toasts, dropdowns, tooltips, and lightweight custom
|
|
1645
|
+
overlays that must escape ``overflow: "hidden"`` ancestors. For a
|
|
1646
|
+
system-styled dialog with its own presentation and dismissal
|
|
1647
|
+
gestures, use [`Modal`][pythonnative.Modal] instead.
|
|
1975
1648
|
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1649
|
+
The overlay itself does not intercept touches; only the children
|
|
1650
|
+
themselves are hit-testable. Children are laid out against the
|
|
1651
|
+
full viewport, so position them with absolute insets:
|
|
1652
|
+
|
|
1653
|
+
```python
|
|
1654
|
+
pn.Portal(
|
|
1655
|
+
pn.View(
|
|
1656
|
+
pn.Text("Saved!"),
|
|
1657
|
+
style=pn.style(position="absolute", bottom=40, left=40, right=40),
|
|
1658
|
+
),
|
|
1659
|
+
)
|
|
1660
|
+
```
|
|
1661
|
+
|
|
1662
|
+
Args:
|
|
1663
|
+
*children: Overlay content.
|
|
1664
|
+
key: Stable identity for keyed reconciliation.
|
|
1665
|
+
|
|
1666
|
+
Returns:
|
|
1667
|
+
An [`Element`][pythonnative.Element] of type ``"Portal"``.
|
|
1982
1668
|
"""
|
|
1983
|
-
|
|
1984
|
-
return Element("__Fragment__", {}, filtered, key=key)
|
|
1669
|
+
return Element("Portal", {}, list(children), key=key)
|
|
1985
1670
|
|
|
1986
1671
|
|
|
1987
1672
|
# ======================================================================
|
|
@@ -1992,23 +1677,33 @@ def Fragment(*children: Optional[Element], key: Optional[str] = None) -> Element
|
|
|
1992
1677
|
def ErrorBoundary(
|
|
1993
1678
|
*children: Element,
|
|
1994
1679
|
fallback: Optional[Any] = None,
|
|
1680
|
+
on_error: Optional[Callable[[BaseException], None]] = None,
|
|
1995
1681
|
key: Optional[str] = None,
|
|
1996
1682
|
) -> Element:
|
|
1997
1683
|
"""Catch render errors in the wrapped subtree and display ``fallback`` instead.
|
|
1998
1684
|
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
1685
|
+
When any descendant raises during render (initial mount, a parent
|
|
1686
|
+
re-render, or a local state-driven update), the failed subtree is
|
|
1687
|
+
torn down and ``fallback`` is mounted in its place. Without a
|
|
1688
|
+
boundary the error propagates to the screen host (which shows the
|
|
1689
|
+
dev error overlay in dev mode).
|
|
2003
1690
|
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
1691
|
+
``fallback`` may be:
|
|
1692
|
+
|
|
1693
|
+
- An [`Element`][pythonnative.Element], shown as-is.
|
|
1694
|
+
- ``fallback(error) -> Element``.
|
|
1695
|
+
- ``fallback(error, reset) -> Element``, where ``reset`` is a
|
|
1696
|
+
zero-arg callable that clears the error and remounts the
|
|
1697
|
+
original children (fresh state), for retry buttons.
|
|
2007
1698
|
|
|
2008
1699
|
Args:
|
|
2009
1700
|
*children: Subtree to wrap.
|
|
2010
|
-
fallback:
|
|
2011
|
-
|
|
1701
|
+
fallback: Fallback content (see above). Required for the
|
|
1702
|
+
boundary to actually catch; without it errors propagate
|
|
1703
|
+
to the next boundary up.
|
|
1704
|
+
on_error: Callback invoked with the exception when the
|
|
1705
|
+
boundary catches, before the fallback mounts. Use it for
|
|
1706
|
+
error reporting.
|
|
2012
1707
|
key: Stable identity for keyed reconciliation.
|
|
2013
1708
|
|
|
2014
1709
|
Returns:
|
|
@@ -2021,18 +1716,20 @@ def ErrorBoundary(
|
|
|
2021
1716
|
|
|
2022
1717
|
pn.ErrorBoundary(
|
|
2023
1718
|
MyRiskyComponent(),
|
|
2024
|
-
fallback=lambda err: pn.
|
|
1719
|
+
fallback=lambda err, reset: pn.Column(
|
|
1720
|
+
pn.Text(f"Error: {err}"),
|
|
1721
|
+
pn.Button("Retry", on_press=reset),
|
|
1722
|
+
),
|
|
1723
|
+
on_error=lambda err: log.exception(err),
|
|
2025
1724
|
)
|
|
2026
1725
|
```
|
|
2027
1726
|
"""
|
|
2028
1727
|
props: Dict[str, Any] = {}
|
|
2029
1728
|
if fallback is not None:
|
|
2030
1729
|
props["__fallback__"] = fallback
|
|
2031
|
-
if
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
kids = [Fragment(*children)]
|
|
2035
|
-
return Element("__ErrorBoundary__", props, kids, key=key)
|
|
1730
|
+
if on_error is not None:
|
|
1731
|
+
props["__on_error__"] = on_error
|
|
1732
|
+
return Element("__ErrorBoundary__", props, list(children), key=key)
|
|
2036
1733
|
|
|
2037
1734
|
|
|
2038
1735
|
# ======================================================================
|
|
@@ -2082,7 +1779,7 @@ class _RowSpec:
|
|
|
2082
1779
|
|
|
2083
1780
|
def _dispatch_scroll_command(scroll_ref: Any, name: str, args: Dict[str, Any]) -> Any:
|
|
2084
1781
|
"""Send an imperative command to the ScrollView under ``scroll_ref``."""
|
|
2085
|
-
tag = scroll_ref
|
|
1782
|
+
tag = getattr(scroll_ref, "_pn_tag", None)
|
|
2086
1783
|
if tag is None:
|
|
2087
1784
|
return None
|
|
2088
1785
|
from .native_views import get_registry
|
|
@@ -2093,6 +1790,55 @@ def _dispatch_scroll_command(scroll_ref: Any, name: str, args: Dict[str, Any]) -
|
|
|
2093
1790
|
return None
|
|
2094
1791
|
|
|
2095
1792
|
|
|
1793
|
+
class ListController:
|
|
1794
|
+
"""Imperative scroll handle published on a list's ``ref``.
|
|
1795
|
+
|
|
1796
|
+
[`FlatList`][pythonnative.FlatList] and
|
|
1797
|
+
[`SectionList`][pythonnative.SectionList] install a
|
|
1798
|
+
``ListController`` on ``ref.current`` (via
|
|
1799
|
+
[`use_imperative_handle`][pythonnative.use_imperative_handle])
|
|
1800
|
+
after mount and clear it back to ``None`` on unmount.
|
|
1801
|
+
|
|
1802
|
+
Example:
|
|
1803
|
+
```python
|
|
1804
|
+
import pythonnative as pn
|
|
1805
|
+
|
|
1806
|
+
@pn.component
|
|
1807
|
+
def Chat(messages):
|
|
1808
|
+
list_ref = pn.use_ref()
|
|
1809
|
+
pn.use_layout_effect(
|
|
1810
|
+
lambda: list_ref.current and list_ref.current.scroll_to_end(animated=False),
|
|
1811
|
+
[len(messages)],
|
|
1812
|
+
)
|
|
1813
|
+
return pn.FlatList(data=messages, render_item=Bubble, ref=list_ref)
|
|
1814
|
+
```
|
|
1815
|
+
"""
|
|
1816
|
+
|
|
1817
|
+
__slots__ = ("_scroll_to_offset", "_scroll_to_index", "_scroll_to_end")
|
|
1818
|
+
|
|
1819
|
+
def __init__(
|
|
1820
|
+
self,
|
|
1821
|
+
scroll_to_offset: Callable[[float, bool], None],
|
|
1822
|
+
scroll_to_index: Callable[[int, bool], None],
|
|
1823
|
+
scroll_to_end: Callable[[bool], None],
|
|
1824
|
+
) -> None:
|
|
1825
|
+
self._scroll_to_offset = scroll_to_offset
|
|
1826
|
+
self._scroll_to_index = scroll_to_index
|
|
1827
|
+
self._scroll_to_end = scroll_to_end
|
|
1828
|
+
|
|
1829
|
+
def scroll_to_offset(self, offset: float, animated: bool = True) -> None:
|
|
1830
|
+
"""Scroll to an absolute content offset in points."""
|
|
1831
|
+
self._scroll_to_offset(offset, animated)
|
|
1832
|
+
|
|
1833
|
+
def scroll_to_index(self, index: int, animated: bool = True) -> None:
|
|
1834
|
+
"""Scroll so the row at ``index`` sits at the top of the viewport."""
|
|
1835
|
+
self._scroll_to_index(index, animated)
|
|
1836
|
+
|
|
1837
|
+
def scroll_to_end(self, animated: bool = True) -> None:
|
|
1838
|
+
"""Scroll to the end of the content."""
|
|
1839
|
+
self._scroll_to_end(animated)
|
|
1840
|
+
|
|
1841
|
+
|
|
2096
1842
|
@component
|
|
2097
1843
|
def _VirtualizedList(**p: Any) -> Element:
|
|
2098
1844
|
"""Shared windowing engine behind FlatList and SectionList."""
|
|
@@ -2104,18 +1850,18 @@ def _VirtualizedList(**p: Any) -> Element:
|
|
|
2104
1850
|
initial_extent: float = float(p.get("initial_window_extent") or 800.0)
|
|
2105
1851
|
|
|
2106
1852
|
window, set_window = use_state((0, -1))
|
|
2107
|
-
measured = use_ref({}) # row key -> measured extent (points)
|
|
2108
|
-
row_refs = use_ref({}) # row key ->
|
|
1853
|
+
measured: Ref[Dict[str, float]] = use_ref({}) # row key -> measured extent (points)
|
|
1854
|
+
row_refs: Ref[Dict[str, Ref]] = use_ref({}) # row key -> Ref for live rows
|
|
2109
1855
|
end_latch = use_ref({"fired_for": -1})
|
|
2110
|
-
viewable_ref = use_ref({"keys": ()})
|
|
1856
|
+
viewable_ref: Ref[Dict[str, Tuple[str, ...]]] = use_ref({"keys": ()})
|
|
2111
1857
|
scroll_pos = use_ref({"offset": 0.0})
|
|
2112
|
-
sv_ref = use_ref(None)
|
|
1858
|
+
sv_ref: Ref = use_ref(None)
|
|
2113
1859
|
|
|
2114
1860
|
# ------------------------------------------------------------------
|
|
2115
1861
|
# Extent model: measured > per-row hint > estimate. ``starts`` are
|
|
2116
1862
|
# prefix sums; ``starts[n]`` is the total content extent.
|
|
2117
1863
|
# ------------------------------------------------------------------
|
|
2118
|
-
measured_map: Dict[str, float] = measured
|
|
1864
|
+
measured_map: Dict[str, float] = measured.current
|
|
2119
1865
|
starts: List[float] = [0.0] * (n + 1)
|
|
2120
1866
|
acc = 0.0
|
|
2121
1867
|
for i, spec in enumerate(rows):
|
|
@@ -2128,7 +1874,7 @@ def _VirtualizedList(**p: Any) -> Element:
|
|
|
2128
1874
|
total_extent = acc
|
|
2129
1875
|
|
|
2130
1876
|
def _viewport_extent() -> float:
|
|
2131
|
-
frame = sv_ref.
|
|
1877
|
+
frame = sv_ref._pn_frame
|
|
2132
1878
|
if frame:
|
|
2133
1879
|
extent = frame[2] if horizontal else frame[3]
|
|
2134
1880
|
if extent and extent > 0:
|
|
@@ -2147,7 +1893,7 @@ def _VirtualizedList(**p: Any) -> Element:
|
|
|
2147
1893
|
|
|
2148
1894
|
first, last = window
|
|
2149
1895
|
if last < 0 or first >= n:
|
|
2150
|
-
first, last = _window_for(scroll_pos
|
|
1896
|
+
first, last = _window_for(scroll_pos.current["offset"], _viewport_extent())
|
|
2151
1897
|
last = min(last, n - 1)
|
|
2152
1898
|
first = max(0, min(first, max(0, n - 1)))
|
|
2153
1899
|
|
|
@@ -2163,8 +1909,8 @@ def _VirtualizedList(**p: Any) -> Element:
|
|
|
2163
1909
|
user_on_scroll = p.get("on_scroll")
|
|
2164
1910
|
|
|
2165
1911
|
def _sweep_measured() -> None:
|
|
2166
|
-
for row_key,
|
|
2167
|
-
frame =
|
|
1912
|
+
for row_key, row_ref in row_refs.current.items():
|
|
1913
|
+
frame = getattr(row_ref, "_pn_frame", None)
|
|
2168
1914
|
if frame:
|
|
2169
1915
|
extent = frame[2] if horizontal else frame[3]
|
|
2170
1916
|
if extent and extent > 0:
|
|
@@ -2175,7 +1921,7 @@ def _VirtualizedList(**p: Any) -> Element:
|
|
|
2175
1921
|
offset = float(payload.get("x" if horizontal else "y", 0.0) or 0.0)
|
|
2176
1922
|
else:
|
|
2177
1923
|
offset = float(payload or 0.0)
|
|
2178
|
-
scroll_pos
|
|
1924
|
+
scroll_pos.current["offset"] = offset
|
|
2179
1925
|
_sweep_measured()
|
|
2180
1926
|
viewport = _viewport_extent()
|
|
2181
1927
|
|
|
@@ -2186,18 +1932,18 @@ def _VirtualizedList(**p: Any) -> Element:
|
|
|
2186
1932
|
if on_end_reached is not None and total_extent > 0:
|
|
2187
1933
|
remaining = total_extent - (offset + viewport)
|
|
2188
1934
|
if remaining <= end_threshold * viewport:
|
|
2189
|
-
if end_latch
|
|
2190
|
-
end_latch
|
|
1935
|
+
if end_latch.current["fired_for"] != n:
|
|
1936
|
+
end_latch.current["fired_for"] = n
|
|
2191
1937
|
on_end_reached()
|
|
2192
1938
|
elif remaining > end_threshold * viewport + viewport:
|
|
2193
|
-
end_latch
|
|
1939
|
+
end_latch.current["fired_for"] = -1
|
|
2194
1940
|
|
|
2195
1941
|
if on_viewable is not None and n > 0:
|
|
2196
1942
|
v_first = max(0, bisect.bisect_right(starts, offset, 0, n) - 1)
|
|
2197
1943
|
v_last = min(n - 1, bisect.bisect_left(starts, offset + viewport, 0, n))
|
|
2198
1944
|
keys = tuple(rows[i].key for i in range(v_first, v_last + 1))
|
|
2199
|
-
if keys != viewable_ref
|
|
2200
|
-
viewable_ref
|
|
1945
|
+
if keys != viewable_ref.current["keys"]:
|
|
1946
|
+
viewable_ref.current["keys"] = keys
|
|
2201
1947
|
on_viewable(
|
|
2202
1948
|
[
|
|
2203
1949
|
{"index": rows[i].index, "key": rows[i].key, "item": rows[i].item}
|
|
@@ -2209,33 +1955,26 @@ def _VirtualizedList(**p: Any) -> Element:
|
|
|
2209
1955
|
user_on_scroll(payload)
|
|
2210
1956
|
|
|
2211
1957
|
# ------------------------------------------------------------------
|
|
2212
|
-
# Imperative controller (scroll_to_index / offset / end)
|
|
2213
|
-
# the user's ref
|
|
2214
|
-
# fresh extents
|
|
2215
|
-
# hook order stable.
|
|
1958
|
+
# Imperative controller (scroll_to_index / offset / end) published
|
|
1959
|
+
# on the user's ref. Rebuilt every render (deps=None) so the
|
|
1960
|
+
# closures see fresh extents.
|
|
2216
1961
|
# ------------------------------------------------------------------
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
if not isinstance(controller, dict):
|
|
2221
|
-
return
|
|
2222
|
-
|
|
2223
|
-
def scroll_to_offset(offset: float, animated: bool = True) -> None:
|
|
2224
|
-
axis = "x" if horizontal else "y"
|
|
2225
|
-
_dispatch_scroll_command(sv_ref, "scroll_to_offset", {axis: float(offset), "animated": animated})
|
|
2226
|
-
|
|
2227
|
-
def scroll_to_index(index: int, animated: bool = True) -> None:
|
|
2228
|
-
idx = max(0, min(int(index), n - 1)) if n else 0
|
|
2229
|
-
scroll_to_offset(starts[idx], animated)
|
|
1962
|
+
def _scroll_to_offset(offset: float, animated: bool = True) -> None:
|
|
1963
|
+
axis = "x" if horizontal else "y"
|
|
1964
|
+
_dispatch_scroll_command(sv_ref, "scroll_to_offset", {axis: float(offset), "animated": animated})
|
|
2230
1965
|
|
|
2231
|
-
|
|
2232
|
-
|
|
1966
|
+
def _scroll_to_index(index: int, animated: bool = True) -> None:
|
|
1967
|
+
idx = max(0, min(int(index), n - 1)) if n else 0
|
|
1968
|
+
_scroll_to_offset(starts[idx], animated)
|
|
2233
1969
|
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
controller["scroll_to_end"] = scroll_to_end
|
|
1970
|
+
def _scroll_to_end(animated: bool = True) -> None:
|
|
1971
|
+
_scroll_to_offset(max(0.0, total_extent - _viewport_extent()), animated)
|
|
2237
1972
|
|
|
2238
|
-
|
|
1973
|
+
use_imperative_handle(
|
|
1974
|
+
p.get("controller_ref"),
|
|
1975
|
+
lambda: ListController(_scroll_to_offset, _scroll_to_index, _scroll_to_end),
|
|
1976
|
+
None,
|
|
1977
|
+
)
|
|
2239
1978
|
|
|
2240
1979
|
# ------------------------------------------------------------------
|
|
2241
1980
|
# Children: header, leading spacer, windowed rows, trailing spacer,
|
|
@@ -2254,17 +1993,17 @@ def _VirtualizedList(**p: Any) -> Element:
|
|
|
2254
1993
|
if empty is not None:
|
|
2255
1994
|
children.append(View(empty, key="__pn_empty__"))
|
|
2256
1995
|
else:
|
|
2257
|
-
live_refs: Dict[str,
|
|
1996
|
+
live_refs: Dict[str, Ref] = {}
|
|
2258
1997
|
lead = starts[first]
|
|
2259
1998
|
if lead > 0:
|
|
2260
1999
|
lead_style: Dict[str, Any] = {spacer_key: lead}
|
|
2261
2000
|
children.append(View(style=lead_style, key="__pn_lead__"))
|
|
2262
2001
|
for i in range(first, last + 1):
|
|
2263
2002
|
spec = rows[i]
|
|
2264
|
-
row_ref = row_refs
|
|
2003
|
+
row_ref = row_refs.current.get(spec.key) or Ref()
|
|
2265
2004
|
live_refs[spec.key] = row_ref
|
|
2266
2005
|
children.append(View(spec.make(), ref=row_ref, key=spec.key))
|
|
2267
|
-
row_refs
|
|
2006
|
+
row_refs.current = live_refs
|
|
2268
2007
|
trail = total_extent - starts[last + 1]
|
|
2269
2008
|
if trail > 0:
|
|
2270
2009
|
trail_style: Dict[str, Any] = {spacer_key: trail}
|
|
@@ -2318,9 +2057,9 @@ def _NativeList(**p: Any) -> Element:
|
|
|
2318
2057
|
heights: List[float] = [float(spec.extent or 0.0) for spec in rows]
|
|
2319
2058
|
uniform = len(set(heights)) <= 1
|
|
2320
2059
|
|
|
2321
|
-
internal_ref = use_ref(None)
|
|
2060
|
+
internal_ref: Ref = use_ref(None)
|
|
2322
2061
|
end_latch = use_ref({"fired_for": -1})
|
|
2323
|
-
viewable_ref = use_ref({"keys": ()})
|
|
2062
|
+
viewable_ref: Ref[Dict[str, Tuple[str, ...]]] = use_ref({"keys": ()})
|
|
2324
2063
|
|
|
2325
2064
|
starts: List[float] = [0.0] * (n + 1)
|
|
2326
2065
|
acc = 0.0
|
|
@@ -2349,18 +2088,18 @@ def _NativeList(**p: Any) -> Element:
|
|
|
2349
2088
|
if on_end_reached is not None and total_extent > 0:
|
|
2350
2089
|
remaining = total_extent - (offset + viewport)
|
|
2351
2090
|
if remaining <= end_threshold * viewport:
|
|
2352
|
-
if end_latch
|
|
2353
|
-
end_latch
|
|
2091
|
+
if end_latch.current["fired_for"] != n:
|
|
2092
|
+
end_latch.current["fired_for"] = n
|
|
2354
2093
|
on_end_reached()
|
|
2355
2094
|
elif remaining > end_threshold * viewport + viewport:
|
|
2356
|
-
end_latch
|
|
2095
|
+
end_latch.current["fired_for"] = -1
|
|
2357
2096
|
|
|
2358
2097
|
if on_viewable is not None and n > 0:
|
|
2359
2098
|
v_first = max(0, bisect.bisect_right(starts, offset, 0, n) - 1)
|
|
2360
2099
|
v_last = min(n - 1, bisect.bisect_left(starts, offset + viewport, 0, n))
|
|
2361
2100
|
keys = tuple(rows[i].key for i in range(v_first, v_last + 1))
|
|
2362
|
-
if keys != viewable_ref
|
|
2363
|
-
viewable_ref
|
|
2101
|
+
if keys != viewable_ref.current["keys"]:
|
|
2102
|
+
viewable_ref.current["keys"] = keys
|
|
2364
2103
|
on_viewable(
|
|
2365
2104
|
[
|
|
2366
2105
|
{"index": rows[i].index, "key": rows[i].key, "item": rows[i].item}
|
|
@@ -2371,26 +2110,20 @@ def _NativeList(**p: Any) -> Element:
|
|
|
2371
2110
|
if user_on_scroll is not None:
|
|
2372
2111
|
user_on_scroll({"x": 0.0, "y": offset})
|
|
2373
2112
|
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
def _attach_controller() -> None:
|
|
2377
|
-
if not isinstance(controller, dict):
|
|
2378
|
-
return
|
|
2379
|
-
|
|
2380
|
-
def scroll_to_offset(offset: float, animated: bool = True) -> None:
|
|
2381
|
-
_dispatch_scroll_command(internal_ref, "scroll_to_offset", {"y": float(offset), "animated": animated})
|
|
2113
|
+
def _scroll_to_offset(offset: float, animated: bool = True) -> None:
|
|
2114
|
+
_dispatch_scroll_command(internal_ref, "scroll_to_offset", {"y": float(offset), "animated": animated})
|
|
2382
2115
|
|
|
2383
|
-
|
|
2384
|
-
|
|
2116
|
+
def _scroll_to_index(index: int, animated: bool = True) -> None:
|
|
2117
|
+
_dispatch_scroll_command(internal_ref, "scroll_to_index", {"index": int(index), "animated": animated})
|
|
2385
2118
|
|
|
2386
|
-
|
|
2387
|
-
|
|
2119
|
+
def _scroll_to_end(animated: bool = True) -> None:
|
|
2120
|
+
_dispatch_scroll_command(internal_ref, "scroll_to_end", {"animated": animated})
|
|
2388
2121
|
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2122
|
+
use_imperative_handle(
|
|
2123
|
+
p.get("controller_ref"),
|
|
2124
|
+
lambda: ListController(_scroll_to_offset, _scroll_to_index, _scroll_to_end),
|
|
2125
|
+
None,
|
|
2126
|
+
)
|
|
2394
2127
|
|
|
2395
2128
|
props: Dict[str, Any] = dict(p.get("list_style") or {})
|
|
2396
2129
|
props["count"] = n
|
|
@@ -2434,7 +2167,7 @@ def FlatList(
|
|
|
2434
2167
|
shows_scroll_indicator: bool = True,
|
|
2435
2168
|
content_container_style: StyleProp = None,
|
|
2436
2169
|
style: StyleProp = None,
|
|
2437
|
-
ref: Optional[
|
|
2170
|
+
ref: Optional[Ref] = None,
|
|
2438
2171
|
key: Optional[str] = None,
|
|
2439
2172
|
) -> Element:
|
|
2440
2173
|
"""Virtualized scrollable list that renders items from ``data`` lazily.
|
|
@@ -2447,10 +2180,12 @@ def FlatList(
|
|
|
2447
2180
|
unknown rows start at ``estimated_item_height`` and are corrected
|
|
2448
2181
|
with their measured extent once they've been on screen.
|
|
2449
2182
|
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2183
|
+
Pass a [`Ref`][pythonnative.Ref] (from
|
|
2184
|
+
[`use_ref`][pythonnative.use_ref]) to receive a
|
|
2185
|
+
[`ListController`][pythonnative.ListController] on ``ref.current``:
|
|
2186
|
+
``ref.current.scroll_to_index(i)``,
|
|
2187
|
+
``ref.current.scroll_to_offset(pts)``, and
|
|
2188
|
+
``ref.current.scroll_to_end()``.
|
|
2454
2189
|
|
|
2455
2190
|
Args:
|
|
2456
2191
|
data: List of arbitrary item values.
|
|
@@ -2485,8 +2220,9 @@ def FlatList(
|
|
|
2485
2220
|
content_container_style: Style applied to the inner content
|
|
2486
2221
|
wrapper.
|
|
2487
2222
|
style: Style for the outer scroll container.
|
|
2488
|
-
ref: Optional
|
|
2489
|
-
|
|
2223
|
+
ref: Optional [`Ref`][pythonnative.Ref]; receives a
|
|
2224
|
+
[`ListController`][pythonnative.ListController] on
|
|
2225
|
+
``ref.current`` after mount.
|
|
2490
2226
|
key: Stable identity for keyed reconciliation of the list.
|
|
2491
2227
|
|
|
2492
2228
|
Returns:
|
|
@@ -2630,7 +2366,7 @@ def SectionList(
|
|
|
2630
2366
|
on_end_reached_threshold: float = 0.5,
|
|
2631
2367
|
on_scroll: Optional[Callable[[Dict[str, float]], None]] = None,
|
|
2632
2368
|
style: StyleProp = None,
|
|
2633
|
-
ref: Optional[
|
|
2369
|
+
ref: Optional[Ref] = None,
|
|
2634
2370
|
key: Optional[str] = None,
|
|
2635
2371
|
) -> Element:
|
|
2636
2372
|
"""Virtualized list with section headers interleaved between row groups.
|
|
@@ -2664,8 +2400,9 @@ def SectionList(
|
|
|
2664
2400
|
multiples, at which ``on_end_reached`` fires.
|
|
2665
2401
|
on_scroll: Called with the raw scroll payload.
|
|
2666
2402
|
style: Style for the outer scroll container.
|
|
2667
|
-
ref: Optional
|
|
2668
|
-
|
|
2403
|
+
ref: Optional [`Ref`][pythonnative.Ref]; receives a
|
|
2404
|
+
[`ListController`][pythonnative.ListController] on
|
|
2405
|
+
``ref.current`` after mount.
|
|
2669
2406
|
key: Stable identity for keyed reconciliation of the list.
|
|
2670
2407
|
|
|
2671
2408
|
Returns:
|
|
@@ -2945,10 +2682,10 @@ def Picker(
|
|
|
2945
2682
|
accessibility_label: Optional[str] = None,
|
|
2946
2683
|
accessibility_hint: Optional[str] = None,
|
|
2947
2684
|
accessible: Optional[bool] = None,
|
|
2948
|
-
accessibility_state: Optional[
|
|
2685
|
+
accessibility_state: Optional[AccessibilityState] = None,
|
|
2949
2686
|
accessibility_live_region: Optional[Literal["none", "polite", "assertive"]] = None,
|
|
2950
2687
|
test_id: Optional[str] = None,
|
|
2951
|
-
ref: Optional[
|
|
2688
|
+
ref: Optional[Ref] = None,
|
|
2952
2689
|
key: Optional[str] = None,
|
|
2953
2690
|
) -> Element:
|
|
2954
2691
|
"""A real native dropdown / select widget.
|
|
@@ -2981,7 +2718,7 @@ def Picker(
|
|
|
2981
2718
|
test_id: Stable identifier for UI tests; exposed as
|
|
2982
2719
|
``resource-id`` on Android and ``accessibilityIdentifier``
|
|
2983
2720
|
on iOS.
|
|
2984
|
-
ref: Optional ``use_ref()
|
|
2721
|
+
ref: Optional [`Ref`][pythonnative.Ref] from ``use_ref()``.
|
|
2985
2722
|
key: Stable identity for keyed reconciliation.
|
|
2986
2723
|
|
|
2987
2724
|
Returns:
|