|
1 | 1 | import { useTextField } from "@react-aria/textfield";
|
2 | 2 | import { useRef, useState } from "react";
|
3 |
| -import { Box, IconButton, Field } from ".."; |
| 3 | +import { Box, IconButton, Field, Children, Columns } from ".."; |
4 | 4 | import { LocalizedString } from "../util/LocalizedString";
|
5 | 5 | import { inputRecipe } from "../Field/Field.css";
|
6 | 6 | import { FieldProps } from "../Field/FieldProps";
|
7 | 7 | import { bodyRecipe } from "../Typography/Body/Body.css";
|
8 | 8 | import useDimensions from "react-cool-dimensions";
|
9 | 9 | import { defaultMessages } from "../../test/util/defaultMessages";
|
10 | 10 | import { useBentoConfig } from "../BentoConfigContext";
|
| 11 | +import { match } from "ts-pattern"; |
11 | 12 |
|
12 | 13 | type Props = FieldProps<string> & {
|
13 | 14 | placeholder: LocalizedString;
|
14 |
| - type?: "text" | "email" | "url" | "password"; |
15 | 15 | isReadOnly?: boolean;
|
16 |
| - showPasswordLabel?: LocalizedString; |
17 |
| - hidePasswordLabel?: LocalizedString; |
| 16 | + type?: "text" | "email" | "url" | "password"; |
| 17 | + rightAccessory?: Children; |
| 18 | + showPasswordLabel?: never; |
| 19 | + hidePasswordLabel?: never; |
18 | 20 | };
|
19 | 21 |
|
20 | 22 | export function TextField(props: Props) {
|
@@ -47,6 +49,24 @@ export function TextField(props: Props) {
|
47 | 49 |
|
48 | 50 | const type = props.type === "password" && !showPassword ? "password" : "text";
|
49 | 51 |
|
| 52 | + const rightAccessory = match(props.type ?? "text") |
| 53 | + .with("password", () => ( |
| 54 | + // if we have both a rightAccessory and type='password', display the accessory on the left of the password toggle field |
| 55 | + <Columns space={config.paddingX} alignY="center"> |
| 56 | + <IconButton |
| 57 | + size={config.passwordIconSize} |
| 58 | + icon={passwordIcon} |
| 59 | + onPress={() => setShowPassword((prevValue) => !prevValue)} |
| 60 | + kind="transparent" |
| 61 | + hierarchy="secondary" |
| 62 | + label={passwordIconLabel} |
| 63 | + /> |
| 64 | + {props.rightAccessory} |
| 65 | + </Columns> |
| 66 | + )) |
| 67 | + .with("email", "text", "url", () => props.rightAccessory) |
| 68 | + .exhaustive(); |
| 69 | + |
50 | 70 | return (
|
51 | 71 | <Field
|
52 | 72 | {...props}
|
@@ -75,28 +95,21 @@ export function TextField(props: Props) {
|
75 | 95 | size: config.fontSize,
|
76 | 96 | }),
|
77 | 97 | ]}
|
78 |
| - style={{ paddingRight: rightAccessoryWidth, flexGrow: 1 }} |
| 98 | + style={{ paddingRight: rightAccessory ? rightAccessoryWidth : undefined, flexGrow: 1 }} |
79 | 99 | />
|
80 |
| - {props.type === "password" && ( |
| 100 | + {rightAccessory && ( |
81 | 101 | <Box
|
82 | 102 | ref={rightAccessoryRef}
|
83 | 103 | position="absolute"
|
84 | 104 | display="flex"
|
85 | 105 | justifyContent="center"
|
86 | 106 | alignItems="center"
|
87 |
| - paddingX={16} |
| 107 | + paddingX={config.paddingX} |
88 | 108 | top={0}
|
89 | 109 | bottom={0}
|
90 | 110 | right={0}
|
91 | 111 | >
|
92 |
| - <IconButton |
93 |
| - size={config.passwordIconSize} |
94 |
| - icon={passwordIcon} |
95 |
| - onPress={() => setShowPassword((prevValue) => !prevValue)} |
96 |
| - kind="transparent" |
97 |
| - hierarchy="secondary" |
98 |
| - label={passwordIconLabel} |
99 |
| - /> |
| 112 | + {rightAccessory} |
100 | 113 | </Box>
|
101 | 114 | )}
|
102 | 115 | </Box>
|
|
0 commit comments