ps-helix 3.0.7 → 3.0.8

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 21+ featuring modern design patterns, accessibility-first development, and optimal developer experience.
4
4
 
5
- [![npm version](https://img.shields.io/badge/npm-3.0.7-blue.svg)](https://www.npmjs.com/package/ps-helix)
5
+ [![npm version](https://img.shields.io/badge/npm-3.0.8-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-21.0.3-red.svg)](https://angular.dev/)
8
8
  [![TypeScript](https://img.shields.io/badge/TypeScript-5.9.0-blue.svg)](https://www.typescriptlang.org/)
@@ -118,7 +118,7 @@ After installation, verify that ps-helix is in your `package.json`:
118
118
  ```json
119
119
  {
120
120
  "dependencies": {
121
- "ps-helix": "^3.0.7"
121
+ "ps-helix": "^3.0.8"
122
122
  }
123
123
  }
124
124
  ```
@@ -1173,7 +1173,7 @@ Copyright (c) 2025 PACK Solutions
1173
1173
 
1174
1174
  ---
1175
1175
 
1176
- **Version**: 3.0.7
1176
+ **Version**: 3.0.8
1177
1177
  **Built with**: Angular 21.0.3, TypeScript 5.9.0, Phosphor Icons 2.0.3
1178
1178
  **Author**: Fabrice PEREZ | Product Designer at PACK Solutions
1179
1179
  **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, ChangeDetectorRef, DestroyRef, forwardRef, Injectable, Renderer2, contentChild, contentChildren, afterNextRender } from '@angular/core';
2
+ import { input, output, computed, ChangeDetectionStrategy, Component, model, inject, ElementRef, signal, PLATFORM_ID, ViewEncapsulation, InjectionToken, viewChild, EventEmitter, effect, Output, Input, ChangeDetectorRef, DestroyRef, forwardRef, Injectable, Renderer2, contentChild, contentChildren, afterNextRender } from '@angular/core';
3
3
  import * as i1 from '@angular/common';
4
4
  import { CommonModule, isPlatformBrowser, NgTemplateOutlet } from '@angular/common';
5
5
  import { NG_VALUE_ACCESSOR, FormsModule } from '@angular/forms';
@@ -953,16 +953,25 @@ const CHECKBOX_CONFIG = new InjectionToken('CHECKBOX_CONFIG', {
953
953
  });
954
954
  let checkboxIdCounter = 0;
955
955
  class PshCheckboxComponent {
956
+ set checkedInput(v) { this.checked.set(v); }
957
+ set disabledInput(v) { this.disabled.set(v); }
958
+ set indeterminateInput(v) { this.indeterminate.set(v); }
956
959
  constructor() {
957
960
  this.config = inject(CHECKBOX_CONFIG);
958
961
  this.uniqueId = `checkbox-${++checkboxIdCounter}`;
959
962
  this.checkboxInput = viewChild('checkboxInput', ...(ngDevMode ? [{ debugName: "checkboxInput" }] : []));
960
963
  this.onChange = (value) => { };
961
964
  this.onTouched = () => { };
962
- this.checked = model(this.config.checked ?? false, ...(ngDevMode ? [{ debugName: "checked" }] : []));
963
- this.disabled = model(this.config.disabled ?? false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
964
- this.required = model(this.config.required ?? false, ...(ngDevMode ? [{ debugName: "required" }] : []));
965
- this.indeterminate = model(this.config.indeterminate ?? false, ...(ngDevMode ? [{ debugName: "indeterminate" }] : []));
965
+ // CVA-managed state: plain signals + manual @Input/@Output to prevent
966
+ // auto-emission during writeValue()/setDisabledState().
967
+ this.checked = signal(this.config.checked ?? false, ...(ngDevMode ? [{ debugName: "checked" }] : []));
968
+ this.disabled = signal(this.config.disabled ?? false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
969
+ this.indeterminate = signal(this.config.indeterminate ?? false, ...(ngDevMode ? [{ debugName: "indeterminate" }] : []));
970
+ this.required = input(this.config.required ?? false, ...(ngDevMode ? [{ debugName: "required" }] : []));
971
+ // Outputs — EventEmitter to decouple from signal writes.
972
+ this.checkedChange = new EventEmitter();
973
+ this.disabledChange = new EventEmitter();
974
+ this.indeterminateChange = new EventEmitter();
966
975
  this.label = input(this.config.label ?? '', ...(ngDevMode ? [{ debugName: "label" }] : []));
967
976
  this.error = input('', ...(ngDevMode ? [{ debugName: "error" }] : []));
968
977
  this.success = input('', ...(ngDevMode ? [{ debugName: "success" }] : []));
@@ -1004,6 +1013,7 @@ class PshCheckboxComponent {
1004
1013
  this.checked.update(v => !v);
1005
1014
  this.indeterminate.set(false);
1006
1015
  this.onChange(this.checked());
1016
+ this.checkedChange.emit(this.checked());
1007
1017
  this.onTouched();
1008
1018
  }
1009
1019
  }
@@ -1044,7 +1054,7 @@ class PshCheckboxComponent {
1044
1054
  }
1045
1055
  }
1046
1056
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: PshCheckboxComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1047
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: PshCheckboxComponent, isStandalone: true, selector: "psh-checkbox", inputs: { checked: { classPropertyName: "checked", publicName: "checked", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, indeterminate: { classPropertyName: "indeterminate", publicName: "indeterminate", 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 }, 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: { checked: "checkedChange", disabled: "disabledChange", required: "requiredChange", indeterminate: "indeterminateChange" }, host: { properties: { "class.checkbox-disabled": "disabled()", "class.checkbox-error": "!!error()", "class.checkbox-success": "!!success()", "class.checkbox-small": "size() === \"small\"", "class.checkbox-large": "size() === \"large\"", "attr.data-state": "state()" } }, providers: [{
1057
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: PshCheckboxComponent, isStandalone: true, selector: "psh-checkbox", inputs: { checkedInput: { classPropertyName: "checkedInput", publicName: "checked", isSignal: false, isRequired: false, transformFunction: null }, disabledInput: { classPropertyName: "disabledInput", publicName: "disabled", isSignal: false, isRequired: false, transformFunction: null }, indeterminateInput: { classPropertyName: "indeterminateInput", publicName: "indeterminate", 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 }, 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", indeterminateChange: "indeterminateChange" }, host: { properties: { "class.checkbox-disabled": "disabled()", "class.checkbox-error": "!!error()", "class.checkbox-success": "!!success()", "class.checkbox-small": "size() === \"small\"", "class.checkbox-large": "size() === \"large\"", "attr.data-state": "state()" } }, providers: [{
1048
1058
  provide: NG_VALUE_ACCESSOR,
1049
1059
  useExisting: PshCheckboxComponent,
1050
1060
  multi: true
@@ -1064,7 +1074,22 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
1064
1074
  '[class.checkbox-large]': 'size() === "large"',
1065
1075
  '[attr.data-state]': 'state()'
1066
1076
  }, template: "<div class=\"checkbox-container\">\n <label class=\"checkbox-label\" [class.label-left]=\"labelPosition() === 'left'\">\n <input\n #checkboxInput\n type=\"checkbox\"\n class=\"checkbox-input\"\n [checked]=\"checked()\"\n [disabled]=\"disabled()\"\n [required]=\"required()\"\n [attr.aria-label]=\"computedAriaLabel()\"\n [attr.aria-required]=\"required() || null\"\n [attr.aria-invalid]=\"error() ? 'true' : null\"\n [attr.aria-checked]=\"ariaChecked()\"\n [attr.aria-describedby]=\"ariaDescribedBy()\"\n (change)=\"toggle()\"\n (keydown)=\"handleKeydown($event)\"\n />\n <span \n class=\"checkbox-control\"\n [class.error]=\"!!error()\"\n [class.success]=\"!!success()\"\n [class.indeterminate]=\"indeterminate()\"\n >\n @if (checked() && !indeterminate()) {\n <i class=\"ph ph-check\" aria-hidden=\"true\"></i>\n }\n @if (indeterminate()) {\n <i class=\"ph ph-minus\" aria-hidden=\"true\"></i>\n }\n </span>\n <span class=\"checkbox-text\">\n @if (label()) {\n {{ label() }}\n } @else {\n <ng-content></ng-content>\n }\n </span>\n </label>\n\n @if (error()) {\n <div [id]=\"errorMessageId()\" class=\"checkbox-error\" role=\"alert\">\n {{ error() }}\n </div>\n }\n\n @if (success()) {\n <div [id]=\"successMessageId()\" class=\"checkbox-success\" role=\"status\">\n {{ success() }}\n </div>\n }\n</div>", styles: [".checkbox-container{display:inline-flex;flex-direction:column;gap:var(--spacing-xs)}.checkbox-label{display:inline-flex;align-items:center;gap:var(--spacing-sm);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:var(--size-4-5);height:var(--size-4-5);min-width:var(--size-4-5);min-height:var(--size-4-5);border:var(--border-width-2) solid var(--surface-border);border-radius:var(--border-radius);background:var(--surface-card);transition:background-color var(--animation-duration-fast) var(--animation-easing-default),border-color var(--animation-duration-fast) var(--animation-easing-default);color:var(--primary-color-text);position:relative;flex-shrink:0}.checkbox-input:checked+.checkbox-control{background:var(--primary-color);border-color:var(--primary-color)}.checkbox-input:focus-visible+.checkbox-control{outline:var(--focus-outline-width) var(--focus-outline-style) var(--focus-outline-color);outline-offset:var(--focus-outline-offset)}.checkbox-control i{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%) scale(0);font-size:var(--font-size-xs);opacity:0;transition:opacity var(--animation-duration-fast) var(--animation-easing-default),transform var(--animation-duration-fast) var(--animation-easing-default)}.checkbox-input:checked+.checkbox-control i,.checkbox-control.indeterminate i{opacity:1;transform:translate(-50%,-50%) scale(1.1)}.checkbox-control.indeterminate{background:var(--primary-color);border-color:var(--primary-color)}:host(.checkbox-disabled) .checkbox-label{opacity:var(--opacity-disabled);cursor:not-allowed}:host(.checkbox-error) .checkbox-control{border-color:var(--danger-color)}:host(.checkbox-error) .checkbox-input:checked+.checkbox-control{background:var(--danger-color);border-color:var(--danger-color)}:host(.checkbox-success) .checkbox-control{border-color:var(--success-color)}:host(.checkbox-success) .checkbox-input:checked+.checkbox-control{background:var(--success-color);border-color:var(--success-color)}.checkbox-error{font-size:var(--font-size-sm);color:var(--danger-color)}.checkbox-success{font-size:var(--font-size-sm);color:var(--success-color)}:host(.checkbox-small) .checkbox-control{width:var(--size-4);height:var(--size-4);min-width:var(--size-4);min-height:var(--size-4)}:host(.checkbox-small) .checkbox-text{font-size:var(--font-size-sm)}:host(.checkbox-large) .checkbox-control{width:var(--size-5-5);height:var(--size-5-5);min-width:var(--size-5-5);min-height:var(--size-5-5)}:host(.checkbox-large) .checkbox-text{font-size:var(--font-size-lg)}.checkbox-text{color:var(--text-color)}\n"] }]
1067
- }], 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"] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }, { type: i0.Output, args: ["requiredChange"] }], indeterminate: [{ type: i0.Input, args: [{ isSignal: true, alias: "indeterminate", required: false }] }, { type: i0.Output, args: ["indeterminateChange"] }], 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 }] }] } });
1077
+ }], ctorParameters: () => [], propDecorators: { checkboxInput: [{ type: i0.ViewChild, args: ['checkboxInput', { isSignal: true }] }], checkedInput: [{
1078
+ type: Input,
1079
+ args: ['checked']
1080
+ }], disabledInput: [{
1081
+ type: Input,
1082
+ args: ['disabled']
1083
+ }], indeterminateInput: [{
1084
+ type: Input,
1085
+ args: ['indeterminate']
1086
+ }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], checkedChange: [{
1087
+ type: Output
1088
+ }], disabledChange: [{
1089
+ type: Output
1090
+ }], indeterminateChange: [{
1091
+ type: Output
1092
+ }], 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 }] }] } });
1068
1093
 
