pythonnative 0.6.0__py3-none-any.whl → 0.8.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 +30 -19
- pythonnative/cli/pn.py +10 -18
- pythonnative/components.py +192 -347
- pythonnative/hooks.py +174 -21
- pythonnative/hot_reload.py +2 -2
- pythonnative/native_views/__init__.py +87 -0
- pythonnative/native_views/android.py +832 -0
- pythonnative/native_views/base.py +150 -0
- pythonnative/native_views/ios.py +777 -0
- pythonnative/navigation.py +571 -0
- pythonnative/page.py +178 -167
- pythonnative/reconciler.py +89 -1
- pythonnative/style.py +27 -7
- pythonnative/templates/android_template/app/src/main/java/com/pythonnative/android_template/PageFragment.kt +2 -9
- pythonnative/templates/ios_template/ios_template/ViewController.swift +7 -20
- {pythonnative-0.6.0.dist-info → pythonnative-0.8.0.dist-info}/METADATA +17 -20
- {pythonnative-0.6.0.dist-info → pythonnative-0.8.0.dist-info}/RECORD +21 -17
- pythonnative/native_views.py +0 -1334
- {pythonnative-0.6.0.dist-info → pythonnative-0.8.0.dist-info}/WHEEL +0 -0
- {pythonnative-0.6.0.dist-info → pythonnative-0.8.0.dist-info}/entry_points.txt +0 -0
- {pythonnative-0.6.0.dist-info → pythonnative-0.8.0.dist-info}/licenses/LICENSE +0 -0
- {pythonnative-0.6.0.dist-info → pythonnative-0.8.0.dist-info}/top_level.txt +0 -0
pythonnative/components.py
CHANGED
|
@@ -4,52 +4,29 @@ Each function returns an :class:`Element` describing a native UI widget.
|
|
|
4
4
|
These are pure data — no native views are created until the reconciler
|
|
5
5
|
mounts the element tree.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
``align_self``) are supported by all components.
|
|
10
|
-
"""
|
|
11
|
-
|
|
12
|
-
from typing import Any, Callable, Dict, List, Optional, Union
|
|
13
|
-
|
|
14
|
-
from .element import Element
|
|
7
|
+
All visual and layout properties are passed via the ``style`` parameter,
|
|
8
|
+
which accepts a dict or a list of dicts (later entries override earlier).
|
|
15
9
|
|
|
16
|
-
|
|
17
|
-
# Shared helpers
|
|
18
|
-
# ======================================================================
|
|
10
|
+
Layout properties supported by all components::
|
|
19
11
|
|
|
20
|
-
|
|
21
|
-
|
|
12
|
+
width, height, flex, flex_grow, flex_shrink, margin,
|
|
13
|
+
min_width, max_width, min_height, max_height, align_self
|
|
22
14
|
|
|
15
|
+
Flex container properties (View / Column / Row)::
|
|
23
16
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
return {k: v for k, v in kwargs.items() if v is not None}
|
|
17
|
+
flex_direction, justify_content, align_items, overflow,
|
|
18
|
+
spacing, padding
|
|
27
19
|
|
|
20
|
+
``View`` is the universal flex container (like React Native's ``View``).
|
|
21
|
+
It defaults to ``flex_direction: "column"``. ``Column`` and ``Row``
|
|
22
|
+
are convenience wrappers that fix the direction to ``"column"`` and
|
|
23
|
+
``"row"`` respectively.
|
|
24
|
+
"""
|
|
28
25
|
|
|
29
|
-
|
|
30
|
-
width: Optional[float] = None,
|
|
31
|
-
height: Optional[float] = None,
|
|
32
|
-
flex: Optional[float] = None,
|
|
33
|
-
margin: Optional[MarginValue] = None,
|
|
34
|
-
min_width: Optional[float] = None,
|
|
35
|
-
max_width: Optional[float] = None,
|
|
36
|
-
min_height: Optional[float] = None,
|
|
37
|
-
max_height: Optional[float] = None,
|
|
38
|
-
align_self: Optional[str] = None,
|
|
39
|
-
) -> Dict[str, Any]:
|
|
40
|
-
"""Collect common layout props into a dict (excluding Nones)."""
|
|
41
|
-
return _filter_none(
|
|
42
|
-
width=width,
|
|
43
|
-
height=height,
|
|
44
|
-
flex=flex,
|
|
45
|
-
margin=margin,
|
|
46
|
-
min_width=min_width,
|
|
47
|
-
max_width=max_width,
|
|
48
|
-
min_height=min_height,
|
|
49
|
-
max_height=max_height,
|
|
50
|
-
align_self=align_self,
|
|
51
|
-
)
|
|
26
|
+
from typing import Any, Callable, Dict, List, Optional
|
|
52
27
|
|
|
28
|
+
from .element import Element
|
|
29
|
+
from .style import StyleValue, resolve_style
|
|
53
30
|
|
|
54
31
|
# ======================================================================
|
|
55
32
|
# Leaf components
|
|
@@ -59,46 +36,16 @@ def _layout_props(
|
|
|
59
36
|
def Text(
|
|
60
37
|
text: str = "",
|
|
61
38
|
*,
|
|
62
|
-
|
|
63
|
-
color: Optional[str] = None,
|
|
64
|
-
bold: bool = False,
|
|
65
|
-
text_align: Optional[str] = None,
|
|
66
|
-
background_color: Optional[str] = None,
|
|
67
|
-
max_lines: Optional[int] = None,
|
|
68
|
-
width: Optional[float] = None,
|
|
69
|
-
height: Optional[float] = None,
|
|
70
|
-
flex: Optional[float] = None,
|
|
71
|
-
margin: Optional[MarginValue] = None,
|
|
72
|
-
min_width: Optional[float] = None,
|
|
73
|
-
max_width: Optional[float] = None,
|
|
74
|
-
min_height: Optional[float] = None,
|
|
75
|
-
max_height: Optional[float] = None,
|
|
76
|
-
align_self: Optional[str] = None,
|
|
39
|
+
style: StyleValue = None,
|
|
77
40
|
key: Optional[str] = None,
|
|
78
41
|
) -> Element:
|
|
79
|
-
"""Display text.
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
background_color=background_color,
|
|
87
|
-
max_lines=max_lines,
|
|
88
|
-
)
|
|
89
|
-
props.update(
|
|
90
|
-
_layout_props(
|
|
91
|
-
width=width,
|
|
92
|
-
height=height,
|
|
93
|
-
flex=flex,
|
|
94
|
-
margin=margin,
|
|
95
|
-
min_width=min_width,
|
|
96
|
-
max_width=max_width,
|
|
97
|
-
min_height=min_height,
|
|
98
|
-
max_height=max_height,
|
|
99
|
-
align_self=align_self,
|
|
100
|
-
)
|
|
101
|
-
)
|
|
42
|
+
"""Display text.
|
|
43
|
+
|
|
44
|
+
Style properties: ``font_size``, ``color``, ``bold``, ``text_align``,
|
|
45
|
+
``background_color``, ``max_lines``, plus common layout props.
|
|
46
|
+
"""
|
|
47
|
+
props: Dict[str, Any] = {"text": text}
|
|
48
|
+
props.update(resolve_style(style))
|
|
102
49
|
return Element("Text", props, [], key=key)
|
|
103
50
|
|
|
104
51
|
|
|
@@ -106,46 +53,21 @@ def Button(
|
|
|
106
53
|
title: str = "",
|
|
107
54
|
*,
|
|
108
55
|
on_click: Optional[Callable[[], None]] = None,
|
|
109
|
-
color: Optional[str] = None,
|
|
110
|
-
background_color: Optional[str] = None,
|
|
111
|
-
font_size: Optional[float] = None,
|
|
112
56
|
enabled: bool = True,
|
|
113
|
-
|
|
114
|
-
height: Optional[float] = None,
|
|
115
|
-
flex: Optional[float] = None,
|
|
116
|
-
margin: Optional[MarginValue] = None,
|
|
117
|
-
min_width: Optional[float] = None,
|
|
118
|
-
max_width: Optional[float] = None,
|
|
119
|
-
min_height: Optional[float] = None,
|
|
120
|
-
max_height: Optional[float] = None,
|
|
121
|
-
align_self: Optional[str] = None,
|
|
57
|
+
style: StyleValue = None,
|
|
122
58
|
key: Optional[str] = None,
|
|
123
59
|
) -> Element:
|
|
124
|
-
"""Create a tappable button.
|
|
60
|
+
"""Create a tappable button.
|
|
61
|
+
|
|
62
|
+
Style properties: ``color``, ``background_color``, ``font_size``,
|
|
63
|
+
plus common layout props.
|
|
64
|
+
"""
|
|
125
65
|
props: Dict[str, Any] = {"title": title}
|
|
126
66
|
if on_click is not None:
|
|
127
67
|
props["on_click"] = on_click
|
|
128
|
-
if color is not None:
|
|
129
|
-
props["color"] = color
|
|
130
|
-
if background_color is not None:
|
|
131
|
-
props["background_color"] = background_color
|
|
132
|
-
if font_size is not None:
|
|
133
|
-
props["font_size"] = font_size
|
|
134
68
|
if not enabled:
|
|
135
69
|
props["enabled"] = False
|
|
136
|
-
props.update(
|
|
137
|
-
_layout_props(
|
|
138
|
-
width=width,
|
|
139
|
-
height=height,
|
|
140
|
-
flex=flex,
|
|
141
|
-
margin=margin,
|
|
142
|
-
min_width=min_width,
|
|
143
|
-
max_width=max_width,
|
|
144
|
-
min_height=min_height,
|
|
145
|
-
max_height=max_height,
|
|
146
|
-
align_self=align_self,
|
|
147
|
-
)
|
|
148
|
-
)
|
|
70
|
+
props.update(resolve_style(style))
|
|
149
71
|
return Element("Button", props, [], key=key)
|
|
150
72
|
|
|
151
73
|
|
|
@@ -155,21 +77,14 @@ def TextInput(
|
|
|
155
77
|
placeholder: str = "",
|
|
156
78
|
on_change: Optional[Callable[[str], None]] = None,
|
|
157
79
|
secure: bool = False,
|
|
158
|
-
|
|
159
|
-
color: Optional[str] = None,
|
|
160
|
-
background_color: Optional[str] = None,
|
|
161
|
-
width: Optional[float] = None,
|
|
162
|
-
height: Optional[float] = None,
|
|
163
|
-
flex: Optional[float] = None,
|
|
164
|
-
margin: Optional[MarginValue] = None,
|
|
165
|
-
min_width: Optional[float] = None,
|
|
166
|
-
max_width: Optional[float] = None,
|
|
167
|
-
min_height: Optional[float] = None,
|
|
168
|
-
max_height: Optional[float] = None,
|
|
169
|
-
align_self: Optional[str] = None,
|
|
80
|
+
style: StyleValue = None,
|
|
170
81
|
key: Optional[str] = None,
|
|
171
82
|
) -> Element:
|
|
172
|
-
"""Create a single-line text entry field.
|
|
83
|
+
"""Create a single-line text entry field.
|
|
84
|
+
|
|
85
|
+
Style properties: ``font_size``, ``color``, ``background_color``,
|
|
86
|
+
plus common layout props.
|
|
87
|
+
"""
|
|
173
88
|
props: Dict[str, Any] = {"value": value}
|
|
174
89
|
if placeholder:
|
|
175
90
|
props["placeholder"] = placeholder
|
|
@@ -177,63 +92,27 @@ def TextInput(
|
|
|
177
92
|
props["on_change"] = on_change
|
|
178
93
|
if secure:
|
|
179
94
|
props["secure"] = True
|
|
180
|
-
|
|
181
|
-
props["font_size"] = font_size
|
|
182
|
-
if color is not None:
|
|
183
|
-
props["color"] = color
|
|
184
|
-
if background_color is not None:
|
|
185
|
-
props["background_color"] = background_color
|
|
186
|
-
props.update(
|
|
187
|
-
_layout_props(
|
|
188
|
-
width=width,
|
|
189
|
-
height=height,
|
|
190
|
-
flex=flex,
|
|
191
|
-
margin=margin,
|
|
192
|
-
min_width=min_width,
|
|
193
|
-
max_width=max_width,
|
|
194
|
-
min_height=min_height,
|
|
195
|
-
max_height=max_height,
|
|
196
|
-
align_self=align_self,
|
|
197
|
-
)
|
|
198
|
-
)
|
|
95
|
+
props.update(resolve_style(style))
|
|
199
96
|
return Element("TextInput", props, [], key=key)
|
|
200
97
|
|
|
201
98
|
|
|
202
99
|
def Image(
|
|
203
100
|
source: str = "",
|
|
204
101
|
*,
|
|
205
|
-
width: Optional[float] = None,
|
|
206
|
-
height: Optional[float] = None,
|
|
207
102
|
scale_type: Optional[str] = None,
|
|
208
|
-
|
|
209
|
-
flex: Optional[float] = None,
|
|
210
|
-
margin: Optional[MarginValue] = None,
|
|
211
|
-
min_width: Optional[float] = None,
|
|
212
|
-
max_width: Optional[float] = None,
|
|
213
|
-
min_height: Optional[float] = None,
|
|
214
|
-
max_height: Optional[float] = None,
|
|
215
|
-
align_self: Optional[str] = None,
|
|
103
|
+
style: StyleValue = None,
|
|
216
104
|
key: Optional[str] = None,
|
|
217
105
|
) -> Element:
|
|
218
|
-
"""Display an image from a resource path or URL.
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
flex=flex,
|
|
229
|
-
margin=margin,
|
|
230
|
-
min_width=min_width,
|
|
231
|
-
max_width=max_width,
|
|
232
|
-
min_height=min_height,
|
|
233
|
-
max_height=max_height,
|
|
234
|
-
align_self=align_self,
|
|
235
|
-
)
|
|
236
|
-
)
|
|
106
|
+
"""Display an image from a resource path or URL.
|
|
107
|
+
|
|
108
|
+
Style properties: ``background_color``, plus common layout props.
|
|
109
|
+
"""
|
|
110
|
+
props: Dict[str, Any] = {}
|
|
111
|
+
if source:
|
|
112
|
+
props["source"] = source
|
|
113
|
+
if scale_type is not None:
|
|
114
|
+
props["scale_type"] = scale_type
|
|
115
|
+
props.update(resolve_style(style))
|
|
237
116
|
return Element("Image", props, [], key=key)
|
|
238
117
|
|
|
239
118
|
|
|
@@ -241,68 +120,52 @@ def Switch(
|
|
|
241
120
|
*,
|
|
242
121
|
value: bool = False,
|
|
243
122
|
on_change: Optional[Callable[[bool], None]] = None,
|
|
244
|
-
|
|
245
|
-
height: Optional[float] = None,
|
|
246
|
-
flex: Optional[float] = None,
|
|
247
|
-
margin: Optional[MarginValue] = None,
|
|
248
|
-
align_self: Optional[str] = None,
|
|
123
|
+
style: StyleValue = None,
|
|
249
124
|
key: Optional[str] = None,
|
|
250
125
|
) -> Element:
|
|
251
126
|
"""Create a toggle switch."""
|
|
252
127
|
props: Dict[str, Any] = {"value": value}
|
|
253
128
|
if on_change is not None:
|
|
254
129
|
props["on_change"] = on_change
|
|
255
|
-
props.update(
|
|
130
|
+
props.update(resolve_style(style))
|
|
256
131
|
return Element("Switch", props, [], key=key)
|
|
257
132
|
|
|
258
133
|
|
|
259
134
|
def ProgressBar(
|
|
260
135
|
*,
|
|
261
136
|
value: float = 0.0,
|
|
262
|
-
|
|
263
|
-
width: Optional[float] = None,
|
|
264
|
-
height: Optional[float] = None,
|
|
265
|
-
flex: Optional[float] = None,
|
|
266
|
-
margin: Optional[MarginValue] = None,
|
|
267
|
-
align_self: Optional[str] = None,
|
|
137
|
+
style: StyleValue = None,
|
|
268
138
|
key: Optional[str] = None,
|
|
269
139
|
) -> Element:
|
|
270
140
|
"""Show determinate progress (0.0 – 1.0)."""
|
|
271
|
-
props =
|
|
272
|
-
props.update(
|
|
141
|
+
props: Dict[str, Any] = {"value": value}
|
|
142
|
+
props.update(resolve_style(style))
|
|
273
143
|
return Element("ProgressBar", props, [], key=key)
|
|
274
144
|
|
|
275
145
|
|
|
276
146
|
def ActivityIndicator(
|
|
277
147
|
*,
|
|
278
148
|
animating: bool = True,
|
|
279
|
-
|
|
280
|
-
height: Optional[float] = None,
|
|
281
|
-
margin: Optional[MarginValue] = None,
|
|
282
|
-
align_self: Optional[str] = None,
|
|
149
|
+
style: StyleValue = None,
|
|
283
150
|
key: Optional[str] = None,
|
|
284
151
|
) -> Element:
|
|
285
152
|
"""Show an indeterminate loading spinner."""
|
|
286
153
|
props: Dict[str, Any] = {"animating": animating}
|
|
287
|
-
props.update(
|
|
154
|
+
props.update(resolve_style(style))
|
|
288
155
|
return Element("ActivityIndicator", props, [], key=key)
|
|
289
156
|
|
|
290
157
|
|
|
291
158
|
def WebView(
|
|
292
159
|
*,
|
|
293
160
|
url: str = "",
|
|
294
|
-
|
|
295
|
-
height: Optional[float] = None,
|
|
296
|
-
flex: Optional[float] = None,
|
|
297
|
-
margin: Optional[MarginValue] = None,
|
|
298
|
-
align_self: Optional[str] = None,
|
|
161
|
+
style: StyleValue = None,
|
|
299
162
|
key: Optional[str] = None,
|
|
300
163
|
) -> Element:
|
|
301
164
|
"""Embed web content."""
|
|
302
165
|
props: Dict[str, Any] = {}
|
|
303
166
|
if url:
|
|
304
167
|
props["url"] = url
|
|
305
|
-
props.update(
|
|
168
|
+
props.update(resolve_style(style))
|
|
306
169
|
return Element("WebView", props, [], key=key)
|
|
307
170
|
|
|
308
171
|
|
|
@@ -312,158 +175,147 @@ def Spacer(
|
|
|
312
175
|
flex: Optional[float] = None,
|
|
313
176
|
key: Optional[str] = None,
|
|
314
177
|
) -> Element:
|
|
315
|
-
"""Insert empty space with an optional fixed size."""
|
|
316
|
-
props
|
|
178
|
+
"""Insert empty space with an optional fixed size or flex weight."""
|
|
179
|
+
props: Dict[str, Any] = {}
|
|
180
|
+
if size is not None:
|
|
181
|
+
props["size"] = size
|
|
182
|
+
if flex is not None:
|
|
183
|
+
props["flex"] = flex
|
|
317
184
|
return Element("Spacer", props, [], key=key)
|
|
318
185
|
|
|
319
186
|
|
|
187
|
+
def Slider(
|
|
188
|
+
*,
|
|
189
|
+
value: float = 0.0,
|
|
190
|
+
min_value: float = 0.0,
|
|
191
|
+
max_value: float = 1.0,
|
|
192
|
+
on_change: Optional[Callable[[float], None]] = None,
|
|
193
|
+
style: StyleValue = None,
|
|
194
|
+
key: Optional[str] = None,
|
|
195
|
+
) -> Element:
|
|
196
|
+
"""Continuous value slider."""
|
|
197
|
+
props: Dict[str, Any] = {
|
|
198
|
+
"value": value,
|
|
199
|
+
"min_value": min_value,
|
|
200
|
+
"max_value": max_value,
|
|
201
|
+
}
|
|
202
|
+
if on_change is not None:
|
|
203
|
+
props["on_change"] = on_change
|
|
204
|
+
props.update(resolve_style(style))
|
|
205
|
+
return Element("Slider", props, [], key=key)
|
|
206
|
+
|
|
207
|
+
|
|
320
208
|
# ======================================================================
|
|
321
209
|
# Container components
|
|
322
210
|
# ======================================================================
|
|
323
211
|
|
|
324
212
|
|
|
213
|
+
def View(
|
|
214
|
+
*children: Element,
|
|
215
|
+
style: StyleValue = None,
|
|
216
|
+
key: Optional[str] = None,
|
|
217
|
+
) -> Element:
|
|
218
|
+
"""Universal flex container (like React Native's ``View``).
|
|
219
|
+
|
|
220
|
+
Defaults to ``flex_direction: "column"``. Override via ``style``::
|
|
221
|
+
|
|
222
|
+
pn.View(child_a, child_b, style={"flex_direction": "row"})
|
|
223
|
+
|
|
224
|
+
Flex container properties (inside ``style``):
|
|
225
|
+
|
|
226
|
+
- ``flex_direction`` — ``"column"`` (default), ``"row"``,
|
|
227
|
+
``"column_reverse"``, ``"row_reverse"``
|
|
228
|
+
- ``justify_content`` — main-axis distribution:
|
|
229
|
+
``"flex_start"`` (default), ``"center"``, ``"flex_end"``,
|
|
230
|
+
``"space_between"``, ``"space_around"``, ``"space_evenly"``
|
|
231
|
+
- ``align_items`` — cross-axis alignment:
|
|
232
|
+
``"stretch"`` (default), ``"flex_start"``, ``"center"``,
|
|
233
|
+
``"flex_end"``
|
|
234
|
+
- ``overflow`` — ``"visible"`` (default) or ``"hidden"``
|
|
235
|
+
- ``spacing``, ``padding``, ``background_color``
|
|
236
|
+
"""
|
|
237
|
+
props: Dict[str, Any] = {"flex_direction": "column"}
|
|
238
|
+
props.update(resolve_style(style))
|
|
239
|
+
return Element("View", props, list(children), key=key)
|
|
240
|
+
|
|
241
|
+
|
|
325
242
|
def Column(
|
|
326
243
|
*children: Element,
|
|
327
|
-
|
|
328
|
-
padding: Optional[PaddingValue] = None,
|
|
329
|
-
alignment: Optional[str] = None,
|
|
330
|
-
background_color: Optional[str] = None,
|
|
331
|
-
width: Optional[float] = None,
|
|
332
|
-
height: Optional[float] = None,
|
|
333
|
-
flex: Optional[float] = None,
|
|
334
|
-
margin: Optional[MarginValue] = None,
|
|
335
|
-
min_width: Optional[float] = None,
|
|
336
|
-
max_width: Optional[float] = None,
|
|
337
|
-
min_height: Optional[float] = None,
|
|
338
|
-
max_height: Optional[float] = None,
|
|
339
|
-
align_self: Optional[str] = None,
|
|
244
|
+
style: StyleValue = None,
|
|
340
245
|
key: Optional[str] = None,
|
|
341
246
|
) -> Element:
|
|
342
|
-
"""Arrange children vertically
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
props.
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
247
|
+
"""Arrange children vertically (``flex_direction: "column"``).
|
|
248
|
+
|
|
249
|
+
Convenience wrapper around :func:`View`. The direction is fixed;
|
|
250
|
+
use :func:`View` directly if you need ``flex_direction: "row"``.
|
|
251
|
+
|
|
252
|
+
Style properties: ``spacing``, ``padding``, ``align_items``,
|
|
253
|
+
``justify_content``, ``background_color``, ``overflow``,
|
|
254
|
+
plus common layout props.
|
|
255
|
+
|
|
256
|
+
``align_items`` controls cross-axis (horizontal) alignment:
|
|
257
|
+
``"stretch"`` (default), ``"flex_start"``/``"leading"``,
|
|
258
|
+
``"center"``, ``"flex_end"``/``"trailing"``.
|
|
259
|
+
|
|
260
|
+
``justify_content`` controls main-axis (vertical) distribution:
|
|
261
|
+
``"flex_start"`` (default), ``"center"``, ``"flex_end"``,
|
|
262
|
+
``"space_between"``, ``"space_around"``, ``"space_evenly"``.
|
|
263
|
+
"""
|
|
264
|
+
props: Dict[str, Any] = {"flex_direction": "column"}
|
|
265
|
+
props.update(resolve_style(style))
|
|
266
|
+
props["flex_direction"] = "column"
|
|
362
267
|
return Element("Column", props, list(children), key=key)
|
|
363
268
|
|
|
364
269
|
|
|
365
270
|
def Row(
|
|
366
271
|
*children: Element,
|
|
367
|
-
|
|
368
|
-
padding: Optional[PaddingValue] = None,
|
|
369
|
-
alignment: Optional[str] = None,
|
|
370
|
-
background_color: Optional[str] = None,
|
|
371
|
-
width: Optional[float] = None,
|
|
372
|
-
height: Optional[float] = None,
|
|
373
|
-
flex: Optional[float] = None,
|
|
374
|
-
margin: Optional[MarginValue] = None,
|
|
375
|
-
min_width: Optional[float] = None,
|
|
376
|
-
max_width: Optional[float] = None,
|
|
377
|
-
min_height: Optional[float] = None,
|
|
378
|
-
max_height: Optional[float] = None,
|
|
379
|
-
align_self: Optional[str] = None,
|
|
272
|
+
style: StyleValue = None,
|
|
380
273
|
key: Optional[str] = None,
|
|
381
274
|
) -> Element:
|
|
382
|
-
"""Arrange children horizontally
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
props.
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
275
|
+
"""Arrange children horizontally (``flex_direction: "row"``).
|
|
276
|
+
|
|
277
|
+
Convenience wrapper around :func:`View`. The direction is fixed;
|
|
278
|
+
use :func:`View` directly if you need ``flex_direction: "column"``.
|
|
279
|
+
|
|
280
|
+
Style properties: ``spacing``, ``padding``, ``align_items``,
|
|
281
|
+
``justify_content``, ``background_color``, ``overflow``,
|
|
282
|
+
plus common layout props.
|
|
283
|
+
|
|
284
|
+
``align_items`` controls cross-axis (vertical) alignment:
|
|
285
|
+
``"stretch"`` (default), ``"flex_start"``/``"top"``,
|
|
286
|
+
``"center"``, ``"flex_end"``/``"bottom"``.
|
|
287
|
+
|
|
288
|
+
``justify_content`` controls main-axis (horizontal) distribution:
|
|
289
|
+
``"flex_start"`` (default), ``"center"``, ``"flex_end"``,
|
|
290
|
+
``"space_between"``, ``"space_around"``, ``"space_evenly"``.
|
|
291
|
+
"""
|
|
292
|
+
props: Dict[str, Any] = {"flex_direction": "row"}
|
|
293
|
+
props.update(resolve_style(style))
|
|
294
|
+
props["flex_direction"] = "row"
|
|
402
295
|
return Element("Row", props, list(children), key=key)
|
|
403
296
|
|
|
404
297
|
|
|
405
298
|
def ScrollView(
|
|
406
299
|
child: Optional[Element] = None,
|
|
407
300
|
*,
|
|
408
|
-
|
|
409
|
-
width: Optional[float] = None,
|
|
410
|
-
height: Optional[float] = None,
|
|
411
|
-
flex: Optional[float] = None,
|
|
412
|
-
margin: Optional[MarginValue] = None,
|
|
413
|
-
align_self: Optional[str] = None,
|
|
301
|
+
style: StyleValue = None,
|
|
414
302
|
key: Optional[str] = None,
|
|
415
303
|
) -> Element:
|
|
416
304
|
"""Wrap a single child in a scrollable container."""
|
|
417
305
|
children = [child] if child is not None else []
|
|
418
|
-
props =
|
|
419
|
-
props.update(
|
|
306
|
+
props: Dict[str, Any] = {}
|
|
307
|
+
props.update(resolve_style(style))
|
|
420
308
|
return Element("ScrollView", props, children, key=key)
|
|
421
309
|
|
|
422
310
|
|
|
423
|
-
def View(
|
|
424
|
-
*children: Element,
|
|
425
|
-
background_color: Optional[str] = None,
|
|
426
|
-
padding: Optional[PaddingValue] = None,
|
|
427
|
-
width: Optional[float] = None,
|
|
428
|
-
height: Optional[float] = None,
|
|
429
|
-
flex: Optional[float] = None,
|
|
430
|
-
margin: Optional[MarginValue] = None,
|
|
431
|
-
min_width: Optional[float] = None,
|
|
432
|
-
max_width: Optional[float] = None,
|
|
433
|
-
min_height: Optional[float] = None,
|
|
434
|
-
max_height: Optional[float] = None,
|
|
435
|
-
align_self: Optional[str] = None,
|
|
436
|
-
key: Optional[str] = None,
|
|
437
|
-
) -> Element:
|
|
438
|
-
"""Generic container view (``UIView`` / ``android.view.View``)."""
|
|
439
|
-
props = _filter_none(
|
|
440
|
-
background_color=background_color,
|
|
441
|
-
padding=padding,
|
|
442
|
-
)
|
|
443
|
-
props.update(
|
|
444
|
-
_layout_props(
|
|
445
|
-
width=width,
|
|
446
|
-
height=height,
|
|
447
|
-
flex=flex,
|
|
448
|
-
margin=margin,
|
|
449
|
-
min_width=min_width,
|
|
450
|
-
max_width=max_width,
|
|
451
|
-
min_height=min_height,
|
|
452
|
-
max_height=max_height,
|
|
453
|
-
align_self=align_self,
|
|
454
|
-
)
|
|
455
|
-
)
|
|
456
|
-
return Element("View", props, list(children), key=key)
|
|
457
|
-
|
|
458
|
-
|
|
459
311
|
def SafeAreaView(
|
|
460
312
|
*children: Element,
|
|
461
|
-
|
|
462
|
-
padding: Optional[PaddingValue] = None,
|
|
313
|
+
style: StyleValue = None,
|
|
463
314
|
key: Optional[str] = None,
|
|
464
315
|
) -> Element:
|
|
465
316
|
"""Container that respects safe area insets (notch, status bar)."""
|
|
466
|
-
props
|
|
317
|
+
props: Dict[str, Any] = {}
|
|
318
|
+
props.update(resolve_style(style))
|
|
467
319
|
return Element("SafeAreaView", props, list(children), key=key)
|
|
468
320
|
|
|
469
321
|
|
|
@@ -472,7 +324,7 @@ def Modal(
|
|
|
472
324
|
visible: bool = False,
|
|
473
325
|
on_dismiss: Optional[Callable[[], None]] = None,
|
|
474
326
|
title: Optional[str] = None,
|
|
475
|
-
|
|
327
|
+
style: StyleValue = None,
|
|
476
328
|
key: Optional[str] = None,
|
|
477
329
|
) -> Element:
|
|
478
330
|
"""Overlay modal dialog.
|
|
@@ -484,34 +336,10 @@ def Modal(
|
|
|
484
336
|
props["on_dismiss"] = on_dismiss
|
|
485
337
|
if title is not None:
|
|
486
338
|
props["title"] = title
|
|
487
|
-
|
|
488
|
-
props["background_color"] = background_color
|
|
339
|
+
props.update(resolve_style(style))
|
|
489
340
|
return Element("Modal", props, list(children), key=key)
|
|
490
341
|
|
|
491
342
|
|
|
492
|
-
def Slider(
|
|
493
|
-
*,
|
|
494
|
-
value: float = 0.0,
|
|
495
|
-
min_value: float = 0.0,
|
|
496
|
-
max_value: float = 1.0,
|
|
497
|
-
on_change: Optional[Callable[[float], None]] = None,
|
|
498
|
-
width: Optional[float] = None,
|
|
499
|
-
margin: Optional[MarginValue] = None,
|
|
500
|
-
align_self: Optional[str] = None,
|
|
501
|
-
key: Optional[str] = None,
|
|
502
|
-
) -> Element:
|
|
503
|
-
"""Continuous value slider."""
|
|
504
|
-
props: Dict[str, Any] = {
|
|
505
|
-
"value": value,
|
|
506
|
-
"min_value": min_value,
|
|
507
|
-
"max_value": max_value,
|
|
508
|
-
}
|
|
509
|
-
if on_change is not None:
|
|
510
|
-
props["on_change"] = on_change
|
|
511
|
-
props.update(_layout_props(width=width, margin=margin, align_self=align_self))
|
|
512
|
-
return Element("Slider", props, [], key=key)
|
|
513
|
-
|
|
514
|
-
|
|
515
343
|
def Pressable(
|
|
516
344
|
child: Optional[Element] = None,
|
|
517
345
|
*,
|
|
@@ -529,26 +357,43 @@ def Pressable(
|
|
|
529
357
|
return Element("Pressable", props, children, key=key)
|
|
530
358
|
|
|
531
359
|
|
|
360
|
+
def ErrorBoundary(
|
|
361
|
+
child: Optional[Element] = None,
|
|
362
|
+
*,
|
|
363
|
+
fallback: Optional[Any] = None,
|
|
364
|
+
key: Optional[str] = None,
|
|
365
|
+
) -> Element:
|
|
366
|
+
"""Catch render errors in *child* and display *fallback* instead.
|
|
367
|
+
|
|
368
|
+
*fallback* may be an ``Element`` or a callable that receives the
|
|
369
|
+
exception and returns an ``Element``::
|
|
370
|
+
|
|
371
|
+
pn.ErrorBoundary(
|
|
372
|
+
MyRiskyComponent(),
|
|
373
|
+
fallback=lambda err: pn.Text(f"Error: {err}"),
|
|
374
|
+
)
|
|
375
|
+
"""
|
|
376
|
+
props: Dict[str, Any] = {}
|
|
377
|
+
if fallback is not None:
|
|
378
|
+
props["__fallback__"] = fallback
|
|
379
|
+
children = [child] if child is not None else []
|
|
380
|
+
return Element("__ErrorBoundary__", props, children, key=key)
|
|
381
|
+
|
|
382
|
+
|
|
532
383
|
def FlatList(
|
|
533
384
|
*,
|
|
534
385
|
data: Optional[List[Any]] = None,
|
|
535
386
|
render_item: Optional[Callable[[Any, int], Element]] = None,
|
|
536
387
|
key_extractor: Optional[Callable[[Any, int], str]] = None,
|
|
537
388
|
separator_height: float = 0,
|
|
538
|
-
|
|
539
|
-
width: Optional[float] = None,
|
|
540
|
-
height: Optional[float] = None,
|
|
541
|
-
flex: Optional[float] = None,
|
|
542
|
-
margin: Optional[MarginValue] = None,
|
|
543
|
-
align_self: Optional[str] = None,
|
|
389
|
+
style: StyleValue = None,
|
|
544
390
|
key: Optional[str] = None,
|
|
545
391
|
) -> Element:
|
|
546
392
|
"""Scrollable list that renders items from *data* using *render_item*.
|
|
547
393
|
|
|
548
394
|
Each item is rendered by calling ``render_item(item, index)``. If
|
|
549
395
|
``key_extractor`` is provided, it is called as ``key_extractor(item, index)``
|
|
550
|
-
to produce a stable key for each child element.
|
|
551
|
-
reconciler to preserve widget state across data changes.
|
|
396
|
+
to produce a stable key for each child element.
|
|
552
397
|
"""
|
|
553
398
|
items: List[Element] = []
|
|
554
399
|
for i, item in enumerate(data or []):
|
|
@@ -557,7 +402,7 @@ def FlatList(
|
|
|
557
402
|
el = Element(el.type, el.props, el.children, key=key_extractor(item, i))
|
|
558
403
|
items.append(el)
|
|
559
404
|
|
|
560
|
-
inner = Column(*items, spacing
|
|
561
|
-
sv_props =
|
|
562
|
-
sv_props.update(
|
|
405
|
+
inner = Column(*items, style={"spacing": separator_height} if separator_height else None)
|
|
406
|
+
sv_props: Dict[str, Any] = {}
|
|
407
|
+
sv_props.update(resolve_style(style))
|
|
563
408
|
return Element("ScrollView", sv_props, [inner], key=key)
|