| 
									
										
										
										
											2025-06-26 15:08:14 +00:00
										 |  |  | import { | 
					
						
							|  |  |  |   customElement, | 
					
						
							|  |  |  |   type TemplateResult, | 
					
						
							|  |  |  |   property, | 
					
						
							|  |  |  |   html, | 
					
						
							|  |  |  |   css, | 
					
						
							|  |  |  |   cssManager, | 
					
						
							|  |  |  | } from '@design.estate/dees-element'; | 
					
						
							|  |  |  | import { DeesInputBase } from './dees-input-base.js'; | 
					
						
							|  |  |  | import { demoFunc } from './dees-input-radiogroup.demo.js'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | declare global { | 
					
						
							|  |  |  |   interface HTMLElementTagNameMap { | 
					
						
							|  |  |  |     'dees-input-radiogroup': DeesInputRadiogroup; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type RadioOption = string | { option: string; key: string; payload?: any }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @customElement('dees-input-radiogroup') | 
					
						
							|  |  |  | export class DeesInputRadiogroup extends DeesInputBase<string | object> { | 
					
						
							|  |  |  |   public static demo = demoFunc; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // INSTANCE
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @property({ type: Array }) | 
					
						
							|  |  |  |   public options: RadioOption[] = []; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @property() | 
					
						
							|  |  |  |   public selectedOption: string = ''; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @property({ type: String }) | 
					
						
							|  |  |  |   public direction: 'vertical' | 'horizontal' = 'vertical'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @property({ type: String, reflect: true }) | 
					
						
							|  |  |  |   public validationState: 'valid' | 'invalid' | 'warn' | 'pending' = null; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Form compatibility
 | 
					
						
							|  |  |  |   public get value() { | 
					
						
							|  |  |  |     const option = this.getOptionByKey(this.selectedOption); | 
					
						
							|  |  |  |     if (typeof option === 'object' && option.payload !== undefined) { | 
					
						
							|  |  |  |       return option.payload; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return this.selectedOption; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   public set value(val: string | any) { | 
					
						
							|  |  |  |     if (typeof val === 'string') { | 
					
						
							|  |  |  |       this.selectedOption = val; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       // Try to find option by payload
 | 
					
						
							|  |  |  |       const option = this.options.find(opt =>  | 
					
						
							|  |  |  |         typeof opt === 'object' && opt.payload === val | 
					
						
							|  |  |  |       ); | 
					
						
							|  |  |  |       if (option && typeof option === 'object') { | 
					
						
							|  |  |  |         this.selectedOption = option.key; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   public static styles = [ | 
					
						
							|  |  |  |     ...DeesInputBase.baseStyles, | 
					
						
							|  |  |  |     cssManager.defaultStyles, | 
					
						
							|  |  |  |     css`
 | 
					
						
							|  |  |  |       * { | 
					
						
							|  |  |  |         box-sizing: border-box; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       :host { | 
					
						
							|  |  |  |         display: block; | 
					
						
							|  |  |  |         position: relative; | 
					
						
							| 
									
										
										
										
											2025-06-27 16:20:06 +00:00
										 |  |  |         font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif; | 
					
						
							| 
									
										
										
										
											2025-06-26 15:08:14 +00:00
										 |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       .maincontainer { | 
					
						
							|  |  |  |         display: flex; | 
					
						
							|  |  |  |         flex-direction: column; | 
					
						
							| 
									
										
										
										
											2025-06-27 16:20:06 +00:00
										 |  |  |         gap: 10px; | 
					
						
							| 
									
										
										
										
											2025-06-26 15:08:14 +00:00
										 |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       .maincontainer.horizontal { | 
					
						
							|  |  |  |         flex-direction: row; | 
					
						
							|  |  |  |         flex-wrap: wrap; | 
					
						
							| 
									
										
										
										
											2025-06-27 16:20:06 +00:00
										 |  |  |         gap: 20px; | 
					
						
							| 
									
										
										
										
											2025-06-26 15:08:14 +00:00
										 |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       .radio-option { | 
					
						
							|  |  |  |         display: flex; | 
					
						
							|  |  |  |         align-items: center; | 
					
						
							| 
									
										
										
										
											2025-06-27 16:20:06 +00:00
										 |  |  |         gap: 10px; | 
					
						
							|  |  |  |         padding: 6px 0; | 
					
						
							| 
									
										
										
										
											2025-06-26 15:08:14 +00:00
										 |  |  |         cursor: pointer; | 
					
						
							| 
									
										
										
										
											2025-06-27 16:20:06 +00:00
										 |  |  |         transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1); | 
					
						
							| 
									
										
										
										
											2025-06-26 15:08:14 +00:00
										 |  |  |         user-select: none; | 
					
						
							|  |  |  |         position: relative; | 
					
						
							| 
									
										
										
										
											2025-06-27 16:20:06 +00:00
										 |  |  |         border-radius: 4px; | 
					
						
							| 
									
										
										
										
											2025-06-26 15:08:14 +00:00
										 |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       .maincontainer.horizontal .radio-option { | 
					
						
							| 
									
										
										
										
											2025-06-27 16:20:06 +00:00
										 |  |  |         padding: 6px 20px 6px 0; | 
					
						
							| 
									
										
										
										
											2025-06-26 15:08:14 +00:00
										 |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       .radio-option:hover .radio-circle { | 
					
						
							| 
									
										
										
										
											2025-06-27 16:20:06 +00:00
										 |  |  |         border-color: ${cssManager.bdTheme('hsl(215 20.2% 65.1%)', 'hsl(215 20.2% 35.1%)')}; | 
					
						
							|  |  |  |         background: ${cssManager.bdTheme('hsl(210 40% 96.1%)', 'hsl(215 20.2% 11.8%)')}; | 
					
						
							| 
									
										
										
										
											2025-06-26 15:08:14 +00:00
										 |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       .radio-option:hover .radio-label { | 
					
						
							| 
									
										
										
										
											2025-06-27 16:20:06 +00:00
										 |  |  |         color: ${cssManager.bdTheme('hsl(215.3 25% 8.8%)', 'hsl(210 40% 98%)')}; | 
					
						
							| 
									
										
										
										
											2025-06-26 15:08:14 +00:00
										 |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       .radio-circle { | 
					
						
							|  |  |  |         width: 20px; | 
					
						
							|  |  |  |         height: 20px; | 
					
						
							|  |  |  |         border-radius: 50%; | 
					
						
							| 
									
										
										
										
											2025-06-27 16:20:06 +00:00
										 |  |  |         border: 2px solid ${cssManager.bdTheme('hsl(215 20.2% 65.1%)', 'hsl(215 20.2% 35.1%)')}; | 
					
						
							|  |  |  |         background: ${cssManager.bdTheme('hsl(0 0% 100%)', 'hsl(215 30% 6.8%)')}; | 
					
						
							|  |  |  |         transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1); | 
					
						
							| 
									
										
										
										
											2025-06-26 15:08:14 +00:00
										 |  |  |         position: relative; | 
					
						
							|  |  |  |         flex-shrink: 0; | 
					
						
							| 
									
										
										
										
											2025-06-27 16:20:06 +00:00
										 |  |  |         display: flex; | 
					
						
							|  |  |  |         align-items: center; | 
					
						
							|  |  |  |         justify-content: center; | 
					
						
							| 
									
										
										
										
											2025-06-26 15:08:14 +00:00
										 |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       .radio-option.selected .radio-circle { | 
					
						
							| 
									
										
										
										
											2025-06-27 16:20:06 +00:00
										 |  |  |         border-color: ${cssManager.bdTheme('hsl(217.2 91.2% 59.8%)', 'hsl(213.1 93.9% 67.8%)')}; | 
					
						
							|  |  |  |         background: ${cssManager.bdTheme('hsl(217.2 91.2% 59.8%)', 'hsl(213.1 93.9% 67.8%)')}; | 
					
						
							| 
									
										
										
										
											2025-06-26 15:08:14 +00:00
										 |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       .radio-option.selected .radio-circle::after { | 
					
						
							|  |  |  |         content: ''; | 
					
						
							|  |  |  |         position: absolute; | 
					
						
							|  |  |  |         width: 8px; | 
					
						
							|  |  |  |         height: 8px; | 
					
						
							|  |  |  |         border-radius: 50%; | 
					
						
							| 
									
										
										
										
											2025-06-27 16:20:06 +00:00
										 |  |  |         background: ${cssManager.bdTheme('hsl(0 0% 100%)', 'hsl(215 30% 6.8%)')}; | 
					
						
							|  |  |  |         transform: scale(0); | 
					
						
							|  |  |  |         transition: transform 0.2s cubic-bezier(0.4, 0, 0.2, 1); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       .radio-option.selected .radio-circle::after { | 
					
						
							|  |  |  |         transform: scale(1); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       .radio-circle:focus-visible { | 
					
						
							|  |  |  |         outline: none; | 
					
						
							|  |  |  |         box-shadow: 0 0 0 2px ${cssManager.bdTheme('hsl(0 0% 100%)', 'hsl(215 30% 3.9%)')}, | 
					
						
							|  |  |  |                     0 0 0 4px ${cssManager.bdTheme('hsl(217.2 91.2% 59.8%)', 'hsl(213.1 93.9% 67.8%)')}; | 
					
						
							| 
									
										
										
										
											2025-06-26 15:08:14 +00:00
										 |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       .radio-label { | 
					
						
							|  |  |  |         font-size: 14px; | 
					
						
							| 
									
										
										
										
											2025-06-27 16:20:06 +00:00
										 |  |  |         font-weight: 500; | 
					
						
							|  |  |  |         color: ${cssManager.bdTheme('hsl(215.3 25% 26.7%)', 'hsl(217.9 10.6% 74.9%)')}; | 
					
						
							|  |  |  |         transition: color 0.2s cubic-bezier(0.4, 0, 0.2, 1); | 
					
						
							|  |  |  |         letter-spacing: -0.006em; | 
					
						
							|  |  |  |         line-height: 20px; | 
					
						
							| 
									
										
										
										
											2025-06-26 15:08:14 +00:00
										 |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       .radio-option.selected .radio-label { | 
					
						
							| 
									
										
										
										
											2025-06-27 16:20:06 +00:00
										 |  |  |         color: ${cssManager.bdTheme('hsl(215.3 25% 8.8%)', 'hsl(210 40% 98%)')}; | 
					
						
							| 
									
										
										
										
											2025-06-26 15:08:14 +00:00
										 |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       :host([disabled]) .radio-option { | 
					
						
							|  |  |  |         cursor: not-allowed; | 
					
						
							|  |  |  |         opacity: 0.5; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       :host([disabled]) .radio-option:hover .radio-circle { | 
					
						
							| 
									
										
										
										
											2025-06-27 16:20:06 +00:00
										 |  |  |         border-color: ${cssManager.bdTheme('hsl(215 20.2% 65.1%)', 'hsl(215 20.2% 35.1%)')}; | 
					
						
							|  |  |  |         background: ${cssManager.bdTheme('hsl(0 0% 100%)', 'hsl(215 30% 6.8%)')}; | 
					
						
							| 
									
										
										
										
											2025-06-26 15:08:14 +00:00
										 |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       :host([disabled]) .radio-option:hover .radio-label { | 
					
						
							| 
									
										
										
										
											2025-06-27 16:20:06 +00:00
										 |  |  |         color: ${cssManager.bdTheme('hsl(215.3 25% 26.7%)', 'hsl(217.9 10.6% 74.9%)')}; | 
					
						
							| 
									
										
										
										
											2025-06-26 15:08:14 +00:00
										 |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       .label-text { | 
					
						
							|  |  |  |         font-size: 14px; | 
					
						
							|  |  |  |         font-weight: 500; | 
					
						
							| 
									
										
										
										
											2025-06-27 16:20:06 +00:00
										 |  |  |         color: ${cssManager.bdTheme('hsl(215.3 25% 8.8%)', 'hsl(210 40% 98%)')}; | 
					
						
							|  |  |  |         margin-bottom: 10px; | 
					
						
							|  |  |  |         letter-spacing: -0.006em; | 
					
						
							|  |  |  |         line-height: 20px; | 
					
						
							| 
									
										
										
										
											2025-06-26 15:08:14 +00:00
										 |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       .description-text { | 
					
						
							| 
									
										
										
										
											2025-06-27 16:20:06 +00:00
										 |  |  |         font-size: 13px; | 
					
						
							|  |  |  |         color: ${cssManager.bdTheme('hsl(215.4 16.3% 56.9%)', 'hsl(215 20.2% 55.1%)')}; | 
					
						
							|  |  |  |         margin-top: 10px; | 
					
						
							|  |  |  |         line-height: 1.5; | 
					
						
							|  |  |  |         letter-spacing: -0.003em; | 
					
						
							| 
									
										
										
										
											2025-06-26 15:08:14 +00:00
										 |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       /* Validation styles */ | 
					
						
							|  |  |  |       :host([validationState="invalid"]) .radio-circle { | 
					
						
							| 
									
										
										
										
											2025-06-27 16:20:06 +00:00
										 |  |  |         border-color: ${cssManager.bdTheme('hsl(0 72.2% 50.6%)', 'hsl(0 62.8% 30.6%)')}; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       :host([validationState="invalid"]) .radio-option.selected .radio-circle { | 
					
						
							|  |  |  |         border-color: ${cssManager.bdTheme('hsl(0 72.2% 50.6%)', 'hsl(0 62.8% 30.6%)')}; | 
					
						
							|  |  |  |         background: ${cssManager.bdTheme('hsl(0 72.2% 50.6%)', 'hsl(0 62.8% 30.6%)')}; | 
					
						
							| 
									
										
										
										
											2025-06-26 15:08:14 +00:00
										 |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       :host([validationState="valid"]) .radio-option.selected .radio-circle { | 
					
						
							| 
									
										
										
										
											2025-06-27 16:20:06 +00:00
										 |  |  |         border-color: ${cssManager.bdTheme('hsl(142.1 70.6% 45.3%)', 'hsl(142.1 76.2% 36.3%)')}; | 
					
						
							|  |  |  |         background: ${cssManager.bdTheme('hsl(142.1 70.6% 45.3%)', 'hsl(142.1 76.2% 36.3%)')}; | 
					
						
							| 
									
										
										
										
											2025-06-26 15:08:14 +00:00
										 |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       :host([validationState="warn"]) .radio-option.selected .radio-circle { | 
					
						
							| 
									
										
										
										
											2025-06-27 16:20:06 +00:00
										 |  |  |         border-color: ${cssManager.bdTheme('hsl(45.4 93.4% 47.5%)', 'hsl(45.4 93.4% 47.5%)')}; | 
					
						
							|  |  |  |         background: ${cssManager.bdTheme('hsl(45.4 93.4% 47.5%)', 'hsl(45.4 93.4% 47.5%)')}; | 
					
						
							| 
									
										
										
										
											2025-06-26 15:08:14 +00:00
										 |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       /* Override base grid layout for radiogroup to prevent large gaps */ | 
					
						
							|  |  |  |       :host([label-position="left"]) .input-wrapper { | 
					
						
							|  |  |  |         grid-template-columns: auto auto; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       :host([label-position="right"]) .input-wrapper { | 
					
						
							|  |  |  |         grid-template-columns: auto auto; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     `,
 | 
					
						
							|  |  |  |   ]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   public render(): TemplateResult { | 
					
						
							|  |  |  |     return html`
 | 
					
						
							|  |  |  |       <div class="input-wrapper"> | 
					
						
							|  |  |  |         ${this.label ? html`<div class="label-text">${this.label}</div>` : ''} | 
					
						
							|  |  |  |         <div class="maincontainer ${this.direction}"> | 
					
						
							|  |  |  |           ${this.options.map((option) => { | 
					
						
							|  |  |  |             const optionKey = this.getOptionKey(option); | 
					
						
							|  |  |  |             const optionLabel = this.getOptionLabel(option); | 
					
						
							|  |  |  |             const isSelected = this.selectedOption === optionKey; | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |             return html`
 | 
					
						
							|  |  |  |               <div  | 
					
						
							|  |  |  |                 class="radio-option ${isSelected ? 'selected' : ''}" | 
					
						
							|  |  |  |                 @click="${() => this.selectOption(optionKey)}" | 
					
						
							| 
									
										
										
										
											2025-06-27 16:20:06 +00:00
										 |  |  |                 @keydown="${(e: KeyboardEvent) => this.handleKeydown(e, optionKey)}" | 
					
						
							| 
									
										
										
										
											2025-06-26 15:08:14 +00:00
										 |  |  |               > | 
					
						
							| 
									
										
										
										
											2025-06-27 16:20:06 +00:00
										 |  |  |                 <div  | 
					
						
							|  |  |  |                   class="radio-circle"  | 
					
						
							|  |  |  |                   tabindex="${this.disabled ? '-1' : '0'}" | 
					
						
							|  |  |  |                   role="radio" | 
					
						
							|  |  |  |                   aria-checked="${isSelected}" | 
					
						
							|  |  |  |                   aria-label="${optionLabel}" | 
					
						
							|  |  |  |                 ></div> | 
					
						
							| 
									
										
										
										
											2025-06-26 15:08:14 +00:00
										 |  |  |                 <div class="radio-label">${optionLabel}</div> | 
					
						
							|  |  |  |               </div> | 
					
						
							|  |  |  |             `;
 | 
					
						
							|  |  |  |           })} | 
					
						
							|  |  |  |         </div> | 
					
						
							|  |  |  |         ${this.description ? html`<div class="description-text">${this.description}</div>` : ''} | 
					
						
							|  |  |  |       </div> | 
					
						
							|  |  |  |     `;
 | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   private getOptionKey(option: RadioOption): string { | 
					
						
							|  |  |  |     if (typeof option === 'string') { | 
					
						
							|  |  |  |       return option; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return option.key; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   private getOptionLabel(option: RadioOption): string { | 
					
						
							|  |  |  |     if (typeof option === 'string') { | 
					
						
							|  |  |  |       return option; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return option.option; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   private getOptionByKey(key: string): RadioOption | undefined { | 
					
						
							|  |  |  |     return this.options.find(opt => this.getOptionKey(opt) === key); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   private selectOption(key: string): void { | 
					
						
							|  |  |  |     if (this.disabled) { | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const oldValue = this.selectedOption; | 
					
						
							|  |  |  |     this.selectedOption = key; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (oldValue !== key) { | 
					
						
							|  |  |  |       this.dispatchEvent(new CustomEvent('change', { | 
					
						
							|  |  |  |         detail: { value: this.value }, | 
					
						
							|  |  |  |         bubbles: true, | 
					
						
							|  |  |  |         composed: true, | 
					
						
							|  |  |  |       })); | 
					
						
							|  |  |  |        | 
					
						
							|  |  |  |       this.dispatchEvent(new CustomEvent('input', { | 
					
						
							|  |  |  |         detail: { value: this.value }, | 
					
						
							|  |  |  |         bubbles: true, | 
					
						
							|  |  |  |         composed: true, | 
					
						
							|  |  |  |       })); | 
					
						
							|  |  |  |        | 
					
						
							|  |  |  |       this.changeSubject.next(this); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   public getValue(): string | any { | 
					
						
							|  |  |  |     return this.value; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   public setValue(val: string | any): void { | 
					
						
							|  |  |  |     this.value = val; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   public async validate(): Promise<boolean> { | 
					
						
							|  |  |  |     if (this.required && !this.selectedOption) { | 
					
						
							|  |  |  |       this.validationState = 'invalid'; | 
					
						
							|  |  |  |       return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     this.validationState = 'valid'; | 
					
						
							|  |  |  |     return true; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   public async firstUpdated() { | 
					
						
							|  |  |  |     // Auto-select first option if none selected and not required
 | 
					
						
							|  |  |  |     if (!this.selectedOption && this.options.length > 0 && !this.required) { | 
					
						
							|  |  |  |       const firstOption = this.options[0]; | 
					
						
							|  |  |  |       this.selectedOption = this.getOptionKey(firstOption); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2025-06-27 16:20:06 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   private handleKeydown(event: KeyboardEvent, optionKey: string) { | 
					
						
							|  |  |  |     if (this.disabled) return; | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     if (event.key === ' ' || event.key === 'Enter') { | 
					
						
							|  |  |  |       event.preventDefault(); | 
					
						
							|  |  |  |       this.selectOption(optionKey); | 
					
						
							|  |  |  |     } else if (event.key === 'ArrowDown' || event.key === 'ArrowRight') { | 
					
						
							|  |  |  |       event.preventDefault(); | 
					
						
							|  |  |  |       this.focusNextOption(); | 
					
						
							|  |  |  |     } else if (event.key === 'ArrowUp' || event.key === 'ArrowLeft') { | 
					
						
							|  |  |  |       event.preventDefault(); | 
					
						
							|  |  |  |       this.focusPreviousOption(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   private focusNextOption() { | 
					
						
							|  |  |  |     const radioCircles = Array.from(this.shadowRoot.querySelectorAll('.radio-circle')); | 
					
						
							|  |  |  |     const currentIndex = radioCircles.findIndex(el => el === this.shadowRoot.activeElement); | 
					
						
							|  |  |  |     const nextIndex = (currentIndex + 1) % radioCircles.length; | 
					
						
							|  |  |  |     (radioCircles[nextIndex] as HTMLElement).focus(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   private focusPreviousOption() { | 
					
						
							|  |  |  |     const radioCircles = Array.from(this.shadowRoot.querySelectorAll('.radio-circle')); | 
					
						
							|  |  |  |     const currentIndex = radioCircles.findIndex(el => el === this.shadowRoot.activeElement); | 
					
						
							|  |  |  |     const prevIndex = currentIndex <= 0 ? radioCircles.length - 1 : currentIndex - 1; | 
					
						
							|  |  |  |     (radioCircles[prevIndex] as HTMLElement).focus(); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2025-06-26 15:08:14 +00:00
										 |  |  | } |