11import { LitElement , html , type TemplateResult , type PropertyValues } from 'lit' ;
22import { customElement } from 'lit/decorators/custom-element.js' ;
3- import { state } from 'lit/decorators.js' ;
43import { property } from 'lit/decorators/property.js' ;
54import { classMap } from 'lit/directives/class-map.js' ;
65import { SlotController } from '@patternfly/pfe-core/controllers/slot-controller.js' ;
6+ import '@patternfly/elements/pf-icon/pf-icon.js' ;
77import styles from './pf-alert.css' ;
88
9- export type AlertVariant = (
10- | 'default'
11- | 'info'
12- | 'warning'
13- | 'danger'
14- | 'success'
15- ) ;
16-
17- interface AlertAction {
18- action : 'dismiss' | 'confirm' | string ;
19- text : string ;
20- }
21- interface ToastOptions {
22- id ?: string ;
23- children : string | TemplateResult ;
24- title ?: string ;
25- variant ?: AlertVariant ;
26- timeout ?: number ;
27- actionLinks ?: AlertAction [ ] ;
28- }
29-
309
31-
32- const toasts = new Set < Required < ToastOptions > > ( ) ;
10+ const variantToIcon = ( variant : PfAlert [ 'variant' ] ) : string | undefined => {
11+ switch ( variant ) {
12+ case 'info' :
13+ return 'circle-info' ;
14+ case 'success' :
15+ return 'circle-check' ;
16+ case 'warning' :
17+ return 'triangle-exclamation' ;
18+ case 'danger' :
19+ return 'circle-exclamation' ;
20+ case 'neutral' :
21+ return 'bell' ;
22+ case 'custom' :
23+ default :
24+ return undefined ;
25+ }
26+ } ;
3327
3428@customElement ( 'pf-alert' )
3529export class PfAlert extends LitElement {
3630 static readonly styles : CSSStyleSheet [ ] = [ styles ] ;
3731
38- @property ( { reflect : true } ) variant ?: AlertVariant ;
32+ @property ( { reflect : true } )
33+ variant :
34+ | 'warning'
35+ | 'custom'
36+ | 'neutral'
37+ | 'info'
38+ | 'success'
39+ | 'danger' = 'neutral' ;
3940
4041 @property ( ) icon ?: string ;
4142
4243 #slots = new SlotController ( this , null , 'icon' , 'actionClose' , 'title' , 'actionLinks' ) ;
4344
4445
45-
46- private static readonly TIMEOUT_MS = 8000 ;
47- private static _toastContainer : HTMLElement | null = null ;
48- private static _instanceCounter = 0 ;
49-
50- public static async toast ( options : ToastOptions ) : Promise < PfAlert > {
51- if ( ! PfAlert . _toastContainer ) {
52- PfAlert . _toastContainer = document . getElementById ( 'toast-alerts-container' ) ;
53- if ( ! PfAlert . _toastContainer ) {
54- throw new Error ( "Toast container '#toast-alerts-container' not found in DOM." ) ;
55- }
56- }
57-
58- const alertElement = document . createElement ( 'pf-alert' ) as PfAlert ;
59- PfAlert . _instanceCounter ++ ;
60- alertElement . variant = options . variant || 'default' ;
61- alertElement . icon = options . variant === 'default' ? 'bell' :
62- options . variant || 'bell' ;
63- if ( options . title ) {
64- const title = document . createElement ( 'h3' ) ; title . slot = 'title' ; title . textContent = options . title ;
65- alertElement . appendChild ( title ) ;
66- }
67- if ( typeof options . children === 'string' ) {
68- const p = document . createElement ( 'p' ) ; p . textContent = options . children ;
69- alertElement . appendChild ( p ) ;
70- }
71-
72- if ( options . actionLinks && options . actionLinks . length > 0 ) {
73- const actionsDiv = document . createElement ( 'div' ) ; actionsDiv . slot = 'actionLinks' ;
74- options . actionLinks . forEach ( actionLinks => {
75- const button = document . createElement ( 'pf-button' ) ; button . setAttribute ( 'variant' , 'link' ) ;
76- button . textContent = actionLinks . text ;
77- switch ( actionLinks . text ) {
78- case 'View details' :
79- button . addEventListener ( 'click' , ( ) => {
80- PfAlert . _toastContainer ! . innerHTML = '' ;
81- } ) ;
82- break ;
83- case 'Ignore' :
84- // button.addEventListener('click', () => { });
85- break ;
86- default :
87- button . addEventListener ( 'click' , ( ) => { alertElement . remove ( ) ; } ) ;
88- break ;
89- }
90- actionsDiv . appendChild ( button ) ;
91- } ) ;
92- alertElement . appendChild ( actionsDiv ) ;
93- }
94-
95- PfAlert . _toastContainer ! . prepend ( alertElement ) ;
96-
97-
98- if ( ! options . timeout ) {
99- let timer : number ;
100- const startTimer = ( ) => { timer = window . setTimeout ( ( ) => alertElement . remove ( ) , PfAlert . TIMEOUT_MS ) ; } ;
101- alertElement . addEventListener ( 'mouseenter' , ( ) => window . clearTimeout ( timer ) ) ;
102- alertElement . addEventListener ( 'mouseleave' , startTimer ) ;
103- startTimer ( ) ;
104- }
105- return alertElement ;
106- }
107-
108-
109-
110-
111- override willUpdate ( changed : PropertyValues < this> ) : void {
112- if ( changed . has ( 'icon' ) && this . icon ) {
113- import ( '@patternfly/elements/pf-icon/pf-icon.js' ) ;
114- }
115- }
116-
117-
11846 override render ( ) : TemplateResult < 1 > {
119- const { variant, icon } = this ;
120- const hasIcon = ! ! icon || this . #slots. hasSlotted ( 'icon' ) ;
47+ const { variant } = this ;
48+ const calculatedIcon = this . icon ?? variantToIcon ( variant ) ;
49+ const hasIcon = ! ! calculatedIcon || this . #slots. hasSlotted ( 'icon' ) ;
12150 return html `
12251 < div id ="container " part ="container "
12352 class =${ classMap ( { hasIcon, [ variant ?? '' ] : ! ! variant } ) } >
12453
12554 < div id ="icon-container " part ="icon-container ">
126- < slot name ="icon " part ="icon "> ${ ! this . icon ? '' : html `
127- < pf-icon icon ="${ this . icon } "> </ pf-icon > ` }
55+ < slot name ="icon " part ="icon "> ${ ! calculatedIcon ? '' : html `
56+ < pf-icon icon ="${ calculatedIcon } "> </ pf-icon > ` }
12857 </ slot >
12958 </ div >
13059
@@ -148,43 +77,7 @@ export class PfAlert extends LitElement {
14877 ` ;
14978 }
15079}
151- @customElement ( 'alert-demo-page' )
152- export class AlertDemoPage extends LitElement {
153-
154- @state ( ) private alertCounter = 0 ;
155- private addToastAlert ( ) {
156- this . alertCounter ++ ;
157- const id = this . alertCounter ;
158-
159- PfAlert . toast ( {
160- variant : 'default' ,
161- title : `Default timeout Alert` ,
162- children : `This alert will dismiss after 8 seconds.` ,
163- actionLinks : [
164- { action : 'view' , text : 'View details' } ,
165- { action : 'ignore' , text : 'Ignore' } ,
166- ] ,
167- } ) ;
168- }
169- private removeAllToastAlerts ( ) {
170- const container = document . getElementById ( 'toast-alerts-container' ) ;
171- if ( container ) {
172- container . innerHTML = '' ;
173- }
174- }
175- override render ( ) : TemplateResult {
176- return html `
177- < div class ="demo-controls ">
178- < pf-button variant ="control " @click ="${ this . addToastAlert } ">
179- Add alert
180- </ pf-button >
181- < pf-button variant ="control " @click ="${ this . removeAllToastAlerts } ">
182- Remove all alerts
183- </ pf-button >
184- </ div >
185- ` ;
186- }
187- }
80+
18881
18982declare global {
19083 interface HTMLElementTagNameMap {
0 commit comments