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.
Files changed (92) hide show
  1. dara/components/__init__.py +18 -0
  2. dara/components/_assets/__init__.py +30 -0
  3. dara/components/_assets/auto_js/.gitkeep +0 -0
  4. dara/components/_assets/auto_js/dara.components.css +1494 -0
  5. dara/components/_assets/auto_js/dara.components.umd.js +182837 -0
  6. dara/components/_assets/common/bokeh-3.1.1.min.js +690 -0
  7. dara/components/_assets/common/bokeh-api-3.1.1.min.js +60 -0
  8. dara/components/_assets/common/bokeh-gl-3.1.1.min.js +67 -0
  9. dara/components/_assets/common/bokeh-mathjax-3.1.1.min.js +329 -0
  10. dara/components/_assets/common/bokeh-tables-3.1.1.min.js +132 -0
  11. dara/components/_assets/common/bokeh-widgets-3.1.1.min.js +129 -0
  12. dara/components/_assets/common/pixi-filters.min.js +17 -0
  13. dara/components/_assets/common/pixi.min.js +2214 -0
  14. dara/components/_assets/common/pixi_viewport.js +1 -0
  15. dara/components/_assets/common/plotly.min.js +8 -0
  16. dara/components/common/__init__.py +11 -2
  17. dara/components/common/accordion.py +20 -26
  18. dara/components/common/anchor.py +9 -10
  19. dara/components/common/base_component.py +23 -36
  20. dara/components/common/bullet_list.py +1 -3
  21. dara/components/common/button.py +35 -26
  22. dara/components/common/button_bar.py +25 -20
  23. dara/components/common/card.py +4 -5
  24. dara/components/common/carousel.py +9 -9
  25. dara/components/common/checkbox_group.py +26 -19
  26. dara/components/common/code.py +8 -5
  27. dara/components/common/component_select_list.py +9 -13
  28. dara/components/common/datepicker.py +16 -16
  29. dara/components/common/dropdown_menu.py +161 -0
  30. dara/components/common/dropzone.py +42 -33
  31. dara/components/common/form.py +5 -7
  32. dara/components/common/form_page.py +4 -6
  33. dara/components/common/grid.py +21 -18
  34. dara/components/common/heading.py +5 -4
  35. dara/components/common/icon.py +1 -3
  36. dara/components/common/if_cmp.py +23 -17
  37. dara/components/common/image.py +2 -2
  38. dara/components/common/input.py +9 -11
  39. dara/components/common/label.py +13 -14
  40. dara/components/common/markdown.py +3 -5
  41. dara/components/common/modal.py +2 -2
  42. dara/components/common/overlay.py +8 -14
  43. dara/components/common/paragraph.py +2 -2
  44. dara/components/common/progress_bar.py +6 -8
  45. dara/components/common/radio_group.py +38 -21
  46. dara/components/common/select.py +33 -30
  47. dara/components/common/slider.py +74 -29
  48. dara/components/common/spacer.py +4 -6
  49. dara/components/common/stack.py +7 -4
  50. dara/components/common/switch.py +6 -8
  51. dara/components/common/tabbed_card.py +8 -11
  52. dara/components/common/table.py +224 -73
  53. dara/components/common/text.py +7 -9
  54. dara/components/common/textarea.py +7 -7
  55. dara/components/common/time_utils.py +2 -5
  56. dara/components/common/tooltip.py +4 -6
  57. dara/components/common/utils.py +29 -35
  58. dara/components/graphs/__init__.py +1 -0
  59. dara/components/graphs/components/base_graph_component.py +34 -22
  60. dara/components/graphs/components/causal_graph_viewer.py +13 -15
  61. dara/components/graphs/components/edge_encoder.py +49 -26
  62. dara/components/graphs/components/node_hierarchy_builder.py +17 -16
  63. dara/components/graphs/definitions.py +27 -20
  64. dara/components/graphs/graph_layout.py +90 -53
  65. dara/components/plotting/__init__.py +2 -1
  66. dara/components/plotting/bokeh/bokeh.py +7 -10
  67. dara/components/plotting/bokeh/utils.py +5 -3
  68. dara/components/plotting/plotly/plotly.py +24 -19
  69. dara/components/plotting/plotly/themes.py +7 -5
  70. dara/components/smart/__init__.py +7 -1
  71. dara/components/smart/chat/chat.py +7 -8
  72. dara/components/smart/chat/config.py +1 -1
  73. dara/components/smart/chat/types.py +4 -6
  74. dara/components/smart/code_editor/code_editor.py +18 -4
  75. dara/components/smart/code_editor/util.py +11 -11
  76. dara/components/smart/data_slicer/__init__.py +4 -0
  77. dara/components/smart/data_slicer/data_slicer.py +14 -18
  78. dara/components/smart/data_slicer/data_slicer_modal.py +4 -6
  79. dara/components/smart/data_slicer/extension/data_slicer_filter.py +3 -4
  80. dara/components/smart/data_slicer/extension/filter_status_button.py +1 -3
  81. dara/components/smart/data_slicer/utils/core.py +23 -23
  82. dara/components/smart/data_slicer/utils/data_preview.py +1 -3
  83. dara/components/smart/data_slicer/utils/plotting.py +8 -6
  84. dara/components/smart/hierarchy.py +9 -10
  85. {dara_components-1.8.5.dist-info → dara_components-1.22.1.dist-info}/METADATA +7 -7
  86. dara_components-1.22.1.dist-info/RECORD +100 -0
  87. {dara_components-1.8.5.dist-info → dara_components-1.22.1.dist-info}/WHEEL +1 -1
  88. dara_components-1.22.1.dist-info/entry_points.txt +3 -0
  89. dara/components/umd/dara.components.umd.js +0 -396288
  90. dara/components/umd/style.css +0 -745
  91. dara_components-1.8.5.dist-info/RECORD +0 -86
  92. {dara_components-1.8.5.dist-info → dara_components-1.22.1.dist-info}/LICENSE +0 -0