1069
1094
  class PshCollapseComponent {
1070
1095
  constructor() {
@@ -1402,6 +1427,8 @@ const INPUT_LABELS = {
1402
1427
 
1403
1428
  class PshInputComponent {
1404
1429
  static { this.nextId = 0; }
1430
+ set valueInput(v) { this.value.set(v ?? ''); }
1431
+ set disabledInput(v) { this.disabled.set(v); }
1405
1432
  getState() {
1406
1433
  if (this.disabled())
1407
1434
  return 'disabled';
@@ -1422,9 +1449,11 @@ class PshInputComponent {
1422
1449
  this.cdr = inject(ChangeDetectorRef);
1423
1450
  this.destroyRef = inject(DestroyRef);
1424
1451
  this.inputId = `psh-input-${PshInputComponent.nextId++}`;
1425
- // Model inputs (two-way bindable state)
1426
- this.value = model('', ...(ngDevMode ? [{ debugName: "value" }] : []));
1427
- this.disabled = model(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
1452
+ // CVA-managed state: plain signals + manual @Input/@Output to prevent
1453
+ // auto-emission during writeValue()/setDisabledState().
1454
+ this.value = signal('', ...(ngDevMode ? [{ debugName: "value" }] : []));
1455
+ this.disabled = signal(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
1456
+ // Non-CVA model inputs (two-way bindable, not written by CVA methods)
1428
1457
  this.readonly = model(false, ...(ngDevMode ? [{ debugName: "readonly" }] : []));
1429
1458
  this.loading = model(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
1430
1459
  // Configuration inputs (one-directional)
@@ -1456,8 +1485,9 @@ class PshInputComponent {
1456
1485
  this.passwordVisibleSignal = signal(false, ...(ngDevMode ? [{ debugName: "passwordVisibleSignal" }] : []));
1457
1486
  this.blurTimeoutId = null;
1458
1487
  this.debounceTimeoutId = null;
1459
- // Outputs
1460
- this.valueChange = output();
1488
+ // Outputs — valueChange/disabledChange use EventEmitter to decouple from signal writes.
1489
+ this.valueChange = new EventEmitter();
1490
+ this.disabledChange = new EventEmitter();
1461
1491
  this.inputFocus = output();
1462
1492
  this.inputBlur = output();
1463
1493
  this.suggestionSelect = output();
@@ -1617,7 +1647,7 @@ class PshInputComponent {
1617
1647
  }
1618
1648
  }
1619
1649
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: PshInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1620
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: PshInputComponent, isStandalone: true, selector: "psh-input", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, fullWidth: { classPropertyName: "fullWidth", publicName: "fullWidth", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, showLabel: { classPropertyName: "showLabel", publicName: "showLabel", isSignal: true, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, iconStart: { classPropertyName: "iconStart", publicName: "iconStart", isSignal: true, isRequired: false, transformFunction: null }, iconEnd: { classPropertyName: "iconEnd", publicName: "iconEnd", 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 }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, suggestions: { classPropertyName: "suggestions", publicName: "suggestions", isSignal: true, isRequired: false, transformFunction: null }, autocompleteConfig: { classPropertyName: "autocompleteConfig", publicName: "autocompleteConfig", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", disabled: "disabledChange", readonly: "readonlyChange", loading: "loadingChange", valueChange: "valueChange", inputFocus: "inputFocus", inputBlur: "inputBlur", suggestionSelect: "suggestionSelect" }, providers: [
1650
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: PshInputComponent, isStandalone: true, selector: "psh-input", inputs: { valueInput: { classPropertyName: "valueInput", publicName: "value", isSignal: false, isRequired: false, transformFunction: null }, disabledInput: { classPropertyName: "disabledInput", publicName: "disabled", isSignal: false, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, fullWidth: { classPropertyName: "fullWidth", publicName: "fullWidth", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, showLabel: { classPropertyName: "showLabel", publicName: "showLabel", isSignal: true, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, iconStart: { classPropertyName: "iconStart", publicName: "iconStart", isSignal: true, isRequired: false, transformFunction: null }, iconEnd: { classPropertyName: "iconEnd", publicName: "iconEnd", 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 }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, suggestions: { classPropertyName: "suggestions", publicName: "suggestions", isSignal: true, isRequired: false, transformFunction: null }, autocompleteConfig: { classPropertyName: "autocompleteConfig", publicName: "autocompleteConfig", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { readonly: "readonlyChange", loading: "loadingChange", valueChange: "valueChange", disabledChange: "disabledChange", inputFocus: "inputFocus", inputBlur: "inputBlur", suggestionSelect: "suggestionSelect" }, providers: [
1621
1651
  {
1622
1652
  provide: NG_VALUE_ACCESSOR,
1623
1653
  useExisting: forwardRef(() => PshInputComponent),
@@ -1634,7 +1664,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
1634
1664
  multi: true
1635
1665
  }
1636
1666
  ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div \n class=\"input-container\"\n [class.full-width]=\"fullWidth()\"\n [class.small]=\"size() === 'small'\"\n [class.large]=\"size() === 'large'\"\n [class.error]=\"!!error()\"\n [class.success]=\"!!success()\"\n [class.disabled]=\"disabled()\"\n [class.readonly]=\"readonly()\"\n [class.loading]=\"loading()\"\n [class.focused]=\"focused()\"\n [class.has-start-icon]=\"!!iconStart()\"\n [class.has-end-icon]=\"!!iconEnd() || type() === 'password'\"\n [class.outlined]=\"variant() === 'outlined'\"\n [class.filled]=\"variant() === 'filled'\"\n>\n <!-- Label slot -->\n @if (showLabel()) {\n <label class=\"input-label\" [for]=\"inputId\" (click)=\"focusSelect()\" [class.required]=\"required()\">\n <ng-content select=\"[input-label]\"></ng-content>\n @if (!hasLabelContent()) {\n {{ label() }}\n }\n </label>\n }\n\n <div class=\"input-wrapper\">\n @if (iconStart()) {\n <i class=\"ph ph-{{ iconStart() }}\" aria-hidden=\"true\"></i>\n }\n\n <input\n [id]=\"inputId\"\n [type]=\"effectiveType()\"\n [attr.placeholder]=\"placeholder()\"\n [attr.aria-label]=\"computedAriaLabel()\"\n [attr.aria-invalid]=\"!!error()\"\n [attr.aria-required]=\"required()\"\n [attr.aria-describedby]=\"error() ? 'error-message' : success() ? 'success-message' : hint() ? 'hint-message' : null\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n [required]=\"required()\"\n [value]=\"value()\"\n (input)=\"handleInput($event)\"\n (keydown)=\"handleKeydown($event)\"\n (focus)=\"handleFocus()\"\n (blur)=\"handleBlur()\"\n [attr.data-state]=\"state()\"\n />\n\n @if (iconEnd()) {\n <i class=\"ph ph-{{ iconEnd() }}\" aria-hidden=\"true\"></i>\n }\n\n @if (type() === 'password') {\n <button\n type=\"button\"\n class=\"password-toggle\"\n (click)=\"togglePasswordVisibility()\"\n [attr.aria-label]=\"passwordToggleLabel()\"\n [disabled]=\"disabled() || readonly()\"\n >\n <i \n [class]=\"'ph ph-' + (passwordVisible() ? 'eye-slash' : 'eye')\"\n aria-hidden=\"true\"\n ></i>\n </button>\n }\n\n @if (loading()) {\n <div class=\"input-loader\" aria-hidden=\"true\">\n <div class=\"loader\"></div>\n </div>\n }\n\n @if (showSuggestions()) {\n <div class=\"suggestions-list\" role=\"listbox\">\n @for (suggestion of filteredSuggestions(); track suggestion; let i = $index) {\n <div \n class=\"suggestion-item\"\n [class.focused]=\"i === focusedSuggestionIndex()\"\n role=\"option\"\n [attr.aria-selected]=\"i === focusedSuggestionIndex()\"\n (click)=\"handleSuggestionClick(suggestion)\"\n (mouseenter)=\"focusedSuggestionIndex.set(i)\"\n >\n {{ suggestion }}\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Error message slot -->\n @if (error()) {\n <div id=\"error-message\" class=\"input-error\" role=\"alert\">\n <ng-content select=\"[input-error]\">\n {{ error() }}\n </ng-content>\n </div>\n }\n\n <!-- Success message slot -->\n @if (success()) {\n <div id=\"success-message\" class=\"input-success\" role=\"status\">\n <ng-content select=\"[input-success]\">\n {{ success() }}\n </ng-content>\n </div>\n }\n\n <!-- Hint message slot -->\n @if (hint()) {\n <div id=\"hint-message\" class=\"input-hint\">\n <ng-content select=\"[input-hint]\">\n {{ hint() }}\n </ng-content>\n </div>\n }\n</div>", styles: [".input-container{position:relative;width:100%;max-width:300px}.input-container.full-width{max-width:none}.input-label{display:block;color:var(--text-color);font-size:var(--font-size-sm);font-weight:500;margin-bottom:var(--spacing-xs);width:100%;cursor:pointer}.input-label.required:after{content:\"*\";color:var(--danger-color);margin-left:var(--spacing-xxs)}.input-wrapper{position:relative;display:flex;align-items:center;width:100%}input{width:100%;height:var(--height-input-md);padding:0 var(--spacing-md);font-family:inherit;font-size:var(--font-size-base);color:var(--text-color);background:var(--surface-0);border:var(--border-width-1) solid var(--surface-border);border-radius:var(--border-radius);transition:all var(--animation-duration-default) var(--animation-easing-default)}input:hover:not(:disabled):not(:focus){border-color:var(--primary-color)}input::placeholder{color:var(--text-color-tertiary);opacity:1}input:focus{outline:none;border-color:var(--primary-color);box-shadow:0 0 0 var(--focus-ring-width) var(--focus-ring-color)}.input-container.outlined input{background:transparent;border:var(--border-width-2) solid var(--surface-border)}.input-container.outlined input:hover:not(:disabled):not(:focus){border-color:var(--primary-color)}.input-container.outlined input:focus{border-color:var(--primary-color);box-shadow:0 0 0 var(--focus-ring-width) var(--focus-ring-color)}.input-container.filled input{background:var(--surface-ground);border:var(--border-width-1) solid transparent}.input-container.filled input:hover:not(:disabled):not(:focus){background:var(--surface-hover)}.input-container.filled input:focus{background:var(--surface-0);border-color:var(--primary-color);box-shadow:0 0 0 var(--focus-ring-width) var(--focus-ring-color)}.input-container.error input{border-color:var(--danger-color)}.input-container.error input:focus{box-shadow:0 0 0 var(--focus-ring-width) var(--focus-ring-error)}.input-container.success input{border-color:var(--success-color)}.input-container.success input:focus{box-shadow:0 0 0 var(--focus-ring-width) var(--focus-ring-success)}.input-container.disabled input{background:var(--surface-ground);cursor:not-allowed;opacity:var(--opacity-disabled)}.input-container.readonly input{background:var(--surface-ground);cursor:default}.input-container.has-start-icon input{padding-left:calc(var(--spacing-md) * 2 + 1rem)}.input-container.has-end-icon input{padding-right:calc(var(--spacing-md) * 2 + 1rem)}.input-wrapper i{position:absolute;font-size:var(--icon-size-md);color:var(--text-color-secondary);pointer-events:none}.input-wrapper i:first-child{left:var(--spacing-md)}.input-wrapper i:last-child{right:var(--spacing-md)}.password-toggle{position:absolute;right:var(--spacing-md);background:transparent;border:none;color:var(--text-color-secondary);cursor:pointer;padding:var(--spacing-xs);border-radius:var(--border-radius);display:flex;align-items:center;justify-content:center;transition:all .2s ease}.password-toggle:hover{background:var(--surface-hover);color:var(--text-color)}.password-toggle:focus{outline:none;box-shadow:0 0 0 var(--focus-ring-width) var(--focus-ring-color)}.password-toggle i{font-size:var(--icon-size-md);position:static;pointer-events:auto}.input-container.small input{height:var(--height-input-sm);padding:0 var(--spacing-md);font-size:var(--font-size-sm)}.input-container.large input{height:var(--height-input-lg);padding:0 var(--spacing-lg);font-size:var(--font-size-lg)}.input-error,.input-success,.input-hint{font-size:var(--font-size-sm);margin-top:var(--spacing-xs)}.input-error{color:var(--danger-color);display:flex;align-items:center;gap:var(--spacing-xs)}.input-error i{font-size:var(--icon-size-sm)}.input-success{color:var(--success-color)}.input-hint{color:var(--text-color-secondary)}.input-loader{position:absolute;right:var(--spacing-md);display:flex;align-items:center;justify-content:center}.loader{width:var(--icon-size-sm);height:var(--icon-size-sm);border:var(--border-width-2) solid var(--surface-border);border-top-color:var(--primary-color);border-radius:50%;animation:spin .8s linear infinite}.suggestions-list{position:absolute;top:100%;left:0;right:0;background:var(--surface-0);border:var(--border-width-1) solid var(--surface-border);border-radius:var(--border-radius);box-shadow:var(--shadow-lg);z-index:var(--z-index-dropdown);max-height:var(--size-48);overflow-y:auto;margin-top:var(--spacing-xs)}.suggestion-item{padding:var(--spacing-sm) var(--spacing-md);cursor:pointer;transition:all var(--animation-duration-default) var(--animation-easing-default);color:var(--text-color)}.suggestion-item:hover,.suggestion-item.focused{background:var(--surface-hover);color:var(--primary-color)}@keyframes spin{to{transform:rotate(360deg)}}\n"] }]
1637
- }], ctorParameters: () => [], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }, { type: i0.Output, args: ["disabledChange"] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }, { type: i0.Output, args: ["readonlyChange"] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }, { type: i0.Output, args: ["loadingChange"] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], fullWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "fullWidth", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], showLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "showLabel", required: false }] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], iconStart: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconStart", required: false }] }], iconEnd: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconEnd", required: false }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], success: [{ type: i0.Input, args: [{ isSignal: true, alias: "success", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], suggestions: [{ type: i0.Input, args: [{ isSignal: true, alias: "suggestions", required: false }] }], autocompleteConfig: [{ type: i0.Input, args: [{ isSignal: true, alias: "autocompleteConfig", required: false }] }], valueChange: [{ type: i0.Output, args: ["valueChange"] }], inputFocus: [{ type: i0.Output, args: ["inputFocus"] }], inputBlur: [{ type: i0.Output, args: ["inputBlur"] }], suggestionSelect: [{ type: i0.Output, args: ["suggestionSelect"] }] } });
1667
+ }], ctorParameters: () => [], propDecorators: { valueInput: [{
1668
+ type: Input,
1669
+ args: ['value']
1670
+ }], disabledInput: [{
1671
+ type: Input,
1672
+ args: ['disabled']
1673
+ }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }, { type: i0.Output, args: ["readonlyChange"] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }, { type: i0.Output, args: ["loadingChange"] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], fullWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "fullWidth", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], showLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "showLabel", required: false }] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], iconStart: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconStart", required: false }] }], iconEnd: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconEnd", required: false }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], success: [{ type: i0.Input, args: [{ isSignal: true, alias: "success", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], suggestions: [{ type: i0.Input, args: [{ isSignal: true, alias: "suggestions", required: false }] }], autocompleteConfig: [{ type: i0.Input, args: [{ isSignal: true, alias: "autocompleteConfig", required: false }] }], valueChange: [{
1674
+ type: Output
1675
+ }], disabledChange: [{
1676
+ type: Output
1677
+ }], inputFocus: [{ type: i0.Output, args: ["inputFocus"] }], inputBlur: [{ type: i0.Output, args: ["inputBlur"] }], suggestionSelect: [{ type: i0.Output, args: ["suggestionSelect"] }] } });
1638
1678
 
