Skip to content

Commit

Permalink
🎨 more accessibility for forms #2505 (#2510)
Browse files Browse the repository at this point in the history
* 🎨 more accessibility

* 🎨 add tel type

* 🎨 remove logs

* 🎨 update documentation with eds feature request link

* 🎨 fix typo

* 🎨update to small text and remove placeholders
  • Loading branch information
BorghildSelle authored Nov 4, 2024
1 parent 42c73ab commit 8464530
Show file tree
Hide file tree
Showing 10 changed files with 970 additions and 749 deletions.
16 changes: 13 additions & 3 deletions sanityv3/schemas/textSnippets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ export const groups = {
}
const snippets: textSnippet = {
country_code_format: {
title: 'e.g. +47',
defaultValue: 'e.g. +47',
title: 'Enter country code with phone number',
defaultValue: 'Enter country code with phone number',
group: groups.form,
},
all_fields_mandatory: {
Expand Down Expand Up @@ -671,7 +671,7 @@ const snippets: textSnippet = {
careers_contact_form_supporting_documents: {
title: 'Supporting Documents checkbox',
defaultValue: 'Tick the box if you would like to send supporting documents, and we will get in touch with you',
group: groups.careerFairForm,
group: groups.careerContactForm,
},

form_sending: {
Expand Down Expand Up @@ -719,6 +719,16 @@ const snippets: textSnippet = {
defaultValue: 'Reopen the form',
group: groups.form,
},
form_validation_maxChars: {
title: 'Max X chars',
defaultValue: 'Max {maxChars} characters',
group: groups.form,
},
form_antirobot_validation_required: {
title: 'Anti-Robot verification is required',
defaultValue: 'Anti-Robot verification is required',
group: groups.form,
},
newsroom_topic_filter: {
title: 'Topic filter heading',
defaultValue: 'Topic',
Expand Down
3 changes: 3 additions & 0 deletions web/components/src/Form/FormSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ const StyledEdsNativeSelectField = styled(EdsNativeSelect)`
select {
font-size: var(--typeScale-1);
}
label {
color: var(--default-text);
}
`

export const FormSelect = forwardRef<HTMLDivElement, NativeSelectProps>(function EdsNativeSelect(
Expand Down
4 changes: 3 additions & 1 deletion web/components/src/Form/FormTextField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import styled from 'styled-components'
import { TextField as EdsTextField, TextFieldProps } from '@equinor/eds-core-react'

export const TextFieldWrapper = styled.div`
padding: var(--space-small) 0px var(--space-medium) 0px;
p {
color: var(--clear-red-100);
font-size: var(--typeScale-0);
Expand All @@ -15,6 +14,9 @@ const StyledEdsTextField = styled(EdsTextField)`
textarea {
font-size: var(--typeScale-1);
}
label {
color: var(--default-text);
}
`

export const FormTextField = forwardRef<HTMLDivElement, TextFieldProps>(function TextField({ children, ...rest }, ref) {
Expand Down
65 changes: 65 additions & 0 deletions web/core/TextField/TextArea.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { forwardRef, useState, TextareaHTMLAttributes, useCallback, CSSProperties } from 'react'
import { mergeRefs, useAutoResize } from '@equinor/eds-utils'
import { SharedTextFieldProps } from './TextField'
import { Input } from '@equinor/eds-core-react'

export type TextareaProps = {
/** Type */
type?: string
/** Read Only */
readOnly?: boolean
/** Specifies max rows for multiline */
rowsMax?: number
} & SharedTextFieldProps &
TextareaHTMLAttributes<HTMLTextAreaElement>

/** Temporary. Until feature request,
* https://github.com/equinor/design-system/issues/3622,
* is resolved */
export const Textarea = forwardRef<HTMLTextAreaElement, TextareaProps>(function Textarea(
{ variant, disabled = false, type = 'text', rowsMax = 10, className = '', ...other },
ref,
) {
const [textareaEl, setTextareaEl] = useState<HTMLTextAreaElement | null>(null)
let fontSize = 16

if (textareaEl) {
fontSize = parseInt(window.getComputedStyle(textareaEl).fontSize)
}

const padding = 12 //6px from InputToken in EDS
const maxHeight = parseFloat('1.5') * fontSize * rowsMax + padding
//@ts-ignore: textareaEl is required, null is handled in hook
useAutoResize(textareaEl, rowsMax ? maxHeight : undefined)

const combinedRef = useCallback(() => mergeRefs<HTMLTextAreaElement>(ref, setTextareaEl), [setTextareaEl, ref])()

const inputProps = {
ref: combinedRef,
type,
disabled,
variant,
...other,
style: { height: 'auto' },
className,
}

const leftAdornmentStyles = {
style: { alignItems: 'flex-start' },
}
const rightAdornmentStyles = {
style: {
alignItems: 'flex-start',
pointerEvents: 'none' as CSSProperties['pointerEvents'],
},
}

return (
<Input
as="textarea"
rightAdornmentsProps={rightAdornmentStyles}
leftAdornmentsProps={leftAdornmentStyles}
{...inputProps}
/>
)
})
141 changes: 141 additions & 0 deletions web/core/TextField/TextField.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
import { InputProps, Input } from '@equinor/eds-core-react'
import { ReactNode, InputHTMLAttributes, forwardRef, ForwardedRef, useId, TextareaHTMLAttributes } from 'react'
import envisTwMerge from '../../twMerge'
import { Textarea } from './TextArea'

export type Variants = 'error' | 'warning' | 'success'

export type SharedTextFieldProps = {
/** Variants */
variant?: Variants
/** Description,shown below label */
description?: ReactNode
/** Input unique id. This is required to ensure accesibility */
id: string
/** Label text */
label?: ReactNode
/** Meta text */
meta?: ReactNode
/** Unit text */
unit?: string
/** Helper text */
helperText?: string
/** Input ref */
inputRef?: ForwardedRef<HTMLInputElement>
/** InputIcon */
inputIcon?: ReactNode
/** HelperIcon */
helperIcon?: ReactNode
helperTextClassName?: string
/** If `true` a `textarea` is rendered for multiline support. Make sure to use `textareaRef` if you need to access reference element */
multiline?: boolean
/** Maximum number of rows if `multiline` is set to `true` */
rowsMax?: number
/** Textarea ref when multiline is set to `true` */
textareaRef?: ForwardedRef<HTMLTextAreaElement>
} & InputProps

type TextFieldProps = SharedTextFieldProps &
(TextareaHTMLAttributes<HTMLTextAreaElement> | InputHTMLAttributes<HTMLInputElement>)

type FieldProps = SharedTextFieldProps & {
multiline: boolean
} & React.HTMLAttributes<HTMLTextAreaElement | HTMLInputElement>
/** Proxy component for working around typescript and element type switching */
const Field = forwardRef<HTMLTextAreaElement | HTMLInputElement, FieldProps>(function Field(props, ref) {
return props.multiline ? (
<Textarea ref={ref as ForwardedRef<HTMLTextAreaElement>} {...props} className={`[&_textarea]:text-base`} />
) : (
<Input ref={ref as ForwardedRef<HTMLInputElement>} {...props} className={`[&_input]:text-base`} />
)
})

/** Temporary. Until feature request
* https://github.com/equinor/design-system/issues/3622
* is resolved */
export const TextField = forwardRef<HTMLDivElement, TextFieldProps>(function TextField(
{
id,
label,
description,
unit,
helperText,
placeholder,
disabled,
inputIcon,
helperIcon,
variant,
className = '',
helperTextClassName = '',
multiline = false,
rowsMax,
textareaRef,
inputRef,
...other
},
ref,
) {
const helperTextId = useId()
const inputDescriptionId = useId()
const hasRightAdornments = Boolean(unit || inputIcon)
let fieldProps = {
'aria-invalid': variant === 'error' || undefined,
disabled,
placeholder,
id,
variant,
rightAdornments: hasRightAdornments && (
<>
{inputIcon}
<span>{unit}</span>
</>
),
ref: inputRef || textareaRef,
rowsMax,
multiline,
...other,
}

if (helperText || description) {
fieldProps = {
'aria-describedby': `${helperText ? helperTextId : ''}${helperText && description ? ' ' : ''}${
description ? inputDescriptionId : ''
}`,
...fieldProps,
}
}

const variantClassName = {
error: 'text-clear-red-100',
success: 'text-norwegian-woods-100',
warning: '',
}

return (
<div ref={ref} className={envisTwMerge(``, className)}>
<label htmlFor={id} className="mx-2 text-base font-medium">
{label}
</label>
{!!description && (
<div id={inputDescriptionId} className="px-2 pt-2 pb-1 text-xs font-normal">
{description}
</div>
)}
<Field {...fieldProps} />
{!!helperText && (
<div
id={helperTextId}
className={envisTwMerge(
`${
variant ? variantClassName[variant] : ''
} mt-2 ml-2 grid auto-cols-auto gap-2 items-start justify-start whitespace-pre-line font-semibold`,
helperTextClassName,
)}
>
{helperIcon && helperIcon}
{helperText}
</div>
)}
</div>
)
})
Loading

0 comments on commit 8464530

Please sign in to comment.