Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
169 changes: 149 additions & 20 deletions apps/portal/src/content/docs/components/alert.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,63 @@ description: Alert component
beta: true
---

The `Alert` component provides a flexible UI element for displaying alert messages. It is composed of several subcomponents such as `AlertContainer`, `AlertTitle`, and `AlertDescription` to offer a structured and customizable interface.
The `Alert` component provides a flexible UI element for displaying alert messages. It is composed of several subcomponents such as `Alert.Root`, `Alert.Title`, `Alert.Description`, and `Alert.Link` to offer a structured and customizable interface.

import { DocsPage } from "@/components/docs-page";

<DocsPage.ComponentExample
client:only
code={`<div className="space-y-4">
<Alert.Container className="bg-red-100 border-red-400 text-red-700 px-4 py-3">
<Alert.Title className="font-bold">Error Alert</Alert.Title>
<Alert.Description className="text-red-800">This is an error alert description.</Alert.Description>
</Alert.Container>
<Alert.Container className="bg-yellow-100 border-yellow-400 text-yellow-700 px-4 py-3">
<Alert.Title className="font-bold">Warning Alert</Alert.Title>
<Alert.Description className="text-yellow-800">This is a warning alert description.</Alert.Description>
</Alert.Container>
<Alert.Root theme="info">
<Alert.Title>Alert Title</Alert.Title>
<Alert.Description>This is an alert description.</Alert.Description>
</Alert.Root>
<Alert.Root theme="danger" dismissible>
<Alert.Description>We couldn’t complete your request because it violates an Open Policy Agent (OPA) rule set by your organization. Please review the applicable policies or contact your administrator for clarification, then try creating the feature flag again.</Alert.Description>
</Alert.Root>
<Alert.Root theme="warning" dismissible>
<Alert.Title>Warning Alert</Alert.Title>
<Alert.Description>This is a warning alert description.</Alert.Description>
</Alert.Root>
<Alert.Root dismissible>
<Alert.Title>Dismissible Alert</Alert.Title>
</Alert.Root>
<Alert.Root>
<Alert.Title>Link Alert</Alert.Title>
<Alert.Link to="/abc">Learn more</Alert.Link>
</Alert.Root>
<Alert.Root>
<Alert.Title theme="warning">Link Alert as child</Alert.Title>
<Alert.Link to="/abc" asChild><Button>Learn more</Button></Alert.Link>
</Alert.Root>
<Alert.Root theme="danger">
<Alert.Title>Crowded Alert not expandable</Alert.Title>
<Alert.Description>LoremLorem ipsum dolor sit amet consectetur adipisicing elit. Unde molestiae hic, iste nostrum, quia eaque amet autem optio rem earum nihil rerum illo! Possimus</Alert.Description>
</Alert.Root>
<Alert.Root expandable>
<Alert.Title>Crowded Alert</Alert.Title>
<Alert.Description>Lorem, ipsum dolor sit amet consectetur adipisicing elit. Placeat magnam suscipit fugit officiis dignissimos iusto similique deleniti. Quod odio amet quisquam, blanditiis necessitatibus aliquam cumque beatae debitis sunt nemo perspiciatis a saepe enim voluptas? Incidunt vel officiis quam, corrupti ea aliquid nobis! Soluta accusantium ex, alias quod velit explicabo modi exercitationem eaque incidunt fuga, nihil fugiat voluptatum doloribus repudiandae atque.</Alert.Description>
<Alert.Link to="/abc">Learn more</Alert.Link>
</Alert.Root>
<Alert.Root theme="danger" expandable>
<Alert.Title>Crowded Alert</Alert.Title>
<Alert.Description>Lorem, ipsum dolor sit amet consectetur adipisicing elit. Placeat magnam suscipit fugit officiis dignissimos iusto similique deleniti. Quod odio amet quisquam, blanditiis necessitatibus aliquam cumque beatae debitis sunt nemo perspiciatis a saepe enim voluptas? Incidunt vel officiis quam, corrupti ea aliquid nobis! Soluta accusantium ex, alias quod velit explicabo modi exercitationem eaque incidunt fuga, nihil fugiat voluptatum doloribus repudiandae atque.</Alert.Description>
</Alert.Root>
<Alert.Root theme="warning" expandable>
<Alert.Title>Crowded Alert</Alert.Title>
<Alert.Description>Lorem, ipsum dolor sit amet consectetur adipisicing elit. Placeat magnam suscipit fugit officiis dignissimos iusto similique deleniti. Quod odio amet quisquam, blanditiis necessitatibus aliquam cumque beatae debitis sunt nemo perspiciatis a saepe enim voluptas? Incidunt vel officiis quam, corrupti ea aliquid nobis! Soluta accusantium ex, alias quod velit explicabo modi exercitationem eaque incidunt fuga, nihil fugiat voluptatum doloribus repudiandae atque.</Alert.Description>
</Alert.Root>
<Alert.Root expandable>
<Alert.Title>Expandable but not crowded</Alert.Title>
<Alert.Description>Lorem, ipsum dolor sit amet consectetur adipisicing elit.</Alert.Description>
</Alert.Root>
<Alert.Root theme="danger" expandable>
<Alert.Title>Crowded title Crowded title Crowded title Crowded title Crowded title Crowded title Crowded title Crowded title Crowded title Crowded title Crowded title</Alert.Title>
<Alert.Description>Lorem, ipsum dolor sit amet consectetur adipisicing elit. Placeat magnam suscipit fugit officiis dignissimos iusto similique deleniti. Quod odio amet quisquam, blanditiis necessitatibus aliquam cumque beatae debitis sunt nemo perspiciatis a saepe enim voluptas? Incidunt vel officiis quam, corrupti ea aliquid nobis! Soluta accusantium ex, alias quod velit explicabo modi exercitationem eaque incidunt fuga, nihil fugiat voluptatum doloribus repudiandae atque.</Alert.Description>
</Alert.Root>
<Alert.Root theme="warning" expandable>
<Alert.Description>Without Title Lorem, ipsum dolor sit amet consectetur adipisicing elit. Placeat magnam suscipit fugit officiis dignissimos iusto similique deleniti. Quod odio amet quisquam, blanditiis necessitatibus aliquam cumque beatae debitis sunt nemo perspiciatis a saepe enim voluptas? Incidunt vel officiis quam, corrupti ea aliquid nobis! Soluta accusantium ex, alias quod velit explicabo modi exercitationem eaque incidunt fuga, nihil fugiat voluptatum doloribus repudiandae atque.</Alert.Description>
</Alert.Root>
</div>`}
/>