@@ -15,14 +15,14 @@ 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, List, Optional, Union
18
+ from typing import Any
19
19
 
20
- from pydantic import validator
20
+ from pydantic import 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.interactivity import NonDataVariable, UrlVariable, Variable
25
+ from dara.core.interactivity import ClientVariable, Variable
26
26
 
27
27
 
28
28
  class CheckboxGroup(FormComponent):
@@ -37,7 +37,7 @@ class CheckboxGroup(FormComponent):
37
37
 
38
38
  ```python
39
39
  from dara.core import Variable
40
- from dara.components.common import CheckboxGroup
40
+ from dara.components import CheckboxGroup
41
41
 
42
42
 
43
43
  CheckboxGroup(
@@ -46,17 +46,26 @@ class CheckboxGroup(FormComponent):
46
46
  )
47
47
  ```
48
48
 
49
- CheckboxGroup component with at most two values selectable at a time:
49
+ CheckboxGroup with items with custom labels and values:
50
50
 
51
51
  ```python
52
52
  from dara.core import Variable
53
- from dara.components.common import CheckboxGroup
53
+ from dara.components import CheckboxGroup, Item
54
54
 
55
- var_to_update = Variable()
55
+ CheckboxGroup(
56
+ items=[Item(label='first',value=1), Item(label='second',value=2)],
57
+ value=Variable([1]),
58
+ )
59
+ ```
60
+
61
+ CheckboxGroup component with at most two values selectable at a time:
62
+
63
+ ```python
64
+ from dara.core import Variable
65
+ from dara.components import CheckboxGroup
56
66
 
57
67
  CheckboxGroup(
58
68
  items=['first', 'second', 'third', 'fourth', 'fifth'],
59
- onchange=var_to_update.sync(),
60
69
  value=Variable(),
61
70
  select_max=2,
62
71
  )
@@ -69,11 +78,9 @@ class CheckboxGroup(FormComponent):
69
78
  from dara.components.common import CheckboxGroup
70
79
 
71
80
  var = Variable()
72
- var_to_update = Variable()
73
81
 
74
82
  CheckboxGroup(
75
83
  items=['first', 'second', 'third', 'fourth', 'fifth'],
76
- onchange=var_to_update.sync(),
77
84
  value=var,
78
85
  select_min=2,
79
86
  list_styling=True,
@@ -90,18 +97,18 @@ class CheckboxGroup(FormComponent):
90
97
  :param id: the key to be used if this component is within a form
91
98
  """
92
99
 
93
- items: Union[List[Item], NonDataVariable]
94
- select_max: Optional[int] = None
95
- select_min: Optional[int] = None
100
+ items: list[Item] | ClientVariable
101
+ select_max: int | None = None
102
+ select_min: int | None = None
96
103
  list_styling: bool = False
97
- value: Optional[Union[Variable[Any], UrlVariable[Any]]] = None
98
- onchange: Optional[Action] = None
99
- id: Optional[str] = None
104
+ value: Variable[Any] | None = None
105
+ onchange: Action | None = None
106
+ id: str | None = None
100
107
 
101
- @validator('items', pre=True)
108
+ @field_validator('items', mode='before')
102
109
  @classmethod
103
- def validate_items(cls, items: Any) -> Union[List[Item], NonDataVariable]:
104
- if isinstance(items, NonDataVariable):
110
+ def validate_items(cls, items: Any) -> list[Item] | ClientVariable:
111
+ if isinstance(items, ClientVariable):
105
112
  return items
106
113
  if not isinstance(items, list):
107
114
  raise ValueError('Items must be passed as a list to the CheckboxGroup component')
@@ -16,10 +16,10 @@ limitations under the License.
16
16
  """
17
17
 
18
18
  from enum import Enum
19
- from typing import Optional, Union
19
+ from typing import ClassVar
20
20
 
21
21
  from dara.components.common.base_component import ContentComponent
22
- from dara.core.interactivity import NonDataVariable
22
+ from dara.core.interactivity import ClientVariable
23
23
 
24
24
 
25
25
  class Themes(str, Enum):
@@ -29,6 +29,9 @@ class Themes(str, Enum):
29
29
  DARK = 'dark'
30
30
 
31
31
 
32
+ ThemesType = type[Themes]
33
+
34
+
32
35
  class Code(ContentComponent):
33
36
  """
34
37
  ![Code](../../../../docs/packages/dara-components/common/assets/Code.png)
@@ -64,8 +67,8 @@ class Code(ContentComponent):
64
67
  :param language: The language to use for code highlighting
65
68
  """
66
69
 
67
- code: Union[str, NonDataVariable]
68
- theme: Optional[Themes] = None
70
+ code: str | ClientVariable
71
+ theme: Themes | None = None
69
72
  language: str = 'python'
70
73
 
71
- Themes = Themes
74
+ Themes: ClassVar[ThemesType] = Themes
@@ -15,23 +15,19 @@ See the License for the specific language governing permissions and
15
15
  limitations under the License.
16
16
  """
17
17
 
18
- from typing import List, Optional, Union
19
-
20
- from pydantic import BaseModel
21
-
22
18
  from dara.components.common.base_component import LayoutComponent
23
19
  from dara.core.base_definitions import Action
20
+ from dara.core.base_definitions import DaraBaseModel as BaseModel
24
21
  from dara.core.definitions import ComponentInstanceType
25
22
  from dara.core.interactivity import Variable
26
23
 
27
24
 
28
25
  class ComponentItem(BaseModel):
29
26
  title: str
30
- subtitle: Optional[str]
27
+ subtitle: str | None = None
31
28
  component: ComponentInstanceType
32
29
 
33
30
 
34
- # TODO: update docs with examples once component is fixed
35
31
  class ComponentSelectList(LayoutComponent):
36
32
  """
37
33
  ![ComponentSelectList](../../../../docs/packages/dara-components/common/assets/ComponentSelectList.png)
@@ -41,11 +37,11 @@ class ComponentSelectList(LayoutComponent):
41
37
  A ComponentSelectList can be created via:
42
38
  ```python
