ps-helix 6.2.1 → 6.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  A comprehensive Angular component library built with Angular 22+ featuring modern design patterns, accessibility-first development, and optimal developer experience.
4
4
 
5
- [![npm version](https://img.shields.io/badge/npm-6.2.1-blue.svg)](https://www.npmjs.com/package/ps-helix)
5
+ [![npm version](https://img.shields.io/badge/npm-6.2.3-blue.svg)](https://www.npmjs.com/package/ps-helix)
6
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
7
  [![Angular](https://img.shields.io/badge/Angular-22.0.0-red.svg)](https://angular.dev/)
8
8
  [![TypeScript](https://img.shields.io/badge/TypeScript-6.0.0-blue.svg)](https://www.typescriptlang.org/)
@@ -106,7 +106,7 @@ After installation, verify that ps-helix is in your `package.json`:
106
106
  ```json
107
107
  {
108
108
  "dependencies": {
109
- "ps-helix": "^6.2.1"
109
+ "ps-helix": "^6.2.3"
110
110
  }
111
111
  }
112
112
  ```
@@ -1182,7 +1182,7 @@ Copyright (c) 2025 PACK Solutions
1182
1182
 
1183
1183
  ---
1184
1184
 
1185
- **Version**: 6.2.1
1185
+ **Version**: 6.2.3
1186
1186
  **Built with**: Angular 22.0.0, TypeScript 6.0.0, Phosphor Icons 2.0.3
1187
1187
  **Author**: Fabrice PEREZ | Design Engineer at PACK Solutions
1188
1188
  **Last Updated**: January 2026
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { input, output, computed, ChangeDetectionStrategy, Component, model, inject, ElementRef, signal, PLATFORM_ID, ViewEncapsulation, InjectionToken, viewChild, effect, Injectable, DestroyRef, Directive, ViewContainerRef, ChangeDetectorRef, ViewChild, Injector, afterNextRender, HostListener, Renderer2, contentChild, linkedSignal, isDevMode, EventEmitter, Output, Input, contentChildren } from '@angular/core';
2
+ import { input, output, computed, ChangeDetectionStrategy, Component, model, inject, ElementRef, signal, PLATFORM_ID, ViewEncapsulation, InjectionToken, viewChild, isDevMode, Injectable, DestroyRef, Directive, ViewContainerRef, ChangeDetectorRef, effect, ViewChild, Injector, afterNextRender, HostListener, Renderer2, contentChild, linkedSignal, EventEmitter, Output, Input, contentChildren } from '@angular/core';
3
3
  import * as i1 from '@angular/common';
4
4
  import { CommonModule, DOCUMENT, isPlatformBrowser, NgTemplateOutlet } from '@angular/common';
5
5
  import { NG_VALUE_ACCESSOR, FormsModule } from '@angular/forms';
@@ -1210,6 +1210,9 @@ class PshCheckboxComponent {
1210
1210
  this.config = inject(CHECKBOX_CONFIG);
1211
1211
  this.checkboxInput = viewChild('checkboxInput', /* @ts-ignore */
1212
1212
  ...(ngDevMode ? [{ debugName: "checkboxInput" }] : /* istanbul ignore next */ []));
1213
+ /** Holds the `label` input or the projected content — whichever provides the visible label. */
1214
+ this.labelSlot = viewChild('labelSlot', /* @ts-ignore */
1215
+ ...(ngDevMode ? [{ debugName: "labelSlot" }] : /* istanbul ignore next */ []));
1213
1216
  this.uniqueId = `psh-cb-${++checkboxIdCounter}`;
1214
1217
  this.onChange = (_) => { };
1215
1218
  this.onTouched = () => { };
@@ -1261,11 +1264,17 @@ class PshCheckboxComponent {
1261
1264
  return this.checked() ? 'checked' : 'unchecked';
1262
1265
  }, /* @ts-ignore */
1263
1266
  ...(ngDevMode ? [{ debugName: "state" }] : /* istanbul ignore next */ []));
1264
- effect(() => {
1265
- if (!this.label() && !this.ariaLabel()) {
1266
- console.warn('[psh-checkbox] Label manquant pour l\'accessibilité.');
1267
- }
1268
- });
1267
+ }
1268
+ ngAfterViewInit() {
1269
+ if (!isDevMode())
1270
+ return;
1271
+ // Read the rendered label slot rather than the `label` input alone: a projected
1272
+ // label (`<psh-checkbox>Accept terms</psh-checkbox>`) is just as accessible, and
1273
+ // `contentChild` cannot see a bare text node. Checked once, after the first render.
1274
+ const hasVisibleLabel = !!this.labelSlot()?.nativeElement.textContent?.trim();
1275
+ if (!hasVisibleLabel && !this.ariaLabel()) {
1276
+ console.warn('[psh-checkbox] No accessible label provided. Please use label input, ariaLabel input, or projected content.');
1277
+ }
1269
1278
  }
1270
1279
  toggle() {
1271
1280
  if (!this.disabled()) {
@@ -1296,7 +1305,7 @@ class PshCheckboxComponent {
1296
1305
  provide: NG_VALUE_ACCESSOR,
1297
1306
  useExisting: PshCheckboxComponent,
1298
1307
  multi: true
1299
- }], viewQueries: [{ propertyName: "checkboxInput", first: true, predicate: ["checkboxInput"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"checkbox-container\">\r\n <label class=\"checkbox-label\" [class.label-left]=\"labelPosition() === 'left'\">\r\n <input\r\n #checkboxInput\r\n type=\"checkbox\"\r\n class=\"checkbox-input\"\r\n [checked]=\"checked()\"\r\n [disabled]=\"disabled()\"\r\n [required]=\"required()\"\r\n [attr.aria-label]=\"computedAriaLabel()\"\r\n [attr.aria-checked]=\"ariaChecked()\"\r\n [attr.aria-required]=\"required() || null\"\r\n [attr.aria-invalid]=\"error() ? 'true' : null\"\r\n [attr.aria-describedby]=\"ariaDescribedBy()\"\r\n (change)=\"toggle()\"\r\n (keydown)=\"handleKeydown($event)\"\r\n />\r\n \r\n <span class=\"checkbox-control\">\r\n @if (checked() && !indeterminate()) {\r\n <i class=\"ph ph-check\" aria-hidden=\"true\"></i>\r\n }\r\n @if (indeterminate()) {\r\n <i class=\"ph ph-minus\" aria-hidden=\"true\"></i>\r\n }\r\n </span>\r\n\r\n <span class=\"checkbox-text\">\r\n @if (label()) {\r\n {{ label() }}\r\n } @else {\r\n <ng-content></ng-content>\r\n }\r\n </span>\r\n </label>\r\n\r\n @if (error()) {\r\n <div [id]=\"uniqueId + '-error'\" class=\"checkbox-message error\" role=\"alert\">\r\n {{ error() }}\r\n </div>\r\n } @else if (success()) {\r\n <div [id]=\"uniqueId + '-success'\" class=\"checkbox-message success\" role=\"status\">\r\n {{ success() }}\r\n </div>\r\n }\r\n</div>", styles: [":host{display:inline-flex;flex-direction:column}.checkbox-container{display:flex;flex-direction:column;gap:var(--form-field-gap)}.checkbox-label{display:inline-flex;align-items:center;gap:var(--form-label-gap);cursor:pointer;-webkit-user-select:none;user-select:none;color:var(--text-color)}.checkbox-label.label-left{flex-direction:row-reverse;justify-content:space-between}.checkbox-input{position:absolute;opacity:0;width:0;height:0}.checkbox-control{display:flex;align-items:center;justify-content:center;width:1.25rem;height:1.25rem;border:.125rem solid var(--surface-border);border-radius:var(--border-radius);background:var(--surface-card);transition:all var(--animation-duration-fast) var(--animation-easing-default);color:#fff;position:relative;flex-shrink:0}:host.checkbox-checked .checkbox-control,:host.checkbox-indeterminate .checkbox-control{background:var(--primary-color);border-color:var(--primary-color)}.checkbox-input:focus-visible+.checkbox-control{outline:.125rem solid var(--focus-outline-color);outline-offset:.125rem}.checkbox-control i{font-size:.875rem;line-height:1}:host.checkbox-small .checkbox-control{width:1rem;height:1rem}:host.checkbox-large .checkbox-control{width:1.5rem;height:1.5rem}:host.checkbox-error .checkbox-control{border-color:var(--danger-color)}:host.checkbox-error.checkbox-checked .checkbox-control{background:var(--danger-color)}:host.checkbox-success .checkbox-control{border-color:var(--success-color)}:host.checkbox-success.checkbox-checked .checkbox-control{background:var(--success-color)}:host.checkbox-disabled{opacity:var(--opacity-disabled);cursor:not-allowed}:host.checkbox-disabled .checkbox-label{cursor:not-allowed}.checkbox-message{font-size:.875rem}.checkbox-message.error{color:var(--danger-color)}.checkbox-message.success{color:var(--success-color)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1308
+ }], viewQueries: [{ propertyName: "checkboxInput", first: true, predicate: ["checkboxInput"], descendants: true, isSignal: true }, { propertyName: "labelSlot", first: true, predicate: ["labelSlot"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"checkbox-container\">\r\n <label class=\"checkbox-label\" [class.label-left]=\"labelPosition() === 'left'\">\r\n <input\r\n #checkboxInput\r\n type=\"checkbox\"\r\n class=\"checkbox-input\"\r\n [checked]=\"checked()\"\r\n [disabled]=\"disabled()\"\r\n [required]=\"required()\"\r\n [attr.aria-label]=\"computedAriaLabel()\"\r\n [attr.aria-checked]=\"ariaChecked()\"\r\n [attr.aria-required]=\"required() || null\"\r\n [attr.aria-invalid]=\"error() ? 'true' : null\"\r\n [attr.aria-describedby]=\"ariaDescribedBy()\"\r\n (change)=\"toggle()\"\r\n (keydown)=\"handleKeydown($event)\"\r\n />\r\n \r\n <span class=\"checkbox-control\">\r\n @if (checked() && !indeterminate()) {\r\n <i class=\"ph ph-check\" aria-hidden=\"true\"></i>\r\n }\r\n @if (indeterminate()) {\r\n <i class=\"ph ph-minus\" aria-hidden=\"true\"></i>\r\n }\r\n </span>\r\n\r\n <span class=\"checkbox-text\" #labelSlot>\r\n @if (label()) {\r\n {{ label() }}\r\n } @else {\r\n <ng-content></ng-content>\r\n }\r\n </span>\r\n </label>\r\n\r\n @if (error()) {\r\n <div [id]=\"uniqueId + '-error'\" class=\"checkbox-message error\" role=\"alert\">\r\n {{ error() }}\r\n </div>\r\n } @else if (success()) {\r\n <div [id]=\"uniqueId + '-success'\" class=\"checkbox-message success\" role=\"status\">\r\n {{ success() }}\r\n </div>\r\n }\r\n</div>", styles: [":host{display:inline-flex;flex-direction:column}.checkbox-container{display:flex;flex-direction:column;gap:var(--form-field-gap)}.checkbox-label{display:inline-flex;align-items:center;gap:var(--form-label-gap);cursor:pointer;-webkit-user-select:none;user-select:none;color:var(--text-color)}.checkbox-label.label-left{flex-direction:row-reverse;justify-content:space-between}.checkbox-input{position:absolute;opacity:0;width:0;height:0}.checkbox-control{display:flex;align-items:center;justify-content:center;width:1.25rem;height:1.25rem;border:.125rem solid var(--surface-border);border-radius:var(--border-radius);background:var(--surface-card);transition:all var(--animation-duration-fast) var(--animation-easing-default);color:#fff;position:relative;flex-shrink:0}:host.checkbox-checked .checkbox-control,:host.checkbox-indeterminate .checkbox-control{background:var(--primary-color);border-color:var(--primary-color)}.checkbox-input:focus-visible+.checkbox-control{outline:.125rem solid var(--focus-outline-color);outline-offset:.125rem}.checkbox-control i{font-size:.875rem;line-height:1}:host.checkbox-small .checkbox-control{width:1rem;height:1rem}:host.checkbox-large .checkbox-control{width:1.5rem;height:1.5rem}:host.checkbox-error .checkbox-control{border-color:var(--danger-color)}:host.checkbox-error.checkbox-checked .checkbox-control{background:var(--danger-color)}:host.checkbox-success .checkbox-control{border-color:var(--success-color)}:host.checkbox-success.checkbox-checked .checkbox-control{background:var(--success-color)}:host.checkbox-disabled{opacity:var(--opacity-disabled);cursor:not-allowed}:host.checkbox-disabled .checkbox-label{cursor:not-allowed}.checkbox-message{font-size:.875rem}.checkbox-message.error{color:var(--danger-color)}.checkbox-message.success{color:var(--success-color)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1300
1309
  }
1301
1310
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: PshCheckboxComponent, decorators: [{
1302
1311
  type: Component,
@@ -1314,8 +1323,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImpor
1314
1323
  '[class.checkbox-indeterminate]': 'indeterminate()',
1315
1324
  '[attr.data-state]': 'state()',
1316
1325
  '[attr.aria-checked]': 'ariaChecked()'
1317
- }, template: "<div class=\"checkbox-container\">\r\n <label class=\"checkbox-label\" [class.label-left]=\"labelPosition() === 'left'\">\r\n <input\r\n #checkboxInput\r\n type=\"checkbox\"\r\n class=\"checkbox-input\"\r\n [checked]=\"checked()\"\r\n [disabled]=\"disabled()\"\r\n [required]=\"required()\"\r\n [attr.aria-label]=\"computedAriaLabel()\"\r\n [attr.aria-checked]=\"ariaChecked()\"\r\n [attr.aria-required]=\"required() || null\"\r\n [attr.aria-invalid]=\"error() ? 'true' : null\"\r\n [attr.aria-describedby]=\"ariaDescribedBy()\"\r\n (change)=\"toggle()\"\r\n (keydown)=\"handleKeydown($event)\"\r\n />\r\n \r\n <span class=\"checkbox-control\">\r\n @if (checked() && !indeterminate()) {\r\n <i class=\"ph ph-check\" aria-hidden=\"true\"></i>\r\n }\r\n @if (indeterminate()) {\r\n <i class=\"ph ph-minus\" aria-hidden=\"true\"></i>\r\n }\r\n </span>\r\n\r\n <span class=\"checkbox-text\">\r\n @if (label()) {\r\n {{ label() }}\r\n } @else {\r\n <ng-content></ng-content>\r\n }\r\n </span>\r\n </label>\r\n\r\n @if (error()) {\r\n <div [id]=\"uniqueId + '-error'\" class=\"checkbox-message error\" role=\"alert\">\r\n {{ error() }}\r\n </div>\r\n } @else if (success()) {\r\n <div [id]=\"uniqueId + '-success'\" class=\"checkbox-message success\" role=\"status\">\r\n {{ success() }}\r\n </div>\r\n }\r\n</div>", styles: [":host{display:inline-flex;flex-direction:column}.checkbox-container{display:flex;flex-direction:column;gap:var(--form-field-gap)}.checkbox-label{display:inline-flex;align-items:center;gap:var(--form-label-gap);cursor:pointer;-webkit-user-select:none;user-select:none;color:var(--text-color)}.checkbox-label.label-left{flex-direction:row-reverse;justify-content:space-between}.checkbox-input{position:absolute;opacity:0;width:0;height:0}.checkbox-control{display:flex;align-items:center;justify-content:center;width:1.25rem;height:1.25rem;border:.125rem solid var(--surface-border);border-radius:var(--border-radius);background:var(--surface-card);transition:all var(--animation-duration-fast) var(--animation-easing-default);color:#fff;position:relative;flex-shrink:0}:host.checkbox-checked .checkbox-control,:host.checkbox-indeterminate .checkbox-control{background:var(--primary-color);border-color:var(--primary-color)}.checkbox-input:focus-visible+.checkbox-control{outline:.125rem solid var(--focus-outline-color);outline-offset:.125rem}.checkbox-control i{font-size:.875rem;line-height:1}:host.checkbox-small .checkbox-control{width:1rem;height:1rem}:host.checkbox-large .checkbox-control{width:1.5rem;height:1.5rem}:host.checkbox-error .checkbox-control{border-color:var(--danger-color)}:host.checkbox-error.checkbox-checked .checkbox-control{background:var(--danger-color)}:host.checkbox-success .checkbox-control{border-color:var(--success-color)}:host.checkbox-success.checkbox-checked .checkbox-control{background:var(--success-color)}:host.checkbox-disabled{opacity:var(--opacity-disabled);cursor:not-allowed}:host.checkbox-disabled .checkbox-label{cursor:not-allowed}.checkbox-message{font-size:.875rem}.checkbox-message.error{color:var(--danger-color)}.checkbox-message.success{color:var(--success-color)}\n"] }]
1318
- }], ctorParameters: () => [], propDecorators: { checkboxInput: [{ type: i0.ViewChild, args: ['checkboxInput', { isSignal: true }] }], checked: [{ type: i0.Input, args: [{ isSignal: true, alias: "checked", required: false }] }, { type: i0.Output, args: ["checkedChange"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }, { type: i0.Output, args: ["disabledChange"] }], indeterminate: [{ type: i0.Input, args: [{ isSignal: true, alias: "indeterminate", required: false }] }, { type: i0.Output, args: ["indeterminateChange"] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }, { type: i0.Output, args: ["touchedChange"] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], success: [{ type: i0.Input, args: [{ isSignal: true, alias: "success", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], labelPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "labelPosition", required: false }] }] } });
1326
+ }, template: "<div class=\"checkbox-container\">\r\n <label class=\"checkbox-label\" [class.label-left]=\"labelPosition() === 'left'\">\r\n <input\r\n #checkboxInput\r\n type=\"checkbox\"\r\n class=\"checkbox-input\"\r\n [checked]=\"checked()\"\r\n [disabled]=\"disabled()\"\r\n [required]=\"required()\"\r\n [attr.aria-label]=\"computedAriaLabel()\"\r\n [attr.aria-checked]=\"ariaChecked()\"\r\n [attr.aria-required]=\"required() || null\"\r\n [attr.aria-invalid]=\"error() ? 'true' : null\"\r\n [attr.aria-describedby]=\"ariaDescribedBy()\"\r\n (change)=\"toggle()\"\r\n (keydown)=\"handleKeydown($event)\"\r\n />\r\n \r\n <span class=\"checkbox-control\">\r\n @if (checked() && !indeterminate()) {\r\n <i class=\"ph ph-check\" aria-hidden=\"true\"></i>\r\n }\r\n @if (indeterminate()) {\r\n <i class=\"ph ph-minus\" aria-hidden=\"true\"></i>\r\n }\r\n </span>\r\n\r\n <span class=\"checkbox-text\" #labelSlot>\r\n @if (label()) {\r\n {{ label() }}\r\n } @else {\r\n <ng-content></ng-content>\r\n }\r\n </span>\r\n </label>\r\n\r\n @if (error()) {\r\n <div [id]=\"uniqueId + '-error'\" class=\"checkbox-message error\" role=\"alert\">\r\n {{ error() }}\r\n </div>\r\n } @else if (success()) {\r\n <div [id]=\"uniqueId + '-success'\" class=\"checkbox-message success\" role=\"status\">\r\n {{ success() }}\r\n </div>\r\n }\r\n</div>", styles: [":host{display:inline-flex;flex-direction:column}.checkbox-container{display:flex;flex-direction:column;gap:var(--form-field-gap)}.checkbox-label{display:inline-flex;align-items:center;gap:var(--form-label-gap);cursor:pointer;-webkit-user-select:none;user-select:none;color:var(--text-color)}.checkbox-label.label-left{flex-direction:row-reverse;justify-content:space-between}.checkbox-input{position:absolute;opacity:0;width:0;height:0}.checkbox-control{display:flex;align-items:center;justify-content:center;width:1.25rem;height:1.25rem;border:.125rem solid var(--surface-border);border-radius:var(--border-radius);background:var(--surface-card);transition:all var(--animation-duration-fast) var(--animation-easing-default);color:#fff;position:relative;flex-shrink:0}:host.checkbox-checked .checkbox-control,:host.checkbox-indeterminate .checkbox-control{background:var(--primary-color);border-color:var(--primary-color)}.checkbox-input:focus-visible+.checkbox-control{outline:.125rem solid var(--focus-outline-color);outline-offset:.125rem}.checkbox-control i{font-size:.875rem;line-height:1}:host.checkbox-small .checkbox-control{width:1rem;height:1rem}:host.checkbox-large .checkbox-control{width:1.5rem;height:1.5rem}:host.checkbox-error .checkbox-control{border-color:var(--danger-color)}:host.checkbox-error.checkbox-checked .checkbox-control{background:var(--danger-color)}:host.checkbox-success .checkbox-control{border-color:var(--success-color)}:host.checkbox-success.checkbox-checked .checkbox-control{background:var(--success-color)}:host.checkbox-disabled{opacity:var(--opacity-disabled);cursor:not-allowed}:host.checkbox-disabled .checkbox-label{cursor:not-allowed}.checkbox-message{font-size:.875rem}.checkbox-message.error{color:var(--danger-color)}.checkbox-message.success{color:var(--success-color)}\n"] }]
1327
+ }], propDecorators: { checkboxInput: [{ type: i0.ViewChild, args: ['checkboxInput', { isSignal: true }] }], labelSlot: [{ type: i0.ViewChild, args: ['labelSlot', { isSignal: true }] }], checked: [{ type: i0.Input, args: [{ isSignal: true, alias: "checked", required: false }] }, { type: i0.Output, args: ["checkedChange"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }, { type: i0.Output, args: ["disabledChange"] }], indeterminate: [{ type: i0.Input, args: [{ isSignal: true, alias: "indeterminate", required: false }] }, { type: i0.Output, args: ["indeterminateChange"] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }, { type: i0.Output, args: ["touchedChange"] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], success: [{ type: i0.Input, args: [{ isSignal: true, alias: "success", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], labelPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "labelPosition", required: false }] }] } });
1319
1328
 
1320
1329
  class PshCollapseComponent {
1321
1330
  constructor() {
@@ -1325,14 +1334,18 @@ class PshCollapseComponent {
1325
1334
  ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
1326
1335
  this.variant = input('default', { ...(ngDevMode ? { debugName: "variant" } : /* istanbul ignore next */ {}), transform: (value) => {
1327
1336
  if (!['default', 'outline'].includes(value)) {
1328
- console.warn(`[psh-collapse] Invalid variant "${value}", falling back to "default"`);
1337
+ if (isDevMode()) {
1338
+ console.warn(`[psh-collapse] Invalid variant "${value}", falling back to "default"`);
1339
+ }
1329
1340
  return 'default';
1330
1341
  }
1331
1342
  return value;
1332
1343
  } });
1333
1344
  this.size = input('medium', { ...(ngDevMode ? { debugName: "size" } : /* istanbul ignore next */ {}), transform: (value) => {
1334
1345
  if (!['small', 'medium', 'large'].includes(value)) {
1335
- console.warn(`[psh-collapse] Invalid size "${value}", falling back to "medium"`);
1346
+ if (isDevMode()) {
1347
+ console.warn(`[psh-collapse] Invalid size "${value}", falling back to "medium"`);
1348
+ }
1336
1349
  return 'medium';
1337
1350
  }
1338
1351
  return value;
@@ -3828,12 +3841,13 @@ const RADIO_STYLES = new InjectionToken('RADIO_STYLES', {
3828
3841
  */
3829
3842
  let radioIdCounter = 0;
3830
3843
  class PshRadioComponent {
3831
- set checkedInput(v) { this.checked.set(v); }
3832
- set disabledInput(v) { this.disabled.set(v); }
3833
3844
  constructor() {
3834
3845
  this.config = inject(RADIO_CONFIG);
3835
3846
  this.styles = inject(RADIO_STYLES, { optional: true }) ?? [];
3836
3847
  this.uniqueId = `radio-${++radioIdCounter}`;
3848
+ /** Holds the `label` input or the projected content — whichever provides the visible label. */
3849
+ this.labelSlot = viewChild('labelSlot', /* @ts-ignore */
3850
+ ...(ngDevMode ? [{ debugName: "labelSlot" }] : /* istanbul ignore next */ []));
3837
3851
  // Plain signals + manual @Input/@Output to prevent auto-emission
3838
3852
  // when parent sets [checked] or [disabled] via template binding.
3839
3853
  // model() would auto-emit checkedChange/disabledChange on .set().
@@ -3879,7 +3893,10 @@ class PshRadioComponent {
3879
3893
  const labelText = this.label();
3880
3894
  if (labelText)
3881
3895
  return labelText;
3882
- return this.hasProjectedContent() ? undefined : 'Radio';
3896
+ // No `aria-label` at all when nothing is declared: the `<label>` wrapping the input
3897
+ // already names it from a projected label. A hard-coded fallback would override that
3898
+ // visible text for screen readers (WCAG 2.5.3 "Label in Name").
3899
+ return undefined;
3883
3900
  }, /* @ts-ignore */
3884
3901
  ...(ngDevMode ? [{ debugName: "computedAriaLabel" }] : /* istanbul ignore next */ []));
3885
3902
  this.errorMessageId = computed(() => this.error() ? `${this.uniqueId}-error` : undefined, /* @ts-ignore */
@@ -3890,11 +3907,19 @@ class PshRadioComponent {
3890
3907
  // so aria-describedby references whichever message is actually rendered.
3891
3908
  this.ariaDescribedBy = computed(() => this.errorMessageId() ?? this.successMessageId(), /* @ts-ignore */
3892
3909
  ...(ngDevMode ? [{ debugName: "ariaDescribedBy" }] : /* istanbul ignore next */ []));
3893
- effect(() => {
3894
- if (!this.label() && !this.ariaLabel() && !this.hasProjectedContent()) {
3895
- console.warn('[psh-radio] No accessible label provided. Please use label input, ariaLabel input, or projected content.');
3896
- }
3897
- }, { allowSignalWrites: false });
3910
+ }
3911
+ set checkedInput(v) { this.checked.set(v); }
3912
+ set disabledInput(v) { this.disabled.set(v); }
3913
+ ngAfterViewInit() {
3914
+ if (!isDevMode())
3915
+ return;
3916
+ // Read the rendered label slot rather than the `label` input alone: a projected
3917
+ // label (`<psh-radio>Accept terms</psh-radio>`) is just as accessible, and
3918
+ // `contentChild` cannot see a bare text node. Checked once, after the first render.
3919
+ const hasVisibleLabel = !!this.labelSlot()?.nativeElement.textContent?.trim();
3920
+ if (!hasVisibleLabel && !this.ariaLabel() && !this.hasProjectedContent()) {
3921
+ console.warn('[psh-radio] No accessible label provided. Please use label input, ariaLabel input, or projected content.');
3922
+ }
3898
3923
  }
3899
3924
  getState() {
3900
3925
  if (this.disabled())
@@ -3905,6 +3930,11 @@ class PshRadioComponent {
3905
3930
  return 'success';
3906
3931
  return this.checked() ? 'checked' : 'unchecked';
3907
3932
  }
3933
+ /**
3934
+ * Declares whether a label is projected. No longer required — projected content is now
3935
+ * detected from the rendered label slot. Kept for backwards compatibility: calling it
3936
+ * with `true` still suppresses the dev-only accessibility warning.
3937
+ */
3908
3938
  updateProjectedContent(hasContent) {
3909
3939
  this.hasProjectedContent.set(hasContent);
3910
3940
  }
@@ -3949,7 +3979,7 @@ class PshRadioComponent {
3949
3979
  // Implementation requires radio group context
3950
3980
  }
3951
3981
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: PshRadioComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3952
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.4", type: PshRadioComponent, isStandalone: true, selector: "psh-radio", inputs: { checkedInput: { classPropertyName: "checkedInput", publicName: "checked", isSignal: false, isRequired: false, transformFunction: null }, disabledInput: { classPropertyName: "disabledInput", publicName: "disabled", isSignal: false, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, error: { classPropertyName: "error", publicName: "error", isSignal: true, isRequired: false, transformFunction: null }, success: { classPropertyName: "success", publicName: "success", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, labelPosition: { classPropertyName: "labelPosition", publicName: "labelPosition", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { checkedChange: "checkedChange", disabledChange: "disabledChange", valueChange: "valueChange" }, host: { properties: { "class.radio-disabled": "disabled()", "class.radio-error": "!!error()", "class.radio-success": "!!success()", "class.radio-small": "size() === \"small\"", "class.radio-large": "size() === \"large\"", "attr.data-state": "state()" } }, ngImport: i0, template: "<div class=\"radio-container\">\r\n <label class=\"radio-label\" [class.label-left]=\"labelPosition() === 'left'\">\r\n <input\r\n type=\"radio\"\r\n class=\"radio-input\"\r\n [checked]=\"checked()\"\r\n [disabled]=\"disabled()\"\r\n [required]=\"required()\"\r\n [name]=\"name()\"\r\n [attr.value]=\"value()\"\r\n [attr.aria-label]=\"computedAriaLabel()\"\r\n [attr.aria-required]=\"required() || null\"\r\n [attr.aria-invalid]=\"error() ? 'true' : null\"\r\n [attr.aria-checked]=\"checked()\"\r\n [attr.aria-describedby]=\"ariaDescribedBy()\"\r\n (change)=\"handleChange()\"\r\n (keydown)=\"handleKeydown($event)\"\r\n />\r\n <span \r\n class=\"radio-control\"\r\n [class.error]=\"!!error()\"\r\n [class.success]=\"!!success()\"\r\n >\r\n <span class=\"radio-dot\"></span>\r\n </span>\r\n <span class=\"radio-text\">\r\n @if (label()) {\r\n {{ label() }}\r\n } @else {\r\n <ng-content>Radio</ng-content>\r\n }\r\n </span>\r\n </label>\r\n\r\n @if (error()) {\r\n <div [id]=\"errorMessageId()\" class=\"radio-error\" role=\"alert\">\r\n {{ error() }}\r\n </div>\r\n } @else if (success()) {\r\n <div [id]=\"successMessageId()\" class=\"radio-success\" role=\"status\">\r\n {{ success() }}\r\n </div>\r\n }\r\n</div>", styles: [".radio-container{display:inline-flex;flex-direction:column;gap:var(--form-field-gap)}.radio-label{display:inline-flex;align-items:center;gap:var(--form-label-gap);cursor:pointer;-webkit-user-select:none;user-select:none;color:var(--text-color)}.radio-label.label-left{flex-direction:row-reverse;justify-content:space-between}.radio-input{position:absolute;opacity:0;width:0;height:0}.radio-control{display:flex;align-items:center;justify-content:center;width:var(--size-5);height:var(--size-5);min-width:var(--size-5);min-height:var(--size-5);border:var(--border-width-2) solid var(--surface-border);border-radius:var(--radius-full);background:var(--surface-card);transition:all var(--animation-duration-fast) var(--animation-easing-default);flex-shrink:0}.radio-dot{width:var(--size-2);height:var(--size-2);border-radius:var(--radius-full);background:var(--primary-color-text);opacity:0;transform:scale(.8);transition:all var(--animation-duration-fast) var(--animation-easing-default)}.radio-input:checked+.radio-control{background:var(--primary-color);border-color:var(--primary-color)}.radio-input:checked+.radio-control .radio-dot{opacity:1;transform:scale(1)}.radio-input:focus-visible+.radio-control{box-shadow:0 0 0 var(--focus-outline-width) var(--focus-ring-color)}:host(.radio-disabled) .radio-label{opacity:var(--opacity-disabled);cursor:not-allowed}:host(.radio-error) .radio-control{border-color:var(--danger-color)}:host(.radio-error) .radio-input:checked+.radio-control{background:var(--danger-color);border-color:var(--danger-color)}:host(.radio-success) .radio-control{border-color:var(--success-color)}:host(.radio-success) .radio-input:checked+.radio-control{background:var(--success-color);border-color:var(--success-color)}.radio-error{font-size:var(--font-size-sm);color:var(--danger-color)}.radio-success{font-size:var(--font-size-sm);color:var(--success-color)}:host(.radio-small) .radio-control{width:var(--size-4);height:var(--size-4);min-width:var(--size-4);min-height:var(--size-4)}:host(.radio-small) .radio-dot{width:var(--size-1-5);height:var(--size-1-5)}:host(.radio-small) .radio-text{font-size:var(--font-size-sm)}:host(.radio-large) .radio-control{width:var(--size-6);height:var(--size-6);min-width:var(--size-6);min-height:var(--size-6)}:host(.radio-large) .radio-dot{width:var(--size-3);height:var(--size-3)}:host(.radio-large) .radio-text{font-size:var(--font-size-lg)}.radio-text{color:var(--text-color)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3982
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.4", type: PshRadioComponent, isStandalone: true, selector: "psh-radio", inputs: { checkedInput: { classPropertyName: "checkedInput", publicName: "checked", isSignal: false, isRequired: false, transformFunction: null }, disabledInput: { classPropertyName: "disabledInput", publicName: "disabled", isSignal: false, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, error: { classPropertyName: "error", publicName: "error", isSignal: true, isRequired: false, transformFunction: null }, success: { classPropertyName: "success", publicName: "success", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, labelPosition: { classPropertyName: "labelPosition", publicName: "labelPosition", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { checkedChange: "checkedChange", disabledChange: "disabledChange", valueChange: "valueChange" }, host: { properties: { "class.radio-disabled": "disabled()", "class.radio-error": "!!error()", "class.radio-success": "!!success()", "class.radio-small": "size() === \"small\"", "class.radio-large": "size() === \"large\"", "attr.data-state": "state()" } }, viewQueries: [{ propertyName: "labelSlot", first: true, predicate: ["labelSlot"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"radio-container\">\r\n <label class=\"radio-label\" [class.label-left]=\"labelPosition() === 'left'\">\r\n <input\r\n type=\"radio\"\r\n class=\"radio-input\"\r\n [checked]=\"checked()\"\r\n [disabled]=\"disabled()\"\r\n [required]=\"required()\"\r\n [name]=\"name()\"\r\n [attr.value]=\"value()\"\r\n [attr.aria-label]=\"computedAriaLabel()\"\r\n [attr.aria-required]=\"required() || null\"\r\n [attr.aria-invalid]=\"error() ? 'true' : null\"\r\n [attr.aria-checked]=\"checked()\"\r\n [attr.aria-describedby]=\"ariaDescribedBy()\"\r\n (change)=\"handleChange()\"\r\n (keydown)=\"handleKeydown($event)\"\r\n />\r\n <span \r\n class=\"radio-control\"\r\n [class.error]=\"!!error()\"\r\n [class.success]=\"!!success()\"\r\n >\r\n <span class=\"radio-dot\"></span>\r\n </span>\r\n <span class=\"radio-text\" #labelSlot>\r\n @if (label()) {\r\n {{ label() }}\r\n } @else {\r\n <ng-content></ng-content>\r\n }\r\n </span>\r\n </label>\r\n\r\n @if (error()) {\r\n <div [id]=\"errorMessageId()\" class=\"radio-error\" role=\"alert\">\r\n {{ error() }}\r\n </div>\r\n } @else if (success()) {\r\n <div [id]=\"successMessageId()\" class=\"radio-success\" role=\"status\">\r\n {{ success() }}\r\n </div>\r\n }\r\n</div>", styles: [".radio-container{display:inline-flex;flex-direction:column;gap:var(--form-field-gap)}.radio-label{display:inline-flex;align-items:center;gap:var(--form-label-gap);cursor:pointer;-webkit-user-select:none;user-select:none;color:var(--text-color)}.radio-label.label-left{flex-direction:row-reverse;justify-content:space-between}.radio-input{position:absolute;opacity:0;width:0;height:0}.radio-control{display:flex;align-items:center;justify-content:center;width:var(--size-5);height:var(--size-5);min-width:var(--size-5);min-height:var(--size-5);border:var(--border-width-2) solid var(--surface-border);border-radius:var(--radius-full);background:var(--surface-card);transition:all var(--animation-duration-fast) var(--animation-easing-default);flex-shrink:0}.radio-dot{width:var(--size-2);height:var(--size-2);border-radius:var(--radius-full);background:var(--primary-color-text);opacity:0;transform:scale(.8);transition:all var(--animation-duration-fast) var(--animation-easing-default)}.radio-input:checked+.radio-control{background:var(--primary-color);border-color:var(--primary-color)}.radio-input:checked+.radio-control .radio-dot{opacity:1;transform:scale(1)}.radio-input:focus-visible+.radio-control{box-shadow:0 0 0 var(--focus-outline-width) var(--focus-ring-color)}:host(.radio-disabled) .radio-label{opacity:var(--opacity-disabled);cursor:not-allowed}:host(.radio-error) .radio-control{border-color:var(--danger-color)}:host(.radio-error) .radio-input:checked+.radio-control{background:var(--danger-color);border-color:var(--danger-color)}:host(.radio-success) .radio-control{border-color:var(--success-color)}:host(.radio-success) .radio-input:checked+.radio-control{background:var(--success-color);border-color:var(--success-color)}.radio-error{font-size:var(--font-size-sm);color:var(--danger-color)}.radio-success{font-size:var(--font-size-sm);color:var(--success-color)}:host(.radio-small) .radio-control{width:var(--size-4);height:var(--size-4);min-width:var(--size-4);min-height:var(--size-4)}:host(.radio-small) .radio-dot{width:var(--size-1-5);height:var(--size-1-5)}:host(.radio-small) .radio-text{font-size:var(--font-size-sm)}:host(.radio-large) .radio-control{width:var(--size-6);height:var(--size-6);min-width:var(--size-6);min-height:var(--size-6)}:host(.radio-large) .radio-dot{width:var(--size-3);height:var(--size-3)}:host(.radio-large) .radio-text{font-size:var(--font-size-lg)}.radio-text{color:var(--text-color)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3953
3983
  }
3954
3984
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: PshRadioComponent, decorators: [{
3955
3985
  type: Component,
@@ -3960,8 +3990,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImpor
3960
3990
  '[class.radio-small]': 'size() === "small"',
3961
3991
  '[class.radio-large]': 'size() === "large"',
3962
3992
  '[attr.data-state]': 'state()'
3963
- }, template: "<div class=\"radio-container\">\r\n <label class=\"radio-label\" [class.label-left]=\"labelPosition() === 'left'\">\r\n <input\r\n type=\"radio\"\r\n class=\"radio-input\"\r\n [checked]=\"checked()\"\r\n [disabled]=\"disabled()\"\r\n [required]=\"required()\"\r\n [name]=\"name()\"\r\n [attr.value]=\"value()\"\r\n [attr.aria-label]=\"computedAriaLabel()\"\r\n [attr.aria-required]=\"required() || null\"\r\n [attr.aria-invalid]=\"error() ? 'true' : null\"\r\n [attr.aria-checked]=\"checked()\"\r\n [attr.aria-describedby]=\"ariaDescribedBy()\"\r\n (change)=\"handleChange()\"\r\n (keydown)=\"handleKeydown($event)\"\r\n />\r\n <span \r\n class=\"radio-control\"\r\n [class.error]=\"!!error()\"\r\n [class.success]=\"!!success()\"\r\n >\r\n <span class=\"radio-dot\"></span>\r\n </span>\r\n <span class=\"radio-text\">\r\n @if (label()) {\r\n {{ label() }}\r\n } @else {\r\n <ng-content>Radio</ng-content>\r\n }\r\n </span>\r\n </label>\r\n\r\n @if (error()) {\r\n <div [id]=\"errorMessageId()\" class=\"radio-error\" role=\"alert\">\r\n {{ error() }}\r\n </div>\r\n } @else if (success()) {\r\n <div [id]=\"successMessageId()\" class=\"radio-success\" role=\"status\">\r\n {{ success() }}\r\n </div>\r\n }\r\n</div>", styles: [".radio-container{display:inline-flex;flex-direction:column;gap:var(--form-field-gap)}.radio-label{display:inline-flex;align-items:center;gap:var(--form-label-gap);cursor:pointer;-webkit-user-select:none;user-select:none;color:var(--text-color)}.radio-label.label-left{flex-direction:row-reverse;justify-content:space-between}.radio-input{position:absolute;opacity:0;width:0;height:0}.radio-control{display:flex;align-items:center;justify-content:center;width:var(--size-5);height:var(--size-5);min-width:var(--size-5);min-height:var(--size-5);border:var(--border-width-2) solid var(--surface-border);border-radius:var(--radius-full);background:var(--surface-card);transition:all var(--animation-duration-fast) var(--animation-easing-default);flex-shrink:0}.radio-dot{width:var(--size-2);height:var(--size-2);border-radius:var(--radius-full);background:var(--primary-color-text);opacity:0;transform:scale(.8);transition:all var(--animation-duration-fast) var(--animation-easing-default)}.radio-input:checked+.radio-control{background:var(--primary-color);border-color:var(--primary-color)}.radio-input:checked+.radio-control .radio-dot{opacity:1;transform:scale(1)}.radio-input:focus-visible+.radio-control{box-shadow:0 0 0 var(--focus-outline-width) var(--focus-ring-color)}:host(.radio-disabled) .radio-label{opacity:var(--opacity-disabled);cursor:not-allowed}:host(.radio-error) .radio-control{border-color:var(--danger-color)}:host(.radio-error) .radio-input:checked+.radio-control{background:var(--danger-color);border-color:var(--danger-color)}:host(.radio-success) .radio-control{border-color:var(--success-color)}:host(.radio-success) .radio-input:checked+.radio-control{background:var(--success-color);border-color:var(--success-color)}.radio-error{font-size:var(--font-size-sm);color:var(--danger-color)}.radio-success{font-size:var(--font-size-sm);color:var(--success-color)}:host(.radio-small) .radio-control{width:var(--size-4);height:var(--size-4);min-width:var(--size-4);min-height:var(--size-4)}:host(.radio-small) .radio-dot{width:var(--size-1-5);height:var(--size-1-5)}:host(.radio-small) .radio-text{font-size:var(--font-size-sm)}:host(.radio-large) .radio-control{width:var(--size-6);height:var(--size-6);min-width:var(--size-6);min-height:var(--size-6)}:host(.radio-large) .radio-dot{width:var(--size-3);height:var(--size-3)}:host(.radio-large) .radio-text{font-size:var(--font-size-lg)}.radio-text{color:var(--text-color)}\n"] }]
3964
- }], ctorParameters: () => [], propDecorators: { checkedInput: [{
3993
+ }, template: "<div class=\"radio-container\">\r\n <label class=\"radio-label\" [class.label-left]=\"labelPosition() === 'left'\">\r\n <input\r\n type=\"radio\"\r\n class=\"radio-input\"\r\n [checked]=\"checked()\"\r\n [disabled]=\"disabled()\"\r\n [required]=\"required()\"\r\n [name]=\"name()\"\r\n [attr.value]=\"value()\"\r\n [attr.aria-label]=\"computedAriaLabel()\"\r\n [attr.aria-required]=\"required() || null\"\r\n [attr.aria-invalid]=\"error() ? 'true' : null\"\r\n [attr.aria-checked]=\"checked()\"\r\n [attr.aria-describedby]=\"ariaDescribedBy()\"\r\n (change)=\"handleChange()\"\r\n (keydown)=\"handleKeydown($event)\"\r\n />\r\n <span \r\n class=\"radio-control\"\r\n [class.error]=\"!!error()\"\r\n [class.success]=\"!!success()\"\r\n >\r\n <span class=\"radio-dot\"></span>\r\n </span>\r\n <span class=\"radio-text\" #labelSlot>\r\n @if (label()) {\r\n {{ label() }}\r\n } @else {\r\n <ng-content></ng-content>\r\n }\r\n </span>\r\n </label>\r\n\r\n @if (error()) {\r\n <div [id]=\"errorMessageId()\" class=\"radio-error\" role=\"alert\">\r\n {{ error() }}\r\n </div>\r\n } @else if (success()) {\r\n <div [id]=\"successMessageId()\" class=\"radio-success\" role=\"status\">\r\n {{ success() }}\r\n </div>\r\n }\r\n</div>", styles: [".radio-container{display:inline-flex;flex-direction:column;gap:var(--form-field-gap)}.radio-label{display:inline-flex;align-items:center;gap:var(--form-label-gap);cursor:pointer;-webkit-user-select:none;user-select:none;color:var(--text-color)}.radio-label.label-left{flex-direction:row-reverse;justify-content:space-between}.radio-input{position:absolute;opacity:0;width:0;height:0}.radio-control{display:flex;align-items:center;justify-content:center;width:var(--size-5);height:var(--size-5);min-width:var(--size-5);min-height:var(--size-5);border:var(--border-width-2) solid var(--surface-border);border-radius:var(--radius-full);background:var(--surface-card);transition:all var(--animation-duration-fast) var(--animation-easing-default);flex-shrink:0}.radio-dot{width:var(--size-2);height:var(--size-2);border-radius:var(--radius-full);background:var(--primary-color-text);opacity:0;transform:scale(.8);transition:all var(--animation-duration-fast) var(--animation-easing-default)}.radio-input:checked+.radio-control{background:var(--primary-color);border-color:var(--primary-color)}.radio-input:checked+.radio-control .radio-dot{opacity:1;transform:scale(1)}.radio-input:focus-visible+.radio-control{box-shadow:0 0 0 var(--focus-outline-width) var(--focus-ring-color)}:host(.radio-disabled) .radio-label{opacity:var(--opacity-disabled);cursor:not-allowed}:host(.radio-error) .radio-control{border-color:var(--danger-color)}:host(.radio-error) .radio-input:checked+.radio-control{background:var(--danger-color);border-color:var(--danger-color)}:host(.radio-success) .radio-control{border-color:var(--success-color)}:host(.radio-success) .radio-input:checked+.radio-control{background:var(--success-color);border-color:var(--success-color)}.radio-error{font-size:var(--font-size-sm);color:var(--danger-color)}.radio-success{font-size:var(--font-size-sm);color:var(--success-color)}:host(.radio-small) .radio-control{width:var(--size-4);height:var(--size-4);min-width:var(--size-4);min-height:var(--size-4)}:host(.radio-small) .radio-dot{width:var(--size-1-5);height:var(--size-1-5)}:host(.radio-small) .radio-text{font-size:var(--font-size-sm)}:host(.radio-large) .radio-control{width:var(--size-6);height:var(--size-6);min-width:var(--size-6);min-height:var(--size-6)}:host(.radio-large) .radio-dot{width:var(--size-3);height:var(--size-3)}:host(.radio-large) .radio-text{font-size:var(--font-size-lg)}.radio-text{color:var(--text-color)}\n"] }]
3994
+ }], propDecorators: { labelSlot: [{ type: i0.ViewChild, args: ['labelSlot', { isSignal: true }] }], checkedInput: [{
3965
3995
  type: Input,
3966
3996
  args: ['checked']
3967
3997
  }], disabledInput: [{