dara-components 1.8.5__py3-none-any.whl → 1.22.1__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.
- dara/components/__init__.py +18 -0
- dara/components/_assets/__init__.py +30 -0
- dara/components/_assets/auto_js/.gitkeep +0 -0
- dara/components/_assets/auto_js/dara.components.css +1494 -0
- dara/components/_assets/auto_js/dara.components.umd.js +182837 -0
- dara/components/_assets/common/bokeh-3.1.1.min.js +690 -0
- dara/components/_assets/common/bokeh-api-3.1.1.min.js +60 -0
- dara/components/_assets/common/bokeh-gl-3.1.1.min.js +67 -0
- dara/components/_assets/common/bokeh-mathjax-3.1.1.min.js +329 -0
- dara/components/_assets/common/bokeh-tables-3.1.1.min.js +132 -0
- dara/components/_assets/common/bokeh-widgets-3.1.1.min.js +129 -0
- dara/components/_assets/common/pixi-filters.min.js +17 -0
- dara/components/_assets/common/pixi.min.js +2214 -0
- dara/components/_assets/common/pixi_viewport.js +1 -0
- dara/components/_assets/common/plotly.min.js +8 -0
- dara/components/common/__init__.py +11 -2
- dara/components/common/accordion.py +20 -26
- dara/components/common/anchor.py +9 -10
- dara/components/common/base_component.py +23 -36
- dara/components/common/bullet_list.py +1 -3
- dara/components/common/button.py +35 -26
- dara/components/common/button_bar.py +25 -20
- dara/components/common/card.py +4 -5
- dara/components/common/carousel.py +9 -9
- dara/components/common/checkbox_group.py +26 -19
- dara/components/common/code.py +8 -5
- dara/components/common/component_select_list.py +9 -13
- dara/components/common/datepicker.py +16 -16
- dara/components/common/dropdown_menu.py +161 -0
- dara/components/common/dropzone.py +42 -33
- dara/components/common/form.py +5 -7
- dara/components/common/form_page.py +4 -6
- dara/components/common/grid.py +21 -18
- dara/components/common/heading.py +5 -4
- dara/components/common/icon.py +1 -3
- dara/components/common/if_cmp.py +23 -17
- dara/components/common/image.py +2 -2
- dara/components/common/input.py +9 -11
- dara/components/common/label.py +13 -14
- dara/components/common/markdown.py +3 -5
- dara/components/common/modal.py +2 -2
- dara/components/common/overlay.py +8 -14
- dara/components/common/paragraph.py +2 -2
- dara/components/common/progress_bar.py +6 -8
- dara/components/common/radio_group.py +38 -21
- dara/components/common/select.py +33 -30
- dara/components/common/slider.py +74 -29
- dara/components/common/spacer.py +4 -6
- dara/components/common/stack.py +7 -4
- dara/components/common/switch.py +6 -8
- dara/components/common/tabbed_card.py +8 -11
- dara/components/common/table.py +224 -73
- dara/components/common/text.py +7 -9
- dara/components/common/textarea.py +7 -7
- dara/components/common/time_utils.py +2 -5
- dara/components/common/tooltip.py +4 -6
- dara/components/common/utils.py +29 -35
- dara/components/graphs/__init__.py +1 -0
- dara/components/graphs/components/base_graph_component.py +34 -22
- dara/components/graphs/components/causal_graph_viewer.py +13 -15
- dara/components/graphs/components/edge_encoder.py +49 -26
- dara/components/graphs/components/node_hierarchy_builder.py +17 -16
- dara/components/graphs/definitions.py +27 -20
- dara/components/graphs/graph_layout.py +90 -53
- dara/components/plotting/__init__.py +2 -1
- dara/components/plotting/bokeh/bokeh.py +7 -10
- dara/components/plotting/bokeh/utils.py +5 -3
- dara/components/plotting/plotly/plotly.py +24 -19
- dara/components/plotting/plotly/themes.py +7 -5
- dara/components/smart/__init__.py +7 -1
- dara/components/smart/chat/chat.py +7 -8
- dara/components/smart/chat/config.py +1 -1
- dara/components/smart/chat/types.py +4 -6
- dara/components/smart/code_editor/code_editor.py +18 -4
- dara/components/smart/code_editor/util.py +11 -11
- dara/components/smart/data_slicer/__init__.py +4 -0
- dara/components/smart/data_slicer/data_slicer.py +14 -18
- dara/components/smart/data_slicer/data_slicer_modal.py +4 -6
- dara/components/smart/data_slicer/extension/data_slicer_filter.py +3 -4
- dara/components/smart/data_slicer/extension/filter_status_button.py +1 -3
- dara/components/smart/data_slicer/utils/core.py +23 -23
- dara/components/smart/data_slicer/utils/data_preview.py +1 -3
- dara/components/smart/data_slicer/utils/plotting.py +8 -6
- dara/components/smart/hierarchy.py +9 -10
- {dara_components-1.8.5.dist-info → dara_components-1.22.1.dist-info}/METADATA +7 -7
- dara_components-1.22.1.dist-info/RECORD +100 -0
- {dara_components-1.8.5.dist-info → dara_components-1.22.1.dist-info}/WHEEL +1 -1
- dara_components-1.22.1.dist-info/entry_points.txt +3 -0
- dara/components/umd/dara.components.umd.js +0 -396288
- dara/components/umd/style.css +0 -745
- dara_components-1.8.5.dist-info/RECORD +0 -86
- {dara_components-1.8.5.dist-info → dara_components-1.22.1.dist-info}/LICENSE +0 -0
|
@@ -16,10 +16,9 @@ limitations under the License.
|
|
|
16
16
|
"""
|
|
17
17
|
|
|
18
18
|
import re
|
|
19
|
-
from typing import Union
|
|
20
19
|
|
|
21
20
|
from dara.components.common.base_component import ContentComponent
|
|
22
|
-
from dara.core.interactivity import
|
|
21
|
+
from dara.core.interactivity import ClientVariable
|
|
23
22
|
|
|
24
23
|
|
|
25
24
|
class Heading(ContentComponent):
|
|
@@ -69,12 +68,14 @@ class Heading(ContentComponent):
|
|
|
69
68
|
:param level: The level of heading to display, defaults to 1
|
|
70
69
|
"""
|
|
71
70
|
|
|
72
|
-
heading:
|
|
71
|
+
heading: str | ClientVariable
|
|
73
72
|
level: int = 1
|
|
74
73
|
|
|
75
74
|
@property
|
|
76
75
|
def anchor_name(self):
|
|
76
|
+
if isinstance(self.heading, ClientVariable):
|
|
77
|
+
raise ValueError('Heading anchor name cannot be accessed directly from a variable')
|
|
77
78
|
return re.sub(r'\s+', '-', self.heading.lower())
|
|
78
79
|
|
|
79
|
-
def __init__(self, heading:
|
|
80
|
+
def __init__(self, heading: str | ClientVariable, **kwargs):
|
|
80
81
|
super().__init__(heading=heading, **kwargs)
|
dara/components/common/icon.py
CHANGED
|
@@ -15,8 +15,6 @@ See the License for the specific language governing permissions and
|
|
|
15
15
|
limitations under the License.
|
|
16
16
|
"""
|
|
17
17
|
|
|
18
|
-
from typing import Optional
|
|
19
|
-
|
|
20
18
|
from dara.components.common.base_component import ContentComponent
|
|
21
19
|
|
|
22
20
|
|
|
@@ -65,4 +63,4 @@ class Icon(ContentComponent):
|
|
|
65
63
|
"""
|
|
66
64
|
|
|
67
65
|
icon: str
|
|
68
|
-
color:
|
|
66
|
+
color: str | None = None
|
dara/components/common/if_cmp.py
CHANGED
|
@@ -15,22 +15,25 @@ See the License for the specific language governing permissions and
|
|
|
15
15
|
limitations under the License.
|
|
16
16
|
"""
|
|
17
17
|
|
|
18
|
-
from typing import
|
|
18
|
+
from typing import ClassVar
|
|
19
19
|
|
|
20
|
-
from pydantic import
|
|
20
|
+
from pydantic import field_validator
|
|
21
21
|
|
|
22
22
|
from dara.components.common.base_component import ModifierComponent
|
|
23
|
-
from dara.core.definitions import ComponentInstance
|
|
23
|
+
from dara.core.definitions import ComponentInstance
|
|
24
24
|
from dara.core.interactivity import AnyVariable, Condition, Operator
|
|
25
25
|
|
|
26
26
|
|
|
27
|
-
def cast_list(value:
|
|
27
|
+
def cast_list(value: ComponentInstance | list[ComponentInstance | None]) -> list[ComponentInstance]:
|
|
28
28
|
"""
|
|
29
29
|
Cast the value to a list if it is not or return original list if it is.
|
|
30
30
|
|
|
31
31
|
:param value: the value to cast
|
|
32
32
|
"""
|
|
33
|
-
return value if isinstance(value,
|
|
33
|
+
return [v for v in value if v is not None] if isinstance(value, list) else [value]
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
ConditionType = type[Condition]
|
|
34
37
|
|
|
35
38
|
|
|
36
39
|
class If(ModifierComponent):
|
|
@@ -44,16 +47,17 @@ class If(ModifierComponent):
|
|
|
44
47
|
An If component is created like so, in this example it is comparing the values of two variables:
|
|
45
48
|
|
|
46
49
|
```python
|
|
47
|
-
|
|
48
50
|
from dara.core import Variable
|
|
49
51
|
from dara.components.common import If, Text
|
|
50
52
|
|
|
53
|
+
var_1 = Variable(True)
|
|
54
|
+
var_2 = Variable(False)
|
|
55
|
+
|
|
51
56
|
If(
|
|
52
|
-
condition=
|
|
57
|
+
condition=var_1 == var_2,
|
|
53
58
|
true_children=Text('Equal'),
|
|
54
59
|
false_children=Text('Different')
|
|
55
60
|
)
|
|
56
|
-
|
|
57
61
|
```
|
|
58
62
|
|
|
59
63
|
:param condition: a condition object
|
|
@@ -62,12 +66,12 @@ class If(ModifierComponent):
|
|
|
62
66
|
"""
|
|
63
67
|
|
|
64
68
|
condition: Condition
|
|
65
|
-
true_children:
|
|
66
|
-
false_children:
|
|
69
|
+
true_children: list[ComponentInstance]
|
|
70
|
+
false_children: list[ComponentInstance]
|
|
67
71
|
|
|
68
|
-
Condition = Condition
|
|
72
|
+
Condition: ClassVar[ConditionType] = Condition
|
|
69
73
|
|
|
70
|
-
@
|
|
74
|
+
@field_validator('condition')
|
|
71
75
|
@classmethod
|
|
72
76
|
def validate_condition(cls, value):
|
|
73
77
|
if not isinstance(value, Condition):
|
|
@@ -81,15 +85,17 @@ class If(ModifierComponent):
|
|
|
81
85
|
|
|
82
86
|
def __init__(
|
|
83
87
|
self,
|
|
84
|
-
condition:
|
|
85
|
-
true_children:
|
|
86
|
-
false_children:
|
|
88
|
+
condition: Condition | AnyVariable, # type: ignore
|
|
89
|
+
true_children: ComponentInstance | list[ComponentInstance | None],
|
|
90
|
+
false_children: ComponentInstance | list[ComponentInstance | None] | None = None,
|
|
87
91
|
):
|
|
88
92
|
if false_children is None:
|
|
89
93
|
false_children = []
|
|
90
|
-
if isinstance(condition,
|
|
94
|
+
if isinstance(condition, AnyVariable):
|
|
91
95
|
condition = Condition(operator=Operator.TRUTHY, other=None, variable=condition)
|
|
92
96
|
|
|
93
97
|
super().__init__(
|
|
94
|
-
condition=condition,
|
|
98
|
+
condition=condition,
|
|
99
|
+
true_children=cast_list(true_children),
|
|
100
|
+
false_children=cast_list(false_children), # type: ignore
|
|
95
101
|
)
|
dara/components/common/image.py
CHANGED
|
@@ -15,7 +15,7 @@ See the License for the specific language governing permissions and
|
|
|
15
15
|
limitations under the License.
|
|
16
16
|
"""
|
|
17
17
|
|
|
18
|
-
from pydantic import
|
|
18
|
+
from pydantic import field_validator
|
|
19
19
|
|
|
20
20
|
from dara.components.common.base_component import ContentComponent
|
|
21
21
|
|
|
@@ -57,7 +57,7 @@ class Image(ContentComponent):
|
|
|
57
57
|
|
|
58
58
|
src: str
|
|
59
59
|
|
|
60
|
-
@
|
|
60
|
+
@field_validator('src')
|
|
61
61
|
@classmethod
|
|
62
62
|
def validate_src(cls, value: str):
|
|
63
63
|
if not value.startswith('/static/') and not value.startswith('http'):
|
dara/components/common/input.py
CHANGED
|
@@ -15,8 +15,6 @@ See the License for the specific language governing permissions and
|
|
|
15
15
|
limitations under the License.
|
|
16
16
|
"""
|
|
17
17
|
|
|
18
|
-
from typing import Optional
|
|
19
|
-
|
|
20
18
|
from dara.components.common.base_component import FormComponent
|
|
21
19
|
from dara.core.base_definitions import Action
|
|
22
20
|
from dara.core.interactivity import Variable
|
|
@@ -32,23 +30,23 @@ class Input(FormComponent):
|
|
|
32
30
|
An Input component is created via:
|
|
33
31
|
|
|
34
32
|
```python
|
|
35
|
-
|
|
36
33
|
from dara.core import Variable
|
|
37
34
|
from dara.components.common import Input
|
|
38
35
|
|
|
39
|
-
|
|
36
|
+
value_var = Variable('initial input value')
|
|
40
37
|
|
|
38
|
+
Input(value=value_var)
|
|
41
39
|
```
|
|
42
40
|
|
|
43
41
|
You could define a numerical input with the following:
|
|
44
42
|
|
|
45
43
|
```python
|
|
46
|
-
|
|
47
44
|
from dara.core import Variable
|
|
48
45
|
from dara.components.common import Input
|
|
49
46
|
|
|
50
|
-
|
|
47
|
+
value_var = Variable(0)
|
|
51
48
|
|
|
49
|
+
Input(value=value_var, type='number')
|
|
52
50
|
```
|
|
53
51
|
|
|
54
52
|
:param value: A Variable instance recording the component's state
|
|
@@ -58,8 +56,8 @@ class Input(FormComponent):
|
|
|
58
56
|
:param id: the key to be used if this component is within a form
|
|
59
57
|
"""
|
|
60
58
|
|
|
61
|
-
id:
|
|
62
|
-
placeholder:
|
|
63
|
-
type:
|
|
64
|
-
onchange:
|
|
65
|
-
value:
|
|
59
|
+
id: str | None = None
|
|
60
|
+
placeholder: str | None = None
|
|
61
|
+
type: str | None = None
|
|
62
|
+
onchange: Action | None = None
|
|
63
|
+
value: Variable | None = None
|
dara/components/common/label.py
CHANGED
|
@@ -15,9 +15,7 @@ See the License for the specific language governing permissions and
|
|
|
15
15
|
limitations under the License.
|
|
16
16
|
"""
|
|
17
17
|
|
|
18
|
-
from
|
|
19
|
-
|
|
20
|
-
from pydantic import validator
|
|
18
|
+
from pydantic import field_validator
|
|
21
19
|
|
|
22
20
|
from dara.components.common.base_component import ContentComponent
|
|
23
21
|
from dara.core.definitions import ComponentInstance
|
|
@@ -33,29 +31,31 @@ class Label(ContentComponent):
|
|
|
33
31
|
Example of a simple Label component:
|
|
34
32
|
|
|
35
33
|
```python
|
|
36
|
-
|
|
34
|
+
from dara.core import Variable
|
|
37
35
|
from dara.components.common import Label, Input
|
|
38
36
|
|
|
37
|
+
value_var = Variable()
|
|
38
|
+
|
|
39
39
|
Label(
|
|
40
|
-
Input(),
|
|
40
|
+
Input(value=value_var),
|
|
41
41
|
value='My Input:',
|
|
42
42
|
direction='horizontal',
|
|
43
43
|
)
|
|
44
|
-
|
|
45
44
|
```
|
|
46
45
|
|
|
47
46
|
For further customization you can also pass a ComponentInstance to the value param:
|
|
48
47
|
|
|
49
48
|
```python
|
|
49
|
+
from dara.core import Variable
|
|
50
|
+
from dara.components.common import Label, Input, Heading
|
|
50
51
|
|
|
51
|
-
|
|
52
|
+
value_var = Variable()
|
|
52
53
|
|
|
53
54
|
Label(
|
|
54
|
-
Input(),
|
|
55
|
+
Input(value=value_var),
|
|
55
56
|
value=Heading('My Input:', level=2),
|
|
56
57
|
direction='horizontal',
|
|
57
58
|
)
|
|
58
|
-
|
|
59
59
|
```
|
|
60
60
|
|
|
61
61
|
:param value: A label to be presented with the child component, accepts a string or ComponentInstance
|
|
@@ -63,14 +63,13 @@ class Label(ContentComponent):
|
|
|
63
63
|
:param label_width: A optional string containing the width the label should take
|
|
64
64
|
"""
|
|
65
65
|
|
|
66
|
-
value:
|
|
66
|
+
value: str | ComponentInstance
|
|
67
67
|
direction: Direction = Direction.VERTICAL
|
|
68
|
-
label_width:
|
|
68
|
+
label_width: str | None = None
|
|
69
69
|
|
|
70
|
-
@
|
|
70
|
+
@field_validator('children')
|
|
71
71
|
@classmethod
|
|
72
|
-
def validate_only_one_child(cls, children:
|
|
73
|
-
|
|
72
|
+
def validate_only_one_child(cls, children: list[ComponentInstance]) -> list[ComponentInstance]:
|
|
74
73
|
if len(children) > 1:
|
|
75
74
|
raise TypeError(
|
|
76
75
|
'More than one component was passed to the Label component. Label accepts only one child component'
|
|
@@ -15,10 +15,8 @@ See the License for the specific language governing permissions and
|
|
|
15
15
|
limitations under the License.
|
|
16
16
|
"""
|
|
17
17
|
|
|
18
|
-
from typing import Union
|
|
19
|
-
|
|
20
18
|
from dara.components.common.base_component import BaseDashboardComponent
|
|
21
|
-
from dara.core.interactivity import
|
|
19
|
+
from dara.core.interactivity import ClientVariable
|
|
22
20
|
|
|
23
21
|
|
|
24
22
|
class Markdown(BaseDashboardComponent):
|
|
@@ -42,8 +40,8 @@ class Markdown(BaseDashboardComponent):
|
|
|
42
40
|
if the markdown is user-provided
|
|
43
41
|
"""
|
|
44
42
|
|
|
45
|
-
markdown:
|
|
43
|
+
markdown: ClientVariable | str
|
|
46
44
|
html_raw: bool = False
|
|
47
45
|
|
|
48
|
-
def __init__(self, markdown:
|
|
46
|
+
def __init__(self, markdown: ClientVariable | str, html_raw: bool = False, **kwargs):
|
|
49
47
|
super().__init__(markdown=markdown, html_raw=html_raw, **kwargs)
|
dara/components/common/modal.py
CHANGED
|
@@ -16,7 +16,7 @@ limitations under the License.
|
|
|
16
16
|
"""
|
|
17
17
|
|
|
18
18
|
from dara.components.common.base_component import LayoutComponent
|
|
19
|
-
from dara.core.interactivity import
|
|
19
|
+
from dara.core.interactivity import ClientVariable
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
class Modal(LayoutComponent):
|
|
@@ -47,4 +47,4 @@ class Modal(LayoutComponent):
|
|
|
47
47
|
:param align: How to align the content of the modal, accepts any flexbox alignments
|
|
48
48
|
"""
|
|
49
49
|
|
|
50
|
-
show:
|
|
50
|
+
show: ClientVariable
|
|
@@ -15,12 +15,10 @@ See the License for the specific language governing permissions and
|
|
|
15
15
|
limitations under the License.
|
|
16
16
|
"""
|
|
17
17
|
|
|
18
|
-
from
|
|
19
|
-
|
|
20
|
-
from pydantic import validator
|
|
18
|
+
from pydantic import field_validator
|
|
21
19
|
|
|
22
20
|
from dara.components.common.base_component import LayoutComponent
|
|
23
|
-
from dara.core.interactivity import
|
|
21
|
+
from dara.core.interactivity import ClientVariable
|
|
24
22
|
|
|
25
23
|
|
|
26
24
|
class Overlay(LayoutComponent):
|
|
@@ -43,20 +41,16 @@ class Overlay(LayoutComponent):
|
|
|
43
41
|
|
|
44
42
|
:param show: Boolean Variable instance recording the state, if True it renders the overlay and its' children
|
|
45
43
|
:param position: the position of the overlay; can be top-left, top-right, bottom-left, bottom-right
|
|
46
|
-
:param padding: the padding around the overlay elements passed a string; can also be passed as individual side's padding in css shorthand format
|
|
47
|
-
:param margin: the margin property to shift the overlay in any direction passed as a string; can also be passed as individual side's margin in css shorthand format
|
|
48
44
|
"""
|
|
49
45
|
|
|
50
|
-
show:
|
|
51
|
-
padding: Optional[str] = None
|
|
52
|
-
margin: Optional[str] = None
|
|
46
|
+
show: ClientVariable | None = None
|
|
53
47
|
|
|
54
|
-
@
|
|
48
|
+
@field_validator('position')
|
|
55
49
|
@classmethod
|
|
56
|
-
def validate_position(cls,
|
|
50
|
+
def validate_position(cls, value) -> str:
|
|
57
51
|
position_list = ['top-left', 'top-right', 'bottom-left', 'bottom-right']
|
|
58
|
-
if
|
|
52
|
+
if value not in position_list:
|
|
59
53
|
raise ValueError(
|
|
60
|
-
f'Invalid position: {
|
|
54
|
+
f'Invalid position: {value}, position should be one of the following values: {position_list}'
|
|
61
55
|
)
|
|
62
|
-
return
|
|
56
|
+
return value
|
|
@@ -15,7 +15,7 @@ See the License for the specific language governing permissions and
|
|
|
15
15
|
limitations under the License.
|
|
16
16
|
"""
|
|
17
17
|
|
|
18
|
-
from pydantic import
|
|
18
|
+
from pydantic import field_validator
|
|
19
19
|
|
|
20
20
|
from dara.components.common.anchor import Anchor
|
|
21
21
|
from dara.components.common.base_component import LayoutComponent, LayoutError
|
|
@@ -66,7 +66,7 @@ class Paragraph(LayoutComponent):
|
|
|
66
66
|
|
|
67
67
|
"""
|
|
68
68
|
|
|
69
|
-
@
|
|
69
|
+
@field_validator('children')
|
|
70
70
|
@classmethod
|
|
71
71
|
def validate_children(cls, children):
|
|
72
72
|
for child in children:
|
|
@@ -15,12 +15,10 @@ See the License for the specific language governing permissions and
|
|
|
15
15
|
limitations under the License.
|
|
16
16
|
"""
|
|
17
17
|
|
|
18
|
-
from
|
|
19
|
-
|
|
20
|
-
from pydantic import validator
|
|
18
|
+
from pydantic import field_validator
|
|
21
19
|
|
|
22
20
|
from dara.components.common.base_component import ContentComponent
|
|
23
|
-
from dara.core.interactivity import
|
|
21
|
+
from dara.core.interactivity import ClientVariable
|
|
24
22
|
|
|
25
23
|
|
|
26
24
|
class ProgressBar(ContentComponent):
|
|
@@ -48,13 +46,13 @@ class ProgressBar(ContentComponent):
|
|
|
48
46
|
:param color: Optional color property for the progress bar, this should be the hex value of the color.
|
|
49
47
|
"""
|
|
50
48
|
|
|
51
|
-
progress:
|
|
49
|
+
progress: int | ClientVariable
|
|
52
50
|
small: bool = False
|
|
53
|
-
color:
|
|
51
|
+
color: str | None = None
|
|
54
52
|
|
|
55
|
-
@
|
|
53
|
+
@field_validator('progress')
|
|
56
54
|
@classmethod
|
|
57
55
|
def validate_progress(cls, progress):
|
|
58
|
-
if not isinstance(progress, (int,
|
|
56
|
+
if not isinstance(progress, (int, ClientVariable)):
|
|
59
57
|
raise ValueError('Progress must be an int or Variable')
|
|
60
58
|
return progress
|
|
@@ -15,17 +15,23 @@ See the License for the specific language governing permissions and
|
|
|
15
15
|
limitations under the License.
|
|
16
16
|
"""
|
|
17
17
|
|
|
18
|
-
from typing import Any
|
|
18
|
+
from typing import Any
|
|
19
19
|
|
|
20
|
-
from pydantic import
|
|
20
|
+
from pydantic import field_validator
|
|
21
|
+
from typing_extensions import TypedDict
|
|
21
22
|
|
|
22
23
|
from dara.components.common.base_component import FormComponent
|
|
23
|
-
from dara.components.common.utils import Item
|
|
24
24
|
from dara.core.base_definitions import Action
|
|
25
|
-
from dara.core.
|
|
25
|
+
from dara.core.definitions import ComponentInstance
|
|
26
|
+
from dara.core.interactivity import ClientVariable, Variable
|
|
26
27
|
from dara.core.visual.components.types import Direction
|
|
27
28
|
|
|
28
29
|
|
|
30
|
+
class RadioItem(TypedDict):
|
|
31
|
+
value: Any
|
|
32
|
+
label: str | ComponentInstance
|
|
33
|
+
|
|
34
|
+
|
|
29
35
|
class RadioGroup(FormComponent):
|
|
30
36
|
"""
|
|
31
37
|

|
|
@@ -36,19 +42,32 @@ class RadioGroup(FormComponent):
|
|
|
36
42
|
Simple RadioGroup component:
|
|
37
43
|
|
|
38
44
|
```python
|
|
45
|
+
from dara.core import Variable
|
|
46
|
+
from dara.components import RadioGroup, RadioItem, Text
|
|
39
47
|
|
|
40
|
-
|
|
48
|
+
value_var_str = Variable('first')
|
|
41
49
|
|
|
42
50
|
# you can pass items as a list of values
|
|
43
51
|
RadioGroup(
|
|
44
52
|
items=['first', 'second'],
|
|
45
|
-
value=
|
|
53
|
+
value=value_var_str,
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
value_var_num = Variable(1)
|
|
57
|
+
|
|
58
|
+
# or as an `RadioItem` list
|
|
59
|
+
RadioGroup(
|
|
60
|
+
items=[RadioItem(label='first',value=1), Item(label='second',value=2)],
|
|
61
|
+
value=value_var_num,
|
|
46
62
|
)
|
|
47
63
|
|
|
48
|
-
# or as an `
|
|
64
|
+
# or as an `RadioItem` list with arbitrary components
|
|
49
65
|
RadioGroup(
|
|
50
|
-
items=[
|
|
51
|
-
|
|
66
|
+
items=[
|
|
67
|
+
RadioItem(label=Text(text='first', color='red'), value=1),
|
|
68
|
+
RadioItem(label=Text(text='second', color='blue'), value=2)
|
|
69
|
+
],
|
|
70
|
+
value=value_var_num,
|
|
52
71
|
)
|
|
53
72
|
```
|
|
54
73
|
|
|
@@ -59,7 +78,7 @@ class RadioGroup(FormComponent):
|
|
|
59
78
|
|
|
60
79
|
RadioGroup(
|
|
61
80
|
items=['first', 'second'],
|
|
62
|
-
value=
|
|
81
|
+
value=value_var_str,
|
|
63
82
|
direction='horizontal'
|
|
64
83
|
)
|
|
65
84
|
```
|
|
@@ -72,20 +91,18 @@ class RadioGroup(FormComponent):
|
|
|
72
91
|
:param id: the key to be used if this component is within a form
|
|
73
92
|
"""
|
|
74
93
|
|
|
75
|
-
items:
|
|
76
|
-
value:
|
|
77
|
-
list_styling:
|
|
78
|
-
onchange:
|
|
94
|
+
items: list[RadioItem] | list[str] | ClientVariable
|
|
95
|
+
value: Variable[Any] | None = None
|
|
96
|
+
list_styling: bool | None = False
|
|
97
|
+
onchange: Action | None = None
|
|
79
98
|
direction: Direction = Direction.VERTICAL
|
|
80
|
-
id:
|
|
99
|
+
id: str | None = None
|
|
81
100
|
|
|
82
|
-
@
|
|
101
|
+
@field_validator('items', mode='before')
|
|
83
102
|
@classmethod
|
|
84
|
-
def validate_items(cls, items: Any) ->
|
|
85
|
-
if isinstance(items,
|
|
103
|
+
def validate_items(cls, items: Any) -> list[RadioItem] | ClientVariable:
|
|
104
|
+
if isinstance(items, ClientVariable):
|
|
86
105
|
return items
|
|
87
|
-
if not isinstance(items, list):
|
|
88
|
-
raise ValueError('Items must be passed as a list to the RadioGroup component')
|
|
89
106
|
if len(items) == 0:
|
|
90
107
|
raise ValueError('Items list is empty, you must provide at least one item')
|
|
91
|
-
return [
|
|
108
|
+
return [RadioItem(value=item, label=item) if isinstance(item, str) else item for item in items]
|
dara/components/common/select.py
CHANGED
|
@@ -15,14 +15,15 @@ See the License for the specific language governing permissions and
|
|
|
15
15
|
limitations under the License.
|
|
16
16
|
"""
|
|
17
17
|
|
|
18
|
-
from typing import Any
|
|
18
|
+
from typing import Any
|
|
19
19
|
|
|
20
|
-
from pydantic import
|
|
20
|
+
from pydantic import ValidationInfo, field_validator
|
|
21
21
|
|
|
22
22
|
from dara.components.common.base_component import FormComponent
|
|
23
23
|
from dara.components.common.utils import Item
|
|
24
24
|
from dara.core.base_definitions import Action
|
|
25
|
-
from dara.core.
|
|
25
|
+
from dara.core.base_definitions import DaraBaseModel as BaseModel
|
|
26
|
+
from dara.core.interactivity import ClientVariable, Variable
|
|
26
27
|
from dara.core.logging import dev_logger
|
|
27
28
|
|
|
28
29
|
|
|
@@ -35,11 +36,11 @@ class ListSection(BaseModel):
|
|
|
35
36
|
"""
|
|
36
37
|
|
|
37
38
|
label: str
|
|
38
|
-
items:
|
|
39
|
+
items: list[Item | str | dict]
|
|
39
40
|
|
|
40
|
-
@
|
|
41
|
+
@field_validator('items')
|
|
41
42
|
@classmethod
|
|
42
|
-
def validate_items(cls, items: Any) ->
|
|
43
|
+
def validate_items(cls, items: Any) -> list[Item]:
|
|
43
44
|
if len(items) == 0:
|
|
44
45
|
raise ValueError('Items of ListSection was empty, you must provide at least one item to the component')
|
|
45
46
|
return [Item.to_item(item) for item in items]
|
|
@@ -58,55 +59,59 @@ class Select(FormComponent):
|
|
|
58
59
|
A Select component is created via:
|
|
59
60
|
|
|
60
61
|
```python
|
|
61
|
-
|
|
62
62
|
from dara.core import Variable
|
|
63
63
|
from dara.components.common import Select
|
|
64
64
|
|
|
65
|
+
selection_var = Variable('first')
|
|
66
|
+
|
|
65
67
|
Select(
|
|
66
|
-
value=
|
|
68
|
+
value=selection_var,
|
|
67
69
|
items=['first', 'second', 'third'],
|
|
68
70
|
)
|
|
69
|
-
|
|
70
71
|
```
|
|
71
72
|
|
|
72
73
|
A searchable Select component is created via:
|
|
73
74
|
|
|
74
75
|
```python
|
|
75
|
-
|
|
76
76
|
from dara.core import Variable
|
|
77
77
|
from dara.components.common import Select
|
|
78
78
|
|
|
79
|
+
selection_var = Variable('first')
|
|
80
|
+
|
|
79
81
|
Select(
|
|
80
|
-
value=
|
|
82
|
+
value=selection_var,
|
|
81
83
|
items=['first', 'second', 'third'],
|
|
82
84
|
searchable=True,
|
|
83
85
|
)
|
|
84
|
-
|
|
85
86
|
```
|
|
86
87
|
|
|
87
88
|
A more complicated example with explicit item labels/values that allows multiple items to be selected at the same time:
|
|
88
89
|
|
|
89
90
|
```python
|
|
90
|
-
|
|
91
91
|
from dara.core import Variable
|
|
92
92
|
from dara.components.common import Select, Item
|
|
93
93
|
|
|
94
|
+
selection_var = Variable([1, 2])
|
|
95
|
+
|
|
94
96
|
Select(
|
|
95
97
|
items=[Item(label='first',value=1), Item(label='second',value=2)],
|
|
96
|
-
value=
|
|
98
|
+
value=selection_var,
|
|
97
99
|
multiselect=True
|
|
98
100
|
)
|
|
99
|
-
|
|
100
101
|
```
|
|
101
102
|
|
|
102
|
-
Example of using a
|
|
103
|
+
Example of using a select component to allow selections in a sectioned list:
|
|
103
104
|
|
|
104
105
|
```python
|
|
106
|
+
from dara.core import Variable
|
|
105
107
|
from dara.components.common import Select, ListSection
|
|
106
108
|
|
|
109
|
+
selection_var = Variable()
|
|
110
|
+
|
|
107
111
|
Select(
|
|
108
112
|
items=[ListSection(label='Section 1', items=['1 item 1', '1 item 2', '1 item 3']), ListSection(label='Section 2', items=['2 item 1', '2 item 2'])],
|
|
109
113
|
searchable=True,
|
|
114
|
+
value=selection_var,
|
|
110
115
|
)
|
|
111
116
|
```
|
|
112
117
|
|
|
@@ -120,21 +125,21 @@ class Select(FormComponent):
|
|
|
120
125
|
:param value: A Variable instance recording the component's state
|
|
121
126
|
"""
|
|
122
127
|
|
|
123
|
-
id:
|
|
128
|
+
id: str | None = None
|
|
124
129
|
multiselect: bool = False
|
|
125
130
|
searchable: bool = False
|
|
126
|
-
items:
|
|
131
|
+
items: list[Item | ListSection] | ClientVariable
|
|
127
132
|
max_rows: int = 3
|
|
128
|
-
onchange:
|
|
129
|
-
placeholder:
|
|
130
|
-
value:
|
|
133
|
+
onchange: Action | None = None
|
|
134
|
+
placeholder: str | None = None
|
|
135
|
+
value: Variable[Any] | None = None
|
|
131
136
|
|
|
132
|
-
@
|
|
137
|
+
@field_validator('items', mode='before')
|
|
133
138
|
@classmethod
|
|
134
|
-
def validate_items(cls, items: Any,
|
|
135
|
-
multiselect =
|
|
136
|
-
searchable =
|
|
137
|
-
if isinstance(items,
|
|
139
|
+
def validate_items(cls, items: Any, info: ValidationInfo) -> list[Item | ListSection] | ClientVariable:
|
|
140
|
+
multiselect = info.data.get('multiselect')
|
|
141
|
+
searchable = info.data.get('searchable')
|
|
142
|
+
if isinstance(items, ClientVariable):
|
|
138
143
|
return items
|
|
139
144
|
if not isinstance(items, list):
|
|
140
145
|
raise ValueError('Items must be passed as a list to the select component')
|
|
@@ -151,19 +156,17 @@ class Select(FormComponent):
|
|
|
151
156
|
return [Item.to_item(item) for item in items]
|
|
152
157
|
|
|
153
158
|
|
|
154
|
-
def _parse_item(item: Any, return_listsection: bool = False):
|
|
159
|
+
def _parse_item(item: Any, return_listsection: bool = False) -> Item | ListSection:
|
|
155
160
|
"""
|
|
156
161
|
Converts items to Item objects for a SectionedList. Can return a ListSection for a dictionary if
|
|
157
162
|
return_listsection is set to True.
|
|
158
163
|
"""
|
|
159
|
-
if isinstance(item, list):
|
|
160
|
-
return [_parse_item(subitem) for subitem in item]
|
|
161
164
|
if isinstance(item, dict):
|
|
162
165
|
if return_listsection and item.get('label') is not None and item.get('items') is not None:
|
|
163
166
|
items = item.get('items')
|
|
164
167
|
if not isinstance(items, list):
|
|
165
168
|
raise ValueError(f"Dictionary 'items' value for SectionedList must be a list, got {items}")
|
|
166
|
-
return ListSection(label=str(item.get('label')), items=
|
|
169
|
+
return ListSection(label=str(item.get('label')), items=[Item.to_item(subitem) for subitem in items])
|
|
167
170
|
return Item.to_item(item)
|
|
168
171
|
if isinstance(item, ListSection):
|
|
169
172
|
return item
|