diff --git a/assets/docs/components/switch.md b/assets/docs/components/switch.md index 3a718da6..3c01cc8a 100644 --- a/assets/docs/components/switch.md +++ b/assets/docs/components/switch.md @@ -73,6 +73,28 @@ class ClassNames: INPUT = "peer sr-only" + KNOWN_INPUT_PROPS = ( + "id", + "checked", + "default_checked", + "disabled", + "required", + "name", + "value", + "on_change", + "auto_focus", + "read_only", + "tab_index", + "access_key", + "form", + "form_action", + "form_enc_type", + "form_method", + "form_no_validate", + "form_target", + "custom_attrs", + ) + TRACK = ( "relative rounded-full bg-muted " "outline-none " @@ -80,7 +102,7 @@ class ClassNames: "group-data-[size=sm]/switch:h-[14px] group-data-[size=sm]/switch:w-[24px] " "group-has-[input:checked]/switch:bg-primary " "peer-focus-visible:ring-3 peer-focus-visible:ring-ring/50 peer-focus-visible:outline-1 peer-focus-visible:outline-ring " - "group-aria-[invalid=true]/switch:border-destructive group-aria-[invalid=true]/switch:ring-3 group-aria-[invalid=true]/switch:ring-destructive/20 " + "peer-aria-[invalid=true]:border-destructive peer-aria-[invalid=true]:ring-3 peer-aria-[invalid=true]:ring-destructive/20 " "group-has-[:disabled]/switch:opacity-50 group-has-[:disabled]/switch:pointer-events-none group-has-[:disabled]/switch:cursor-not-allowed" ) @@ -100,33 +122,24 @@ class ClassNames: class NativeSwitch(CoreComponent): @classmethod def create(cls, label_text: str = "", **props) -> rx.Component: - props["data-slot"] = "switch" - size = props.pop("size", "default") - props["data-size"] = size - invalid = props.pop("invalid", False) - if invalid: - props["aria-invalid"] = "true" - track_class_name = props.pop("track_class_name", "") thumb_class_name = props.pop("thumb_class_name", "") input_props = {} - for key in ( - "id", - "checked", - "default_checked", - "disabled", - "required", - "name", - "value", - "on_change", - "custom_attrs", - ): - if key in props: + for key in list(props.keys()): + if key in ClassNames.KNOWN_INPUT_PROPS or key.startswith( + ("on_", "data-", "data_", "aria-", "aria_"), + ): input_props[key] = props.pop(key) + if invalid: + input_props["aria-invalid"] = "true" + + props["data-slot"] = "switch" + props["data-size"] = size + cls.set_class_name(ClassNames.ROOT, props) return rx.el.label( diff --git a/components/ui/switch.py b/components/ui/switch.py index 9f367a0d..8b421f2e 100644 --- a/components/ui/switch.py +++ b/components/ui/switch.py @@ -9,6 +9,28 @@ class ClassNames: INPUT = "peer sr-only" + KNOWN_INPUT_PROPS = ( + "id", + "checked", + "default_checked", + "disabled", + "required", + "name", + "value", + "on_change", + "auto_focus", + "read_only", + "tab_index", + "access_key", + "form", + "form_action", + "form_enc_type", + "form_method", + "form_no_validate", + "form_target", + "custom_attrs", + ) + TRACK = ( "relative rounded-full bg-muted " "outline-none " @@ -16,7 +38,7 @@ class ClassNames: "group-data-[size=sm]/switch:h-[14px] group-data-[size=sm]/switch:w-[24px] " "group-has-[input:checked]/switch:bg-primary " "peer-focus-visible:ring-3 peer-focus-visible:ring-ring/50 peer-focus-visible:outline-1 peer-focus-visible:outline-ring " - "group-aria-[invalid=true]/switch:border-destructive group-aria-[invalid=true]/switch:ring-3 group-aria-[invalid=true]/switch:ring-destructive/20 " + "peer-aria-[invalid=true]:border-destructive peer-aria-[invalid=true]:ring-3 peer-aria-[invalid=true]:ring-destructive/20 " "group-has-[:disabled]/switch:opacity-50 group-has-[:disabled]/switch:pointer-events-none group-has-[:disabled]/switch:cursor-not-allowed" ) @@ -36,33 +58,24 @@ class ClassNames: class NativeSwitch(CoreComponent): @classmethod def create(cls, label_text: str = "", **props) -> rx.Component: - props["data-slot"] = "switch" - size = props.pop("size", "default") - props["data-size"] = size - invalid = props.pop("invalid", False) - if invalid: - props["aria-invalid"] = "true" - track_class_name = props.pop("track_class_name", "") thumb_class_name = props.pop("thumb_class_name", "") input_props = {} - for key in ( - "id", - "checked", - "default_checked", - "disabled", - "required", - "name", - "value", - "on_change", - "custom_attrs", - ): - if key in props: + for key in list(props.keys()): + if key in ClassNames.KNOWN_INPUT_PROPS or key.startswith( + ("on_", "data-", "data_", "aria-", "aria_"), + ): input_props[key] = props.pop(key) + if invalid: + input_props["aria-invalid"] = "true" + + props["data-slot"] = "switch" + props["data-size"] = size + cls.set_class_name(ClassNames.ROOT, props) return rx.el.label( diff --git a/tests/test_switch_passthrough.py b/tests/test_switch_passthrough.py new file mode 100644 index 00000000..e7926283 --- /dev/null +++ b/tests/test_switch_passthrough.py @@ -0,0 +1,353 @@ +"""Regression tests for ``switch.root``'s documented input peer pass-through. + +``switch.root`` renders a hidden native ```` wrapped in a +clickable ``