33 */
44class BlaBlaBlocksInfotip extends HTMLElement {
55 static get observedAttributes ( ) {
6- return [ 'content' , 'underline' ] ;
6+ return [
7+ 'content' ,
8+ 'underline' ,
9+ 'icon-enabled' ,
10+ 'icon-position' ,
11+ 'icon-color' ,
12+ 'icon-type' ,
13+ ] ;
714 }
815
916 connectedCallback ( ) {
1017 const template = this . renderElement ( ) ;
1118 this . attachShadow ( { mode : 'open' } ) ;
1219 this . shadowRoot . appendChild ( template . content . cloneNode ( true ) ) ;
20+
21+ // Add this section to handle initial icon state
22+ const iconEnabled = this . getAttribute ( 'icon-enabled' ) === 'true' ;
23+ if ( iconEnabled ) {
24+ const icon = this . shadowRoot . querySelector ( '.icon' ) ;
25+ icon . innerHTML = this . renderIcon (
26+ this . getAttribute ( 'icon-type' ) || 'info'
27+ ) ;
28+ }
1329 requestAnimationFrame ( ( ) => {
1430 // Wait for the element to be attached to the DOM.
15- this . initializeFloatingUI ( ) ;
31+ this . updatePosition ( ) ;
1632 this . initializeEventListeners ( ) ;
1733 } ) ;
1834 }
1935
20- initializeFloatingUI ( ) {
21- this . updatePosition ( ) ;
22- }
23-
2436 updatePosition ( ) {
37+ // Prevent the infotip overlay from showing when content is blank.
38+ if ( this . getAttribute ( 'content' ) === '' ) {
39+ this . hideTooltip ( ) ;
40+ return ;
41+ }
42+
2543 const floatingUIDOM = window . FloatingUIDOM ;
2644 const anchorText = this . shadowRoot . querySelector ( '.text' ) ;
2745 const infotip = this . shadowRoot . querySelector ( '.infotip' ) ;
@@ -85,14 +103,21 @@ class BlaBlaBlocksInfotip extends HTMLElement {
85103
86104 renderStyle ( ) {
87105 const showUnderline = this . getAttribute ( 'underline' ) !== 'false' ;
106+ const iconEnabled = this . getAttribute ( 'icon-enabled' ) === 'true' ;
107+ const iconPosition = this . getAttribute ( 'icon-position' ) ?? 'left' ;
108+ const iconColor = this . getAttribute ( 'icon-color' ) ?? 'currentColor' ;
88109
89- const style = `
110+ let style = `
90111 .wrapper {
91112 position: relative;
92113 }
93114 .text {
94115 text-decoration: ${ showUnderline ? 'dotted underline' : 'none' } ;
95116 cursor: pointer;
117+ display: inline-flex;
118+ vertical-align: bottom;
119+ gap: 2px;
120+ flex-direction: ${ iconPosition === 'right' ? 'row-reverse' : 'row' } ;
96121 }
97122 .infotip {
98123 display: none;
@@ -102,7 +127,7 @@ class BlaBlaBlocksInfotip extends HTMLElement {
102127 left: 0px;
103128 background: #222;
104129 color: white;
105- padding: 5px ;
130+ padding: 10px ;
106131 border-radius: 4px;
107132 font-size: 90%;
108133 }
@@ -115,9 +140,64 @@ class BlaBlaBlocksInfotip extends HTMLElement {
115140 }
116141 ` ;
117142
143+ if ( iconEnabled ) {
144+ style += `
145+ .icon {
146+ display: inline-flex;
147+ align-items: center;
148+ }
149+ .icon svg {
150+ width: 24px;
151+ height: 24px;
152+ fill: ${ iconColor } ;
153+ }
154+ ` ;
155+ }
156+
118157 return style ;
119158 }
120159
160+ renderIcon ( iconType = 'info' ) {
161+ const iconPaths = {
162+ info : `<path
163+ fill-rule="evenodd"
164+ clip-rule="evenodd"
165+ d="M5.5 12a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0ZM12 4a8 8 0 1 0 0 16 8 8 0 0 0 0-16Zm.75 4v1.5h-1.5V8h1.5Zm0 8v-5h-1.5v5h1.5Z"
166+ />` ,
167+
168+ help : `<path
169+ d="M12 4.75a7.25 7.25 0 100 14.5 7.25 7.25 0 000-14.5zM3.25 12a8.75 8.75 0 1117.5 0 8.75 8.75 0 01-17.5 0zM12 8.75a1.5 1.5 0 01.167 2.99c-.465.052-.917.44-.917 1.01V14h1.5v-.845A3 3 0 109 10.25h1.5a1.5 1.5 0 011.5-1.5zM11.25 15v1.5h1.5V15h-1.5z"
170+ />` ,
171+
172+ caution : `<path
173+ fill-rule="evenodd"
174+ clip-rule="evenodd"
175+ d="M5.5 12a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0ZM12 4a8 8 0 1 0 0 16 8 8 0 0 0 0-16Zm-.75 12v-1.5h1.5V16h-1.5Zm0-8v5h1.5V8h-1.5Z"
176+ />` ,
177+
178+ error : `<path
179+ fill-rule="evenodd"
180+ clip-rule="evenodd"
181+ d="M12.218 5.377a.25.25 0 0 0-.436 0l-7.29 12.96a.25.25 0 0 0 .218.373h14.58a.25.25 0 0 0 .218-.372l-7.29-12.96Zm-1.743-.735c.669-1.19 2.381-1.19 3.05 0l7.29 12.96a1.75 1.75 0 0 1-1.525 2.608H4.71a1.75 1.75 0 0 1-1.525-2.608l7.29-12.96ZM12.75 17.46h-1.5v-1.5h1.5v1.5Zm-1.5-3h1.5v-5h-1.5v5Z"
182+ />` ,
183+
184+ notAllowed : `<path
185+ fill-rule="evenodd"
186+ clip-rule="evenodd"
187+ d="M12 18.5A6.5 6.5 0 0 1 6.93 7.931l9.139 9.138A6.473 6.473 0 0 1 12 18.5Zm5.123-2.498a6.5 6.5 0 0 0-9.124-9.124l9.124 9.124ZM4 12a8 8 0 1 1 16 0 8 8 0 0 1-16 0Z"
188+ />` ,
189+
190+ starEmpty : `<path
191+ fill-rule="evenodd"
192+ d="M9.706 8.646a.25.25 0 01-.188.137l-4.626.672a.25.25 0 00-.139.427l3.348 3.262a.25.25 0 01.072.222l-.79 4.607a.25.25 0 00.362.264l4.138-2.176a.25.25 0 01.233 0l4.137 2.175a.25.25 0 00.363-.263l-.79-4.607a.25.25 0 01.072-.222l3.347-3.262a.25.25 0 00-.139-.427l-4.626-.672a.25.25 0 01-.188-.137l-2.069-4.192a.25.25 0 00-.448 0L9.706 8.646zM12 7.39l-.948 1.921a1.75 1.75 0 01-1.317.957l-2.12.308 1.534 1.495c.412.402.6.982.503 1.55l-.362 2.11 1.896-.997a1.75 1.75 0 011.629 0l1.895.997-.362-2.11a1.75 1.75 0 01.504-1.55l1.533-1.495-2.12-.308a1.75 1.75 0 01-1.317-.957L12 7.39z"
193+ clip-rule="evenodd"
194+ />` ,
195+ } ;
196+ return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true" role="img">
197+ ${ iconPaths [ iconType ] }
198+ </svg>` ;
199+ }
200+
121201 renderElement ( ) {
122202 const content = this . getAttribute ( 'content' ) ;
123203 const template = document . createElement ( 'template' ) ;
@@ -126,11 +206,14 @@ class BlaBlaBlocksInfotip extends HTMLElement {
126206 ${ this . renderStyle ( ) }
127207 </style>
128208 <span class="wrapper">
129- <span class="text" tabindex="0" role="button" aria-describedby="infotip-content">
130- <slot></slot>
209+ <span class="text" tabindex="0" role="button" aria-describedby="infotip-popover">
210+ <span class="icon"></span>
211+ <slot></slot>
131212 </span>
132- <div class="infotip" id="infotip-content">
133- ${ content }
213+ <div class="infotip" id="infotip-popover">
214+ <div class="infotip-popover-content">
215+ ${ content }
216+ </div>
134217 <div class="arrow"></div>
135218 </div>
136219 </span>
@@ -146,17 +229,33 @@ class BlaBlaBlocksInfotip extends HTMLElement {
146229 }
147230
148231 if ( name === 'content' ) {
149- const infotip = shadow . querySelector ( '.infotip' ) ;
232+ const infotip = shadow . querySelector ( '.infotip-popover-content ' ) ;
150233 infotip . innerHTML = newValue ;
151234
152- if ( ! infotip . querySelector ( '.arrow' ) ) {
153- infotip
154- . appendChild ( document . createElement ( 'div' ) )
155- . classList . add ( 'arrow' ) ;
235+ this . updatePosition ( ) ;
236+ this . showTooltip ( ) ;
237+ }
238+
239+ if ( name === 'icon-enabled' ) {
240+ const icon = shadow . querySelector ( '.icon' ) ;
241+
242+ if ( newValue === 'true' ) {
243+ icon . innerHTML = this . renderIcon (
244+ this . getAttribute ( 'icon-type' ) || 'info'
245+ ) ;
246+ } else {
247+ icon . innerHTML = '' ;
156248 }
157249
158250 this . updatePosition ( ) ;
159- this . showTooltip ( ) ;
251+ }
252+
253+ if ( name === 'icon-type' ) {
254+ const icon = shadow . querySelector ( '.icon' ) ;
255+ if ( this . getAttribute ( 'icon-enabled' ) === 'true' ) {
256+ icon . innerHTML = this . renderIcon ( newValue ) ;
257+ }
258+ this . updatePosition ( ) ;
160259 }
161260
162261 const style = shadow . querySelector ( 'style' ) ;
0 commit comments