Expand All @@ -27,11 +69,22 @@ import { DocsPage } from "@/components/docs-page";
```typescript jsx
import { Alert } from '@harnessio/ui/components'

//...

return (
<Alert.Container>
<Alert.Title>Alert Title</Alert.Title>
<Alert.Description>This is the alert description.</Alert.Description>
</Alert.Container>
<Alert.Root
theme="info"
expandable
dismissible
>
<Alert.Title>My Alert</Alert.Title>

<Alert.Description>This is the description of the alert</Alert.Description>

<Alert.Link to="/someplace">
Learn more
</Alert.Link>
</Alert.Root>
)
```

Expand All @@ -40,24 +93,25 @@ return (
All parts of the `Alert` component can be imported and composed as required.

```typescript jsx
<Alert.Container>
<Alert.Root>
<Alert.Title />
<Alert.Description />
</Alert.Container>
<Alert.Link />
</Alert.Root>
```

## API Reference

### Container
### `Root`

The `Container` component serves as the main container for all alert elements.
The `Root` component serves as the main container for all alert elements.

<DocsPage.PropsTable
props={[
{
name: "children",
description:
"You can pass in your `Alert.Title` and `Alert.Description` as children",
"You can pass in your `Alert.Title`, `Alert.Description` and `Alert.Link` as children",
required: true,
value: "ReactNode",
},
Expand All @@ -67,10 +121,38 @@ The `Container` component serves as the main container for all alert elements.
required: false,
value: "string",
},
{
name: "theme",
description:
"Theme of the alert. Can be one of 'info', 'warning', or 'danger'.",
required: false,
value: "'info' | 'warning' | 'danger'",
},
{
name: "dismissible",
description:
"If true, the alert can be dismissed by the user. Default is false.",
required: false,
value: "boolean",
},
{
name: "expandable",
description:
"If true, the alert can be expanded to show more content. Default is false.",
required: false,
value: "boolean",
},
{
name: "onDismiss",
description:
"Callback function that is called when the alert is dismissed.",
required: false,
value: "() => void",
},
]}
/>

