Browse Source
Merge pull request #475 from danditomaso/issue-473-label-inputs-not-connected
fix: connected labels to inputs, improving accessibility and testability
pull/476/head
Hunter Thornsberry
1 year ago
committed by
GitHub
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with
34 additions and
21 deletions
-
src/components/Form/DynamicForm.tsx
-
src/components/Form/FormInput.tsx
-
src/components/Form/FormPasswordGenerator.tsx
-
src/components/Form/FormSelect.tsx
-
src/components/Form/FormToggle.tsx
-
src/components/Form/FormWrapper.tsx
-
src/components/PageComponents/Config/Security/Security.tsx
-
src/components/UI/Generator.tsx
|
|
|
@ -98,24 +98,27 @@ export function DynamicForm<T extends FieldValues>({ |
|
|
|
<Subtle>{fieldGroup.description}</Subtle> |
|
|
|
</div> |
|
|
|
|
|
|
|
{fieldGroup.fields.map((field) => ( |
|
|
|
<FieldWrapper |
|
|
|
key={field.label} |
|
|
|
label={field.label} |
|
|
|
description={field.description} |
|
|
|
valid={ |
|
|
|
field.validationText === undefined || |
|
|
|
field.validationText === "" |
|
|
|
} |
|
|
|
validationText={field.validationText} |
|
|
|
> |
|
|
|
<DynamicFormField |
|
|
|
field={field} |
|
|
|
control={control} |
|
|
|
disabled={isDisabled(field.disabledBy, field.disabled)} |
|
|
|
/> |
|
|
|
</FieldWrapper> |
|
|
|
))} |
|
|
|
{fieldGroup.fields.map((field) => { |
|
|
|
return ( |
|
|
|
<FieldWrapper |
|
|
|
key={field.label} |
|
|
|
label={field.label} |
|
|
|
fieldName={field.name} |
|
|
|
description={field.description} |
|
|
|
valid={ |
|
|
|
field.validationText === undefined || |
|
|
|
field.validationText === "" |
|
|
|
} |
|
|
|
validationText={field.validationText} |
|
|
|
> |
|
|
|
<DynamicFormField |
|
|
|
field={field} |
|
|
|
control={control} |
|
|
|
disabled={isDisabled(field.disabledBy, field.disabled)} |
|
|
|
/> |
|
|
|
</FieldWrapper> |
|
|
|
); |
|
|
|
})} |
|
|
|
</div> |
|
|
|
))} |
|
|
|
{hasSubmitButton && <Button type="submit">Submit</Button>} |
|
|
|
|
|
|
|
@ -53,6 +53,7 @@ export function GenericInput<T extends FieldValues>({ |
|
|
|
} |
|
|
|
step={field.properties?.step} |
|
|
|
value={field.type === "number" ? Number.parseFloat(value) : value} |
|
|
|
id={field.name} |
|
|
|
onChange={(e) => { |
|
|
|
if (field.inputChange) field.inputChange(e); |
|
|
|
onChange( |
|
|
|
|
|
|
|
@ -11,6 +11,7 @@ import { Controller, type FieldValues } from "react-hook-form"; |
|
|
|
|
|
|
|
export interface PasswordGeneratorProps<T> extends BaseFormBuilderProps<T> { |
|
|
|
type: "passwordGenerator"; |
|
|
|
id: string; |
|
|
|
hide?: boolean; |
|
|
|
bits?: { text: string; value: string; key: string }[]; |
|
|
|
devicePSKBitCount: number; |
|
|
|
@ -41,6 +42,7 @@ export function PasswordGenerator<T extends FieldValues>({ |
|
|
|
render={({ field: { value, ...rest } }) => ( |
|
|
|
<Generator |
|
|
|
type={field.hide && !passwordShown ? "password" : "text"} |
|
|
|
id={field.id} |
|
|
|
action={ |
|
|
|
field.hide |
|
|
|
? { |
|
|
|
|
|
|
|
@ -50,7 +50,7 @@ export function SelectInput<T extends FieldValues>({ |
|
|
|
{...remainingProperties} |
|
|
|
{...rest} |
|
|
|
> |
|
|
|
<SelectTrigger> |
|
|
|
<SelectTrigger id={field.name}> |
|
|
|
<SelectValue /> |
|
|
|
</SelectTrigger> |
|
|
|
<SelectContent> |
|
|
|
|
|
|
|
@ -33,6 +33,7 @@ export function ToggleInput<T extends FieldValues>({ |
|
|
|
<Switch |
|
|
|
checked={value} |
|
|
|
onCheckedChange={onChangeHandler(onChange)} |
|
|
|
id={field.name} |
|
|
|
disabled={disabled} |
|
|
|
{...field.properties} |
|
|
|
{...rest} |
|
|
|
|
|
|
|
@ -2,6 +2,7 @@ import { Label } from "@components/UI/Label.tsx"; |
|
|
|
|
|
|
|
export interface FieldWrapperProps { |
|
|
|
label: string; |
|
|
|
fieldName: string; |
|
|
|
description?: string; |
|
|
|
disabled?: boolean; |
|
|
|
children?: React.ReactNode; |
|
|
|
@ -11,6 +12,7 @@ export interface FieldWrapperProps { |
|
|
|
|
|
|
|
export const FieldWrapper = ({ |
|
|
|
label, |
|
|
|
fieldName, |
|
|
|
description, |
|
|
|
children, |
|
|
|
valid, |
|
|
|
@ -19,7 +21,7 @@ export const FieldWrapper = ({ |
|
|
|
<div className="pt-6 sm:pt-5"> |
|
|
|
<fieldset aria-labelledby="label-notifications"> |
|
|
|
<div className="sm:grid sm:grid-cols-3 sm:items-baseline sm:gap-4"> |
|
|
|
<Label>{label}</Label> |
|
|
|
<Label htmlFor={fieldName}>{label}</Label> |
|
|
|
<div className="sm:col-span-2"> |
|
|
|
<div className="max-w-lg"> |
|
|
|
<p className="text-sm text-slate-500">{description}</p> |
|
|
|
|
|
|
|
@ -164,6 +164,7 @@ export const Security = () => { |
|
|
|
fields: [ |
|
|
|
{ |
|
|
|
type: "passwordGenerator", |
|
|
|
id: "pskInput", |
|
|
|
name: "privateKey", |
|
|
|
label: "Private Key", |
|
|
|
description: "Used to create a shared key with a remote device", |
|
|
|
@ -234,6 +235,7 @@ export const Security = () => { |
|
|
|
{ |
|
|
|
type: "passwordGenerator", |
|
|
|
name: "adminKey", |
|
|
|
id: "adminKeyInput", |
|
|
|
label: "Admin Key", |
|
|
|
description: |
|
|
|
"The public key authorized to send admin messages to this node", |
|
|
|
|
|
|
|
@ -15,6 +15,7 @@ export interface GeneratorProps extends React.BaseHTMLAttributes<HTMLElement> { |
|
|
|
type: "text" | "password"; |
|
|
|
devicePSKBitCount?: number; |
|
|
|
value: string; |
|
|
|
id: string; |
|
|
|
variant: "default" | "invalid"; |
|
|
|
actionButtons: { |
|
|
|
text: string; |
|
|
|
@ -37,6 +38,7 @@ const Generator = React.forwardRef<HTMLInputElement, GeneratorProps>( |
|
|
|
{ |
|
|
|
type, |
|
|
|
devicePSKBitCount, |
|
|
|
id = "pskInput", |
|
|
|
variant, |
|
|
|
value, |
|
|
|
actionButtons, |
|
|
|
@ -73,7 +75,7 @@ const Generator = React.forwardRef<HTMLInputElement, GeneratorProps>( |
|
|
|
<> |
|
|
|
<Input |
|
|
|
type={type} |
|
|
|
id="pskInput" |
|
|
|
id={id} |
|
|
|
variant={variant} |
|
|
|
value={value} |
|
|
|
onChange={inputChange} |
|
|
|
|