@passui/react 0.1.26 → 0.1.27
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/dist/types/src/components/segmented-control/segmented-control.d.ts +3 -1
- package/dist/types/src/components/stat-tile/stat-tile.d.ts +3 -1
- package/dist/types/src/components/swatch-picker/swatch-picker.d.ts +3 -1
- package/dist/types/src/components/text-field/text-field.d.ts +7 -2
- package/dist/types/src/components/toggle/toggle.d.ts +3 -1
- package/package.json +1 -1
- package/src/components/segmented-control/segmented-control.tsx +4 -1
- package/src/components/stat-tile/stat-tile.tsx +17 -5
- package/src/components/swatch-picker/swatch-picker.tsx +4 -1
- package/src/components/text-field/text-field.tsx +58 -4
- package/src/components/toggle/toggle.tsx +18 -4
|
@@ -10,6 +10,8 @@ export interface SegmentedControlProps<T extends string> {
|
|
|
10
10
|
onChange: (value: NoInfer<T>) => void;
|
|
11
11
|
/** Accessible name for the group and its compact picker. */
|
|
12
12
|
label: string;
|
|
13
|
+
/** Custom classes for the control container. */
|
|
14
|
+
className?: string;
|
|
13
15
|
}
|
|
14
16
|
/**
|
|
15
17
|
* Mutually exclusive choices with a sliding selection, as on Apple
|
|
@@ -17,4 +19,4 @@ export interface SegmentedControlProps<T extends string> {
|
|
|
17
19
|
* translation, a narrow pane) it becomes a pop-up button instead of
|
|
18
20
|
* squeezing or spilling its text.
|
|
19
21
|
*/
|
|
20
|
-
export declare function SegmentedControl<T extends string>({ value, options, onChange, label, }: SegmentedControlProps<T>): import("react").JSX.Element;
|
|
22
|
+
export declare function SegmentedControl<T extends string>({ value, options, onChange, label, className, }: SegmentedControlProps<T>): import("react").JSX.Element;
|
|
@@ -10,6 +10,8 @@ export interface StatTileProps {
|
|
|
10
10
|
/** Makes the tile a toggle, e.g. a filter. */
|
|
11
11
|
onClick?: () => void;
|
|
12
12
|
active?: boolean;
|
|
13
|
+
/** Custom classes for the tile container. */
|
|
14
|
+
className?: string;
|
|
13
15
|
}
|
|
14
16
|
/** One number with its label, optionally a toggle. */
|
|
15
|
-
export declare function StatTile({ label, value, caption, tone, onClick, active }: StatTileProps): import("react").JSX.Element;
|
|
17
|
+
export declare function StatTile({ label, value, caption, tone, onClick, active, className, }: StatTileProps): import("react").JSX.Element;
|
|
@@ -12,6 +12,8 @@ export interface SwatchPickerProps<T extends string> {
|
|
|
12
12
|
onChange: (value: T) => void;
|
|
13
13
|
/** Accessible name for the group. */
|
|
14
14
|
label: string;
|
|
15
|
+
/** Custom classes for the swatch container. */
|
|
16
|
+
className?: string;
|
|
15
17
|
}
|
|
16
18
|
/** Colour swatches with a check on the chosen one. */
|
|
17
|
-
export declare function SwatchPicker<T extends string>({ value, options, onChange, label, }: SwatchPickerProps<T>): import("react").JSX.Element;
|
|
19
|
+
export declare function SwatchPicker<T extends string>({ value, options, onChange, label, className, }: SwatchPickerProps<T>): import("react").JSX.Element;
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { type ComponentProps, type ReactNode } from "react";
|
|
2
|
+
/** Shared text control classes for components that reuse TextField's surface. */
|
|
2
3
|
export declare const textControlClasses: string;
|
|
3
|
-
|
|
4
|
+
/** Size scale shared across TextField, SecureField, and form fields. */
|
|
5
|
+
export type TextFieldSize = "xs" | "sm" | "md" | "lg";
|
|
6
|
+
export type TextFieldProps = Omit<ComponentProps<"input">, "size"> & {
|
|
4
7
|
label: string;
|
|
5
8
|
description?: ReactNode;
|
|
6
9
|
errors?: string[];
|
|
@@ -16,5 +19,7 @@ export type TextFieldProps = ComponentProps<"input"> & {
|
|
|
16
19
|
};
|
|
17
20
|
/** Float the label into the outline on focus or when filled. @default "above" */
|
|
18
21
|
labelPlacement?: "above" | "floating";
|
|
22
|
+
/** Field height and text scale. @default "md" */
|
|
23
|
+
size?: TextFieldSize;
|
|
19
24
|
};
|
|
20
|
-
export declare function TextField({ label, description, errors, icon, trailingIcon, action, revealLabels, labelPlacement, placeholder, type, id: suppliedId, className, ...props }: TextFieldProps): import("react").JSX.Element;
|
|
25
|
+
export declare function TextField({ label, description, errors, icon, trailingIcon, action, revealLabels, labelPlacement, size, placeholder, type, id: suppliedId, className, ...props }: TextFieldProps): import("react").JSX.Element;
|
|
@@ -13,5 +13,7 @@ export interface ToggleProps {
|
|
|
13
13
|
mixed?: boolean;
|
|
14
14
|
/** Keeps the accessible name while hiding the visible label. @default false */
|
|
15
15
|
labelHidden?: boolean;
|
|
16
|
+
/** Custom classes for the toggle container. */
|
|
17
|
+
className?: string;
|
|
16
18
|
}
|
|
17
|
-
export declare function Toggle({ checked, onChange, label, disabled, style, mixed, labelHidden, }: ToggleProps): import("react").JSX.Element;
|
|
19
|
+
export declare function Toggle({ checked, onChange, label, disabled, style, mixed, labelHidden, className, }: ToggleProps): import("react").JSX.Element;
|
package/package.json
CHANGED
|
@@ -14,6 +14,8 @@ export interface SegmentedControlProps<T extends string> {
|
|
|
14
14
|
onChange: (value: NoInfer<T>) => void
|
|
15
15
|
/** Accessible name for the group and its compact picker. */
|
|
16
16
|
label: string
|
|
17
|
+
/** Custom classes for the control container. */
|
|
18
|
+
className?: string
|
|
17
19
|
}
|
|
18
20
|
|
|
19
21
|
/**
|
|
@@ -27,6 +29,7 @@ export function SegmentedControl<T extends string>({
|
|
|
27
29
|
options,
|
|
28
30
|
onChange,
|
|
29
31
|
label,
|
|
32
|
+
className,
|
|
30
33
|
}: SegmentedControlProps<T>) {
|
|
31
34
|
const id = useId()
|
|
32
35
|
const reducedMotion = useReducedMotion()
|
|
@@ -47,7 +50,7 @@ export function SegmentedControl<T extends string>({
|
|
|
47
50
|
}, [])
|
|
48
51
|
|
|
49
52
|
return (
|
|
50
|
-
<div ref={frame} className="relative w-full min-w-0">
|
|
53
|
+
<div ref={frame} className={cn("relative w-full min-w-0", className)}>
|
|
51
54
|
{/* The control at its natural size, to know whether it fits. */}
|
|
52
55
|
<div
|
|
53
56
|
ref={measure}
|
|
@@ -13,10 +13,20 @@ export interface StatTileProps {
|
|
|
13
13
|
/** Makes the tile a toggle, e.g. a filter. */
|
|
14
14
|
onClick?: () => void
|
|
15
15
|
active?: boolean
|
|
16
|
+
/** Custom classes for the tile container. */
|
|
17
|
+
className?: string
|
|
16
18
|
}
|
|
17
19
|
|
|
18
20
|
/** One number with its label, optionally a toggle. */
|
|
19
|
-
export function StatTile({
|
|
21
|
+
export function StatTile({
|
|
22
|
+
label,
|
|
23
|
+
value,
|
|
24
|
+
caption,
|
|
25
|
+
tone,
|
|
26
|
+
onClick,
|
|
27
|
+
active = false,
|
|
28
|
+
className,
|
|
29
|
+
}: StatTileProps) {
|
|
20
30
|
const body = (
|
|
21
31
|
<>
|
|
22
32
|
<span className="text-label-secondary">{label}</span>
|
|
@@ -26,17 +36,19 @@ export function StatTile({ label, value, caption, tone, onClick, active = false
|
|
|
26
36
|
{caption && <span className="text-label-secondary">{caption}</span>}
|
|
27
37
|
</>
|
|
28
38
|
)
|
|
29
|
-
const
|
|
30
|
-
"flex min-w-0 flex-col gap-2 rounded-2xl border border-separator/35 bg-elevated p-4 text-left shadow-xs"
|
|
39
|
+
const tileClass = cn(
|
|
40
|
+
"flex min-w-0 flex-col gap-2 rounded-2xl border border-separator/35 bg-elevated p-4 text-left shadow-xs",
|
|
41
|
+
className
|
|
42
|
+
)
|
|
31
43
|
|
|
32
|
-
if (!onClick) return <div className={
|
|
44
|
+
if (!onClick) return <div className={tileClass}>{body}</div>
|
|
33
45
|
return (
|
|
34
46
|
<button
|
|
35
47
|
type="button"
|
|
36
48
|
aria-pressed={active}
|
|
37
49
|
onClick={onClick}
|
|
38
50
|
className={cn(
|
|
39
|
-
|
|
51
|
+
tileClass,
|
|
40
52
|
"ring-1 ring-transparent transition-colors hover:bg-fill/60",
|
|
41
53
|
active && "bg-fill/70 ring-label/15"
|
|
42
54
|
)}
|
|
@@ -20,6 +20,8 @@ export interface SwatchPickerProps<T extends string> {
|
|
|
20
20
|
onChange: (value: T) => void
|
|
21
21
|
/** Accessible name for the group. */
|
|
22
22
|
label: string
|
|
23
|
+
/** Custom classes for the swatch container. */
|
|
24
|
+
className?: string
|
|
23
25
|
}
|
|
24
26
|
|
|
25
27
|
/** Colour swatches with a check on the chosen one. */
|
|
@@ -28,10 +30,11 @@ export function SwatchPicker<T extends string>({
|
|
|
28
30
|
options,
|
|
29
31
|
onChange,
|
|
30
32
|
label,
|
|
33
|
+
className,
|
|
31
34
|
}: SwatchPickerProps<T>) {
|
|
32
35
|
const name = useId()
|
|
33
36
|
return (
|
|
34
|
-
<fieldset className="flex flex-wrap gap-3">
|
|
37
|
+
<fieldset className={cn("flex flex-wrap gap-3", className)}>
|
|
35
38
|
<legend className="sr-only">{label}</legend>
|
|
36
39
|
{options.map((option) => {
|
|
37
40
|
const selected = option.value === value
|
|
@@ -2,6 +2,7 @@ import { type ComponentProps, type ReactNode, useId, useState } from "react"
|
|
|
2
2
|
import { Button } from "../button/button"
|
|
3
3
|
import { cn } from "../../lib/class-names"
|
|
4
4
|
|
|
5
|
+
/** Shared text control classes for components that reuse TextField's surface. */
|
|
5
6
|
export const textControlClasses = cn(
|
|
6
7
|
"w-full min-w-0 rounded-xl border border-separator bg-elevated",
|
|
7
8
|
"px-3 py-2 text-body text-label placeholder:text-label-tertiary",
|
|
@@ -11,7 +12,55 @@ export const textControlClasses = cn(
|
|
|
11
12
|
|
|
12
13
|
const fieldIconClasses = "flex shrink-0 items-center text-label-secondary"
|
|
13
14
|
|
|
14
|
-
|
|
15
|
+
/** Size scale shared across TextField, SecureField, and form fields. */
|
|
16
|
+
export type TextFieldSize = "xs" | "sm" | "md" | "lg"
|
|
17
|
+
|
|
18
|
+
interface FieldSize {
|
|
19
|
+
height: string
|
|
20
|
+
floatingHeight: string
|
|
21
|
+
padding: string
|
|
22
|
+
text: string
|
|
23
|
+
radius: string
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function fieldSize(size: TextFieldSize): FieldSize {
|
|
27
|
+
switch (size) {
|
|
28
|
+
case "xs":
|
|
29
|
+
return {
|
|
30
|
+
height: "h-8",
|
|
31
|
+
floatingHeight: "h-9",
|
|
32
|
+
padding: "px-2.5",
|
|
33
|
+
text: "text-caption",
|
|
34
|
+
radius: "rounded-lg",
|
|
35
|
+
}
|
|
36
|
+
case "sm":
|
|
37
|
+
return {
|
|
38
|
+
height: "h-9",
|
|
39
|
+
floatingHeight: "h-10",
|
|
40
|
+
padding: "px-3",
|
|
41
|
+
text: "text-subheadline",
|
|
42
|
+
radius: "rounded-xl",
|
|
43
|
+
}
|
|
44
|
+
case "lg":
|
|
45
|
+
return {
|
|
46
|
+
height: "h-12",
|
|
47
|
+
floatingHeight: "h-14",
|
|
48
|
+
padding: "px-4",
|
|
49
|
+
text: "text-body",
|
|
50
|
+
radius: "rounded-xl",
|
|
51
|
+
}
|
|
52
|
+
default:
|
|
53
|
+
return {
|
|
54
|
+
height: "h-11",
|
|
55
|
+
floatingHeight: "h-12",
|
|
56
|
+
padding: "px-3",
|
|
57
|
+
text: "text-body",
|
|
58
|
+
radius: "rounded-xl",
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export type TextFieldProps = Omit<ComponentProps<"input">, "size"> & {
|
|
15
64
|
label: string
|
|
16
65
|
description?: ReactNode
|
|
17
66
|
errors?: string[]
|
|
@@ -24,6 +73,8 @@ export type TextFieldProps = ComponentProps<"input"> & {
|
|
|
24
73
|
revealLabels?: { show: string; hide: string }
|
|
25
74
|
/** Float the label into the outline on focus or when filled. @default "above" */
|
|
26
75
|
labelPlacement?: "above" | "floating"
|
|
76
|
+
/** Field height and text scale. @default "md" */
|
|
77
|
+
size?: TextFieldSize
|
|
27
78
|
}
|
|
28
79
|
|
|
29
80
|
export function TextField({
|
|
@@ -35,6 +86,7 @@ export function TextField({
|
|
|
35
86
|
action,
|
|
36
87
|
revealLabels,
|
|
37
88
|
labelPlacement = "above",
|
|
89
|
+
size = "md",
|
|
38
90
|
placeholder,
|
|
39
91
|
type = "text",
|
|
40
92
|
id: suppliedId,
|
|
@@ -46,6 +98,7 @@ export function TextField({
|
|
|
46
98
|
const [revealed, setRevealed] = useState(false)
|
|
47
99
|
const messages = Array.from(new Set(errors))
|
|
48
100
|
const reveal = type === "password" && revealLabels
|
|
101
|
+
const dims = fieldSize(size)
|
|
49
102
|
return (
|
|
50
103
|
<div className="not-typeset flex flex-col gap-2">
|
|
51
104
|
{labelPlacement === "above" && (
|
|
@@ -55,7 +108,7 @@ export function TextField({
|
|
|
55
108
|
)}
|
|
56
109
|
<div
|
|
57
110
|
className={cn(
|
|
58
|
-
|
|
111
|
+
`relative flex items-center gap-2 ${dims.padding} ${dims.radius} bg-elevated`,
|
|
59
112
|
labelPlacement === "floating"
|
|
60
113
|
? "passui-floating-field"
|
|
61
114
|
: "border border-separator focus-within:ring-1 focus-within:ring-accent/40 has-[:focus-visible]:ring-2 has-[:focus-visible]:ring-accent-text/70"
|
|
@@ -99,8 +152,9 @@ export function TextField({
|
|
|
99
152
|
.join(" ") || undefined
|
|
100
153
|
}
|
|
101
154
|
className={cn(
|
|
102
|
-
|
|
103
|
-
|
|
155
|
+
labelPlacement === "floating" ? dims.floatingHeight : dims.height,
|
|
156
|
+
"w-full min-w-0 bg-transparent text-label outline-none",
|
|
157
|
+
dims.text,
|
|
104
158
|
"placeholder:text-label-tertiary disabled:opacity-40",
|
|
105
159
|
className
|
|
106
160
|
)}
|
|
@@ -28,6 +28,8 @@ export interface ToggleProps {
|
|
|
28
28
|
mixed?: boolean
|
|
29
29
|
/** Keeps the accessible name while hiding the visible label. @default false */
|
|
30
30
|
labelHidden?: boolean
|
|
31
|
+
/** Custom classes for the toggle container. */
|
|
32
|
+
className?: string
|
|
31
33
|
}
|
|
32
34
|
|
|
33
35
|
export function Toggle({
|
|
@@ -38,6 +40,7 @@ export function Toggle({
|
|
|
38
40
|
style = "switch",
|
|
39
41
|
mixed = false,
|
|
40
42
|
labelHidden = false,
|
|
43
|
+
className,
|
|
41
44
|
}: ToggleProps) {
|
|
42
45
|
const input = useRef<HTMLInputElement>(null)
|
|
43
46
|
useEffect(() => {
|
|
@@ -48,7 +51,8 @@ export function Toggle({
|
|
|
48
51
|
<label
|
|
49
52
|
className={cn(
|
|
50
53
|
"flex cursor-pointer items-center gap-3 text-subheadline",
|
|
51
|
-
disabled && "cursor-not-allowed opacity-40"
|
|
54
|
+
disabled && "cursor-not-allowed opacity-40",
|
|
55
|
+
className
|
|
52
56
|
)}
|
|
53
57
|
>
|
|
54
58
|
<span className="relative inline-flex size-5 shrink-0">
|
|
@@ -82,7 +86,15 @@ export function Toggle({
|
|
|
82
86
|
</label>
|
|
83
87
|
)
|
|
84
88
|
}
|
|
85
|
-
return
|
|
89
|
+
return (
|
|
90
|
+
<SwitchToggle
|
|
91
|
+
checked={checked}
|
|
92
|
+
onChange={onChange}
|
|
93
|
+
label={label}
|
|
94
|
+
disabled={disabled}
|
|
95
|
+
className={className}
|
|
96
|
+
/>
|
|
97
|
+
)
|
|
86
98
|
}
|
|
87
99
|
|
|
88
100
|
function SwitchToggle({
|
|
@@ -90,7 +102,8 @@ function SwitchToggle({
|
|
|
90
102
|
onChange,
|
|
91
103
|
label,
|
|
92
104
|
disabled,
|
|
93
|
-
|
|
105
|
+
className,
|
|
106
|
+
}: Pick<ToggleProps, "checked" | "onChange" | "label" | "disabled" | "className">) {
|
|
94
107
|
const reducedMotion = useReducedMotion()
|
|
95
108
|
const id = `toggle-goo-${useId().replace(/:/g, "")}`
|
|
96
109
|
const x = useMotionValue(checked ? 22 : 2)
|
|
@@ -163,7 +176,8 @@ function SwitchToggle({
|
|
|
163
176
|
className={cn(
|
|
164
177
|
"relative h-[30px] w-[50px] shrink-0 touch-pan-y rounded-full transition-colors duration-normal motion-reduce:transition-none",
|
|
165
178
|
"shadow-[inset_0_1px_2px_rgb(0_0_0/0.10)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent/70 focus-visible:ring-offset-1 focus-visible:ring-offset-background disabled:opacity-45",
|
|
166
|
-
checked ? "bg-accent" : "bg-separator/80"
|
|
179
|
+
checked ? "bg-accent" : "bg-separator/80",
|
|
180
|
+
className
|
|
167
181
|
)}
|
|
168
182
|
>
|
|
169
183
|
<svg aria-hidden="true" width="0" height="0" className="absolute">
|