43
39
  from dara.core import Variable
44
- from dara.components.common import (
40
+ from dara.components import (
45
41
  ComponentSelectList,
42
+ ComponentItem,
46
43
  Text,
47
44
  )
48
- from dara.components.common.component_select_list.component_select_list import ComponentItem
49
45
 
50
46
  ComponentSelectList(
51
47
  items=[
@@ -64,8 +60,8 @@ class ComponentSelectList(LayoutComponent):
64
60
  :param selected_items: The initial selected items, can be an list if multiSelect is true otherwise a string. This takes the titles of the items as value.
65
61
  """
66
62
 
67
- items: List[ComponentItem]
68
- items_per_row: Optional[int] = None
69
- multi_select: Optional[bool] = None
70
- on_select: Optional[Action] = None
71
- selected_items: Optional[Variable[Union[str, List[str]]]] = None
63
+ items: list[ComponentItem]
64
+ items_per_row: int | None = None
65
+ multi_select: bool | None = None
66
+ on_select: Action | None = None
67
+ selected_items: Variable[str | list[str]] | None = None
@@ -16,11 +16,11 @@ limitations under the License.
16
16
  """
17
17
 
18
18
  from datetime import datetime
19
- from typing import Any, Optional, Union
19
+ from typing import Any
20
20
 
21
21
  from dara.components.common.base_component import FormComponent
22
22
  from dara.core.base_definitions import Action
23
- from dara.core.interactivity import UrlVariable, Variable
23
+ from dara.core.interactivity import Variable
24
24
 
25
25
 
26
26
  class Datepicker(FormComponent):
@@ -37,48 +37,48 @@ class Datepicker(FormComponent):
37
37
  A single Datepicker component that tracks the chosen value is created via:
38
38
 
39
39
  ```python
40
-
41
40
  from dara.core import Variable
42
41
  from dara.components.common import Datepicker
43
42
 
43
+ date_var = Variable()
44
+
44
45
  Datepicker(
45
- value=Variable()
46
+ value=date_var
46
47
  )
47
-
48
48
  ```
49
49
 
50
50
  A Datepicker component that allows to choose between a date range is created via:
51
51
 
52
52
  ```python
53
-
54
53
  from dara.core import Variable
55
54
  from dara.components.common import Datepicker
56
55
 
56
+ date_var = Variable()
57
+
57
58
  Datepicker(
58
- value=Variable()
59
+ value=date_var,
59
60
  range=True,
60
61
  )
61
-
62
62
  ```
63
63
 
64
64
  A more complicated example with an initial date, has a custom
65
65
  format, and does not close on selection is created via:
66
66
 
67
67
  ```python
68
-
69
68
  from datetime import datetime
70
69
  from dara.core import Variable
71
70
  from dara.components.common import Datepicker
72
71
 
72
+ date_var = Variable(datetime(2021, 9, 18))
73
+
73
74
  Datepicker(
74
- value=Variable(datetime(2021, 9, 18)),
75
+ value=date_var,
75
76
  date_format='MM/dd/yyyy',
76
77
  enable_time=True,
77
78
  max_date=datetime(2023, 12, 21),
78
79
  min_date=datetime(2020, 3, 20),
79
80
  select_close=False,
80
81
  ),
81
-
82
82
  ```
83
83
 
84
84
  :param value: A Variable with the initial date value
@@ -93,12 +93,12 @@ class Datepicker(FormComponent):
93
93
  :param id: the key to be used if this component is within a form
94
94
  """
95
95
 
96
- value: Optional[Union[Variable[Any], UrlVariable[Any]]] = None
96
+ value: Variable[Any] | None = None
97
97
  date_format: str = 'dd/MM/yyyy'
98
98
  enable_time: bool = False
99
- max_date: Optional[datetime] = None
100
- min_date: Optional[datetime] = None
99
+ max_date: datetime | None = None
100
+ min_date: datetime | None = None
101
101
  range: bool = False
102
102
  select_close: bool = True
103
- onchange: Optional[Action] = None
104
- id: Optional[str] = None
103
+ onchange: Action | None = None
104
+ id: str | None = None
@@ -0,0 +1,161 @@
1
+ from typing import Any
2
+
3
+ from typing_extensions import TypedDict
4
+
5
+ from dara.components.common.base_component import BaseDashboardComponent
6
+ from dara.components.common.button import Button
7
+ from dara.core import Action, ClientVariable, ComponentInstance
8
+
9
+
10
+ class MenuItem(TypedDict, total=False):
11
+ label: str | ComponentInstance
12
+ """the label of the menu item"""
13
+
14
+ icon: str | None
15
+ """optional icon to show next to the label, use get_icon() helper"""
16
+
17
+ style: dict[str, Any] | None
18
+ """optional style to apply to the menu item"""
19
+
20
+ prevent_close: bool | None
21
+ """optional flag to prevent the menu from closing when the item is clicked"""
22
+
23
+ before: ComponentInstance | None
24
+ """optional component to show before the label"""
25
+
26
+ after: ComponentInstance | None
27
+ """optional component to show after the label"""
28
+
29
+
30
+ class DropdownMenu(BaseDashboardComponent):
31
+ """
32
+ A DropdownMenu component that displays a button which opens a dropdown menu with configurable menu items.
33
+ Menu items can be organized into sections and support icons, custom styling, and custom components.
34
+
35
+ A basic dropdown menu with simple text items:
36
+
37
+ ```python
38
+ from dara.core import action, ActionCtx
39
+ from dara.components import Button, DropdownMenu
40
+
41
+ @action
42
+ async def handle_menu_click(ctx: ActionCtx):
43
+ print(f"Clicked: {ctx.input['label']}")
44
+
45
+ DropdownMenu(
46
+ button=Button('Options'),
47
+ onclick=handle_menu_click(),
48
+ menu_items=[
49
+ [
50
+ MenuItem(label='Edit'),
51
+ MenuItem(label='Delete'),
52
+ ]
53
+ ]
54
+ )
55
+ ```
56
+
57
+ A dropdown menu with icons and custom styling:
58
+
59
+ ```python
60
+ from dara.core import action, ActionCtx, get_icon
61
+ from dara.components import Button, DropdownMenu
62
+
63
+ @action
64
+ async def handle_menu_click(ctx: ActionCtx):
65
+ print(f"Clicked: {ctx.input['label']}")
66
+
67
+ DropdownMenu(
68
+ button=Button('Actions', icon=get_icon('chevron-down')),
69
+ onclick=handle_menu_click(),
70
+ menu_items=[
71
+ [
72
+ MenuItem(
73
+ label='Edit',
74
+ icon=get_icon('pen'),
75
+ style={'color': 'blue'}
76
+ ),
77
+ MenuItem(
78
+ label='Delete',
79
+ icon=get_icon('trash'),
80
+ style={'color': 'red'}
81
+ ),
82
+ ],
83
+ [
84
+ MenuItem(label='Settings', icon=get_icon('gear'))
85
+ ]
86
+ ]
87
+ )
88
+ ```
89
+
90
+ A dropdown menu with custom components and prevent close behavior:
91
+
92
+ ```python
93
+ from dara.core import action, ActionCtx, Variable
94
+ from dara.components import Button, DropdownMenu, Text, Stack
95
+
96
+ counter = Variable(0)
97
+
98
+ @action
99
+ async def handle_menu_click(ctx: ActionCtx, counter_value: int):
100
+ print(f"Clicked: {ctx.input['label']}")
101
+
102
+ if ctx.input['label'] == 'Increment':
103
+ await ctx.update(counter, counter_value + 1)
104
+
105
+ DropdownMenu(
106
+ button=Button('Custom Menu'),
107
+ onclick=handle_menu_click(counter),
108
+ menu_items=[
109
+ [
110
+ MenuItem(
111
+ label=Stack(Text('Counter: '), Text(counter)),
112
+ prevent_close=True
113
+ ),
114
+ MenuItem(
115
+ label='Increment',
116
+ before=Text('→'),
117
+ after=Text('↑')
118
+ )
119
+ ]
120
+ ]
121
+ )
122
+ ```
123
+
124
+ A dropdown menu with footer content at the bottom:
125
+
126
+ ```python
127
+ from dara.core import action, ActionCtx
128
+ from dara.components import Button, DropdownMenu, Text, Stack
129
+
130
+ @action
131
+ async def handle_menu_click(ctx: ActionCtx):
132
+ print(f"Clicked: {ctx.input['label']}")
133
+
134
+ DropdownMenu(
135
+ button=Button('Menu with Footer'),
136
+ onclick=handle_menu_click(),
137
+ menu_items=[
138
+ [
139
+ MenuItem(label='Option 1'),
140
+ MenuItem(label='Option 2'),
141
+ ]
142
+ ],
143
+ footer=Stack(
144
+ Text(
145
+ 'Additional info or controls can go here',
146
+ raw_css={'padding': '8px', 'font-size': '0.8rem', 'color': 'gray'},
147
+ )
148
+ )
149
+ )
150
+ ```
151
+
152
+ :param button: The button component that triggers the dropdown menu
153
+ :param onclick: Action triggered when a menu item is clicked, receives the clicked item as parameter
154
+ :param menu_items: List of menu item sections, where each section is a list of MenuItem objects
155
+ :param footer: Optional component to display at the bottom of the dropdown menu
156
+ """
157
+
158
+ button: Button
159
+ onclick: Action
160
+ menu_items: list[list[MenuItem]] | ClientVariable
161
+ footer: ComponentInstance | None = None
@@ -15,62 +15,71 @@ See the License for the specific language governing permissions and
15
15
  limitations under the License.
16
16
  """
17
17
 
18
- from typing import Callable, Optional, Union
18
+ from collections.abc import Callable
19
19
  from uuid import uuid4
20
20
 
21
21
  from pandas import DataFrame
22
+ from pydantic import ConfigDict
22
23
 
23
24
  from dara.core.base_definitions import Action, UploadResolverDef
24
25
  from dara.core.definitions import StyledComponentInstance
25
- from dara.core.interactivity import DataVariable
26
+ from dara.core.interactivity import ServerVariable
26
27
 
27
- DropzoneResolver = Union[
28
- Callable[[bytes, str], DataFrame],
29
- Callable[[bytes, str], None],
30
- ]
28
+ DropzoneResolver = Callable[[bytes, str], DataFrame] | Callable[[bytes, str], None]
31
29
 
32
30
 
33
31
  class UploadDropzone(StyledComponentInstance):
34
32
  """
35
- A component that exposes a dropzone for uploading files. Takes a DataVariable instance
33
+ ![UploadDropzone](../../../../docs/packages/dara-components/common/assets/UploadDropzone.png)
34
+
35
+ A component that exposes a dropzone for uploading files. Takes a ServerVariable instance
36
36
  that will store the dataset uploaded and an on_drop action that is triggered when
37
37
  a file is successfully uploaded after being dropped or pasted.
38
+
39
+ ```python
40
+ import os
41
+ from dara.components import UploadDropzone
42
+
43
+ def handle_file_uploaded(file_data: bytes, file_name: str):
44
+ os.makedirs('data', exist_ok=True)
45
+ with open(os.path.join('data', file_name), 'wb') as f:
46
+ f.write(file_data)
47
+
48
+ UploadDropzone(
49
+ accept="image/png, image/jpeg",
50
+ resolver=handle_file_uploaded
51
+ )
52
+ ```
53
+
54
+ :param accept: optional comma-separated list of MIME-types or filename extensions accepted by the frontend; see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#unique_file_type_specifiers for detail.
55
+ When not specified, defaults to accepting csv/xlsx; more specifically: `.csv, text/csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel, application/csv, text/x-csv, application/x-csv, text/comma-separated-values, text/x-comma-separated-values`
56
+ :param target: server variable storing the data
57
+ :param resolver: optional resolver accepting `bytes` and filename as a string
58
+ - if a target is specified, can be used to customise how the `bytes` received are turned into a `DataFrame`
59
+ - if a target is not specified, can be treated as a side effect function to run on the `bytes` received (to i.e. store on disk)
60
+ :param on_drop: optional action triggered when a file is successfully uploaded
61
+ :param enable_paste: determines if the component should listen for and handle paste events (e.g., CTRL+V or right-click and paste). When set to True, the component allows text to be pasted directly, creating a file from the pasted content. This feature is disabled by default to accommodate scenarios where pasting text is not intended or could interfere with the component's primary functionality.
38
62
  """
39
63
 
40
64
  js_module = '@darajs/components'
41
65
 
42
- accept: Optional[str] = None
43
- target: Optional[DataVariable] = None
44
- resolver: Optional[DropzoneResolver]
45
- on_drop: Optional[Action] = None
66
+ accept: str | None = None
67
+ target: ServerVariable | None = None
68
+ resolver: DropzoneResolver | None = None
69
+ on_drop: Action | None = None
46
70
  enable_paste: bool = False
47
71
 
48
- class Config:
49
- extra = 'allow'
72
+ model_config = ConfigDict(extra='allow')
50
73
 
51
74
  def __init__(
52
75
  self,
53
- target: Optional[DataVariable] = None,
54
- resolver: Optional[DropzoneResolver] = None,
55
- on_drop: Optional[Action] = None,
56
- accept: Optional[str] = None,
57
- enable_paste: Optional[bool] = False,
58
- **kwargs
76
+ target: ServerVariable | None = None,
77
+ resolver: DropzoneResolver | None = None,
78
+ on_drop: Action | None = None,
79
+ accept: str | None = None,
80
+ enable_paste: bool | None = False,
81
+ **kwargs,
59
82
  ):
60
- """
61
- A component that exposes a dropzone for uploading files. Takes a DataVariable instance
62
- that will store the dataset uploaded and an on_drop action that is triggered when
63
- a file is successfully uploaded after being dropped or pasted.
64
-
65
- :param accept: optional comma-separated list of MIME-types or filename extensions accepted by the frontend; see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#unique_file_type_specifiers for detail.
66
- When not specified, defaults to accepting csv/xlsx; more specifically: `.csv, text/csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel, application/csv, text/x-csv, application/x-csv, text/comma-separated-values, text/x-comma-separated-values`
67
- :param target: data variable storing the data
68
- :param resolver: optional resolver accepting `bytes` and filename as a string
69
- - if a target is specified, can be used to customise how the `bytes` received are turned into a `DataFrame`
70
- - if a target is not specified, can be treated as a side effect function to run on the `bytes` received (to i.e. store on disk)
71
- :param on_drop: optional action triggered when a file is successfully uploaded
72
- :param enable_paste: determines if the component should listen for and handle paste events (e.g., CTRL+V or right-click and paste). When set to True, the component allows text to be pasted directly, creating a file from the pasted content. This feature is disabled by default to accommodate scenarios where pasting text is not intended or could interfere with the component's primary functionality.
73
- """
74
83
  from dara.core.interactivity.any_data_variable import upload
75
84
  from dara.core.internal.registries import upload_resolver_registry
76
85
 
@@ -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 typing import List, Optional
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
21
  from dara.core.base_definitions import Action
@@ -82,12 +80,12 @@ class Form(LayoutComponent):
82
80
  :param align: How to align the content of the form, accepts any flexbox alignments
83
81
  """
84
82
 
85
- value: Optional[Variable[dict]] = None
86
- onsubmit: Optional[Action] = None
83
+ value: Variable[dict] | None = None
84
+ onsubmit: Action | None = None
87
85
 
88
- @validator('children')
86
+ @field_validator('children')
89
87
  @classmethod
90
- def validate_children_pages(cls, children: List[ComponentInstance]) -> List[ComponentInstance]:
88
+ def validate_children_pages(cls, children: list[ComponentInstance]) -> list[ComponentInstance]:
91
89
  # Make sure if FormPage is included, non-pages are not direct children of the Form
92
90
  page_found = False
93
91
  non_page_found = False
@@ -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 typing import List, Optional
19
-
20
- from pydantic import validator
18
+ from pydantic import field_validator
21
19
 
22
20
  from dara.components.common.base_component import FormComponent
23
21
  from dara.core.definitions import ComponentInstance
@@ -50,11 +48,11 @@ class FormPage(FormComponent):
50
48
  :param title: The title of the form page
51
49
  """
52
50
 
53
- title: Optional[str] = None
51
+ title: str | None = None
54
52
 
55
- @validator('children')
53
+ @field_validator('children')
56
54
  @classmethod
57
- def validate_children(cls, children: List[ComponentInstance]) -> List[ComponentInstance]:
55
+ def validate_children(cls, children: list[ComponentInstance]) -> list[ComponentInstance]:
58
56
  for c in children:
59
57
  if isinstance(c, FormPage):
60
58
  raise TypeError('FormPage detected inside another FormPage, nesting is disallowed')
@@ -15,21 +15,20 @@ 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, Union
19
-
20
- from pydantic import BaseModel
18
+ from typing import ClassVar
21
19
 
22
20
  from dara.components.common.base_component import LayoutComponent
21
+ from dara.core.base_definitions import DaraBaseModel as BaseModel
23
22
  from dara.core.definitions import ComponentInstance, discover
24
23
  from dara.core.visual.components.types import Direction
25
24
 
26
25
 
27
26
  class ScreenBreakpoints(BaseModel):
28
- xs: Optional[int] = None
29
- sm: Optional[int] = None
30
- md: Optional[int] = None
31
- lg: Optional[int] = None
32
- xl: Optional[int] = None
27
+ xs: int | None = None
28
+ sm: int | None = None
29
+ md: int | None = None
30
+ lg: int | None = None
31
+ xl: int | None = None
33
32
 
34
33
 
35
34
  class Column(LayoutComponent):
@@ -68,11 +67,11 @@ class Column(LayoutComponent):
68
67
 
69
68
  # TODO: :param order: optional number denoting the order of priority of the columns, with 1 being first to appear, and 12 the last to be added.
70
69
 
71
- span: Optional[Union[int, ScreenBreakpoints]] = None
72
- offset: Optional[Union[int, ScreenBreakpoints]]
70
+ span: int | ScreenBreakpoints | None = None
71
+ offset: int | ScreenBreakpoints | None = None
73
72
  direction: Direction = Direction.HORIZONTAL
74
73
 
75
- def __init__(self, *args: ComponentInstance, **kwargs):
74
+ def __init__(self, *args: ComponentInstance | None, **kwargs):
76
75
  super().__init__(*args, **kwargs)
77
76
 
78
77
 
@@ -100,12 +99,16 @@ class Row(LayoutComponent):
100
99
  :param align: How to align the content of the row, accepts any flexbox alignments
101
100
  """
102
101
 
103
- column_gap: Optional[int] = None
102
+ column_gap: int | None = None
104
103
 
105
- def __init__(self, *args: ComponentInstance, **kwargs):
104
+ def __init__(self, *args: ComponentInstance | None, **kwargs):
106
105
  super().__init__(*args, **kwargs)
107
106
 
108
107
 
108
+ ColumnType = type[Column]
109
+ RowType = type[Row]
110
+
111
+
109
112
  @discover
110
113
  class Grid(LayoutComponent):
111
114
  """
@@ -117,14 +120,14 @@ class Grid(LayoutComponent):
117
120
  """
118
121
 
119
122
  row_gap: str = '0.75rem'
120
- breakpoints: Optional[ScreenBreakpoints] = ScreenBreakpoints()
123
+ breakpoints: ScreenBreakpoints | None = ScreenBreakpoints()
121
124
 
122
- Column = Column
123
- Row = Row
124
- Breakpoints = ScreenBreakpoints
125
+ Column: ClassVar[ColumnType] = Column
126
+ Row: ClassVar[RowType] = Row
127
+ Breakpoints: ClassVar[type[ScreenBreakpoints]] = ScreenBreakpoints
125
128
 
126
129
  # Dummy init that just passes through arguments to superclass, fixes Pylance complaining about types
127
- def __init__(self, *args: ComponentInstance, **kwargs):
130
+ def __init__(self, *args: ComponentInstance | None, **kwargs):
128
131
  """
129
132
  Grid Layout provides a flexbox grid with a twelve column system.
130
133
  Rows will automatically calculate their widths and wrap on the page as needed.