### Title
### `Title`

The `Title` component displays the title of the alert.

Expand All @@ -95,7 +177,7 @@ The `Title` component displays the title of the alert.
]}
/>

### Description
### `Description`

The `Description` component displays the description of the alert.

Expand All @@ -119,3 +201,50 @@ The `Description` component displays the description of the alert.
},
]}
/>

### `Link`

The `Link` component is used to create a link within the alert.

```typescript jsx
<Alert.Link to="/path">Learn more</Alert.Link>
```

<DocsPage.PropsTable
props={[
{
name: "to",
description: "The URL to link to.",
required: true,
value: "string",
},
{
name: "children",
description: "Link content",
required: true,
value: "ReactNode",
},
{
name: "className",
description: "Additional class names to apply to the alert link",
required: false,
value: "string",
},
{
name: "external",
description:
"If true, the link will open in a new tab. Default is false.",
required: false,
value: "boolean",
defaultValue: "false",
},
{
name: "asChild",
description:
"If true, the link will be rendered as a child of the alert. Default is false.",
required: false,
value: "boolean",
defaultValue: "false",
},
]}
/>
8 changes: 8 additions & 0 deletions packages/ui/config/vitest-setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@ import { cleanup } from '@testing-library/react'

import '@testing-library/jest-dom'

beforeAll(() => {
global.ResizeObserver = class {
observe() {}
unobserve() {}
disconnect() {}
}
})

afterEach(() => {
cleanup()
})
Expand Down
4 changes: 2 additions & 2 deletions packages/ui/src/components/alert/Alert.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ describe('Alert', () => {
const description = 'TEST DESCRIPTION'

render(
<Alert.Container>
<Alert.Root>
<Alert.Title>{title}</Alert.Title>
<Alert.Description>
<p>{description}</p>
</Alert.Description>
</Alert.Container>
</Alert.Root>
)

expect(await screen.findByRole('heading', { name: title })).toBeInTheDocument()
Expand Down
64 changes: 0 additions & 64 deletions packages/ui/src/components/alert/AlertContainer.tsx

This file was deleted.

2 changes: 1 addition & 1 deletion packages/ui/src/components/alert/AlertDescription.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export interface AlertDescriptionProps extends PropsWithChildren<React.HTMLAttri
}

export const AlertDescription = forwardRef<HTMLDivElement, AlertDescriptionProps>(({ className, children }, ref) => (
<div ref={ref} className={cn('text-sm [&_p]:leading-relaxed', className)}>
<div ref={ref} className={cn('cn-alert-description', className)}>
{children}
</div>
))
Expand Down
41 changes: 41 additions & 0 deletions packages/ui/src/components/alert/AlertLink.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { forwardRef } from 'react'

import { Link, LinkProps } from '@components/link'
import { Slot } from '@radix-ui/react-slot'
import { cn } from '@utils/cn'

export interface AlertLinkProps extends LinkProps {
external?: boolean
asChild?: boolean
}

export const AlertLink = forwardRef<HTMLAnchorElement, AlertLinkProps>(
({ external = false, asChild = false, children, className, ...linkProps }, ref) => {
if (asChild) {
return (
<div className="cn-alert-link-wrapper">
<Slot ref={ref}>{children}</Slot>
</div>
)
}

const externalProps = external ? { target: '_blank', rel: 'noopener noreferrer' } : {}

return (
<div className="cn-alert-link-wrapper">
<Link
ref={ref}
variant="secondary"
suffixIcon
className={cn('cn-alert-link', className)}
{...externalProps}
{...linkProps}
>
{children}
</Link>
</div>
)
}
)

AlertLink.displayName = 'AlertLink'
Loading