(props: { revealable?: boolean; placeholder?: string; autoFocus?: boolean })
| 228 | } |
| 229 | |
| 230 | function ValueField(props: { revealable?: boolean; placeholder?: string; autoFocus?: boolean }) { |
| 231 | const { state, actions } = useSecretForm(); |
| 232 | const inputId = useId(); |
| 233 | const revealable = props.revealable ?? false; |
| 234 | const revealed = revealable && state.revealed; |
| 235 | const errored = state.status.kind === "error"; |
| 236 | |
| 237 | return ( |
| 238 | <Field> |
| 239 | <FieldLabel htmlFor={inputId}>Value</FieldLabel> |
| 240 | <div className="relative" data-ph-block> |
| 241 | <Input |
| 242 | id={inputId} |
| 243 | type={secretValueInputType({ revealable, revealed })} |
| 244 | value={state.value} |
| 245 | onChange={(e) => actions.setValue((e.target as HTMLInputElement).value)} |
| 246 | placeholder={props.placeholder ?? "ghp_xxxxxxxxxxxxxxxxxxxx"} |
| 247 | autoFocus={props.autoFocus} |
| 248 | autoComplete="new-password" |
| 249 | className={revealable ? "pr-9 font-mono" : "font-mono"} |
| 250 | style={ |
| 251 | revealable && !revealed ? ({ WebkitTextSecurity: "disc" } as CSSProperties) : undefined |
| 252 | } |
| 253 | data-ph-block |
| 254 | /> |
| 255 | {revealable && ( |
| 256 | <Button |
| 257 | type="button" |
| 258 | variant="ghost" |
| 259 | size="icon-xs" |
| 260 | className="absolute right-1 top-1/2 size-7 -translate-y-1/2 text-muted-foreground hover:text-foreground" |
| 261 | onClick={actions.toggleReveal} |
| 262 | aria-label={state.revealed ? "Hide value" : "Reveal value"} |
| 263 | > |
| 264 | <SecretVisibilityIcon revealed={state.revealed} /> |
| 265 | </Button> |
| 266 | )} |
| 267 | </div> |
| 268 | {errored && ( |
| 269 | <FieldError>{state.status.kind === "error" ? state.status.message : ""}</FieldError> |
| 270 | )} |
| 271 | </Field> |
| 272 | ); |
| 273 | } |
| 274 | |
| 275 | function ErrorBanner() { |
| 276 | const { state } = useSecretForm(); |
nothing calls this directly
no test coverage detected