revert pc select to original (#1123)

This commit is contained in:
Elijah Ahianyo 2023-06-02 19:34:48 +00:00 committed by GitHub
parent f790b28c49
commit 45ca318eb2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 422 additions and 308 deletions

View File

@ -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

View File

@ -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,

View File

@ -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 <Box /> 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)

View File

@ -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 <Box /> 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)