1+ import BulbOutlined from "@ant-design/icons/BulbOutlined"
2+ import ExclamationCircleFilled from "@ant-design/icons/ExclamationCircleFilled"
3+ import InfoCircleOutlined from "@ant-design/icons/InfoCircleOutlined"
4+ import WarningOutlined from "@ant-design/icons/WarningOutlined"
15import React from "react"
26
37import cn from "../clsx"
4- import { Button , ButtonProps } from "./Button"
5- import {
6- BulbOutlined ,
7- ExclamationCircleFilled ,
8- InfoCircleOutlined ,
9- WarningOutlined ,
10- } from "@loft-enterprise/icons"
8+ import { Button , ButtonProps , ButtonStyles } from "./Button"
119
12- type Props = {
10+ type AlertVariant = "info" | "warning" | "error" | "blank" | "neutral" | "danger"
11+
12+ type AlertBoxProps = {
1313 title ?: string
14- text : string
15- buttonText ?: string
16- onButtonClick ?: ( ) => Promise < void >
17- linkText ?: string
18- linkUrl ?: string
19- variant ?: "info" | "warning" | "error" | "blank"
14+ variant ?: AlertVariant
2015 className ?: string
2116 children ?: React . ReactNode
17+ role ?: string
18+ }
19+
20+ export type AlertProps = AlertBoxProps & {
21+ text ?: string | React . ReactNode
22+ buttonText ?: React . ReactNode
23+ buttonStyles ?: ButtonStyles
24+ onButtonClick ?: ( ) => void | Promise < void >
25+ linkText ?: React . ReactNode
26+ linkUrl ?: string
27+ linkHideUnderline ?: boolean
2228 icon ?: React . ReactNode
29+ hideIcon ?: boolean
30+ textClassName ?: string
31+ contentClassName ?: string
32+ iconWrapperClassName ?: string
33+ }
34+
35+ function AlertBox ( { title, variant, className, children, role } : AlertBoxProps ) {
36+ return (
37+ < div
38+ role = { role }
39+ className = { cn (
40+ "rounded-md border px-3 py-3" ,
41+ {
42+ "border-primary-light bg-primary-extra-light" : variant === "info" ,
43+ "border-warning-light bg-warning-extra-light" : variant === "warning" ,
44+ "border-error-light bg-error-extra-light" : variant === "error" ,
45+ "border-neutral-light bg-neutral-extra-light" : variant === "neutral" ,
46+ "border-neutral-light" : variant === "blank" ,
47+ "border-danger-light bg-danger-extra-light" : variant === "danger" ,
48+ "flex flex-col gap-2" : title ,
49+ } ,
50+ className
51+ ) } >
52+ { children }
53+ </ div >
54+ )
2355}
2456
2557function Alert ( {
@@ -32,47 +64,89 @@ function Alert({
3264 variant = "info" ,
3365 className,
3466 children,
67+ buttonStyles,
68+ linkHideUnderline,
3569 icon : Icon ,
36- } : Props ) {
70+ hideIcon = false ,
71+ textClassName,
72+ contentClassName,
73+ iconWrapperClassName,
74+ } : AlertProps ) {
3775 const icon = {
3876 info : < InfoCircleOutlined /> ,
77+ neutral : < InfoCircleOutlined /> ,
3978 warning : < WarningOutlined /> ,
4079 error : < ExclamationCircleFilled /> ,
4180 blank : < BulbOutlined /> ,
81+ danger : < WarningOutlined /> ,
4282 }
4383
4484 const buttonChild = React . Children . toArray ( children ) . find (
4585 ( child ) => React . isValidElement ( child ) && ( child . type as any ) ?. name === "AlertButton"
4686 ) as React . ReactElement | undefined
4787
88+ const contentChildren = React . Children . toArray ( children ) . filter (
89+ ( child ) => ! React . isValidElement ( child ) || ( child . type as any ) ?. name !== "AlertButton"
90+ )
91+
92+ const getRole = ( variant : AlertVariant ) : string => {
93+ switch ( variant ) {
94+ case "error" :
95+ case "danger" :
96+ return "alert"
97+ case "info" :
98+ case "warning" :
99+ case "neutral" :
100+ case "blank" :
101+ default :
102+ return "note"
103+ }
104+ }
105+
48106 return (
49- < div
50- className = { cn ( "rounded-md border px-3 py-3" , className , {
51- "border-primary-light bg-primary-extra-light" : variant === "info" ,
52- "border-warning-light bg-warning-extra-light" : variant === "warning" ,
53- "border-error-light bg-error-extra-light" : variant === "error" ,
54- "border-neutral-light" : variant === "blank" ,
55- "flex flex-col gap-2" : title ,
56- } ) } >
57- < span className = "flex flex-row items-center gap-2 [&_svg]:size-4" >
58- { Icon ? Icon : icon [ variant ] }
59- { title ? < span className = "font-bold" > { title } </ span > : < span > { text } </ span > }
60- </ span >
61- { title && < span className = "text-primary-main text-sm" > { text } </ span > }
62- < div className = "flex flex-row items-center gap-2" >
63- { buttonText && ! buttonChild && (
64- < Button className = "self-start" size = "small" onClickAsync = { onButtonClick } >
65- { buttonText }
66- </ Button >
67- ) }
68- { buttonChild }
69- { linkText && linkUrl && (
70- < a href = { linkUrl } rel = "noreferrer" target = "_blank" className = "text-xs underline" >
71- < span className = "text-primary-main" > { linkText } </ span >
72- </ a >
107+ < AlertBox className = { className } title = { title } variant = { variant } role = { getRole ( variant ) } >
108+ < div className = { cn ( "flex flex-row items-center gap-2 [&_svg]:size-4" , contentClassName ) } >
109+ { ! hideIcon && < div className = { iconWrapperClassName } > { Icon ? Icon : icon [ variant ] } </ div > }
110+ { title ? (
111+ < span className = "text-sm font-semibold" > { title } </ span >
112+ ) : (
113+ < span className = { cn ( "text-sm" , textClassName ) } > { text } </ span >
73114 ) }
74115 </ div >
75- </ div >
116+ { title &&
117+ ( contentChildren . length > 0 ? (
118+ < span className = "text-primary-main text-sm" > { contentChildren } </ span >
119+ ) : (
120+ text && (
121+ < span className = { cn ( "text-primary-main whitespace-pre-wrap text-sm" , textClassName ) } >
122+ { text }
123+ </ span >
124+ )
125+ ) ) }
126+ { ! ! ( buttonText || buttonChild || linkText ) && (
127+ < div className = "flex flex-row items-center gap-2" >
128+ { buttonText && ! buttonChild && (
129+ < Button
130+ { ...buttonStyles }
131+ className = "self-start"
132+ size = "small"
133+ onClickAsync = { onButtonClick } >
134+ { buttonText }
135+ </ Button >
136+ ) }
137+ { buttonChild }
138+ { linkText && linkUrl && (
139+ < a
140+ href = { linkUrl }
141+ rel = "noreferrer"
142+ target = "_blank"
143+ className = { cn ( "text-xs" , { underline : ! linkHideUnderline } ) } >
144+ < span className = "text-primary-main" > { linkText } </ span >
145+ </ a >
146+ ) }
147+ </ div >
148+ ) }
149+ </ AlertBox >
76150 )
77151}
78152
@@ -82,6 +156,8 @@ function AlertButton({ children, ...props }: ButtonProps) {
82156
83157AlertButton . displayName = "AlertButton"
84158
159+ Alert . Box = AlertBox
160+
85161Alert . Button = AlertButton
86162
87- export { Alert }
163+ export { Alert , AlertBox }
0 commit comments