diff --git a/pynecone/components/__init__.py b/pynecone/components/__init__.py
index 8dd3f07b0..0c5998cb1 100644
--- a/pynecone/components/__init__.py
+++ b/pynecone/components/__init__.py
@@ -105,6 +105,8 @@ input = Input.create
input_group = InputGroup.create
input_left_addon = InputLeftAddon.create
input_right_addon = InputRightAddon.create
+multi_select = MultiSelect
+multi_select_option = MultiSelectOption
number_decrement_stepper = NumberDecrementStepper.create
number_increment_stepper = NumberIncrementStepper.create
number_input = NumberInput.create
diff --git a/pynecone/components/forms/__init__.py b/pynecone/components/forms/__init__.py
index 936b481be..aeb38fb7b 100644
--- a/pynecone/components/forms/__init__.py
+++ b/pynecone/components/forms/__init__.py
@@ -8,6 +8,8 @@ from .email import Email
from .form import Form, FormControl, FormErrorMessage, FormHelperText, FormLabel
from .iconbutton import IconButton
from .input import Input, InputGroup, InputLeftAddon, InputRightAddon
+from .multiselect import Option as MultiSelectOption
+from .multiselect import Select as MultiSelect
from .numberinput import (
NumberDecrementStepper,
NumberIncrementStepper,
diff --git a/pynecone/components/forms/multiselect.py b/pynecone/components/forms/multiselect.py
new file mode 100644
index 000000000..328c4f1fe
--- /dev/null
+++ b/pynecone/components/forms/multiselect.py
@@ -0,0 +1,346 @@
+"""Provides a feature-rich Select and some (not all) related components."""
+
+from typing import Any, Dict, List, Optional, Set, Union
+
+from pynecone.base import Base
+from pynecone.components.component import Component
+from pynecone.event import EVENT_ARG
+from pynecone.vars import Var
+
+
+class Option(Base):
+ """An option component for the chakra-react-select Select."""
+
+ # What is displayed to the user
+ label: str
+
+ # The value of the option, must be serializable
+ value: Any
+
+ # the variant of the option tag
+ variant: Optional[str] = None
+
+ # [not working yet]
+ # Whether the option is disabled
+ # is_disabled: Optional[bool] = None
+
+ # [not working yet]
+ # The visual color appearance of the component
+ # options: "whiteAlpha" | "blackAlpha" | "gray" | "red" |
+ # "orange" | "yellow" | "green" | "teal" | "blue" | "cyan" |
+ # "purple" | "pink" | "linkedin" | "facebook" | "messenger" |
+ # "whatsapp" | "twitter" | "telegram"
+ # default: "gray"
+ # color_scheme: Optional[str] = None
+
+ # [not working yet]
+ # The icon of the option tag
+ # icon: Optional[str] = None
+
+
+class Select(Component):
+ """The default chakra-react-select Select component.
+ Not every available prop is listed here,
+ for a complete overview check the react-select/chakra-react-select docs.
+ Props added by chakra-react-select are marked with "[chakra]".
+ """
+
+ library = "chakra-react-select"
+ tag = "Select"
+
+ # Focus the control when it is mounted
+ auto_focus: Var[bool]
+
+ # Remove the currently focused option when the user presses backspace
+ # when Select isClearable or isMulti
+ backspace_removes_value: Var[bool]
+
+ # Remove focus from the input when the user selects an option
+ # (handy for dismissing the keyboard on touch devices)
+ blur_input_on_select: Var[bool]
+
+ # When the user reaches the top/bottom of the menu,
+ # prevent scroll on the scroll-parent
+ capture_menu_scroll: Var[bool]
+
+ # [chakra]
+ # To use the chakraStyles prop, first,
+ # check the documentation for the original styles prop from the react-select docs.
+ # This package offers an identical API for the chakraStyles prop, however,
+ # the provided and output style objects use Chakra's sx prop
+ # instead of the default emotion styles the original package offers.
+ # This allows you to both use the shorthand styling props you'd normally use
+ # to style Chakra components, as well as tokens from your theme such as named colors.
+ # All of the style keys offered in the original package can be used in the chakraStyles prop
+ # except for menuPortal. Along with some other caveats, this is explained below.
+ # Most of the components rendered by this package use the basic Chakra component with a few exceptions.
+ # Here are the style keys offered and the corresponding Chakra component that is rendered:
+ # - clearIndicator - Box (uses theme styles for Chakra's CloseButton)
+ # - container - Box
+ # - control - Box (uses theme styles for Chakra's Input)
+ # - dropdownIndicator - Box (uses theme styles for Chrakra's InputRightAddon)
+ # - downChevron - Icon
+ # - crossIcon - Icon
+ # - group - Box
+ # - groupHeading - Box (uses theme styles for Chakra's Menu group title)
+ # - indicatorsContainer - Box
+ # - indicatorSeparator - Divider
+ # - input - chakra.input (wrapped in a Box)
+ # - inputContainer - Box
+ # - loadingIndicator - Spinner
+ # - loadingMessage - Box
+ # - menu - Box
+ # - menuList - Box (uses theme styles for Chakra's Menu)
+ # - multiValue - chakra.span (uses theme styles for Chakra's Tag)
+ # - multiValueLabel - chakra.span (uses theme styles for Chakra's TagLabel)
+ # - multiValueRemove - Box (uses theme styles for Chakra's TagCloseButton)
+ # - noOptionsMessage - Box
+ # - option - Box (uses theme styles for Chakra's MenuItem)
+ # - placeholder - Box
+ # - singleValue - Box
+ # - valueContainer - Box
+ chakra_styles: Var[str]
+
+ # Close the select menu when the user selects an option
+ close_menu_on_select: Var[bool]
+
+ # If true, close the select menu when the user scrolls the document/body.
+ close_menu_on_scroll: Var[bool]
+
+ # [chakra]
+ # The visual color appearance of the component
+ # options: "whiteAlpha" | "blackAlpha" | "gray" | "red" |
+ # "orange" | "yellow" | "green" | "teal" | "blue" | "cyan" |
+ # "purple" | "pink" | "linkedin" | "facebook" | "messenger" |
+ # "whatsapp" | "twitter" | "telegram"
+ # default: "gray"
+ color_scheme: Var[str]
+
+ # This complex object includes all the compositional components
+ # that are used in react-select. If you wish to overwrite a component,
+ # pass in an object with the appropriate namespace.
+ # If you only wish to restyle a component,
+ # we recommend using the styles prop instead.
+ components: Var[Dict[str, Component]]
+
+ # Whether the value of the select, e.g. SingleValue,
+ # should be displayed in the control.
+ control_should_render_value: Var[bool]
+
+ # Delimiter used to join multiple values into a single HTML Input value
+ delimiter: Var[str]
+
+ # [chakra]
+ # Colors the component border with the given chakra color string on error state
+ # default: "red.500"
+ error_border_color: Var[str]
+
+ # Clear all values when the user presses escape AND the menu is closed
+ escape_clears_value: Var[bool]
+
+ # [chakra]
+ # Colors the component border with the given chakra color string on focus
+ # default: "blue.500"
+ focus_border_color: Var[str]
+
+ # Sets the form attribute on the input
+ form: Var[str]
+
+ # Hide the selected option from the menu
+ hide_selected_options: Var[bool]
+
+ # The id to set on the SelectContainer component.
+ # id: Var[str]
+
+ # The value of the search input
+ input_value: Var[str]
+
+ # The id of the search input
+ input_id: Var[str]
+
+ # Is the select value clearable
+ is_clearable: Var[bool]
+
+ # Is the select disabled
+ is_disabled: Var[bool]
+
+ # [chakra]
+ # Style component in the chakra invalid style
+ # default: False
+ is_invalid: Var[bool]
+
+ # Support multiple selected options
+ is_multi: Var[bool]
+
+ # [chakra]
+ # Style component as disabled (chakra style)
+ # default: False
+ is_read_only: Var[bool]
+
+ # Is the select direction right-to-left
+ is_rtl: Var[bool]
+
+ # Whether to enable search functionality
+ is_searchable: Var[bool]
+
+ # Minimum height of the menu before flipping
+ min_menu_height: Var[int]
+
+ # Maximum height of the menu before scrolling
+ max_menu_height: Var[int]
+
+ # Default placement of the menu in relation to the control.
+ # 'auto' will flip when there isn't enough space below the control.
+ # options: "bottom" | "auto" | "top"
+ menu_placement: Var[str]
+
+ # The CSS position value of the menu,
+ # when "fixed" extra layout management is required
+ # options: "absolute" | "fixed"
+ menu_position: Var[str]
+
+ # Whether to block scroll events when the menu is open
+ menu_should_block_scroll: Var[bool]
+
+ # Whether the menu should be scrolled into view when it opens
+ menu_should_scroll_into_view: Var[bool]
+
+ # Name of the HTML Input (optional - without this, no input will be rendered)
+ name: Var[str]
+
+ # Allows control of whether the menu is opened when the Select is focused
+ open_menu_on_focus: Var[bool]
+
+ # Allows control of whether the menu is opened when the Select is clicked
+ open_menu_on_click: Var[bool]
+
+ # Array of options that populate the select menu
+ options: Var[List[Dict]]
+
+ # Number of options to jump in menu when page{up|down} keys are used
+ page_size: Var[int]
+
+ # Placeholder for the select value
+ placeholder: Var[Optional[str]]
+
+ # Marks the value-holding input as required for form validation
+ required: Var[bool]
+
+ # [chakra]
+ # If you choose to stick with the default selectedOptionStyle="color",
+ # you have one additional styling option.
+ # If you do not like the default of blue for the highlight color,
+ # you can pass the selectedOptionColorScheme prop to change it.
+ # This prop will accept any named color from your theme's color palette,
+ # and it will use the 500 value in light mode or the 300 value in dark mode.
+ # This prop can only be used for named colors from your theme, not arbitrary hex/rgb colors.
+ # If you would like to use a specific color for the background that's not a part of your theme,
+ # use the chakraStyles prop to customize it.
+ # default: "blue"
+ selected_option_color_scheme: Var[str]
+
+ # [chakra]
+ # The default option "color" will style a selected option
+ # similar to how react-select does it,
+ # by highlighting the selected option in the color blue.
+ # Alternatively, if you pass "check" for the value,
+ # the selected option will be styled like the Chakra UI Menu component
+ # and include a check icon next to the selected option(s).
+ # If is_multi and selected_option_style="check" are passed,
+ # space will only be added for the check marks
+ # if hide_selected_options=False is also passed.
+ # options: "color" | "check"
+ # default: "color"
+ selected_option_style: Var[str]
+
+ # [chakra]
+ # The size of the component.
+ # options: "sm" | "md" | "lg"
+ # default: "md"
+ size: Var[str]
+
+ # Sets the tabIndex attribute on the input
+ tab_index: Var[int]
+
+ # Select the currently focused option when the user presses tab
+ tab_selects_value: Var[bool]
+
+ # [chakra]
+ # Variant of multi-select tags
+ # options: "subtle" | "solid" | "outline"
+ # default: "subtle"
+ tag_variant: Var[str]
+
+ # Remove all non-essential styles
+ unstyled: Var[bool]
+
+ # [chakra]
+ # If this prop is passed,
+ # the dropdown indicator at the right of the component will be styled
+ # in the same way the original Chakra Select component is styled,
+ # instead of being styled as an InputRightAddon.
+ # The original purpose of styling it as an addon
+ # was to create a visual separation between the dropdown indicator
+ # and the button for clearing the selected options.
+ # However, as this button only appears when isMulti is passed,
+ # using this style could make more sense for a single select.
+ # default: False
+ use_basic_style: Var[bool]
+
+ # [chakra]
+ # The variant of the Select. If no variant is passed,
+ # it will default to defaultProps.variant from the theme for Chakra's Input component.
+ # If your component theme for Input is not modified, it will be outline.
+ # options: "outline" | "filled" | "flushed" | "unstyled"
+ # default: "outline"
+ variant: Var[str]
+
+ # How the options should be displayed in the menu.
+ menu_position: Var[str] = "fixed" # type: ignore
+
+ def get_controlled_triggers(self) -> Dict[str, Var]:
+ """Get the event triggers that pass the component's value to the handler.
+
+ Returns:
+ A dict mapping the event trigger to the var that is passed to the handler.
+ """
+ # A normal select returns the value.
+ value = EVENT_ARG.value
+
+ # Multi-select returns a list of values.
+ if self.is_multi:
+ value = Var.create_safe(f"{EVENT_ARG}.map(e => e.value)", is_local=True)
+ return {"on_change": value}
+
+ @classmethod
+ def get_initial_props(cls) -> Set[str]:
+ """Get the initial props to set for the component.
+
+ Returns:
+ The initial props to set.
+ """
+ return super().get_initial_props() | {"is_multi"}
+
+ @classmethod
+ def create(
+ cls, options: List[Union[Option, str, int, float, bool]], **props
+ ) -> Component:
+ """Takes a list of options and additional properties, checks if each option is an
+ instance of Option, and returns a Select component with the given options and
+ properties. No children allowed.
+
+ Args:
+ options (List[Option | str | int | float | bool]): A list of values.
+ **props: Additional properties to be passed to the Select component.
+
+ Returns:
+ The `create` method is returning an instance of the `Select` class.
+ """
+ converted_options: List[Option] = []
+ for option in options:
+ if not isinstance(option, Option):
+ converted_options.append(Option(label=str(option), value=option))
+ else:
+ converted_options.append(option)
+ props["options"] = [o.dict() for o in converted_options]
+ return super().create(*[], **props)
diff --git a/pynecone/components/forms/select.py b/pynecone/components/forms/select.py
index 328c4f1fe..fca96825c 100644
--- a/pynecone/components/forms/select.py
+++ b/pynecone/components/forms/select.py
@@ -1,346 +1,110 @@
-"""Provides a feature-rich Select and some (not all) related components."""
+"""A select component."""
-from typing import Any, Dict, List, Optional, Set, Union
+from typing import Any, Dict, List
-from pynecone.base import Base
-from pynecone.components.component import Component
-from pynecone.event import EVENT_ARG
+from pynecone.components.component import EVENT_ARG, Component
+from pynecone.components.layout.foreach import Foreach
+from pynecone.components.libs.chakra import ChakraComponent
+from pynecone.components.typography.text import Text
+from pynecone.utils import types
from pynecone.vars import Var
-class Option(Base):
- """An option component for the chakra-react-select Select."""
+class Select(ChakraComponent):
+ """Select component is a component that allows users pick a value from predefined options. Ideally, it should be used when there are more than 5 options, otherwise you might consider using a radio group instead."""
- # What is displayed to the user
- label: str
-
- # The value of the option, must be serializable
- value: Any
-
- # the variant of the option tag
- variant: Optional[str] = None
-
- # [not working yet]
- # Whether the option is disabled
- # is_disabled: Optional[bool] = None
-
- # [not working yet]
- # The visual color appearance of the component
- # options: "whiteAlpha" | "blackAlpha" | "gray" | "red" |
- # "orange" | "yellow" | "green" | "teal" | "blue" | "cyan" |
- # "purple" | "pink" | "linkedin" | "facebook" | "messenger" |
- # "whatsapp" | "twitter" | "telegram"
- # default: "gray"
- # color_scheme: Optional[str] = None
-
- # [not working yet]
- # The icon of the option tag
- # icon: Optional[str] = None
-
-
-class Select(Component):
- """The default chakra-react-select Select component.
- Not every available prop is listed here,
- for a complete overview check the react-select/chakra-react-select docs.
- Props added by chakra-react-select are marked with "[chakra]".
- """
-
- library = "chakra-react-select"
tag = "Select"
- # Focus the control when it is mounted
- auto_focus: Var[bool]
+ # State var to bind the select.
+ value: Var[str]
- # Remove the currently focused option when the user presses backspace
- # when Select isClearable or isMulti
- backspace_removes_value: Var[bool]
+ # The default value of the select.
+ default_value: Var[str]
- # Remove focus from the input when the user selects an option
- # (handy for dismissing the keyboard on touch devices)
- blur_input_on_select: Var[bool]
+ # The placeholder text.
+ placeholder: Var[str]
- # When the user reaches the top/bottom of the menu,
- # prevent scroll on the scroll-parent
- capture_menu_scroll: Var[bool]
-
- # [chakra]
- # To use the chakraStyles prop, first,
- # check the documentation for the original styles prop from the react-select docs.
- # This package offers an identical API for the chakraStyles prop, however,
- # the provided and output style objects use Chakra's sx prop
- # instead of the default emotion styles the original package offers.
- # This allows you to both use the shorthand styling props you'd normally use
- # to style Chakra components, as well as tokens from your theme such as named colors.
- # All of the style keys offered in the original package can be used in the chakraStyles prop
- # except for menuPortal. Along with some other caveats, this is explained below.
- # Most of the components rendered by this package use the basic Chakra component with a few exceptions.
- # Here are the style keys offered and the corresponding Chakra component that is rendered:
- # - clearIndicator - Box (uses theme styles for Chakra's CloseButton)
- # - container - Box
- # - control - Box (uses theme styles for Chakra's Input)
- # - dropdownIndicator - Box (uses theme styles for Chrakra's InputRightAddon)
- # - downChevron - Icon
- # - crossIcon - Icon
- # - group - Box
- # - groupHeading - Box (uses theme styles for Chakra's Menu group title)
- # - indicatorsContainer - Box
- # - indicatorSeparator - Divider
- # - input - chakra.input (wrapped in a Box)
- # - inputContainer - Box
- # - loadingIndicator - Spinner
- # - loadingMessage - Box
- # - menu - Box
- # - menuList - Box (uses theme styles for Chakra's Menu)
- # - multiValue - chakra.span (uses theme styles for Chakra's Tag)
- # - multiValueLabel - chakra.span (uses theme styles for Chakra's TagLabel)
- # - multiValueRemove - Box (uses theme styles for Chakra's TagCloseButton)
- # - noOptionsMessage - Box
- # - option - Box (uses theme styles for Chakra's MenuItem)
- # - placeholder - Box
- # - singleValue - Box
- # - valueContainer - Box
- chakra_styles: Var[str]
-
- # Close the select menu when the user selects an option
- close_menu_on_select: Var[bool]
-
- # If true, close the select menu when the user scrolls the document/body.
- close_menu_on_scroll: Var[bool]
-
- # [chakra]
- # The visual color appearance of the component
- # options: "whiteAlpha" | "blackAlpha" | "gray" | "red" |
- # "orange" | "yellow" | "green" | "teal" | "blue" | "cyan" |
- # "purple" | "pink" | "linkedin" | "facebook" | "messenger" |
- # "whatsapp" | "twitter" | "telegram"
- # default: "gray"
- color_scheme: Var[str]
-
- # This complex object includes all the compositional components
- # that are used in react-select. If you wish to overwrite a component,
- # pass in an object with the appropriate namespace.
- # If you only wish to restyle a component,
- # we recommend using the styles prop instead.
- components: Var[Dict[str, Component]]
-
- # Whether the value of the select, e.g. SingleValue,
- # should be displayed in the control.
- control_should_render_value: Var[bool]
-
- # Delimiter used to join multiple values into a single HTML Input value
- delimiter: Var[str]
-
- # [chakra]
- # Colors the component border with the given chakra color string on error state
- # default: "red.500"
+ # The border color when the select is invalid.
error_border_color: Var[str]
- # Clear all values when the user presses escape AND the menu is closed
- escape_clears_value: Var[bool]
-
- # [chakra]
- # Colors the component border with the given chakra color string on focus
- # default: "blue.500"
+ # The border color when the select is focused.
focus_border_color: Var[str]
- # Sets the form attribute on the input
- form: Var[str]
-
- # Hide the selected option from the menu
- hide_selected_options: Var[bool]
-
- # The id to set on the SelectContainer component.
- # id: Var[str]
-
- # The value of the search input
- input_value: Var[str]
-
- # The id of the search input
- input_id: Var[str]
-
- # Is the select value clearable
- is_clearable: Var[bool]
-
- # Is the select disabled
+ # If true, the select will be disabled.
is_disabled: Var[bool]
- # [chakra]
- # Style component in the chakra invalid style
- # default: False
+ # If true, the form control will be invalid. This has 2 side effects: - The FormLabel and FormErrorIcon will have `data-invalid` set to true - The form element (e.g, Input) will have `aria-invalid` set to true
is_invalid: Var[bool]
- # Support multiple selected options
- is_multi: Var[bool]
-
- # [chakra]
- # Style component as disabled (chakra style)
- # default: False
+ # If true, the form control will be readonly
is_read_only: Var[bool]
- # Is the select direction right-to-left
- is_rtl: Var[bool]
+ # If true, the form control will be required. This has 2 side effects: - The FormLabel will show a required indicator - The form element (e.g, Input) will have `aria-required` set to true
+ is_required: Var[bool]
- # Whether to enable search functionality
- is_searchable: Var[bool]
-
- # Minimum height of the menu before flipping
- min_menu_height: Var[int]
-
- # Maximum height of the menu before scrolling
- max_menu_height: Var[int]
-
- # Default placement of the menu in relation to the control.
- # 'auto' will flip when there isn't enough space below the control.
- # options: "bottom" | "auto" | "top"
- menu_placement: Var[str]
-
- # The CSS position value of the menu,
- # when "fixed" extra layout management is required
- # options: "absolute" | "fixed"
- menu_position: Var[str]
-
- # Whether to block scroll events when the menu is open
- menu_should_block_scroll: Var[bool]
-
- # Whether the menu should be scrolled into view when it opens
- menu_should_scroll_into_view: Var[bool]
-
- # Name of the HTML Input (optional - without this, no input will be rendered)
- name: Var[str]
-
- # Allows control of whether the menu is opened when the Select is focused
- open_menu_on_focus: Var[bool]
-
- # Allows control of whether the menu is opened when the Select is clicked
- open_menu_on_click: Var[bool]
-
- # Array of options that populate the select menu
- options: Var[List[Dict]]
-
- # Number of options to jump in menu when page{up|down} keys are used
- page_size: Var[int]
-
- # Placeholder for the select value
- placeholder: Var[Optional[str]]
-
- # Marks the value-holding input as required for form validation
- required: Var[bool]
-
- # [chakra]
- # If you choose to stick with the default selectedOptionStyle="color",
- # you have one additional styling option.
- # If you do not like the default of blue for the highlight color,
- # you can pass the selectedOptionColorScheme prop to change it.
- # This prop will accept any named color from your theme's color palette,
- # and it will use the 500 value in light mode or the 300 value in dark mode.
- # This prop can only be used for named colors from your theme, not arbitrary hex/rgb colors.
- # If you would like to use a specific color for the background that's not a part of your theme,
- # use the chakraStyles prop to customize it.
- # default: "blue"
- selected_option_color_scheme: Var[str]
-
- # [chakra]
- # The default option "color" will style a selected option
- # similar to how react-select does it,
- # by highlighting the selected option in the color blue.
- # Alternatively, if you pass "check" for the value,
- # the selected option will be styled like the Chakra UI Menu component
- # and include a check icon next to the selected option(s).
- # If is_multi and selected_option_style="check" are passed,
- # space will only be added for the check marks
- # if hide_selected_options=False is also passed.
- # options: "color" | "check"
- # default: "color"
- selected_option_style: Var[str]
-
- # [chakra]
- # The size of the component.
- # options: "sm" | "md" | "lg"
- # default: "md"
- size: Var[str]
-
- # Sets the tabIndex attribute on the input
- tab_index: Var[int]
-
- # Select the currently focused option when the user presses tab
- tab_selects_value: Var[bool]
-
- # [chakra]
- # Variant of multi-select tags
- # options: "subtle" | "solid" | "outline"
- # default: "subtle"
- tag_variant: Var[str]
-
- # Remove all non-essential styles
- unstyled: Var[bool]
-
- # [chakra]
- # If this prop is passed,
- # the dropdown indicator at the right of the component will be styled
- # in the same way the original Chakra Select component is styled,
- # instead of being styled as an InputRightAddon.
- # The original purpose of styling it as an addon
- # was to create a visual separation between the dropdown indicator
- # and the button for clearing the selected options.
- # However, as this button only appears when isMulti is passed,
- # using this style could make more sense for a single select.
- # default: False
- use_basic_style: Var[bool]
-
- # [chakra]
- # The variant of the Select. If no variant is passed,
- # it will default to defaultProps.variant from the theme for Chakra's Input component.
- # If your component theme for Input is not modified, it will be outline.
- # options: "outline" | "filled" | "flushed" | "unstyled"
- # default: "outline"
+ # "outline" | "filled" | "flushed" | "unstyled"
variant: Var[str]
- # How the options should be displayed in the menu.
- menu_position: Var[str] = "fixed" # type: ignore
+ # The size of the select.
+ size: Var[str]
- def get_controlled_triggers(self) -> Dict[str, Var]:
+ @classmethod
+ def get_controlled_triggers(cls) -> Dict[str, Var]:
"""Get the event triggers that pass the component's value to the handler.
Returns:
A dict mapping the event trigger to the var that is passed to the handler.
"""
- # A normal select returns the value.
- value = EVENT_ARG.value
-
- # Multi-select returns a list of values.
- if self.is_multi:
- value = Var.create_safe(f"{EVENT_ARG}.map(e => e.value)", is_local=True)
- return {"on_change": value}
+ return {
+ "on_change": EVENT_ARG.target.value,
+ }
@classmethod
- def get_initial_props(cls) -> Set[str]:
- """Get the initial props to set for the component.
+ def create(cls, *children, **props) -> Component:
+ """Create a select component.
- Returns:
- The initial props to set.
- """
- return super().get_initial_props() | {"is_multi"}
-
- @classmethod
- def create(
- cls, options: List[Union[Option, str, int, float, bool]], **props
- ) -> Component:
- """Takes a list of options and additional properties, checks if each option is an
- instance of Option, and returns a Select component with the given options and
- properties. No children allowed.
+ If a list is provided as the first children, a default component
+ will be created for each item in the list.
Args:
- options (List[Option | str | int | float | bool]): A list of values.
- **props: Additional properties to be passed to the Select component.
+ *children: The children of the component.
+ **props: The props of the component.
Returns:
- The `create` method is returning an instance of the `Select` class.
+ The component.
"""
- converted_options: List[Option] = []
- for option in options:
- if not isinstance(option, Option):
- converted_options.append(Option(label=str(option), value=option))
- else:
- converted_options.append(option)
- props["options"] = [o.dict() for o in converted_options]
- return super().create(*[], **props)
+ if len(children) == 1 and isinstance(children[0], list):
+ children = [Option.create(child) for child in children[0]]
+ if (
+ len(children) == 1
+ and isinstance(children[0], Var)
+ and types._issubclass(children[0].type_, List)
+ ):
+ children = [Foreach.create(children[0], lambda item: Option.create(item))]
+ return super().create(*children, **props)
+
+
+class Option(Text):
+ """A select option."""
+
+ tag = "option"
+
+ value: Var[Any]
+
+ @classmethod
+ def create(cls, *children, **props) -> Component:
+ """Create a select option component.
+
+ By default, the value of the option is the text of the option.
+
+ Args:
+ *children: The children of the component.
+ **props: The props of the component.
+
+ Returns:
+ The component.
+ """
+ if "value" not in props:
+ assert len(children) == 1
+ props["value"] = children[0]
+ return super().create(*children, **props)