form support more inputs (#1554)

This commit is contained in:
Thomas Brandého 2023-08-10 18:54:04 +02:00 committed by GitHub
parent 2c61077796
commit cd47815a4d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 155 additions and 19 deletions

View File

@ -383,12 +383,26 @@ export const preventDefault = (event) => {
* @returns The value. * @returns The value.
*/ */
export const getRefValue = (ref) => { export const getRefValue = (ref) => {
if (!ref || !ref.current){ if (!ref || !ref.current) {
return; return;
} }
if (ref.current.type == "checkbox") { if (ref.current.type == "checkbox") {
return ref.current.checked; return ref.current.checked;
} else { } else {
return ref.current.value; //querySelector(":checked") is needed to get value from radio_group
return ref.current.value || (ref.current.querySelector(':checked') && ref.current.querySelector(':checked').value);
} }
} }
/**
* Get the values from a ref array.
* @param refs The refs to get the values from.
* @returns The values array.
*/
export const getRefValues = (refs) => {
if (!refs) {
return;
}
// getAttribute is used by RangeSlider because it doesn't assign value
return refs.map((ref) => ref.current.value || ref.current.getAttribute("aria-valuenow"));
}

View File

@ -28,6 +28,7 @@ DEFAULT_IMPORTS: imports.ImportDict = {
ImportVar(tag="preventDefault"), ImportVar(tag="preventDefault"),
ImportVar(tag="refs"), ImportVar(tag="refs"),
ImportVar(tag="getRefValue"), ImportVar(tag="getRefValue"),
ImportVar(tag="getRefValues"),
ImportVar(tag="getAllLocalStorageItems"), ImportVar(tag="getAllLocalStorageItems"),
}, },
"": {ImportVar(tag="focus-visible/dist/focus-visible")}, "": {ImportVar(tag="focus-visible/dist/focus-visible")},

View File

@ -22,12 +22,18 @@ class Form(ChakraComponent):
A dict mapping the event trigger to the var that is passed to the handler. A dict mapping the event trigger to the var that is passed to the handler.
""" """
# Send all the input refs to the handler. # Send all the input refs to the handler.
return { form_refs = {}
"on_submit": { for ref in self.get_refs():
ref[4:]: Var.create(f"getRefValue({ref})", is_local=False) # when ref start with refs_ it's an array of refs, so we need different method
for ref in self.get_refs() # to collect data
} if ref.startswith("refs_"):
} form_refs[ref[5:-3]] = Var.create(
f"getRefValues({ref[:-3]})", is_local=False
)
else:
form_refs[ref[4:]] = Var.create(f"getRefValue({ref})", is_local=False)
return {"on_submit": form_refs}
class FormControl(ChakraComponent): class FormControl(ChakraComponent):

View File

@ -88,8 +88,9 @@ class NumberInput(ChakraComponent):
The component. The component.
""" """
if len(children) == 0: if len(children) == 0:
_id = props.pop("id", None)
children = [ children = [
NumberInputField.create(), NumberInputField.create(id=_id) if _id else NumberInputField.create(),
NumberInputStepper.create( NumberInputStepper.create(
NumberIncrementStepper.create(), NumberIncrementStepper.create(),
NumberDecrementStepper.create(), NumberDecrementStepper.create(),

View File

@ -1,10 +1,12 @@
"""A pin input component.""" """A pin input component."""
from typing import Dict from typing import Dict, Optional
from reflex.components.component import Component from reflex.components.component import Component
from reflex.components.layout import Foreach
from reflex.components.libs.chakra import ChakraComponent from reflex.components.libs.chakra import ChakraComponent
from reflex.event import EVENT_ARG from reflex.event import EVENT_ARG
from reflex.utils import format
from reflex.vars import Var from reflex.vars import Var
@ -66,6 +68,26 @@ class PinInput(ChakraComponent):
"on_complete": EVENT_ARG, "on_complete": EVENT_ARG,
} }
def get_ref(self):
"""Return a reference because we actually attached the ref to the PinInputFields.
Returns:
None.
"""
return None
def _get_hooks(self) -> Optional[str]:
"""Override the base get_hooks to handle array refs.
Returns:
The overrided hooks.
"""
if self.id:
ref = format.format_array_ref(self.id, None)
if ref:
return f"const {ref} = Array.from({{length:{self.length}}}, () => useRef(null));"
return super()._get_hooks()
@classmethod @classmethod
def create(cls, *children, **props) -> Component: def create(cls, *children, **props) -> Component:
"""Create a pin input component. """Create a pin input component.
@ -81,7 +103,21 @@ class PinInput(ChakraComponent):
The pin input component. The pin input component.
""" """
if not children and "length" in props: if not children and "length" in props:
children = [PinInputField()] * props["length"] _id = props.get("id", None)
length = props["length"]
if _id:
children = [
Foreach.create(
list(range(length)), # type: ignore
lambda ref, i: PinInputField.create(
key=i,
id=_id,
index=i,
),
)
]
else:
children = [PinInputField()] * length
return super().create(*children, **props) return super().create(*children, **props)
@ -89,3 +125,19 @@ class PinInputField(ChakraComponent):
"""The text field that user types in - must be a direct child of PinInput.""" """The text field that user types in - must be a direct child of PinInput."""
tag = "PinInputField" tag = "PinInputField"
# the position of the PinInputField inside the PinInput.
# Default to None because it is assigned by PinInput when created.
index: Optional[Var[int]] = None
def _get_hooks(self) -> Optional[str]:
return None
def get_ref(self):
"""Get the array ref for the pin input.
Returns:
The array ref.
"""
if self.id:
return format.format_array_ref(self.id, self.index)

View File

@ -1,10 +1,11 @@
"""A range slider component.""" """A range slider component."""
from typing import Dict, List from typing import Dict, List, Optional
from reflex.components.component import Component from reflex.components.component import Component
from reflex.components.libs.chakra import ChakraComponent from reflex.components.libs.chakra import ChakraComponent
from reflex.event import EVENT_ARG from reflex.event import EVENT_ARG
from reflex.utils import format
from reflex.vars import Var from reflex.vars import Var
@ -55,6 +56,26 @@ class RangeSlider(ChakraComponent):
"on_change_start": EVENT_ARG, "on_change_start": EVENT_ARG,
} }
def get_ref(self):
"""Get the ref of the component.
Returns:
The ref of the component.
"""
return None
def _get_hooks(self) -> Optional[str]:
"""Override the base get_hooks to handle array refs.
Returns:
The overrided hooks.
"""
if self.id:
ref = format.format_array_ref(self.id, None)
if ref:
return f"const {ref} = Array.from({{length:2}}, () => useRef(null));"
return super()._get_hooks()
@classmethod @classmethod
def create(cls, *children, **props) -> Component: def create(cls, *children, **props) -> Component:
"""Create a RangeSlider component. """Create a RangeSlider component.
@ -69,13 +90,23 @@ class RangeSlider(ChakraComponent):
The RangeSlider component. The RangeSlider component.
""" """
if len(children) == 0: if len(children) == 0:
children = [ _id = props.get("id", None)
RangeSliderTrack.create( if _id:
RangeSliderFilledTrack.create(), children = [
), RangeSliderTrack.create(
RangeSliderThumb.create(index=0), RangeSliderFilledTrack.create(),
RangeSliderThumb.create(index=1), ),
] RangeSliderThumb.create(index=0, id=_id),
RangeSliderThumb.create(index=1, id=_id),
]
else:
children = [
RangeSliderTrack.create(
RangeSliderFilledTrack.create(),
),
RangeSliderThumb.create(index=0),
RangeSliderThumb.create(index=1),
]
return super().create(*children, **props) return super().create(*children, **props)
@ -98,3 +129,16 @@ class RangeSliderThumb(ChakraComponent):
# The position of the thumb. # The position of the thumb.
index: Var[int] index: Var[int]
def _get_hooks(self) -> Optional[str]:
# hook is None because RangeSlider is handling it.
return None
def get_ref(self):
"""Get an array ref for the range slider thumb.
Returns:
The array ref.
"""
if self.id:
return format.format_array_ref(self.id, self.index)

View File

@ -434,6 +434,24 @@ def format_ref(ref: str) -> str:
return f"ref_{clean_ref}" return f"ref_{clean_ref}"
def format_array_ref(refs: str, idx) -> str:
"""Format a ref accessed by array.
Args:
refs : The ref array to access.
idx : The index of the ref in the array.
Returns:
The formatted ref.
"""
clean_ref = re.sub(r"[^\w]+", "_", refs)
if idx:
idx.is_local = True
return f"refs_{clean_ref}[{idx}]"
else:
return f"refs_{clean_ref}"
def format_dict(prop: ComponentStyle) -> str: def format_dict(prop: ComponentStyle) -> str:
"""Format a dict with vars potentially as values. """Format a dict with vars potentially as values.