form support more inputs (#1554)
This commit is contained in:
parent
2c61077796
commit
cd47815a4d
@ -383,12 +383,26 @@ export const preventDefault = (event) => {
|
||||
* @returns The value.
|
||||
*/
|
||||
export const getRefValue = (ref) => {
|
||||
if (!ref || !ref.current){
|
||||
if (!ref || !ref.current) {
|
||||
return;
|
||||
}
|
||||
if (ref.current.type == "checkbox") {
|
||||
return ref.current.checked;
|
||||
} 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"));
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ DEFAULT_IMPORTS: imports.ImportDict = {
|
||||
ImportVar(tag="preventDefault"),
|
||||
ImportVar(tag="refs"),
|
||||
ImportVar(tag="getRefValue"),
|
||||
ImportVar(tag="getRefValues"),
|
||||
ImportVar(tag="getAllLocalStorageItems"),
|
||||
},
|
||||
"": {ImportVar(tag="focus-visible/dist/focus-visible")},
|
||||
|
@ -22,12 +22,18 @@ class Form(ChakraComponent):
|
||||
A dict mapping the event trigger to the var that is passed to the handler.
|
||||
"""
|
||||
# Send all the input refs to the handler.
|
||||
return {
|
||||
"on_submit": {
|
||||
ref[4:]: Var.create(f"getRefValue({ref})", is_local=False)
|
||||
for ref in self.get_refs()
|
||||
}
|
||||
}
|
||||
form_refs = {}
|
||||
for ref in self.get_refs():
|
||||
# when ref start with refs_ it's an array of refs, so we need different method
|
||||
# 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):
|
||||
|
@ -88,8 +88,9 @@ class NumberInput(ChakraComponent):
|
||||
The component.
|
||||
"""
|
||||
if len(children) == 0:
|
||||
_id = props.pop("id", None)
|
||||
children = [
|
||||
NumberInputField.create(),
|
||||
NumberInputField.create(id=_id) if _id else NumberInputField.create(),
|
||||
NumberInputStepper.create(
|
||||
NumberIncrementStepper.create(),
|
||||
NumberDecrementStepper.create(),
|
||||
|
@ -1,10 +1,12 @@
|
||||
"""A pin input component."""
|
||||
|
||||
from typing import Dict
|
||||
from typing import Dict, Optional
|
||||
|
||||
from reflex.components.component import Component
|
||||
from reflex.components.layout import Foreach
|
||||
from reflex.components.libs.chakra import ChakraComponent
|
||||
from reflex.event import EVENT_ARG
|
||||
from reflex.utils import format
|
||||
from reflex.vars import Var
|
||||
|
||||
|
||||
@ -66,6 +68,26 @@ class PinInput(ChakraComponent):
|
||||
"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
|
||||
def create(cls, *children, **props) -> Component:
|
||||
"""Create a pin input component.
|
||||
@ -81,7 +103,21 @@ class PinInput(ChakraComponent):
|
||||
The pin input component.
|
||||
"""
|
||||
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)
|
||||
|
||||
|
||||
@ -89,3 +125,19 @@ class PinInputField(ChakraComponent):
|
||||
"""The text field that user types in - must be a direct child of PinInput."""
|
||||
|
||||
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)
|
||||
|
@ -1,10 +1,11 @@
|
||||
"""A range slider component."""
|
||||
|
||||
from typing import Dict, List
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
from reflex.components.component import Component
|
||||
from reflex.components.libs.chakra import ChakraComponent
|
||||
from reflex.event import EVENT_ARG
|
||||
from reflex.utils import format
|
||||
from reflex.vars import Var
|
||||
|
||||
|
||||
@ -55,6 +56,26 @@ class RangeSlider(ChakraComponent):
|
||||
"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
|
||||
def create(cls, *children, **props) -> Component:
|
||||
"""Create a RangeSlider component.
|
||||
@ -69,13 +90,23 @@ class RangeSlider(ChakraComponent):
|
||||
The RangeSlider component.
|
||||
"""
|
||||
if len(children) == 0:
|
||||
children = [
|
||||
RangeSliderTrack.create(
|
||||
RangeSliderFilledTrack.create(),
|
||||
),
|
||||
RangeSliderThumb.create(index=0),
|
||||
RangeSliderThumb.create(index=1),
|
||||
]
|
||||
_id = props.get("id", None)
|
||||
if _id:
|
||||
children = [
|
||||
RangeSliderTrack.create(
|
||||
RangeSliderFilledTrack.create(),
|
||||
),
|
||||
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)
|
||||
|
||||
|
||||
@ -98,3 +129,16 @@ class RangeSliderThumb(ChakraComponent):
|
||||
|
||||
# The position of the thumb.
|
||||
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)
|
||||
|
@ -434,6 +434,24 @@ def format_ref(ref: str) -> str:
|
||||
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:
|
||||
"""Format a dict with vars potentially as values.
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user