Skip to content

Commit

Permalink
Add support for custom content and id prop without Form.Handler
Browse files Browse the repository at this point in the history
  • Loading branch information
tujoworker committed Dec 6, 2024
1 parent c70ff92 commit 0de3fef
Show file tree
Hide file tree
Showing 5 changed files with 234 additions and 59 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ hideInMenu: true

## Description

`Form.InfoOverlay` displays a status message that is fully covering the available space and can be used to show success as a receipt or error messages.
`Form.InfoOverlay` is used to display an informational message that fully covers the available space. It can show a custom message or content, a `success` message as a receipt, or an `error` message to indicate an issue.

## Usage

Expand All @@ -21,17 +21,34 @@ render(
)
```

## Showing the success or error message
## Display a message

There are two ways to display a message:

- Using the `Form.InfoOverlay.setContent` method.
- Using the `content` prop.

### Using the `Form.InfoOverlay.setContent` method

You can show the success or error message by using the `Form.InfoOverlay.setContent` method:

```tsx
Form.InfoOverlay.setContent(id, 'success')
Form.InfoOverlay.setContent(myId, <>info content</>)
// or
Form.InfoOverlay.setContent(id, 'error')
Form.InfoOverlay.setContent(myId, 'success')
// or
Form.InfoOverlay.setContent(myId, 'error')
```

And render the component with an `id` prop:

```tsx
<Form.InfoOverlay id={myId}>content</Form.InfoOverlay>
```

You can call it whenever you need to show the success message. Here is an example of how to use it:
You can call it whenever you need to show the success message. Here is an example of how to use it.

**Note:** the `id` prop is inherited from the `Form.Handler` component in this example.

```tsx
import { Form } from '@dnb/eufemia/extensions/forms'
Expand All @@ -43,14 +60,52 @@ render(
<Form.Handler
id={myFormId}
onSubmit={async () => {
// 1. Send the request

// 2. Show the success message
Form.InfoOverlay.setContent(myFormId, 'success')
}}
>
<Form.InfoOverlay>content</Form.InfoOverlay>
<Form.InfoOverlay>fallback content</Form.InfoOverlay>
</Form.Handler>,
)
```

### Using the `content` prop

You can show the success or error message by using the `content` prop:

```tsx
<Form.InfoOverlay content={<>info content</>}>fallback content</Form.InfoOverlay>
<Form.InfoOverlay content="success">fallback content</Form.InfoOverlay>
<Form.InfoOverlay content="error">fallback content</Form.InfoOverlay>
```

## Customization of the `success` and `error` messages

You can customize the `success` and `error` messages by using the `success` and `error` props.

```tsx
<Form.InfoOverlay
success={{
title: 'Custom title',
description: 'Custom description',
buttonText: 'Custom button text',
buttonHref: 'http://custom',
buttonClickHandler: () => {},
}}
error={{
title: 'Custom title',
description: 'Custom description',
cancelButton: 'Custom cancel',
retryButton: 'Custom retry',
retryingText: 'Custom retrying text',
}}
>
fallback content
</Form.InfoOverlay>
```

## Accessibility

The component will manage focus handling, which is important for screen readers and users using keyboard navigation.
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@ import React, { useCallback, useContext, useRef } from 'react'
import classnames from 'classnames'
import Visibility from '../Visibility'
import DataContext from '../../DataContext/Context'
import { useSharedState } from '../../../../shared/helpers/useSharedState'
import {
SharedStateId,
useSharedState,
} from '../../../../shared/helpers/useSharedState'
import useMounted from '../../../../shared/helpers/useMounted'
import setContent, { Status } from './setContent'
import setContent, { InfoOverlayContent } from './setContent'
import {
Button,
Flex,
Expand All @@ -18,37 +21,56 @@ import MainHeading from '../MainHeading'
import SubmitButton from '../SubmitButton'

export type Props = {
/**
* The content to show.
* If not given, the children will be shown.
* Can be `success`, `error` or a custom content.
*/
content?: InfoOverlayContent
onCancel?: () => void

/** Predefined content */
success?: {
title?: React.ReactNode
description?: React.ReactNode
buttonText?: React.ReactNode
buttonHref?: string
buttonClickHandler?: () => void
}
/** Predefined content */
error?: {
title?: React.ReactNode
description?: React.ReactNode
retryButton?: React.ReactNode
cancelButton?: React.ReactNode
}
onCancel?: () => void

// Various props
id?: SharedStateId
children: React.ReactNode
className?: string
}

function InfoOverlay(props: Props) {
const { success, error, onCancel, className, children, ...restProps } =
props

const translations = useTranslation()

const { id, formState } = useContext(DataContext) || {}
const { id: idProp, formState } = useContext(DataContext)

const {
id = idProp,
content: contentProp,
success,
error,
onCancel,
className,
children,
...restProps
} = props

const { data } = useSharedState<{
activeStatus?: Status
content?: InfoOverlayContent
}>(id)
const { activeStatus } = data || {}
const { content = contentProp } = data || {}

const translations = useTranslation()
const mountedRef = useMounted()
const innerRef = useRef<HTMLDivElement>(null)
const onAnimationEnd: HeightAnimationAllProps['onAnimationEnd'] =
Expand All @@ -62,9 +84,9 @@ function InfoOverlay(props: Props) {
)

// To keep the content visible while hiding it with the HightAnimation
const currentStatusRef = useRef<Status>()
if (activeStatus) {
currentStatusRef.current = activeStatus
const currentContentRef = useRef<InfoOverlayContent>()
if (content) {
currentContentRef.current = content
}

const onCancelHandler = useCallback(() => {
Expand All @@ -75,17 +97,17 @@ function InfoOverlay(props: Props) {
}, [id, onCancel])

const childrenAreVisible =
typeof activeStatus !== 'undefined'
? !(activeStatus === activeStatus)
: undefined
typeof content !== 'undefined' ? !(content === content) : undefined
const statusContentIsVisible =
typeof activeStatus !== 'undefined'
? activeStatus === activeStatus
: false
typeof content !== 'undefined' ? content === content : false
const status =
typeof content === 'string' && !content.includes(' ')
? content
: undefined

let statusContent = null
let statusContent = content

if (currentStatusRef.current === 'success') {
if (currentContentRef.current === 'success') {
const tr = translations.InfoOverlaySuccess
const {
title,
Expand Down Expand Up @@ -113,7 +135,7 @@ function InfoOverlay(props: Props) {
</Flex.Stack>
</Section>
)
} else if (currentStatusRef.current === 'error') {
} else if (currentContentRef.current === 'error') {
const tr = translations.InfoOverlayError
const { title, description, cancelButton, retryButton } = error || {}

Expand Down Expand Up @@ -146,8 +168,8 @@ function InfoOverlay(props: Props) {
return (
<div
className={classnames(
'dnb-forms-status',
activeStatus && `dnb-forms-status--${activeStatus}`,
'dnb-forms-info-overlay',
status && `dnb-forms-info-overlay--${status}`,
'dnb-no-focus',
className
)}
Expand Down
Loading

0 comments on commit 0de3fef

Please sign in to comment.