1639
1679
  const TOOLTIP_CONFIG = new InjectionToken('TOOLTIP_CONFIG', {
1640
1680
  factory: () => ({
@@ -2763,14 +2803,18 @@ const RADIO_STYLES = new InjectionToken('RADIO_STYLES', {
2763
2803
  */
2764
2804
  let radioIdCounter = 0;
2765
2805
  class PshRadioComponent {
2806
+ set checkedInput(v) { this.checked.set(v); }
2807
+ set disabledInput(v) { this.disabled.set(v); }
2766
2808
  constructor() {
2767
2809
  this.config = inject(RADIO_CONFIG);
2768
2810
  this.styles = inject(RADIO_STYLES, { optional: true }) ?? [];
2769
2811
  this.uniqueId = `radio-${++radioIdCounter}`;
2770
- // Model inputs with defaults from config
2771
- this.checked = model(this.config.checked ?? false, ...(ngDevMode ? [{ debugName: "checked" }] : []));
2772
- this.disabled = model(this.config.disabled ?? false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
2773
- this.required = model(this.config.required ?? false, ...(ngDevMode ? [{ debugName: "required" }] : []));
2812
+ // Plain signals + manual @Input/@Output to prevent auto-emission
2813
+ // when parent sets [checked] or [disabled] via template binding.
2814
+ // model() would auto-emit checkedChange/disabledChange on .set().
2815
+ this.checked = signal(this.config.checked ?? false, ...(ngDevMode ? [{ debugName: "checked" }] : []));
2816
+ this.disabled = signal(this.config.disabled ?? false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
2817
+ this.required = input(this.config.required ?? false, ...(ngDevMode ? [{ debugName: "required" }] : []));
2774
2818
  // Regular inputs
2775
2819
  this.label = input('', ...(ngDevMode ? [{ debugName: "label" }] : []));
2776
2820
  this.error = input('', ...(ngDevMode ? [{ debugName: "error" }] : []));
@@ -2783,9 +2827,10 @@ class PshRadioComponent {
2783
2827
  // Content projection tracking
2784
2828
  this.radioText = contentChild('.radio-text', ...(ngDevMode ? [{ debugName: "radioText" }] : []));
2785
2829
  this.hasProjectedContent = signal(false, ...(ngDevMode ? [{ debugName: "hasProjectedContent" }] : []));
2786
- // Outputs
2830
+ // Outputs — checkedChange/disabledChange use EventEmitter to decouple from signal writes.
2831
+ this.checkedChange = new EventEmitter();
2832
+ this.disabledChange = new EventEmitter();
2787
2833
  this.valueChange = output();
2788
- this.checkedChange = output();
2789
2834
  // Computed values
2790
2835
  this.customStyles = computed(() => Object.assign({}, ...this.styles), ...(ngDevMode ? [{ debugName: "customStyles" }] : []));
2791
2836
  this.state = computed(() => this.getState(), ...(ngDevMode ? [{ debugName: "state" }] : []));
@@ -2867,7 +2912,7 @@ class PshRadioComponent {
2867
2912
  // Implementation requires radio group context
2868
2913
  }
2869
2914
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: PshRadioComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2870
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: PshRadioComponent, isStandalone: true, selector: "psh-radio", inputs: { checked: { classPropertyName: "checked", publicName: "checked", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, 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: { checked: "checkedChange", disabled: "disabledChange", required: "requiredChange", valueChange: "valueChange", checkedChange: "checkedChange" }, 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()" } }, queries: [{ propertyName: "radioText", first: true, predicate: [".radio-text"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"radio-container\">\n <label class=\"radio-label\" [class.label-left]=\"labelPosition() === 'left'\">\n <input\n type=\"radio\"\n class=\"radio-input\"\n [checked]=\"checked()\"\n [disabled]=\"disabled()\"\n [required]=\"required()\"\n [name]=\"name()\"\n [value]=\"value()\"\n [attr.aria-label]=\"computedAriaLabel()\"\n [attr.aria-required]=\"required() || null\"\n [attr.aria-invalid]=\"error() ? 'true' : null\"\n [attr.aria-checked]=\"checked()\"\n [attr.aria-describedby]=\"ariaDescribedBy()\"\n (change)=\"handleChange()\"\n (keydown)=\"handleKeydown($event)\"\n />\n <span \n class=\"radio-control\"\n [class.error]=\"!!error()\"\n [class.success]=\"!!success()\"\n >\n <span class=\"radio-dot\"></span>\n </span>\n <span class=\"radio-text\">\n @if (label()) {\n {{ label() }}\n } @else {\n <ng-content>Radio</ng-content>\n }\n </span>\n </label>\n\n @if (error()) {\n <div [id]=\"errorMessageId()\" class=\"radio-error\" role=\"alert\">\n {{ error() }}\n </div>\n }\n\n @if (success()) {\n <div [id]=\"successMessageId()\" class=\"radio-success\" role=\"status\">\n {{ success() }}\n </div>\n }\n</div>", styles: [".radio-container{display:inline-flex;flex-direction:column;gap:var(--spacing-xs)}.radio-label{display:inline-flex;align-items:center;gap:var(--spacing-sm);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 }); }
2915
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", 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()" } }, queries: [{ propertyName: "radioText", first: true, predicate: [".radio-text"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"radio-container\">\n <label class=\"radio-label\" [class.label-left]=\"labelPosition() === 'left'\">\n <input\n type=\"radio\"\n class=\"radio-input\"\n [checked]=\"checked()\"\n [disabled]=\"disabled()\"\n [required]=\"required()\"\n [name]=\"name()\"\n [value]=\"value()\"\n [attr.aria-label]=\"computedAriaLabel()\"\n [attr.aria-required]=\"required() || null\"\n [attr.aria-invalid]=\"error() ? 'true' : null\"\n [attr.aria-checked]=\"checked()\"\n [attr.aria-describedby]=\"ariaDescribedBy()\"\n (change)=\"handleChange()\"\n (keydown)=\"handleKeydown($event)\"\n />\n <span \n class=\"radio-control\"\n [class.error]=\"!!error()\"\n [class.success]=\"!!success()\"\n >\n <span class=\"radio-dot\"></span>\n </span>\n <span class=\"radio-text\">\n @if (label()) {\n {{ label() }}\n } @else {\n <ng-content>Radio</ng-content>\n }\n </span>\n </label>\n\n @if (error()) {\n <div [id]=\"errorMessageId()\" class=\"radio-error\" role=\"alert\">\n {{ error() }}\n </div>\n }\n\n @if (success()) {\n <div [id]=\"successMessageId()\" class=\"radio-success\" role=\"status\">\n {{ success() }}\n </div>\n }\n</div>", styles: [".radio-container{display:inline-flex;flex-direction:column;gap:var(--spacing-xs)}.radio-label{display:inline-flex;align-items:center;gap:var(--spacing-sm);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 }); }
2871
2916
  }
2872
2917
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: PshRadioComponent, decorators: [{
2873
2918
  type: Component,
@@ -2879,18 +2924,32 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
2879
2924
  '[class.radio-large]': 'size() === "large"',
2880
2925
  '[attr.data-state]': 'state()'
2881
2926
  }, template: "<div class=\"radio-container\">\n <label class=\"radio-label\" [class.label-left]=\"labelPosition() === 'left'\">\n <input\n type=\"radio\"\n class=\"radio-input\"\n [checked]=\"checked()\"\n [disabled]=\"disabled()\"\n [required]=\"required()\"\n [name]=\"name()\"\n [value]=\"value()\"\n [attr.aria-label]=\"computedAriaLabel()\"\n [attr.aria-required]=\"required() || null\"\n [attr.aria-invalid]=\"error() ? 'true' : null\"\n [attr.aria-checked]=\"checked()\"\n [attr.aria-describedby]=\"ariaDescribedBy()\"\n (change)=\"handleChange()\"\n (keydown)=\"handleKeydown($event)\"\n />\n <span \n class=\"radio-control\"\n [class.error]=\"!!error()\"\n [class.success]=\"!!success()\"\n >\n <span class=\"radio-dot\"></span>\n </span>\n <span class=\"radio-text\">\n @if (label()) {\n {{ label() }}\n } @else {\n <ng-content>Radio</ng-content>\n }\n </span>\n </label>\n\n @if (error()) {\n <div [id]=\"errorMessageId()\" class=\"radio-error\" role=\"alert\">\n {{ error() }}\n </div>\n }\n\n @if (success()) {\n <div [id]=\"successMessageId()\" class=\"radio-success\" role=\"status\">\n {{ success() }}\n </div>\n }\n</div>", styles: [".radio-container{display:inline-flex;flex-direction:column;gap:var(--spacing-xs)}.radio-label{display:inline-flex;align-items:center;gap:var(--spacing-sm);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"] }]
2882
- }], ctorParameters: () => [], propDecorators: { 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"] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }, { type: i0.Output, args: ["requiredChange"] }], 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 }] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", 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 }] }], radioText: [{ type: i0.ContentChild, args: ['.radio-text', { isSignal: true }] }], valueChange: [{ type: i0.Output, args: ["valueChange"] }], checkedChange: [{ type: i0.Output, args: ["checkedChange"] }] } });
2927
+ }], ctorParameters: () => [], propDecorators: { checkedInput: [{
2928
+ type: Input,
2929
+ args: ['checked']
2930
+ }], disabledInput: [{
2931
+ type: Input,
2932
+ args: ['disabled']
2933
+ }], 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 }] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", 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 }] }], radioText: [{ type: i0.ContentChild, args: ['.radio-text', { isSignal: true }] }], checkedChange: [{
2934
+ type: Output
2935
+ }], disabledChange: [{
2936
+ type: Output
2937
+ }], valueChange: [{ type: i0.Output, args: ["valueChange"] }] } });
2883
2938
 
