@purpurds/toggle 7.6.1 → 7.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/toggle.tsx CHANGED
@@ -1,16 +1,17 @@
1
- import React, { type ForwardedRef, forwardRef, useState } from "react";
1
+ import React, { forwardRef, useState } from "react";
2
+ import type { BaseProps } from "@purpurds/common-types";
2
3
  import { Icon } from "@purpurds/icon";
3
4
  import { checkmarkBold } from "@purpurds/icon/assets/checkmark-bold";
4
5
  import { Label } from "@purpurds/label";
5
6
  import { Paragraph } from "@purpurds/paragraph";
6
7
  import * as Switch from "@radix-ui/react-switch";
7
- import c from "classnames";
8
+ import c from "classnames/bind";
8
9
 
9
10
  import { DraggableX } from "./DraggableX";
10
11
  import { useToggleDrag } from "./hooks/useToggleDrag";
11
12
  import styles from "./toggle.module.scss";
12
13
 
13
- export type ToggleProps = Omit<React.HTMLAttributes<HTMLElement>, "onChange"> & {
14
+ export type ToggleProps = Omit<BaseProps<"button">, "onChange" | "children" | "id"> & {
14
15
  /**
15
16
  * To use when no label is given.
16
17
  * */
@@ -19,7 +20,6 @@ export type ToggleProps = Omit<React.HTMLAttributes<HTMLElement>, "onChange"> &
19
20
  * To use with custom label (not recommended).
20
21
  * */
21
22
  ["aria-labelledby"]?: string;
22
- ["data-testid"]?: string;
23
23
  /**
24
24
  * The controlled state of the toggle. Must be used in conjunction with `onChange`.
25
25
  * */
@@ -66,88 +66,80 @@ export type ToggleProps = Omit<React.HTMLAttributes<HTMLElement>, "onChange"> &
66
66
  value?: string;
67
67
  };
68
68
 
69
+ const cx = c.bind(styles);
69
70
  const rootClassName = "purpur-toggle";
70
71
 
71
- const ToggleComponent = (
72
- {
73
- ["data-testid"]: dataTestId,
74
- className,
75
- label,
76
- onChange,
77
- labelPosition = "right",
78
- checked,
79
- disableDrag,
80
- defaultChecked,
81
- ...props
82
- }: ToggleProps,
83
- ref: ForwardedRef<HTMLButtonElement>
84
- ) => {
85
- const [internalChecked, setInternalChecked] = useState(
86
- typeof checked === "boolean" ? checked : !!defaultChecked
87
- );
88
- const isChecked = Boolean(typeof checked === "boolean" ? checked : internalChecked);
89
- const { thumbRef, trackRef, isDragging, onChangeWithDrag, ...draggableXProps } = useToggleDrag({
90
- checked: isChecked,
91
- onChange: (value) => {
92
- if (!props.disabled) {
93
- onChange?.(value);
94
- setInternalChecked(value);
95
- }
72
+ export const Toggle = forwardRef<HTMLButtonElement, ToggleProps>(
73
+ (
74
+ {
75
+ ["data-testid"]: dataTestId,
76
+ className,
77
+ label,
78
+ onChange,
79
+ labelPosition = "right",
80
+ checked,
81
+ disableDrag,
82
+ defaultChecked,
83
+ ...props
96
84
  },
97
- });
85
+ ref
86
+ ) => {
87
+ const [internalChecked, setInternalChecked] = useState(
88
+ typeof checked === "boolean" ? checked : !!defaultChecked
89
+ );
90
+ const isChecked = Boolean(typeof checked === "boolean" ? checked : internalChecked);
91
+ const { thumbRef, trackRef, isDragging, onChangeWithDrag, ...draggableXProps } = useToggleDrag({
92
+ checked: isChecked,
93
+ onChange: (value) => {
94
+ if (!props.disabled) {
95
+ onChange?.(value);
96
+ setInternalChecked(value);
97
+ }
98
+ },
99
+ });
98
100
 
99
- const renderLabel = () => (
100
- <Label
101
- htmlFor={props.id}
102
- data-testid={dataTestId && `${dataTestId}-label`}
103
- disabled={props.disabled}
104
- className={c(
105
- styles[`${rootClassName}__label`],
106
- styles[`${rootClassName}__label--${labelPosition}`]
107
- )}
108
- >
109
- <Paragraph disabled={props.disabled}>{label}</Paragraph>
110
- </Label>
111
- );
112
-
113
- return (
114
- <div className={c([className, styles[`${rootClassName}__container`]])}>
115
- {label && labelPosition === "left" && renderLabel()}
116
- <Switch.Root
117
- {...props}
118
- ref={ref}
119
- id={props.id}
120
- data-testid={dataTestId}
121
- className={styles[rootClassName]}
122
- onCheckedChange={onChangeWithDrag}
123
- checked={isChecked}
101
+ const renderLabel = () => (
102
+ <Label
103
+ htmlFor={props.id}
104
+ data-testid={dataTestId && `${dataTestId}-label`}
105
+ disabled={props.disabled}
106
+ className={cx(`${rootClassName}__label`, `${rootClassName}__label--${labelPosition}`)}
124
107
  >
125
- <span ref={trackRef} className={styles[`${rootClassName}__track`]}>
126
- <span className={styles[`${rootClassName}__checkmark-container`]}>
127
- <Icon
128
- className={styles[`${rootClassName}__checkmark`]}
129
- svg={checkmarkBold}
130
- size="xxs"
131
- />
108
+ <Paragraph disabled={props.disabled}>{label}</Paragraph>
109
+ </Label>
110
+ );
111
+
112
+ return (
113
+ <div className={cx(className, `${rootClassName}__container`)}>
114
+ {label && labelPosition === "left" && renderLabel()}
115
+ <Switch.Root
116
+ {...props}
117
+ ref={ref}
118
+ id={props.id}
119
+ data-testid={dataTestId}
120
+ className={cx(rootClassName)}
121
+ onCheckedChange={onChangeWithDrag}
122
+ checked={isChecked}
123
+ >
124
+ <span ref={trackRef} className={cx(`${rootClassName}__track`)}>
125
+ <span className={cx(`${rootClassName}__checkmark-container`)}>
126
+ <Icon className={cx(`${rootClassName}__checkmark`)} svg={checkmarkBold} size="xxs" />
127
+ </span>
128
+ <DraggableX disabled={disableDrag} {...draggableXProps}>
129
+ <Switch.Thumb
130
+ ref={thumbRef}
131
+ data-testid={dataTestId && `${dataTestId}-thumb`}
132
+ className={cx(`${rootClassName}__thumb`, {
133
+ [`${rootClassName}__thumb--dragging`]: isDragging,
134
+ })}
135
+ />
136
+ </DraggableX>
132
137
  </span>
133
- <DraggableX disabled={disableDrag} {...draggableXProps}>
134
- <Switch.Thumb
135
- ref={thumbRef}
136
- data-testid={dataTestId && `${dataTestId}-thumb`}
137
- className={c([
138
- styles[`${rootClassName}__thumb`],
139
- {
140
- [styles[`${rootClassName}__thumb--dragging`]]: isDragging,
141
- },
142
- ])}
143
- />
144
- </DraggableX>
145
- </span>
146
- </Switch.Root>
147
- {label && labelPosition === "right" && renderLabel()}
148
- </div>
149
- );
150
- };
138
+ </Switch.Root>
139
+ {label && labelPosition === "right" && renderLabel()}
140
+ </div>
141
+ );
142
+ }
143
+ );
151
144
 
152
- export const Toggle = forwardRef(ToggleComponent);
153
145
  Toggle.displayName = "Toggle";