2884
2939
  class PshSelectComponent {
2940
+ set valueInput(v) { this.value.set(v); }
2941
+ set disabledInput(v) { this.disabled.set(v); }
2885
2942
  constructor() {
2886
2943
  this.elementRef = inject(ElementRef);
2887
2944
  this.cdr = inject(ChangeDetectorRef);
2888
2945
  this.destroyRef = inject(DestroyRef);
2889
2946
  // Unique ID for the select
2890
2947
  this.selectId = `select-${Math.random().toString(36).substring(2, 11)}`;
2891
- // Model inputs
2892
- this.value = model(null, ...(ngDevMode ? [{ debugName: "value" }] : []));
2893
- this.disabled = model(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
2948
+ // CVA-managed state: plain signals + manual @Input/@Output to prevent
2949
+ // auto-emission during writeValue()/setDisabledState().
2950
+ // model() would auto-emit on .set(), breaking CVA semantics.
2951
+ this.value = signal(null, ...(ngDevMode ? [{ debugName: "value" }] : []));
2952
+ this.disabled = signal(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
2894
2953
  this.size = input('medium', ...(ngDevMode ? [{ debugName: "size" }] : []));
2895
2954
  this.searchable = input(false, ...(ngDevMode ? [{ debugName: "searchable" }] : []));
2896
2955
  this.multiple = input(false, ...(ngDevMode ? [{ debugName: "multiple" }] : []));
@@ -2923,8 +2982,10 @@ class PshSelectComponent {
2923
2982
  this.hasLabelContentSignal = signal(false, ...(ngDevMode ? [{ debugName: "hasLabelContentSignal" }] : []));
2924
2983
  this.initializedSignal = signal(false, ...(ngDevMode ? [{ debugName: "initializedSignal" }] : []));
2925
2984
  this.activeDescendantId = signal(null, ...(ngDevMode ? [{ debugName: "activeDescendantId" }] : []));
2926
- // Outputs
2927
- this.valueChange = output();
2985
+ // Outputs — valueChange/disabledChange use EventEmitter to decouple from signal writes.
2986
+ // output() auto-subscribes to model signals; EventEmitter does not.
2987
+ this.valueChange = new EventEmitter();
2988
+ this.disabledChange = new EventEmitter();
2928
2989
  this.opened = output();
2929
2990
  this.closed = output();
2930
2991
  this.scrollEnd = output();
@@ -3291,7 +3352,7 @@ class PshSelectComponent {
3291
3352
  }, []);
3292
3353
  }
3293
3354
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: PshSelectComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3294
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: PshSelectComponent, isStandalone: true, selector: "psh-select", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, searchable: { classPropertyName: "searchable", publicName: "searchable", isSignal: true, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, clearable: { classPropertyName: "clearable", publicName: "clearable", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, fullWidth: { classPropertyName: "fullWidth", publicName: "fullWidth", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, multiplePlaceholder: { classPropertyName: "multiplePlaceholder", publicName: "multiplePlaceholder", 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 }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, maxSelections: { classPropertyName: "maxSelections", publicName: "maxSelections", isSignal: true, isRequired: false, transformFunction: null }, minSelections: { classPropertyName: "minSelections", publicName: "minSelections", isSignal: true, isRequired: false, transformFunction: null }, compareWith: { classPropertyName: "compareWith", publicName: "compareWith", isSignal: true, isRequired: false, transformFunction: null }, searchConfig: { classPropertyName: "searchConfig", publicName: "searchConfig", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", disabled: "disabledChange", valueChange: "valueChange", opened: "opened", closed: "closed", scrollEnd: "scrollEnd", searched: "searched" }, host: { properties: { "class.full-width": "fullWidth()", "class.small": "size() === \"small\"", "class.large": "size() === \"large\"", "class.error": "!!error()", "class.success": "!!success()", "class.disabled": "disabled()", "class.loading": "loading()" } }, providers: [
3355
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: PshSelectComponent, isStandalone: true, selector: "psh-select", inputs: { valueInput: { classPropertyName: "valueInput", publicName: "value", isSignal: false, isRequired: false, transformFunction: null }, disabledInput: { classPropertyName: "disabledInput", publicName: "disabled", isSignal: false, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, searchable: { classPropertyName: "searchable", publicName: "searchable", isSignal: true, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, clearable: { classPropertyName: "clearable", publicName: "clearable", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, fullWidth: { classPropertyName: "fullWidth", publicName: "fullWidth", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, multiplePlaceholder: { classPropertyName: "multiplePlaceholder", publicName: "multiplePlaceholder", 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 }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, maxSelections: { classPropertyName: "maxSelections", publicName: "maxSelections", isSignal: true, isRequired: false, transformFunction: null }, minSelections: { classPropertyName: "minSelections", publicName: "minSelections", isSignal: true, isRequired: false, transformFunction: null }, compareWith: { classPropertyName: "compareWith", publicName: "compareWith", isSignal: true, isRequired: false, transformFunction: null }, searchConfig: { classPropertyName: "searchConfig", publicName: "searchConfig", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueChange: "valueChange", disabledChange: "disabledChange", opened: "opened", closed: "closed", scrollEnd: "scrollEnd", searched: "searched" }, host: { properties: { "class.full-width": "fullWidth()", "class.small": "size() === \"small\"", "class.large": "size() === \"large\"", "class.error": "!!error()", "class.success": "!!success()", "class.disabled": "disabled()", "class.loading": "loading()" } }, providers: [
3295
3356
  {
3296
3357
  provide: NG_VALUE_ACCESSOR,
3297
3358
  useExisting: PshSelectComponent,
@@ -3316,7 +3377,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
3316
3377
  '[class.disabled]': 'disabled()',
3317
3378
  '[class.loading]': 'loading()',
3318
3379
  }, template: "<div class=\"select-container\">\n <!-- Label slot -->\n @if (label() || hasLabelContent()) {\n <label class=\"select-label\" [for]=\"selectId\" (click)=\"focusSelect()\" [class.required]=\"!!required()\">\n <ng-content select=\"[select-label]\" />\n @if (!hasLabelContent()) {\n {{ label() }}\n }\n </label>\n }\n\n <div class=\"select-trigger-wrapper\">\n <div\n class=\"select-trigger\"\n [id]=\"selectId\"\n role=\"combobox\"\n aria-haspopup=\"listbox\"\n [attr.aria-controls]=\"selectId + '-listbox'\"\n [attr.aria-expanded]=\"isOpen()\"\n [attr.aria-disabled]=\"disabled()\"\n [attr.aria-busy]=\"loading() ? 'true' : null\"\n [attr.aria-required]=\"required() ? 'true' : 'false'\"\n [attr.aria-invalid]=\"!!error()\"\n [attr.aria-label]=\"computedAriaLabel()\"\n [attr.aria-describedby]=\"error() ? 'error-message' : success() ? 'success-message' : hint() ? 'hint-message' : null\"\n [attr.aria-activedescendant]=\"activeDescendant()\"\n [attr.tabindex]=\"disabled() || loading() ? -1 : 0\"\n (click)=\"toggle()\"\n (keydown)=\"handleKeyDown($event)\"\n >\n <div class=\"select-value\">\n <span [class.placeholder]=\"!hasValue()\">{{ selectedLabel() }}</span>\n </div>\n\n <div class=\"select-actions\">\n @if (clearable() && hasValue() && !loading()) {\n <button\n type=\"button\"\n class=\"select-clear\"\n (click)=\"clear($event)\"\n [attr.aria-label]=\"'Effacer la s\u00E9lection'\"\n [tabindex]=\"disabled() ? -1 : 0\"\n >\n <i class=\"ph ph-x\" aria-hidden=\"true\"></i>\n </button>\n }\n @if (loading()) {\n <div class=\"select-loader-trigger\" aria-hidden=\"true\"></div>\n } @else {\n <i\n class=\"ph ph-caret-down select-arrow\"\n [class.open]=\"isOpen()\"\n aria-hidden=\"true\"\n ></i>\n }\n </div>\n </div>\n\n @if (isOpen()) {\n <div\n class=\"select-dropdown\"\n role=\"listbox\"\n [id]=\"selectId + '-listbox'\"\n [attr.aria-multiselectable]=\"multiple()\"\n >\n @if (searchable()) {\n <div class=\"select-search\">\n <input\n type=\"text\"\n [placeholder]=\"searchConfig().placeholder\"\n [value]=\"searchTerm()\"\n (input)=\"onSearch($event)\"\n (click)=\"$event.stopPropagation()\"\n [attr.aria-label]=\"searchConfig().placeholder\"\n />\n </div>\n }\n\n <div class=\"select-options\" (scroll)=\"onScroll($event)\">\n @if (loading()) {\n <div class=\"select-loading\">\n <div class=\"select-loader\"></div>\n </div>\n } @else if (filteredOptions().length === 0) {\n <div class=\"select-no-results\">\n Aucun r\u00E9sultat\n </div>\n } @else {\n @for (option of filteredOptions(); track getOptionKey(option)) {\n @if (isOptionGroup(option)) {\n <div class=\"select-group\">\n <div class=\"select-group-label\">{{ option.label }}</div>\n @for (groupOption of option.options; track getOptionKey(groupOption)) {\n <div\n class=\"select-option\"\n role=\"option\"\n [class.selected]=\"isSelected(groupOption)\"\n [class.focused]=\"isFocused(groupOption)\"\n [class.disabled]=\"option.disabled || groupOption.disabled\"\n [attr.aria-selected]=\"isSelected(groupOption)\"\n [attr.aria-disabled]=\"(option.disabled || groupOption.disabled) || null\"\n [attr.id]=\"selectId + '-option-' + groupOption.value\"\n [attr.tabindex]=\"option.disabled || groupOption.disabled ? -1 : 0\"\n (click)=\"!option.disabled && select(groupOption)\"\n (keydown)=\"handleOptionKeyDown($event, groupOption)\"\n >\n @if (multiple()) {\n <div class=\"select-checkbox\">\n <i class=\"ph ph-check\" aria-hidden=\"true\"></i>\n </div>\n }\n @if (groupOption.icon) {\n <i class=\"ph ph-{{ groupOption.icon }}\" aria-hidden=\"true\"></i>\n }\n <div class=\"option-content\">\n <div class=\"option-label\">{{ groupOption.label }}</div>\n @if (groupOption.description) {\n <div class=\"option-description\">{{ groupOption.description }}</div>\n }\n </div>\n </div>\n }\n </div>\n } @else {\n <div\n class=\"select-option\"\n role=\"option\"\n [class.selected]=\"isSelected(option)\"\n [class.focused]=\"isFocused(option)\"\n [class.disabled]=\"option.disabled\"\n [attr.aria-selected]=\"isSelected(option)\"\n [attr.aria-disabled]=\"option.disabled || null\"\n [attr.id]=\"selectId + '-option-' + option.value\"\n [attr.tabindex]=\"option.disabled ? -1 : 0\"\n (click)=\"select(option)\"\n (keydown)=\"handleOptionKeyDown($event, option)\"\n >\n @if (multiple()) {\n <div class=\"select-checkbox\">\n <i class=\"ph ph-check\" aria-hidden=\"true\"></i>\n </div>\n }\n @if (option.icon) {\n <i class=\"ph ph-{{ option.icon }}\" aria-hidden=\"true\"></i>\n }\n <div class=\"option-content\">\n <div class=\"option-label\">{{ option.label }}</div>\n @if (option.description) {\n <div class=\"option-description\">{{ option.description }}</div>\n }\n </div>\n </div>\n }\n }\n }\n </div>\n </div>\n }\n </div>\n\n <!-- Error message slot -->\n @if (error()) {\n <div id=\"error-message\" class=\"select-error\" role=\"alert\">\n <ng-content select=\"[select-error]\">\n {{ error() }}\n </ng-content>\n </div>\n }\n\n <!-- Success message slot -->\n @if (success()) {\n <div id=\"success-message\" class=\"select-success\" role=\"status\">\n <ng-content select=\"[select-success]\">\n {{ success() }}\n </ng-content>\n </div>\n }\n\n <!-- Hint message slot -->\n @if (hint()) {\n <div id=\"hint-message\" class=\"select-hint\">\n <ng-content select=\"[select-hint]\">\n {{ hint() }}\n </ng-content>\n </div>\n }\n</div>", styles: [":host{display:block;width:100%;max-width:var(--select-max-width)}:host(.full-width){max-width:none}.select-container{width:100%}.select-trigger-wrapper{position:relative;width:100%}.select-label{display:block;color:var(--text-color);font-size:var(--font-size-sm);font-weight:500;margin-bottom:var(--spacing-xs);width:100%;cursor:pointer}.select-label.required:after{content:\"*\";color:var(--danger-color);margin-left:var(--spacing-xxs)}.select-trigger{display:flex;align-items:center;width:100%;min-width:12rem;height:var(--height-input-md);padding:0 var(--spacing-md);background:var(--surface-card);border:var(--border-width-1) solid var(--surface-border);border-radius:var(--border-radius);cursor:pointer;transition:all var(--animation-duration-normal) var(--animation-easing-default);outline:none}.select-trigger:hover{border-color:var(--primary-color)}:host(.disabled) .select-trigger:hover,:host(.loading) .select-trigger:hover{border-color:var(--surface-border)}.select-trigger:focus-visible{border-color:var(--primary-color);box-shadow:0 0 0 .125rem rgba(var(--primary-color-rgb),.2)}.select-value{display:flex;align-items:center;gap:var(--spacing-xs);flex:1;min-width:0;margin-right:var(--spacing-sm)}.select-value span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:var(--text-color)}.select-value span.placeholder{color:var(--text-color-secondary)}.select-actions{display:flex;align-items:center;gap:var(--spacing-sm);flex-shrink:0}.select-arrow{transition:transform var(--animation-duration-normal) var(--animation-easing-default);font-size:var(--icon-size-sm);color:var(--text-color-secondary);flex-shrink:0}.select-arrow.open{transform:rotate(180deg)}.select-clear{display:flex;align-items:center;justify-content:center;width:var(--size-5);height:var(--size-5);padding:0;background:transparent;border:none;border-radius:50%;color:var(--text-color-secondary);cursor:pointer;transition:all var(--animation-duration-normal) var(--animation-easing-default);flex-shrink:0}.select-clear:hover{background:rgba(var(--danger-color-rgb),.1);color:var(--danger-color)}.select-dropdown{position:absolute;top:calc(100% + var(--spacing-xs));left:0;width:100%;background:var(--surface-card);border:var(--border-width-1) solid var(--surface-border);border-radius:var(--border-radius);box-shadow:var(--shadow-lg);z-index:1000;animation:fadeIn var(--animation-duration-normal) var(--animation-easing-default)}.select-search{display:flex;align-items:center;gap:var(--spacing-sm);padding:var(--spacing-sm);border-bottom:var(--border-width-1) solid var(--surface-border)}.select-search input{width:100%;padding:var(--spacing-xs) var(--spacing-sm);border:var(--border-width-1) solid var(--surface-border);border-radius:var(--border-radius);background:var(--surface-ground)}.select-search input:focus{outline:none;border-color:var(--primary-color)}.select-options{max-height:var(--dropdown-max-height);overflow-y:auto}.select-group{padding:var(--spacing-xs) 0}.select-group-label{padding:var(--spacing-xs) var(--spacing-md);color:var(--text-color-secondary);font-weight:500;font-size:var(--font-size-sm)}.select-option{display:flex;align-items:center;gap:var(--spacing-md);padding:var(--spacing-sm) var(--spacing-md);cursor:pointer;transition:all var(--animation-duration-normal) var(--animation-easing-default)}.select-option:hover:not(.disabled){background:var(--surface-hover)}.select-option.focused:not(.disabled){background:var(--surface-hover);outline:2px solid var(--primary-color);outline-offset:-2px}.select-option.selected{background:rgba(var(--primary-color-rgb),.1);color:var(--primary-color)}.select-option.selected.focused{background:rgba(var(--primary-color-rgb),.15);outline:2px solid var(--primary-color);outline-offset:-2px}.select-option.disabled{opacity:.6;cursor:not-allowed}.select-option i{font-size:var(--icon-size-md);color:var(--text-color-secondary);flex-shrink:0}.select-option.selected i{color:var(--primary-color)}.option-content{flex:1;min-width:0}.option-label{color:inherit;font-size:var(--font-size-base)}.option-description{color:var(--text-color-secondary);font-size:var(--font-size-sm);margin-top:var(--spacing-xs)}.select-checkbox{display:flex;align-items:center;justify-content:center;width:var(--select-checkbox-size);height:var(--select-checkbox-size);border:var(--border-width-2) solid var(--surface-border);border-radius:var(--border-radius);transition:all var(--animation-duration-normal) var(--animation-easing-default)}.selected .select-checkbox{background:var(--primary-gradient);border-color:var(--primary-color);color:var(--primary-color-text)}.select-no-results{padding:var(--spacing-md);text-align:center;color:var(--text-color-secondary)}.select-loading{padding:var(--spacing-md);text-align:center}.select-loader{width:var(--size-6);height:var(--size-6);border:var(--border-width-2) solid var(--surface-border);border-top-color:var(--primary-color);border-radius:50%;animation:spin var(--animation-duration-slow) linear infinite;margin:0 auto}.select-loader-trigger{width:var(--icon-size-sm);height:var(--icon-size-sm);border:var(--border-width-2) solid var(--surface-border);border-top-color:var(--primary-color);border-radius:50%;animation:spin var(--animation-duration-slow) linear infinite;flex-shrink:0}.select-error{margin-top:var(--spacing-xs);color:var(--danger-color);font-size:var(--font-size-sm)}.select-success{margin-top:var(--spacing-xs);color:var(--success-color);font-size:var(--font-size-sm)}.select-hint{font-size:var(--font-size-sm);color:var(--text-color-secondary);margin-top:var(--spacing-xs)}.virtual-scroll{position:relative;overflow:hidden}:host(.disabled) .select-trigger{background:var(--surface-ground);cursor:not-allowed;opacity:.6}:host(.loading) .select-trigger{cursor:wait;opacity:.7}:host(.error) .select-trigger{border-color:var(--danger-color)}:host(.success) .select-trigger{border-color:var(--success-color)}:host(.small) .select-trigger{height:var(--height-input-sm);font-size:var(--font-size-sm);padding:0 var(--spacing-sm)}:host(.small) .select-arrow{font-size:var(--icon-size-xs)}:host(.small) .select-value{margin-right:var(--spacing-xs)}:host(.small) .select-actions{gap:var(--spacing-xs)}:host(.small) .select-dropdown{font-size:var(--font-size-sm)}:host(.small) .select-search{padding:var(--spacing-xs)}:host(.small) .select-search input{padding:var(--spacing-xxs) var(--spacing-xs);font-size:var(--font-size-sm)}:host(.small) .select-option{padding:var(--spacing-xs) var(--spacing-sm);gap:var(--spacing-sm)}:host(.small) .select-option i{font-size:var(--icon-size-sm)}:host(.small) .option-label{font-size:var(--font-size-sm)}:host(.small) .option-description{font-size:var(--font-size-xs);margin-top:var(--spacing-xxs)}:host(.small) .select-group-label{padding:var(--spacing-xxs) var(--spacing-sm);font-size:var(--font-size-xs)}:host(.small) .select-checkbox{width:calc(var(--select-checkbox-size) * .85);height:calc(var(--select-checkbox-size) * .85)}:host(.large) .select-trigger{height:var(--height-input-lg);font-size:var(--font-size-lg);padding:0 var(--spacing-lg)}:host(.large) .select-arrow{font-size:var(--icon-size-md)}:host(.large) .select-value{margin-right:var(--spacing-md)}:host(.large) .select-actions{gap:var(--spacing-md)}:host(.large) .select-dropdown{font-size:var(--font-size-lg)}:host(.large) .select-search{padding:var(--spacing-md)}:host(.large) .select-search input{padding:var(--spacing-sm) var(--spacing-md);font-size:var(--font-size-lg)}:host(.large) .select-option{padding:var(--spacing-md) var(--spacing-lg);gap:var(--spacing-lg)}:host(.large) .select-option i{font-size:var(--icon-size-lg)}:host(.large) .option-label{font-size:var(--font-size-lg)}:host(.large) .option-description{font-size:var(--font-size-base);margin-top:var(--spacing-xs)}:host(.large) .select-group-label{padding:var(--spacing-sm) var(--spacing-lg);font-size:var(--font-size-base)}:host(.large) .select-checkbox{width:calc(var(--select-checkbox-size) * 1.15);height:calc(var(--select-checkbox-size) * 1.15)}@media (max-width: 36em){:host{max-width:none}}@keyframes fadeIn{0%{opacity:0;transform:translateY(calc(-1 * var(--spacing-sm)))}to{opacity:1;transform:translateY(0)}}@keyframes spin{to{transform:rotate(360deg)}}\n"] }]
3319
- }], ctorParameters: () => [], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }, { type: i0.Output, args: ["disabledChange"] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], searchable: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchable", required: false }] }], multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], clearable: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearable", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], fullWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "fullWidth", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], multiplePlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiplePlaceholder", required: false }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], success: [{ type: i0.Input, args: [{ isSignal: true, alias: "success", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], maxSelections: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxSelections", required: false }] }], minSelections: [{ type: i0.Input, args: [{ isSignal: true, alias: "minSelections", required: false }] }], compareWith: [{ type: i0.Input, args: [{ isSignal: true, alias: "compareWith", required: false }] }], searchConfig: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchConfig", required: false }] }], valueChange: [{ type: i0.Output, args: ["valueChange"] }], opened: [{ type: i0.Output, args: ["opened"] }], closed: [{ type: i0.Output, args: ["closed"] }], scrollEnd: [{ type: i0.Output, args: ["scrollEnd"] }], searched: [{ type: i0.Output, args: ["searched"] }] } });
3380
+ }], ctorParameters: () => [], propDecorators: { valueInput: [{
3381
+ type: Input,
3382
+ args: ['value']
3383
+ }], disabledInput: [{
3384
+ type: Input,
3385
+ args: ['disabled']
3386
+ }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], searchable: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchable", required: false }] }], multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], clearable: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearable", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], fullWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "fullWidth", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], multiplePlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiplePlaceholder", required: false }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], success: [{ type: i0.Input, args: [{ isSignal: true, alias: "success", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], maxSelections: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxSelections", required: false }] }], minSelections: [{ type: i0.Input, args: [{ isSignal: true, alias: "minSelections", required: false }] }], compareWith: [{ type: i0.Input, args: [{ isSignal: true, alias: "compareWith", required: false }] }], searchConfig: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchConfig", required: false }] }], valueChange: [{
3387
+ type: Output
3388
+ }], disabledChange: [{
3389
+ type: Output
3390
+ }], opened: [{ type: i0.Output, args: ["opened"] }], closed: [{ type: i0.Output, args: ["closed"] }], scrollEnd: [{ type: i0.Output, args: ["scrollEnd"] }], searched: [{ type: i0.Output, args: ["searched"] }] } });
3320
3391
 
3321
3392
  const SIDEBAR_CONFIG = new InjectionToken('SIDEBAR_CONFIG', {
3322
3393
  factory: () => ({
@@ -3819,12 +3890,17 @@ class PshSwitchComponent {
3819
3890
  this.switchInput = viewChild('switchInput', ...(ngDevMode ? [{ debugName: "switchInput" }] : []));
3820
3891
  this.onChange = (value) => { };
3821
3892
  this.onTouched = () => { };
3822
- // Model inputs with defaults from config
3823
- this.checked = model(this.config.checked ?? false, ...(ngDevMode ? [{ debugName: "checked" }] : []));
3824
- this.disabled = model(this.config.disabled ?? false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
3825
- this.required = model(this.config.required ?? false, ...(ngDevMode ? [{ debugName: "required" }] : []));
3826
- this.size = model(this.config.size ?? 'medium', ...(ngDevMode ? [{ debugName: "size" }] : []));
3827
- this.labelPosition = model(this.config.labelPosition ?? 'right', ...(ngDevMode ? [{ debugName: "labelPosition" }] : []));
3893
+ // CVA-managed state: plain signals + manual @Input/@Output to prevent
3894
+ // auto-emission during writeValue()/setDisabledState().
3895
+ this.checked = signal(this.config.checked ?? false, ...(ngDevMode ? [{ debugName: "checked" }] : []));
3896
+ this.disabled = signal(this.config.disabled ?? false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
3897
+ // Outputs EventEmitter to decouple from signal writes.
3898
+ this.checkedChange = new EventEmitter();
3899
+ this.disabledChange = new EventEmitter();
3900
+ // Configuration inputs (not CVA-managed, not written internally)
3901
+ this.required = input(this.config.required ?? false, ...(ngDevMode ? [{ debugName: "required" }] : []));
3902
+ this.size = input(this.config.size ?? 'medium', ...(ngDevMode ? [{ debugName: "size" }] : []));
3903
+ this.labelPosition = input(this.config.labelPosition ?? 'right', ...(ngDevMode ? [{ debugName: "labelPosition" }] : []));
3828
3904
  // Regular inputs
3829
3905
  this.label = input('', ...(ngDevMode ? [{ debugName: "label" }] : []));
3830
3906
  this.error = input('', ...(ngDevMode ? [{ debugName: "error" }] : []));
@@ -3848,10 +3924,13 @@ class PshSwitchComponent {
3848
3924
  return ids.length > 0 ? ids.join(' ') : null;
3849
3925
  }, ...(ngDevMode ? [{ debugName: "describedBy" }] : []));
3850
3926
  }
3927
+ set checkedInput(v) { this.checked.set(v); }
3928
+ set disabledInput(v) { this.disabled.set(v); }
3851
3929
  toggle() {
3852
3930
  if (!this.disabled()) {
3853
3931
  this.checked.update(v => !v);
3854
3932
  this.onChange(this.checked());
3933
+ this.checkedChange.emit(this.checked());
3855
3934
  this.onTouched();
3856
3935
  }
3857
3936
  }
@@ -3882,7 +3961,7 @@ class PshSwitchComponent {
3882
3961
  }
3883
3962
  }
3884
3963
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: PshSwitchComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3885
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: PshSwitchComponent, isStandalone: true, selector: "psh-switch", inputs: { checked: { classPropertyName: "checked", publicName: "checked", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", 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 }, 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 }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { checked: "checkedChange", disabled: "disabledChange", required: "requiredChange", size: "sizeChange", labelPosition: "labelPositionChange" }, host: { properties: { "class.switch-wrapper": "true", "class.switch-disabled": "disabled()", "class.switch-error": "!!error()", "class.switch-success": "!!success()" } }, providers: [{
3964
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: PshSwitchComponent, isStandalone: true, selector: "psh-switch", 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 }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, labelPosition: { classPropertyName: "labelPosition", publicName: "labelPosition", 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 }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { checkedChange: "checkedChange", disabledChange: "disabledChange" }, host: { properties: { "class.switch-wrapper": "true", "class.switch-disabled": "disabled()", "class.switch-error": "!!error()", "class.switch-success": "!!success()" } }, providers: [{
3886
3965
  provide: NG_VALUE_ACCESSOR,
3887
3966
  useExisting: PshSwitchComponent,
3888
3967
  multi: true
@@ -3900,7 +3979,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
3900
3979
  '[class.switch-error]': '!!error()',
3901
3980
  '[class.switch-success]': '!!success()'
3902
3981
  }, template: "<div\n class=\"switch-container\"\n [class.small]=\"size() === 'small'\"\n [class.large]=\"size() === 'large'\"\n>\n <label class=\"switch-label\" [class]=\"labelPosition() === 'left' ? 'label-left' : 'label-right'\">\n <input\n #switchInput\n type=\"checkbox\"\n class=\"switch-input\"\n [id]=\"id()\"\n [name]=\"name() || id()\"\n [checked]=\"checked()\"\n [disabled]=\"disabled()\"\n [required]=\"required()\"\n [attr.aria-label]=\"computedAriaLabel()\"\n [attr.aria-required]=\"required()\"\n [attr.aria-invalid]=\"!!error()\"\n [attr.aria-checked]=\"checked()\"\n [attr.aria-describedby]=\"describedBy()\"\n (change)=\"toggle()\"\n />\n <span class=\"switch-control\">\n <span class=\"switch-thumb\"></span>\n </span>\n <span class=\"switch-text\">\n @if (label()) {\n {{ label() }}\n } @else {\n <ng-content>Switch</ng-content>\n }\n </span>\n </label>\n\n @if (error()) {\n <div [id]=\"errorId()!\" class=\"switch-error\" role=\"alert\" aria-live=\"polite\">\n {{ error() }}\n </div>\n }\n\n @if (success()) {\n <div [id]=\"successId()!\" class=\"switch-success\" role=\"status\" aria-live=\"polite\">\n {{ success() }}\n </div>\n }\n</div>", styles: [".switch-wrapper{display:inline-block}.switch-container{display:inline-flex;flex-direction:column;gap:var(--spacing-xs)}.switch-label{display:inline-flex;align-items:center;cursor:pointer;-webkit-user-select:none;user-select:none;color:var(--text-color);width:100%}.switch-label.label-right{flex-direction:row;gap:var(--spacing-sm)}.switch-label.label-left{flex-direction:row-reverse;justify-content:space-between;gap:var(--spacing-md)}.switch-input{position:absolute;opacity:0;width:0;height:0}.switch-control{position:relative;display:inline-block;width:var(--size-10);height:var(--size-5-5);background:var(--surface-border);border-radius:var(--radius-full);transition:background var(--animation-duration-fast) var(--animation-easing-default),border-color var(--animation-duration-fast) var(--animation-easing-default)}.switch-thumb{position:absolute;top:var(--size-0-5);left:var(--size-0-5);width:var(--size-4-5);height:var(--size-4-5);background:var(--surface-card);border-radius:var(--radius-full);transition:transform var(--animation-duration-fast) var(--animation-easing-default),left var(--animation-duration-fast) var(--animation-easing-default)}.switch-input:checked+.switch-control{background:var(--primary-color)}.switch-input:checked+.switch-control .switch-thumb{left:calc(100% - var(--size-4-5) - var(--size-0-5))}.switch-input:focus-visible+.switch-control{outline:var(--focus-outline-width) var(--focus-outline-style) var(--focus-outline-color);outline-offset:var(--focus-outline-offset);box-shadow:0 0 0 var(--focus-ring-width) var(--focus-ring-color)}.switch-wrapper.switch-disabled .switch-label{opacity:var(--opacity-disabled);cursor:not-allowed;pointer-events:none}.switch-wrapper.switch-error .switch-input:not(:checked)+.switch-control{background:color-mix(in srgb,var(--danger-color) 15%,var(--surface-border));border:var(--border-width-2) solid var(--danger-color)}.switch-wrapper.switch-error .switch-input:focus-visible+.switch-control{box-shadow:0 0 0 var(--focus-ring-width) var(--focus-ring-error)}.switch-wrapper.switch-success .switch-input:checked+.switch-control{background:var(--success-color)}.switch-wrapper.switch-success .switch-input:focus-visible+.switch-control{box-shadow:0 0 0 var(--focus-ring-width) var(--focus-ring-success)}.switch-error{font-size:var(--font-size-sm);color:var(--danger-color)}.switch-success{font-size:var(--font-size-sm);color:var(--success-color)}.switch-container.small .switch-control{width:var(--size-8-5);height:var(--size-5)}.switch-container.small .switch-thumb{width:var(--size-4);height:var(--size-4)}.switch-container.small .switch-input:checked+.switch-control .switch-thumb{left:calc(100% - var(--size-4) - var(--size-0-5))}.switch-container.large .switch-control{width:var(--size-12);height:var(--size-6-5)}.switch-container.large .switch-thumb{width:var(--size-5-5);height:var(--size-5-5)}.switch-container.large .switch-input:checked+.switch-control .switch-thumb{left:calc(100% - var(--size-5-5) - var(--size-0-5))}@media (prefers-reduced-motion: reduce){.switch-control,.switch-thumb{transition:none}}\n"] }]
3903
- }], propDecorators: { switchInput: [{ type: i0.ViewChild, args: ['switchInput', { 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"] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }, { type: i0.Output, args: ["requiredChange"] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }, { type: i0.Output, args: ["sizeChange"] }], labelPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "labelPosition", required: false }] }, { type: i0.Output, args: ["labelPositionChange"] }], 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 }] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }] } });
3982
+ }], propDecorators: { switchInput: [{ type: i0.ViewChild, args: ['switchInput', { isSignal: true }] }], checkedInput: [{
3983
+ type: Input,
3984
+ args: ['checked']
3985
+ }], disabledInput: [{
3986
+ type: Input,
3987
+ args: ['disabled']
3988
+ }], checkedChange: [{
3989
+ type: Output
3990
+ }], disabledChange: [{
3991
+ type: Output
3992
+ }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], labelPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "labelPosition", 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 }] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }] } });
3904
3993
 
3905
3994
  /**
3906
3995
  * Token d'injection pour la configuration globale de la barre d'onglets