ps-helix 4.0.0 → 4.0.1
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 +3 -3
- package/fesm2022/ps-helix.mjs +188 -452
- package/fesm2022/ps-helix.mjs.map +1 -1
- package/package.json +1 -1
- package/types/ps-helix.d.ts +61 -93
package/fesm2022/ps-helix.mjs
CHANGED
|
@@ -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,
|
|
2
|
+
import { input, output, computed, ChangeDetectionStrategy, Component, model, inject, ElementRef, signal, PLATFORM_ID, ViewEncapsulation, InjectionToken, viewChild, effect, ChangeDetectorRef, DestroyRef, Injectable, Renderer2, contentChild, EventEmitter, Output, Input, 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';
|
|
@@ -955,9 +955,9 @@ let checkboxIdCounter = 0;
|
|
|
955
955
|
class PshCheckboxComponent {
|
|
956
956
|
constructor() {
|
|
957
957
|
this.config = inject(CHECKBOX_CONFIG);
|
|
958
|
-
this.uniqueId = `checkbox-${++checkboxIdCounter}`;
|
|
959
958
|
this.checkboxInput = viewChild('checkboxInput', ...(ngDevMode ? [{ debugName: "checkboxInput" }] : []));
|
|
960
|
-
this.
|
|
959
|
+
this.uniqueId = `psh-cb-${++checkboxIdCounter}`;
|
|
960
|
+
this.onChange = (_) => { };
|
|
961
961
|
this.onTouched = () => { };
|
|
962
962
|
this.checked = model(this.config.checked ?? false, ...(ngDevMode ? [{ debugName: "checked" }] : []));
|
|
963
963
|
this.disabled = model(this.config.disabled ?? false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
|
|
@@ -965,46 +965,44 @@ class PshCheckboxComponent {
|
|
|
965
965
|
this.touched = model(false, ...(ngDevMode ? [{ debugName: "touched" }] : []));
|
|
966
966
|
this.required = input(this.config.required ?? false, ...(ngDevMode ? [{ debugName: "required" }] : []));
|
|
967
967
|
this.label = input(this.config.label ?? '', ...(ngDevMode ? [{ debugName: "label" }] : []));
|
|
968
|
-
this.error = input(
|
|
969
|
-
this.success = input(
|
|
970
|
-
this.ariaLabel = input(...(ngDevMode ? [
|
|
968
|
+
this.error = input(this.config.error, ...(ngDevMode ? [{ debugName: "error" }] : []));
|
|
969
|
+
this.success = input(this.config.success, ...(ngDevMode ? [{ debugName: "success" }] : []));
|
|
970
|
+
this.ariaLabel = input(this.config.ariaLabel, ...(ngDevMode ? [{ debugName: "ariaLabel" }] : []));
|
|
971
971
|
this.size = input(this.config.size ?? 'medium', ...(ngDevMode ? [{ debugName: "size" }] : []));
|
|
972
972
|
this.labelPosition = input(this.config.labelPosition ?? 'right', ...(ngDevMode ? [{ debugName: "labelPosition" }] : []));
|
|
973
973
|
this.ariaChecked = computed(() => this.indeterminate() ? 'mixed' : (this.checked() ? 'true' : 'false'), ...(ngDevMode ? [{ debugName: "ariaChecked" }] : []));
|
|
974
|
-
this.computedAriaLabel = computed(() => this.ariaLabel(), ...(ngDevMode ? [{ debugName: "computedAriaLabel" }] : []));
|
|
975
|
-
this.errorMessageId = computed(() => this.error() ? `${this.uniqueId}-error` : undefined, ...(ngDevMode ? [{ debugName: "errorMessageId" }] : []));
|
|
976
|
-
this.successMessageId = computed(() => this.success() ? `${this.uniqueId}-success` : undefined, ...(ngDevMode ? [{ debugName: "successMessageId" }] : []));
|
|
974
|
+
this.computedAriaLabel = computed(() => this.ariaLabel() || this.label() || undefined, ...(ngDevMode ? [{ debugName: "computedAriaLabel" }] : []));
|
|
977
975
|
this.ariaDescribedBy = computed(() => {
|
|
978
976
|
const ids = [];
|
|
979
|
-
if (this.
|
|
980
|
-
ids.push(this.
|
|
981
|
-
if (this.
|
|
982
|
-
ids.push(this.
|
|
977
|
+
if (this.error())
|
|
978
|
+
ids.push(`${this.uniqueId}-error`);
|
|
979
|
+
if (this.success())
|
|
980
|
+
ids.push(`${this.uniqueId}-success`);
|
|
983
981
|
return ids.length > 0 ? ids.join(' ') : undefined;
|
|
984
982
|
}, ...(ngDevMode ? [{ debugName: "ariaDescribedBy" }] : []));
|
|
985
|
-
this.state = computed(() =>
|
|
983
|
+
this.state = computed(() => {
|
|
984
|
+
if (this.disabled())
|
|
985
|
+
return 'disabled';
|
|
986
|
+
if (this.indeterminate())
|
|
987
|
+
return 'indeterminate';
|
|
988
|
+
if (this.error())
|
|
989
|
+
return 'error';
|
|
990
|
+
if (this.success())
|
|
991
|
+
return 'success';
|
|
992
|
+
return this.checked() ? 'checked' : 'unchecked';
|
|
993
|
+
}, ...(ngDevMode ? [{ debugName: "state" }] : []));
|
|
986
994
|
effect(() => {
|
|
987
995
|
if (!this.label() && !this.ariaLabel()) {
|
|
988
|
-
console.warn('[psh-checkbox]
|
|
996
|
+
console.warn('[psh-checkbox] Label manquant pour l\'accessibilité.');
|
|
989
997
|
}
|
|
990
|
-
}
|
|
991
|
-
}
|
|
992
|
-
getState() {
|
|
993
|
-
if (this.disabled())
|
|
994
|
-
return 'disabled';
|
|
995
|
-
if (this.indeterminate())
|
|
996
|
-
return 'indeterminate';
|
|
997
|
-
if (this.error())
|
|
998
|
-
return 'error';
|
|
999
|
-
if (this.success())
|
|
1000
|
-
return 'success';
|
|
1001
|
-
return this.checked() ? 'checked' : 'unchecked';
|
|
998
|
+
});
|
|
1002
999
|
}
|
|
1003
1000
|
toggle() {
|
|
1004
1001
|
if (!this.disabled()) {
|
|
1005
|
-
this.checked
|
|
1002
|
+
const newValue = !this.checked();
|
|
1003
|
+
this.checked.set(newValue);
|
|
1006
1004
|
this.indeterminate.set(false);
|
|
1007
|
-
this.onChange(
|
|
1005
|
+
this.onChange(newValue);
|
|
1008
1006
|
this.onTouched();
|
|
1009
1007
|
this.touched.set(true);
|
|
1010
1008
|
}
|
|
@@ -1012,49 +1010,26 @@ class PshCheckboxComponent {
|
|
|
1012
1010
|
handleKeydown(event) {
|
|
1013
1011
|
if (this.disabled())
|
|
1014
1012
|
return;
|
|
1015
|
-
if (event.key === ' ' || event.key === 'Spacebar') {
|
|
1016
|
-
event.preventDefault();
|
|
1017
|
-
this.toggle();
|
|
1018
|
-
}
|
|
1019
|
-
else if (event.key === 'Enter') {
|
|
1013
|
+
if (event.key === ' ' || event.key === 'Spacebar' || event.key === 'Enter') {
|
|
1020
1014
|
event.preventDefault();
|
|
1021
1015
|
this.toggle();
|
|
1022
1016
|
}
|
|
1023
1017
|
}
|
|
1024
|
-
writeValue(value) {
|
|
1025
|
-
|
|
1026
|
-
}
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
}
|
|
1030
|
-
registerOnTouched(fn) {
|
|
1031
|
-
this.onTouched = fn;
|
|
1032
|
-
}
|
|
1033
|
-
setDisabledState(isDisabled) {
|
|
1034
|
-
this.disabled.set(isDisabled);
|
|
1035
|
-
}
|
|
1036
|
-
focus() {
|
|
1037
|
-
const el = this.checkboxInput();
|
|
1038
|
-
if (el?.nativeElement) {
|
|
1039
|
-
el.nativeElement.focus();
|
|
1040
|
-
}
|
|
1041
|
-
}
|
|
1042
|
-
blur() {
|
|
1043
|
-
const el = this.checkboxInput();
|
|
1044
|
-
if (el?.nativeElement) {
|
|
1045
|
-
el.nativeElement.blur();
|
|
1046
|
-
}
|
|
1047
|
-
}
|
|
1018
|
+
writeValue(value) { this.checked.set(!!value); }
|
|
1019
|
+
registerOnChange(fn) { this.onChange = fn; }
|
|
1020
|
+
registerOnTouched(fn) { this.onTouched = fn; }
|
|
1021
|
+
setDisabledState(isDisabled) { this.disabled.set(isDisabled); }
|
|
1022
|
+
focus() { this.checkboxInput()?.nativeElement.focus(); }
|
|
1048
1023
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: PshCheckboxComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1049
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.5", 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 }, indeterminate: { classPropertyName: "indeterminate", publicName: "indeterminate", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", 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 }, 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", indeterminate: "indeterminateChange", touched: "touchedChange" }, 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: [{
|
|
1024
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.5", 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 }, indeterminate: { classPropertyName: "indeterminate", publicName: "indeterminate", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", 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 }, 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", indeterminate: "indeterminateChange", touched: "touchedChange" }, host: { properties: { "class.checkbox-disabled": "disabled()", "class.checkbox-error": "!!error()", "class.checkbox-success": "!!success()", "class.checkbox-small": "size() === \"small\"", "class.checkbox-large": "size() === \"large\"", "class.checkbox-checked": "checked() && !indeterminate()", "class.checkbox-indeterminate": "indeterminate()", "attr.data-state": "state()", "attr.aria-checked": "ariaChecked()" } }, providers: [{
|
|
1050
1025
|
provide: NG_VALUE_ACCESSOR,
|
|
1051
1026
|
useExisting: PshCheckboxComponent,
|
|
1052
1027
|
multi: true
|
|
1053
|
-
}], viewQueries: [{ propertyName: "checkboxInput", first: true, predicate: ["checkboxInput"], descendants: true, isSignal: true }], ngImport: i0, 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-
|
|
1028
|
+
}], viewQueries: [{ propertyName: "checkboxInput", first: true, predicate: ["checkboxInput"], descendants: true, isSignal: true }], ngImport: i0, 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-checked]=\"ariaChecked()\"\n [attr.aria-describedby]=\"ariaDescribedBy()\"\n (change)=\"toggle()\"\n (keydown)=\"handleKeydown($event)\"\n />\n \n <span class=\"checkbox-control\">\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\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]=\"uniqueId + '-error'\" class=\"checkbox-message error\" role=\"alert\">\n {{ error() }}\n </div>\n }\n @if (success()) {\n <div [id]=\"uniqueId + '-success'\" class=\"checkbox-message success\" role=\"status\">\n {{ success() }}\n </div>\n }\n</div>", styles: [":host{display:inline-flex;flex-direction:column;gap:.5rem}.checkbox-container{display:flex;flex-direction:column}.checkbox-label{display:inline-flex;align-items:center;gap:.75rem;cursor:pointer;-webkit-user-select:none;user-select:none;color:var(--text-color)}.checkbox-label.label-left{flex-direction:row-reverse;justify-content:space-between}.checkbox-input{position:absolute;opacity:0;width:0;height:0}.checkbox-control{display:flex;align-items:center;justify-content:center;width:1.25rem;height:1.25rem;border:.125rem solid var(--surface-border);border-radius:var(--border-radius);background:var(--surface-card);transition:all var(--animation-duration-fast) var(--animation-easing-default);color:#fff;position:relative;flex-shrink:0}:host.checkbox-checked .checkbox-control,:host.checkbox-indeterminate .checkbox-control{background:var(--primary-color);border-color:var(--primary-color)}.checkbox-input:focus-visible+.checkbox-control{outline:.125rem solid var(--focus-outline-color);outline-offset:.125rem}.checkbox-control i{font-size:.875rem;line-height:1}:host.checkbox-small .checkbox-control{width:1rem;height:1rem}:host.checkbox-large .checkbox-control{width:1.5rem;height:1.5rem}:host.checkbox-error .checkbox-control{border-color:var(--danger-color)}:host.checkbox-error.checkbox-checked .checkbox-control{background:var(--danger-color)}:host.checkbox-success .checkbox-control{border-color:var(--success-color)}:host.checkbox-success.checkbox-checked .checkbox-control{background:var(--success-color)}:host.checkbox-disabled{opacity:var(--opacity-disabled);cursor:not-allowed}:host.checkbox-disabled .checkbox-label{cursor:not-allowed}.checkbox-message{font-size:.875rem;margin-top:.125rem}.checkbox-message.error{color:var(--danger-color)}.checkbox-message.success{color:var(--success-color)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
1054
1029
|
}
|
|
1055
1030
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: PshCheckboxComponent, decorators: [{
|
|
1056
1031
|
type: Component,
|
|
1057
|
-
args: [{ selector: 'psh-checkbox', imports: [], changeDetection: ChangeDetectionStrategy.OnPush, providers: [{
|
|
1032
|
+
args: [{ selector: 'psh-checkbox', standalone: true, imports: [], changeDetection: ChangeDetectionStrategy.OnPush, providers: [{
|
|
1058
1033
|
provide: NG_VALUE_ACCESSOR,
|
|
1059
1034
|
useExisting: PshCheckboxComponent,
|
|
1060
1035
|
multi: true
|
|
@@ -1064,8 +1039,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImpor
|
|
|
1064
1039
|
'[class.checkbox-success]': '!!success()',
|
|
1065
1040
|
'[class.checkbox-small]': 'size() === "small"',
|
|
1066
1041
|
'[class.checkbox-large]': 'size() === "large"',
|
|
1067
|
-
'[
|
|
1068
|
-
|
|
1042
|
+
'[class.checkbox-checked]': 'checked() && !indeterminate()',
|
|
1043
|
+
'[class.checkbox-indeterminate]': 'indeterminate()',
|
|
1044
|
+
'[attr.data-state]': 'state()',
|
|
1045
|
+
'[attr.aria-checked]': 'ariaChecked()'
|
|
1046
|
+
}, 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-checked]=\"ariaChecked()\"\n [attr.aria-describedby]=\"ariaDescribedBy()\"\n (change)=\"toggle()\"\n (keydown)=\"handleKeydown($event)\"\n />\n \n <span class=\"checkbox-control\">\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\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]=\"uniqueId + '-error'\" class=\"checkbox-message error\" role=\"alert\">\n {{ error() }}\n </div>\n }\n @if (success()) {\n <div [id]=\"uniqueId + '-success'\" class=\"checkbox-message success\" role=\"status\">\n {{ success() }}\n </div>\n }\n</div>", styles: [":host{display:inline-flex;flex-direction:column;gap:.5rem}.checkbox-container{display:flex;flex-direction:column}.checkbox-label{display:inline-flex;align-items:center;gap:.75rem;cursor:pointer;-webkit-user-select:none;user-select:none;color:var(--text-color)}.checkbox-label.label-left{flex-direction:row-reverse;justify-content:space-between}.checkbox-input{position:absolute;opacity:0;width:0;height:0}.checkbox-control{display:flex;align-items:center;justify-content:center;width:1.25rem;height:1.25rem;border:.125rem solid var(--surface-border);border-radius:var(--border-radius);background:var(--surface-card);transition:all var(--animation-duration-fast) var(--animation-easing-default);color:#fff;position:relative;flex-shrink:0}:host.checkbox-checked .checkbox-control,:host.checkbox-indeterminate .checkbox-control{background:var(--primary-color);border-color:var(--primary-color)}.checkbox-input:focus-visible+.checkbox-control{outline:.125rem solid var(--focus-outline-color);outline-offset:.125rem}.checkbox-control i{font-size:.875rem;line-height:1}:host.checkbox-small .checkbox-control{width:1rem;height:1rem}:host.checkbox-large .checkbox-control{width:1.5rem;height:1.5rem}:host.checkbox-error .checkbox-control{border-color:var(--danger-color)}:host.checkbox-error.checkbox-checked .checkbox-control{background:var(--danger-color)}:host.checkbox-success .checkbox-control{border-color:var(--success-color)}:host.checkbox-success.checkbox-checked .checkbox-control{background:var(--success-color)}:host.checkbox-disabled{opacity:var(--opacity-disabled);cursor:not-allowed}:host.checkbox-disabled .checkbox-label{cursor:not-allowed}.checkbox-message{font-size:.875rem;margin-top:.125rem}.checkbox-message.error{color:var(--danger-color)}.checkbox-message.success{color:var(--success-color)}\n"] }]
|
|
1069
1047
|
}], ctorParameters: () => [], propDecorators: { checkboxInput: [{ type: i0.ViewChild, args: ['checkboxInput', { isSignal: true }] }], checked: [{ type: i0.Input, args: [{ isSignal: true, alias: "checked", required: false }] }, { type: i0.Output, args: ["checkedChange"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }, { type: i0.Output, args: ["disabledChange"] }], indeterminate: [{ type: i0.Input, args: [{ isSignal: true, alias: "indeterminate", required: false }] }, { type: i0.Output, args: ["indeterminateChange"] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }, { type: i0.Output, args: ["touchedChange"] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], success: [{ type: i0.Input, args: [{ isSignal: true, alias: "success", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], labelPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "labelPosition", required: false }] }] } });
|
|
1070
1048
|
|
|
1071
1049
|
class PshCollapseComponent {
|
|
@@ -1452,34 +1430,25 @@ class PshInputComponent {
|
|
|
1452
1430
|
}
|
|
1453
1431
|
return this.type();
|
|
1454
1432
|
}, ...(ngDevMode ? [{ debugName: "effectiveType" }] : []));
|
|
1455
|
-
this.computedAriaLabel = computed(() => {
|
|
1456
|
-
|
|
1457
|
-
}, ...(ngDevMode ? [{ debugName: "computedAriaLabel" }] : []));
|
|
1458
|
-
this.passwordToggleLabel = computed(() => {
|
|
1459
|
-
return this.passwordVisible() ? INPUT_LABELS.hidePassword : INPUT_LABELS.showPassword;
|
|
1460
|
-
}, ...(ngDevMode ? [{ debugName: "passwordToggleLabel" }] : []));
|
|
1433
|
+
this.computedAriaLabel = computed(() => this.ariaLabel() || this.label() || this.placeholder(), ...(ngDevMode ? [{ debugName: "computedAriaLabel" }] : []));
|
|
1434
|
+
this.passwordToggleLabel = computed(() => this.passwordVisible() ? INPUT_LABELS.hidePassword : INPUT_LABELS.showPassword, ...(ngDevMode ? [{ debugName: "passwordToggleLabel" }] : []));
|
|
1461
1435
|
this.state = computed(() => this.getState(), ...(ngDevMode ? [{ debugName: "state" }] : []));
|
|
1462
1436
|
this.onChange = (_) => { };
|
|
1463
1437
|
this.onTouched = () => { };
|
|
1464
1438
|
this.destroyRef.onDestroy(() => {
|
|
1465
|
-
if (this.blurTimeoutId
|
|
1466
|
-
clearTimeout(this.blurTimeoutId);
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
clearTimeout(this.debounceTimeoutId);
|
|
1470
|
-
}
|
|
1439
|
+
if (this.blurTimeoutId)
|
|
1440
|
+
window.clearTimeout(this.blurTimeoutId);
|
|
1441
|
+
if (this.debounceTimeoutId)
|
|
1442
|
+
window.clearTimeout(this.debounceTimeoutId);
|
|
1471
1443
|
});
|
|
1472
1444
|
}
|
|
1473
1445
|
writeValue(value) {
|
|
1474
|
-
|
|
1446
|
+
const safeValue = typeof value === 'string' ? value : '';
|
|
1447
|
+
this.value.set(safeValue);
|
|
1475
1448
|
this.cdr.markForCheck();
|
|
1476
1449
|
}
|
|
1477
|
-
registerOnChange(fn) {
|
|
1478
|
-
|
|
1479
|
-
}
|
|
1480
|
-
registerOnTouched(fn) {
|
|
1481
|
-
this.onTouched = fn;
|
|
1482
|
-
}
|
|
1450
|
+
registerOnChange(fn) { this.onChange = fn; }
|
|
1451
|
+
registerOnTouched(fn) { this.onTouched = fn; }
|
|
1483
1452
|
setDisabledState(isDisabled) {
|
|
1484
1453
|
this.disabled.set(isDisabled);
|
|
1485
1454
|
}
|
|
@@ -1494,8 +1463,9 @@ class PshInputComponent {
|
|
|
1494
1463
|
handleFocus() {
|
|
1495
1464
|
this.focusedSignal.set(true);
|
|
1496
1465
|
this.inputFocus.emit();
|
|
1497
|
-
|
|
1498
|
-
|
|
1466
|
+
const val = this.value();
|
|
1467
|
+
if (this.suggestions() && val.length >= this.autocompleteConfig().minLength) {
|
|
1468
|
+
this.updateSuggestions(val);
|
|
1499
1469
|
}
|
|
1500
1470
|
}
|
|
1501
1471
|
handleBlur() {
|
|
@@ -1503,9 +1473,8 @@ class PshInputComponent {
|
|
|
1503
1473
|
this.inputBlur.emit();
|
|
1504
1474
|
this.onTouched();
|
|
1505
1475
|
this.touched.set(true);
|
|
1506
|
-
if (this.blurTimeoutId
|
|
1507
|
-
clearTimeout(this.blurTimeoutId);
|
|
1508
|
-
}
|
|
1476
|
+
if (this.blurTimeoutId)
|
|
1477
|
+
window.clearTimeout(this.blurTimeoutId);
|
|
1509
1478
|
this.blurTimeoutId = window.setTimeout(() => {
|
|
1510
1479
|
this.suggestionsVisible.set(false);
|
|
1511
1480
|
this.focusedSuggestionIndex.set(-1);
|
|
@@ -1520,18 +1489,18 @@ class PshInputComponent {
|
|
|
1520
1489
|
switch (event.key) {
|
|
1521
1490
|
case 'ArrowDown':
|
|
1522
1491
|
event.preventDefault();
|
|
1523
|
-
this.focusedSuggestionIndex.update(i => i < suggestions.length - 1 ? i + 1 : 0);
|
|
1492
|
+
this.focusedSuggestionIndex.update(i => (i < suggestions.length - 1 ? i + 1 : 0));
|
|
1524
1493
|
break;
|
|
1525
1494
|
case 'ArrowUp':
|
|
1526
1495
|
event.preventDefault();
|
|
1527
|
-
this.focusedSuggestionIndex.update(i => i > 0 ? i - 1 : suggestions.length - 1);
|
|
1496
|
+
this.focusedSuggestionIndex.update(i => (i > 0 ? i - 1 : suggestions.length - 1));
|
|
1528
1497
|
break;
|
|
1529
1498
|
case 'Enter':
|
|
1530
|
-
event.preventDefault();
|
|
1531
1499
|
if (currentIndex >= 0 && currentIndex < suggestions.length) {
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1500
|
+
event.preventDefault();
|
|
1501
|
+
const selected = suggestions[currentIndex];
|
|
1502
|
+
if (selected !== undefined) {
|
|
1503
|
+
this.handleSuggestionClick(selected);
|
|
1535
1504
|
}
|
|
1536
1505
|
}
|
|
1537
1506
|
break;
|
|
@@ -1543,12 +1512,11 @@ class PshInputComponent {
|
|
|
1543
1512
|
}
|
|
1544
1513
|
}
|
|
1545
1514
|
handleSuggestionClick(suggestion) {
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
}
|
|
1515
|
+
this.value.set(suggestion);
|
|
1516
|
+
this.onChange(suggestion);
|
|
1517
|
+
this.suggestionSelect.emit(suggestion);
|
|
1518
|
+
this.suggestionsVisible.set(false);
|
|
1519
|
+
this.focusedSuggestionIndex.set(-1);
|
|
1552
1520
|
}
|
|
1553
1521
|
togglePasswordVisibility() {
|
|
1554
1522
|
this.passwordVisibleSignal.update(v => !v);
|
|
@@ -1558,62 +1526,68 @@ class PshInputComponent {
|
|
|
1558
1526
|
}
|
|
1559
1527
|
focus() {
|
|
1560
1528
|
const inputEl = this.elementRef.nativeElement.querySelector('input');
|
|
1561
|
-
|
|
1562
|
-
inputEl.focus();
|
|
1563
|
-
}
|
|
1529
|
+
inputEl?.focus();
|
|
1564
1530
|
}
|
|
1565
1531
|
focusSelect() {
|
|
1566
1532
|
this.focus();
|
|
1567
1533
|
}
|
|
1568
1534
|
debouncedUpdateSuggestions(value) {
|
|
1569
|
-
if (this.debounceTimeoutId
|
|
1570
|
-
clearTimeout(this.debounceTimeoutId);
|
|
1571
|
-
}
|
|
1572
|
-
const debounceTime = this.autocompleteConfig().debounceTime;
|
|
1535
|
+
if (this.debounceTimeoutId)
|
|
1536
|
+
window.clearTimeout(this.debounceTimeoutId);
|
|
1573
1537
|
this.debounceTimeoutId = window.setTimeout(() => {
|
|
1574
1538
|
this.updateSuggestions(value);
|
|
1575
1539
|
this.debounceTimeoutId = null;
|
|
1576
|
-
}, debounceTime);
|
|
1540
|
+
}, this.autocompleteConfig().debounceTime);
|
|
1577
1541
|
}
|
|
1578
1542
|
async updateSuggestions(value) {
|
|
1579
|
-
const
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
this.filteredSuggestionsSignal.set(results);
|
|
1585
|
-
this.suggestionsVisible.set(true);
|
|
1586
|
-
}
|
|
1543
|
+
const provider = this.suggestions();
|
|
1544
|
+
try {
|
|
1545
|
+
let results = [];
|
|
1546
|
+
if (typeof provider === 'function') {
|
|
1547
|
+
results = await provider(value);
|
|
1587
1548
|
}
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
this.filteredSuggestionsSignal.set([]);
|
|
1549
|
+
else if (Array.isArray(provider)) {
|
|
1550
|
+
results = provider.filter(s => s.toLowerCase().includes(value.toLowerCase()));
|
|
1591
1551
|
}
|
|
1552
|
+
this.filteredSuggestionsSignal.set(results);
|
|
1553
|
+
this.suggestionsVisible.set(results.length > 0);
|
|
1592
1554
|
}
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
this.filteredSuggestionsSignal.set(filtered);
|
|
1596
|
-
this.suggestionsVisible.set(true);
|
|
1555
|
+
catch (error) {
|
|
1556
|
+
this.filteredSuggestionsSignal.set([]);
|
|
1597
1557
|
}
|
|
1598
1558
|
}
|
|
1599
1559
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: PshInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1600
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.5", 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 }, touched: { classPropertyName: "touched", publicName: "touched", 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", touched: "touchedChange", inputFocus: "inputFocus", inputBlur: "inputBlur", suggestionSelect: "suggestionSelect" }, providers: [
|
|
1560
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.5", 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 }, touched: { classPropertyName: "touched", publicName: "touched", 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", touched: "touchedChange", inputFocus: "inputFocus", inputBlur: "inputBlur", suggestionSelect: "suggestionSelect" }, host: { properties: { "class.full-width": "fullWidth()", "class.small": "size() === \"small\"", "class.large": "size() === \"large\"", "class.error": "!!error()", "class.success": "!!success()", "class.disabled": "disabled()", "class.readonly": "readonly()", "class.loading": "loading()", "class.focused": "focused()", "class.has-start-icon": "!!iconStart()", "class.has-end-icon": "!!iconEnd() || type() === \"password\"", "class.outlined": "variant() === \"outlined\"", "class.filled": "variant() === \"filled\"" } }, providers: [
|
|
1601
1561
|
{
|
|
1602
1562
|
provide: NG_VALUE_ACCESSOR,
|
|
1603
|
-
useExisting:
|
|
1563
|
+
useExisting: PshInputComponent,
|
|
1604
1564
|
multi: true
|
|
1605
1565
|
}
|
|
1606
|
-
], ngImport: i0, template: "<div
|
|
1566
|
+
], ngImport: i0, template: "<div class=\"input-container\">\n @if (showLabel()) {\n <label \n class=\"input-label\" \n [for]=\"inputId\" \n (click)=\"focusSelect()\" \n [class.required]=\"required()\"\n >\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 @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 @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 @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: [":host{display:block;width:100%;max-width:18.75rem;transition:all var(--animation-duration-default) var(--animation-easing-default)}:host.full-width{max-width:none}.input-container{position:relative;width:100%}.input-label{display:block;color:var(--text-color);font-size:.875rem;font-weight:500;margin-bottom:.25rem;width:100%;cursor:pointer}.input-label.required:after{content:\"*\";color:var(--danger-color);margin-left:.125rem}.input-wrapper{position:relative;display:flex;align-items:center;width:100%}input{width:100%;height:2.5rem;padding:0 1rem;font-family:inherit;font-size:1rem;color:var(--text-color);background:var(--surface-0);border:.0625rem 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 .125rem var(--focus-ring-color)}:host.outlined input{background:transparent;border:.125rem solid var(--surface-border)}:host.filled input{background:var(--surface-ground);border:.0625rem solid transparent}:host.filled input:hover:not(:disabled):not(:focus){background:var(--surface-hover)}:host.filled input:focus{background:var(--surface-0)}:host.error input{border-color:var(--danger-color)}:host.error input:focus{box-shadow:0 0 0 .125rem var(--focus-ring-error)}:host.success input{border-color:var(--success-color)}:host.success input:focus{box-shadow:0 0 0 .125rem var(--focus-ring-success)}:host.disabled input{background:var(--surface-ground);cursor:not-allowed;opacity:var(--opacity-disabled)}:host.readonly input{background:var(--surface-ground);cursor:default}:host.small input{height:2rem;font-size:.875rem}:host.large input{height:3rem;font-size:1.125rem}:host.has-start-icon input{padding-left:2.75rem}:host.has-end-icon input{padding-right:2.75rem}.input-wrapper i{position:absolute;top:50%;transform:translateY(-50%);font-size:1.25rem;color:var(--text-color-secondary);pointer-events:none;z-index:2}.input-wrapper i:first-of-type{left:1rem}.input-wrapper i:last-of-type{right:1rem}.password-toggle{position:absolute;right:.5rem;top:50%;transform:translateY(-50%);background:transparent;border:none;color:var(--text-color-secondary);cursor:pointer;padding:.25rem;border-radius:var(--border-radius);display:flex;align-items:center;justify-content:center;transition:all .2s ease;z-index:3}.password-toggle:hover:not(:disabled){background:var(--surface-hover);color:var(--text-color)}.password-toggle i{position:static;transform:none;pointer-events:auto}.input-loader{position:absolute;right:1rem;top:50%;transform:translateY(-50%);z-index:3}.loader{width:1rem;height:1rem;border:.125rem 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:.0625rem solid var(--surface-border);border-radius:var(--border-radius);box-shadow:var(--shadow-lg);z-index:var(--z-index-dropdown);max-height:12.5rem;overflow-y:auto;margin-top:.25rem}.suggestion-item{padding:.5rem 1rem;cursor:pointer;color:var(--text-color)}.suggestion-item:hover,.suggestion-item.focused{background:var(--surface-hover);color:var(--primary-color)}.input-error,.input-success,.input-hint{font-size:.875rem;margin-top:.25rem}.input-error{color:var(--danger-color)}.input-success{color:var(--success-color)}.input-hint{color:var(--text-color-secondary)}@keyframes spin{to{transform:translateY(-50%) rotate(360deg)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
1607
1567
|
}
|
|
1608
1568
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: PshInputComponent, decorators: [{
|
|
1609
1569
|
type: Component,
|
|
1610
1570
|
args: [{ selector: 'psh-input', imports: [CommonModule], providers: [
|
|
1611
1571
|
{
|
|
1612
1572
|
provide: NG_VALUE_ACCESSOR,
|
|
1613
|
-
useExisting:
|
|
1573
|
+
useExisting: PshInputComponent,
|
|
1614
1574
|
multi: true
|
|
1615
1575
|
}
|
|
1616
|
-
], changeDetection: ChangeDetectionStrategy.OnPush,
|
|
1576
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, host: {
|
|
1577
|
+
'[class.full-width]': 'fullWidth()',
|
|
1578
|
+
'[class.small]': 'size() === "small"',
|
|
1579
|
+
'[class.large]': 'size() === "large"',
|
|
1580
|
+
'[class.error]': '!!error()',
|
|
1581
|
+
'[class.success]': '!!success()',
|
|
1582
|
+
'[class.disabled]': 'disabled()',
|
|
1583
|
+
'[class.readonly]': 'readonly()',
|
|
1584
|
+
'[class.loading]': 'loading()',
|
|
1585
|
+
'[class.focused]': 'focused()',
|
|
1586
|
+
'[class.has-start-icon]': '!!iconStart()',
|
|
1587
|
+
'[class.has-end-icon]': '!!iconEnd() || type() === "password"',
|
|
1588
|
+
'[class.outlined]': 'variant() === "outlined"',
|
|
1589
|
+
'[class.filled]': 'variant() === "filled"',
|
|
1590
|
+
}, template: "<div class=\"input-container\">\n @if (showLabel()) {\n <label \n class=\"input-label\" \n [for]=\"inputId\" \n (click)=\"focusSelect()\" \n [class.required]=\"required()\"\n >\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 @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 @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 @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: [":host{display:block;width:100%;max-width:18.75rem;transition:all var(--animation-duration-default) var(--animation-easing-default)}:host.full-width{max-width:none}.input-container{position:relative;width:100%}.input-label{display:block;color:var(--text-color);font-size:.875rem;font-weight:500;margin-bottom:.25rem;width:100%;cursor:pointer}.input-label.required:after{content:\"*\";color:var(--danger-color);margin-left:.125rem}.input-wrapper{position:relative;display:flex;align-items:center;width:100%}input{width:100%;height:2.5rem;padding:0 1rem;font-family:inherit;font-size:1rem;color:var(--text-color);background:var(--surface-0);border:.0625rem 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 .125rem var(--focus-ring-color)}:host.outlined input{background:transparent;border:.125rem solid var(--surface-border)}:host.filled input{background:var(--surface-ground);border:.0625rem solid transparent}:host.filled input:hover:not(:disabled):not(:focus){background:var(--surface-hover)}:host.filled input:focus{background:var(--surface-0)}:host.error input{border-color:var(--danger-color)}:host.error input:focus{box-shadow:0 0 0 .125rem var(--focus-ring-error)}:host.success input{border-color:var(--success-color)}:host.success input:focus{box-shadow:0 0 0 .125rem var(--focus-ring-success)}:host.disabled input{background:var(--surface-ground);cursor:not-allowed;opacity:var(--opacity-disabled)}:host.readonly input{background:var(--surface-ground);cursor:default}:host.small input{height:2rem;font-size:.875rem}:host.large input{height:3rem;font-size:1.125rem}:host.has-start-icon input{padding-left:2.75rem}:host.has-end-icon input{padding-right:2.75rem}.input-wrapper i{position:absolute;top:50%;transform:translateY(-50%);font-size:1.25rem;color:var(--text-color-secondary);pointer-events:none;z-index:2}.input-wrapper i:first-of-type{left:1rem}.input-wrapper i:last-of-type{right:1rem}.password-toggle{position:absolute;right:.5rem;top:50%;transform:translateY(-50%);background:transparent;border:none;color:var(--text-color-secondary);cursor:pointer;padding:.25rem;border-radius:var(--border-radius);display:flex;align-items:center;justify-content:center;transition:all .2s ease;z-index:3}.password-toggle:hover:not(:disabled){background:var(--surface-hover);color:var(--text-color)}.password-toggle i{position:static;transform:none;pointer-events:auto}.input-loader{position:absolute;right:1rem;top:50%;transform:translateY(-50%);z-index:3}.loader{width:1rem;height:1rem;border:.125rem 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:.0625rem solid var(--surface-border);border-radius:var(--border-radius);box-shadow:var(--shadow-lg);z-index:var(--z-index-dropdown);max-height:12.5rem;overflow-y:auto;margin-top:.25rem}.suggestion-item{padding:.5rem 1rem;cursor:pointer;color:var(--text-color)}.suggestion-item:hover,.suggestion-item.focused{background:var(--surface-hover);color:var(--primary-color)}.input-error,.input-success,.input-hint{font-size:.875rem;margin-top:.25rem}.input-error{color:var(--danger-color)}.input-success{color:var(--success-color)}.input-hint{color:var(--text-color-secondary)}@keyframes spin{to{transform:translateY(-50%) rotate(360deg)}}\n"] }]
|
|
1617
1591
|
}], 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"] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }, { type: i0.Output, args: ["touchedChange"] }], 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 }] }], inputFocus: [{ type: i0.Output, args: ["inputFocus"] }], inputBlur: [{ type: i0.Output, args: ["inputBlur"] }], suggestionSelect: [{ type: i0.Output, args: ["suggestionSelect"] }] } });
|
|
1618
1592
|
|
|
1619
1593
|
const TOOLTIP_CONFIG = new InjectionToken('TOOLTIP_CONFIG', {
|
|
@@ -2865,10 +2839,11 @@ class PshSelectComponent {
|
|
|
2865
2839
|
this.elementRef = inject(ElementRef);
|
|
2866
2840
|
this.cdr = inject(ChangeDetectorRef);
|
|
2867
2841
|
this.destroyRef = inject(DestroyRef);
|
|
2868
|
-
this.selectId = `
|
|
2842
|
+
this.selectId = `psh-sel-${Math.random().toString(36).substring(2, 11)}`;
|
|
2869
2843
|
this.value = model(null, ...(ngDevMode ? [{ debugName: "value" }] : []));
|
|
2870
2844
|
this.disabled = model(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
|
|
2871
2845
|
this.touched = model(false, ...(ngDevMode ? [{ debugName: "touched" }] : []));
|
|
2846
|
+
// Rétablissement de l'API complète pour la démo
|
|
2872
2847
|
this.size = input('medium', ...(ngDevMode ? [{ debugName: "size" }] : []));
|
|
2873
2848
|
this.searchable = input(false, ...(ngDevMode ? [{ debugName: "searchable" }] : []));
|
|
2874
2849
|
this.multiple = input(false, ...(ngDevMode ? [{ debugName: "multiple" }] : []));
|
|
@@ -2878,14 +2853,9 @@ class PshSelectComponent {
|
|
|
2878
2853
|
this.required = input(false, ...(ngDevMode ? [{ debugName: "required" }] : []));
|
|
2879
2854
|
this.options = input([], ...(ngDevMode ? [{ debugName: "options" }] : []));
|
|
2880
2855
|
this.label = input('', ...(ngDevMode ? [{ debugName: "label" }] : []));
|
|
2881
|
-
this.ariaLabel = input(null, ...(ngDevMode ? [{ debugName: "ariaLabel" }] : []));
|
|
2882
2856
|
this.placeholder = input('Sélectionner une option', ...(ngDevMode ? [{ debugName: "placeholder" }] : []));
|
|
2883
2857
|
this.multiplePlaceholder = input('Sélectionner des options', ...(ngDevMode ? [{ debugName: "multiplePlaceholder" }] : []));
|
|
2884
|
-
this.error = input(
|
|
2885
|
-
this.success = input('', ...(ngDevMode ? [{ debugName: "success" }] : []));
|
|
2886
|
-
this.hint = input('', ...(ngDevMode ? [{ debugName: "hint" }] : []));
|
|
2887
|
-
this.maxSelections = input(undefined, ...(ngDevMode ? [{ debugName: "maxSelections" }] : []));
|
|
2888
|
-
this.minSelections = input(undefined, ...(ngDevMode ? [{ debugName: "minSelections" }] : []));
|
|
2858
|
+
this.error = input(undefined, ...(ngDevMode ? [{ debugName: "error" }] : []));
|
|
2889
2859
|
this.compareWith = input((a, b) => a === b, ...(ngDevMode ? [{ debugName: "compareWith" }] : []));
|
|
2890
2860
|
this.searchConfig = input({
|
|
2891
2861
|
debounceTime: 300,
|
|
@@ -2894,27 +2864,26 @@ class PshSelectComponent {
|
|
|
2894
2864
|
}, ...(ngDevMode ? [{ debugName: "searchConfig" }] : []));
|
|
2895
2865
|
this.isOpenSignal = signal(false, ...(ngDevMode ? [{ debugName: "isOpenSignal" }] : []));
|
|
2896
2866
|
this.searchTermSignal = signal('', ...(ngDevMode ? [{ debugName: "searchTermSignal" }] : []));
|
|
2897
|
-
this.selectedLabelSignal = signal('', ...(ngDevMode ? [{ debugName: "selectedLabelSignal" }] : []));
|
|
2898
|
-
this.focusedOptionIndex = signal(-1, ...(ngDevMode ? [{ debugName: "focusedOptionIndex" }] : []));
|
|
2899
|
-
this.hasLabelContentSignal = signal(false, ...(ngDevMode ? [{ debugName: "hasLabelContentSignal" }] : []));
|
|
2900
2867
|
this.initializedSignal = signal(false, ...(ngDevMode ? [{ debugName: "initializedSignal" }] : []));
|
|
2901
|
-
this.activeDescendantId = signal(null, ...(ngDevMode ? [{ debugName: "activeDescendantId" }] : []));
|
|
2902
2868
|
this.opened = output();
|
|
2903
2869
|
this.closed = output();
|
|
2870
|
+
this.searched = output(); // Émet une string, pas un Event
|
|
2904
2871
|
this.scrollEnd = output();
|
|
2905
|
-
this.searched = output();
|
|
2906
2872
|
this.isOpen = computed(() => this.isOpenSignal(), ...(ngDevMode ? [{ debugName: "isOpen" }] : []));
|
|
2907
2873
|
this.searchTerm = computed(() => this.searchTermSignal(), ...(ngDevMode ? [{ debugName: "searchTerm" }] : []));
|
|
2908
|
-
this.
|
|
2909
|
-
this.activeDescendant = computed(() => this.activeDescendantId(), ...(ngDevMode ? [{ debugName: "activeDescendant" }] : []));
|
|
2910
|
-
this.computedAriaLabel = computed(() => {
|
|
2911
|
-
return this.ariaLabel() || this.label() || this.placeholder();
|
|
2912
|
-
}, ...(ngDevMode ? [{ debugName: "computedAriaLabel" }] : []));
|
|
2874
|
+
this.state = computed(() => this.disabled() ? 'disabled' : this.error() ? 'error' : 'default', ...(ngDevMode ? [{ debugName: "state" }] : []));
|
|
2913
2875
|
this.selectedLabel = computed(() => {
|
|
2914
|
-
|
|
2876
|
+
const currentValue = this.value();
|
|
2877
|
+
const currentOptions = this.flattenOptions(this.options());
|
|
2878
|
+
if (!this.initializedSignal() || (currentValue === null || currentValue === undefined)) {
|
|
2915
2879
|
return this.multiple() ? this.multiplePlaceholder() : this.placeholder();
|
|
2916
2880
|
}
|
|
2917
|
-
|
|
2881
|
+
if (this.multiple() && Array.isArray(currentValue)) {
|
|
2882
|
+
const selected = currentOptions.filter(opt => currentValue.some(v => this.compareWith()(v, opt.value)));
|
|
2883
|
+
return selected.length > 0 ? selected.map(o => o.label).join(', ') : this.multiplePlaceholder();
|
|
2884
|
+
}
|
|
2885
|
+
const selected = currentOptions.find(opt => this.compareWith()(opt.value, currentValue));
|
|
2886
|
+
return selected ? selected.label : this.placeholder();
|
|
2918
2887
|
}, ...(ngDevMode ? [{ debugName: "selectedLabel" }] : []));
|
|
2919
2888
|
this.filteredOptions = computed(() => {
|
|
2920
2889
|
const term = this.searchTermSignal().toLowerCase();
|
|
@@ -2923,349 +2892,115 @@ class PshSelectComponent {
|
|
|
2923
2892
|
return opts;
|
|
2924
2893
|
return opts.map(opt => {
|
|
2925
2894
|
if (this.isOptionGroup(opt)) {
|
|
2926
|
-
const
|
|
2927
|
-
|
|
2928
|
-
return filteredOptions.length > 0 ? { ...opt, options: filteredOptions } : null;
|
|
2895
|
+
const filtered = opt.options.filter(o => o.label.toLowerCase().includes(term));
|
|
2896
|
+
return filtered.length > 0 ? { ...opt, options: filtered } : null;
|
|
2929
2897
|
}
|
|
2930
|
-
return opt.label.toLowerCase().includes(term)
|
|
2931
|
-
opt.description?.toLowerCase().includes(term)
|
|
2932
|
-
? opt
|
|
2933
|
-
: null;
|
|
2898
|
+
return opt.label.toLowerCase().includes(term) ? opt : null;
|
|
2934
2899
|
}).filter((opt) => opt !== null);
|
|
2935
2900
|
}, ...(ngDevMode ? [{ debugName: "filteredOptions" }] : []));
|
|
2936
2901
|
this.onChange = (_) => { };
|
|
2937
2902
|
this.onTouched = () => { };
|
|
2938
2903
|
const clickHandler = (event) => {
|
|
2939
|
-
if (this.isOpen()) {
|
|
2940
|
-
|
|
2941
|
-
if (!this.elementRef.nativeElement.contains(target)) {
|
|
2942
|
-
this.close();
|
|
2943
|
-
}
|
|
2904
|
+
if (this.isOpen() && !this.elementRef.nativeElement.contains(event.target)) {
|
|
2905
|
+
this.close();
|
|
2944
2906
|
}
|
|
2945
2907
|
};
|
|
2946
2908
|
document.addEventListener('click', clickHandler);
|
|
2947
|
-
this.destroyRef.onDestroy(() =>
|
|
2948
|
-
document.removeEventListener('click', clickHandler);
|
|
2949
|
-
});
|
|
2909
|
+
this.destroyRef.onDestroy(() => document.removeEventListener('click', clickHandler));
|
|
2950
2910
|
}
|
|
2951
2911
|
ngAfterContentInit() {
|
|
2952
|
-
|
|
2953
|
-
const hasLabel = !!this.elementRef.nativeElement.querySelector('[select-label]');
|
|
2954
|
-
this.hasLabelContentSignal.set(hasLabel);
|
|
2955
|
-
this.initializedSignal.set(true);
|
|
2956
|
-
this.cdr.markForCheck();
|
|
2957
|
-
});
|
|
2958
|
-
}
|
|
2959
|
-
handleKeyDown(event) {
|
|
2960
|
-
if (this.disabled() || this.loading())
|
|
2961
|
-
return;
|
|
2962
|
-
switch (event.key) {
|
|
2963
|
-
case 'Enter':
|
|
2964
|
-
case ' ':
|
|
2965
|
-
event.preventDefault();
|
|
2966
|
-
if (!this.isOpen()) {
|
|
2967
|
-
this.toggle();
|
|
2968
|
-
}
|
|
2969
|
-
else if (this.focusedOptionIndex() >= 0) {
|
|
2970
|
-
const options = this.flattenOptions(this.filteredOptions());
|
|
2971
|
-
const option = options[this.focusedOptionIndex()];
|
|
2972
|
-
if (option)
|
|
2973
|
-
this.select(option);
|
|
2974
|
-
}
|
|
2975
|
-
break;
|
|
2976
|
-
case 'ArrowDown':
|
|
2977
|
-
event.preventDefault();
|
|
2978
|
-
if (!this.isOpen()) {
|
|
2979
|
-
this.toggle();
|
|
2980
|
-
}
|
|
2981
|
-
else {
|
|
2982
|
-
this.focusNextOption();
|
|
2983
|
-
}
|
|
2984
|
-
break;
|
|
2985
|
-
case 'ArrowUp':
|
|
2986
|
-
event.preventDefault();
|
|
2987
|
-
if (this.isOpen()) {
|
|
2988
|
-
this.focusPreviousOption();
|
|
2989
|
-
}
|
|
2990
|
-
break;
|
|
2991
|
-
case 'Escape':
|
|
2992
|
-
if (this.isOpen()) {
|
|
2993
|
-
event.preventDefault();
|
|
2994
|
-
this.close();
|
|
2995
|
-
}
|
|
2996
|
-
break;
|
|
2997
|
-
case 'Tab':
|
|
2998
|
-
if (this.isOpen()) {
|
|
2999
|
-
this.close();
|
|
3000
|
-
}
|
|
3001
|
-
break;
|
|
3002
|
-
case 'Home':
|
|
3003
|
-
if (this.isOpen()) {
|
|
3004
|
-
event.preventDefault();
|
|
3005
|
-
this.focusFirstOption();
|
|
3006
|
-
}
|
|
3007
|
-
break;
|
|
3008
|
-
case 'End':
|
|
3009
|
-
if (this.isOpen()) {
|
|
3010
|
-
event.preventDefault();
|
|
3011
|
-
this.focusLastOption();
|
|
3012
|
-
}
|
|
3013
|
-
break;
|
|
3014
|
-
}
|
|
3015
|
-
}
|
|
3016
|
-
handleOptionKeyDown(event, option) {
|
|
3017
|
-
switch (event.key) {
|
|
3018
|
-
case 'Enter':
|
|
3019
|
-
case ' ':
|
|
3020
|
-
event.preventDefault();
|
|
3021
|
-
this.select(option);
|
|
3022
|
-
break;
|
|
3023
|
-
case 'Escape':
|
|
3024
|
-
event.preventDefault();
|
|
3025
|
-
this.close();
|
|
3026
|
-
break;
|
|
3027
|
-
}
|
|
3028
|
-
}
|
|
3029
|
-
focusNextOption() {
|
|
3030
|
-
const options = this.flattenOptions(this.filteredOptions());
|
|
3031
|
-
if (options.length === 0)
|
|
3032
|
-
return;
|
|
3033
|
-
const currentIndex = this.focusedOptionIndex();
|
|
3034
|
-
const nextIndex = currentIndex < options.length - 1 ? currentIndex + 1 : 0;
|
|
3035
|
-
this.focusedOptionIndex.set(nextIndex);
|
|
3036
|
-
const nextOption = options[nextIndex];
|
|
3037
|
-
if (nextOption) {
|
|
3038
|
-
this.updateActiveDescendant(nextOption);
|
|
3039
|
-
}
|
|
3040
|
-
this.scrollOptionIntoView();
|
|
3041
|
-
}
|
|
3042
|
-
focusPreviousOption() {
|
|
3043
|
-
const options = this.flattenOptions(this.filteredOptions());
|
|
3044
|
-
if (options.length === 0)
|
|
3045
|
-
return;
|
|
3046
|
-
const currentIndex = this.focusedOptionIndex();
|
|
3047
|
-
const previousIndex = currentIndex > 0 ? currentIndex - 1 : options.length - 1;
|
|
3048
|
-
this.focusedOptionIndex.set(previousIndex);
|
|
3049
|
-
const prevOption = options[previousIndex];
|
|
3050
|
-
if (prevOption) {
|
|
3051
|
-
this.updateActiveDescendant(prevOption);
|
|
3052
|
-
}
|
|
3053
|
-
this.scrollOptionIntoView();
|
|
3054
|
-
}
|
|
3055
|
-
focusFirstOption() {
|
|
3056
|
-
const options = this.flattenOptions(this.filteredOptions());
|
|
3057
|
-
if (options.length === 0)
|
|
3058
|
-
return;
|
|
3059
|
-
this.focusedOptionIndex.set(0);
|
|
3060
|
-
const firstOption = options[0];
|
|
3061
|
-
if (firstOption) {
|
|
3062
|
-
this.updateActiveDescendant(firstOption);
|
|
3063
|
-
}
|
|
3064
|
-
this.scrollOptionIntoView();
|
|
3065
|
-
}
|
|
3066
|
-
focusLastOption() {
|
|
3067
|
-
const options = this.flattenOptions(this.filteredOptions());
|
|
3068
|
-
if (options.length === 0)
|
|
3069
|
-
return;
|
|
3070
|
-
const lastIndex = options.length - 1;
|
|
3071
|
-
this.focusedOptionIndex.set(lastIndex);
|
|
3072
|
-
const lastOption = options[lastIndex];
|
|
3073
|
-
if (lastOption) {
|
|
3074
|
-
this.updateActiveDescendant(lastOption);
|
|
3075
|
-
}
|
|
3076
|
-
this.scrollOptionIntoView();
|
|
3077
|
-
}
|
|
3078
|
-
scrollOptionIntoView() {
|
|
3079
|
-
requestAnimationFrame(() => {
|
|
3080
|
-
const activeId = this.activeDescendantId();
|
|
3081
|
-
if (activeId) {
|
|
3082
|
-
const option = this.elementRef.nativeElement.querySelector(`#${activeId}`);
|
|
3083
|
-
if (option) {
|
|
3084
|
-
option.scrollIntoView({ block: 'nearest' });
|
|
3085
|
-
}
|
|
3086
|
-
}
|
|
3087
|
-
});
|
|
3088
|
-
}
|
|
3089
|
-
updateActiveDescendant(option) {
|
|
3090
|
-
const optionId = `${this.selectId}-option-${String(option.value)}`;
|
|
3091
|
-
this.activeDescendantId.set(optionId);
|
|
3092
|
-
this.cdr.markForCheck();
|
|
3093
|
-
}
|
|
3094
|
-
isFocused(option) {
|
|
3095
|
-
const activeId = this.activeDescendantId();
|
|
3096
|
-
if (!activeId)
|
|
3097
|
-
return false;
|
|
3098
|
-
const optionId = `${this.selectId}-option-${String(option.value)}`;
|
|
3099
|
-
return activeId === optionId;
|
|
2912
|
+
this.initializedSignal.set(true);
|
|
3100
2913
|
}
|
|
3101
2914
|
writeValue(value) {
|
|
3102
|
-
this.initializedSignal.set(true);
|
|
3103
2915
|
this.value.set(value);
|
|
3104
|
-
this.
|
|
2916
|
+
this.initializedSignal.set(true);
|
|
3105
2917
|
this.cdr.markForCheck();
|
|
3106
2918
|
}
|
|
3107
|
-
registerOnChange(fn) {
|
|
3108
|
-
|
|
3109
|
-
}
|
|
3110
|
-
|
|
3111
|
-
this.
|
|
3112
|
-
|
|
3113
|
-
|
|
3114
|
-
this.
|
|
3115
|
-
}
|
|
3116
|
-
isOptionGroup(option) {
|
|
3117
|
-
return 'options' in option;
|
|
3118
|
-
}
|
|
3119
|
-
getOptionKey(option) {
|
|
3120
|
-
return this.isOptionGroup(option) ? `group-${option.label}` : `option-${String(option.value)}`;
|
|
3121
|
-
}
|
|
3122
|
-
hasValue() {
|
|
3123
|
-
const currentValue = this.value();
|
|
3124
|
-
if (this.multiple()) {
|
|
3125
|
-
return Array.isArray(currentValue) && currentValue.length > 0;
|
|
3126
|
-
}
|
|
3127
|
-
return currentValue !== null && currentValue !== undefined;
|
|
3128
|
-
}
|
|
3129
|
-
focus() {
|
|
3130
|
-
const trigger = this.elementRef.nativeElement.querySelector('.select-trigger');
|
|
3131
|
-
if (trigger) {
|
|
3132
|
-
trigger.focus();
|
|
3133
|
-
}
|
|
2919
|
+
registerOnChange(fn) { this.onChange = fn; }
|
|
2920
|
+
registerOnTouched(fn) { this.onTouched = fn; }
|
|
2921
|
+
setDisabledState(isDisabled) { this.disabled.set(isDisabled); }
|
|
2922
|
+
toggle() {
|
|
2923
|
+
if (this.disabled() || this.loading())
|
|
2924
|
+
return;
|
|
2925
|
+
this.isOpenSignal.update(v => !v);
|
|
2926
|
+
this.isOpen() ? this.opened.emit() : this.closed.emit();
|
|
3134
2927
|
}
|
|
3135
|
-
|
|
3136
|
-
this.
|
|
2928
|
+
close() {
|
|
2929
|
+
this.isOpenSignal.set(false);
|
|
2930
|
+
this.searchTermSignal.set('');
|
|
3137
2931
|
}
|
|
3138
2932
|
select(option) {
|
|
3139
|
-
if (
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
|
|
3143
|
-
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
if (index === -1) {
|
|
3147
|
-
const maxSelections = this.maxSelections();
|
|
3148
|
-
if (!maxSelections || values.length < maxSelections) {
|
|
3149
|
-
values.push(option.value);
|
|
3150
|
-
changed = true;
|
|
3151
|
-
}
|
|
3152
|
-
}
|
|
3153
|
-
else {
|
|
3154
|
-
const minSelections = this.minSelections();
|
|
3155
|
-
if (!minSelections || values.length > minSelections) {
|
|
3156
|
-
values.splice(index, 1);
|
|
3157
|
-
changed = true;
|
|
3158
|
-
}
|
|
3159
|
-
}
|
|
3160
|
-
if (changed) {
|
|
3161
|
-
this.value.set(values);
|
|
3162
|
-
this.onChange(values);
|
|
3163
|
-
this.updateSelectedLabel();
|
|
3164
|
-
}
|
|
3165
|
-
}
|
|
3166
|
-
else {
|
|
3167
|
-
this.value.set(option.value);
|
|
3168
|
-
this.onChange(option.value);
|
|
3169
|
-
this.updateSelectedLabel();
|
|
3170
|
-
this.close();
|
|
3171
|
-
}
|
|
3172
|
-
this.onTouched();
|
|
3173
|
-
this.touched.set(true);
|
|
3174
|
-
}
|
|
3175
|
-
}
|
|
3176
|
-
isSelected(option) {
|
|
3177
|
-
const currentValue = this.value();
|
|
3178
|
-
if (this.multiple() && Array.isArray(currentValue)) {
|
|
3179
|
-
return currentValue.some(v => this.compareWith()(v, option.value));
|
|
3180
|
-
}
|
|
3181
|
-
return currentValue !== null && this.compareWith()(currentValue, option.value);
|
|
3182
|
-
}
|
|
3183
|
-
toggle() {
|
|
3184
|
-
if (!this.disabled() && !this.loading()) {
|
|
3185
|
-
const newValue = !this.isOpenSignal();
|
|
3186
|
-
this.isOpenSignal.set(newValue);
|
|
3187
|
-
if (newValue) {
|
|
3188
|
-
this.opened.emit();
|
|
2933
|
+
if (this.disabled() || option.disabled)
|
|
2934
|
+
return;
|
|
2935
|
+
if (this.multiple()) {
|
|
2936
|
+
const current = Array.isArray(this.value()) ? [...this.value()] : [];
|
|
2937
|
+
const index = current.findIndex(v => this.compareWith()(v, option.value));
|
|
2938
|
+
if (index === -1) {
|
|
2939
|
+
current.push(option.value);
|
|
3189
2940
|
}
|
|
3190
2941
|
else {
|
|
3191
|
-
|
|
3192
|
-
this.closed.emit();
|
|
2942
|
+
current.splice(index, 1);
|
|
3193
2943
|
}
|
|
2944
|
+
this.value.set(current);
|
|
2945
|
+
this.onChange(current);
|
|
3194
2946
|
}
|
|
3195
|
-
|
|
3196
|
-
|
|
3197
|
-
|
|
3198
|
-
this.
|
|
3199
|
-
this.focusedOptionIndex.set(-1);
|
|
3200
|
-
this.activeDescendantId.set(null);
|
|
3201
|
-
this.searchTermSignal.set('');
|
|
3202
|
-
this.closed.emit();
|
|
2947
|
+
else {
|
|
2948
|
+
this.value.set(option.value);
|
|
2949
|
+
this.onChange(option.value);
|
|
2950
|
+
this.close();
|
|
3203
2951
|
}
|
|
2952
|
+
this.onTouched();
|
|
2953
|
+
this.touched.set(true);
|
|
3204
2954
|
}
|
|
3205
2955
|
clear(event) {
|
|
3206
2956
|
event.stopPropagation();
|
|
3207
|
-
|
|
3208
|
-
|
|
3209
|
-
this.value.set(newValue);
|
|
3210
|
-
this.onChange(newValue);
|
|
3211
|
-
this.updateSelectedLabel();
|
|
3212
|
-
this.onTouched();
|
|
3213
|
-
this.touched.set(true);
|
|
3214
|
-
}
|
|
2957
|
+
this.value.set(this.multiple() ? [] : null);
|
|
2958
|
+
this.onChange(this.value());
|
|
3215
2959
|
}
|
|
3216
2960
|
onSearch(event) {
|
|
3217
2961
|
const term = event.target.value;
|
|
3218
2962
|
this.searchTermSignal.set(term);
|
|
3219
|
-
|
|
3220
|
-
this.searched.emit(term);
|
|
3221
|
-
}
|
|
2963
|
+
this.searched.emit(term);
|
|
3222
2964
|
}
|
|
3223
2965
|
onScroll(event) {
|
|
3224
|
-
const
|
|
3225
|
-
if (
|
|
2966
|
+
const el = event.target;
|
|
2967
|
+
if (el.scrollHeight - el.scrollTop === el.clientHeight) {
|
|
3226
2968
|
this.scrollEnd.emit();
|
|
3227
2969
|
}
|
|
3228
2970
|
}
|
|
3229
|
-
|
|
3230
|
-
|
|
3231
|
-
|
|
3232
|
-
|
|
3233
|
-
|
|
3234
|
-
|
|
3235
|
-
|
|
3236
|
-
|
|
3237
|
-
|
|
3238
|
-
|
|
3239
|
-
this.selectedLabelSignal.set('');
|
|
3240
|
-
}
|
|
3241
|
-
}
|
|
3242
|
-
else {
|
|
3243
|
-
const selected = currentOptions.find(opt => currentValue !== null && this.compareWith()(opt.value, currentValue));
|
|
3244
|
-
if (selected) {
|
|
3245
|
-
this.selectedLabelSignal.set(selected.label);
|
|
3246
|
-
}
|
|
3247
|
-
else {
|
|
3248
|
-
this.selectedLabelSignal.set('');
|
|
3249
|
-
}
|
|
2971
|
+
isOptionGroup(item) {
|
|
2972
|
+
return 'options' in item;
|
|
2973
|
+
}
|
|
2974
|
+
getOptionKey(item) {
|
|
2975
|
+
return this.isOptionGroup(item) ? `g-${item.label}` : `o-${item.label}`;
|
|
2976
|
+
}
|
|
2977
|
+
isSelected(option) {
|
|
2978
|
+
const val = this.value();
|
|
2979
|
+
if (this.multiple() && Array.isArray(val)) {
|
|
2980
|
+
return val.some(v => this.compareWith()(v, option.value));
|
|
3250
2981
|
}
|
|
3251
|
-
this.
|
|
2982
|
+
return val !== null && this.compareWith()(val, option.value);
|
|
2983
|
+
}
|
|
2984
|
+
hasValue() {
|
|
2985
|
+
const val = this.value();
|
|
2986
|
+
if (this.multiple())
|
|
2987
|
+
return Array.isArray(val) && val.length > 0;
|
|
2988
|
+
return val !== null && val !== undefined;
|
|
3252
2989
|
}
|
|
3253
2990
|
flattenOptions(options) {
|
|
3254
|
-
return options.reduce((acc, opt) =>
|
|
3255
|
-
|
|
3256
|
-
|
|
3257
|
-
|
|
3258
|
-
return [...acc, opt];
|
|
3259
|
-
}, []);
|
|
2991
|
+
return options.reduce((acc, opt) => this.isOptionGroup(opt) ? [...acc, ...opt.options] : [...acc, opt], []);
|
|
2992
|
+
}
|
|
2993
|
+
focusSelect() {
|
|
2994
|
+
this.elementRef.nativeElement.querySelector('.select-trigger')?.focus();
|
|
3260
2995
|
}
|
|
3261
2996
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: PshSelectComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
3262
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.5", 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 }, touched: { classPropertyName: "touched", publicName: "touched", 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 },
|
|
2997
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.5", 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 }, touched: { classPropertyName: "touched", publicName: "touched", 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 }, 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 }, 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", touched: "touchedChange", opened: "opened", closed: "closed", searched: "searched", scrollEnd: "scrollEnd" }, host: { properties: { "class.select-full-width": "fullWidth()", "class.select-small": "size() === \"small\"", "class.select-large": "size() === \"large\"", "class.select-error": "!!error()", "class.select-disabled": "disabled()", "class.select-loading": "loading()", "attr.aria-expanded": "isOpen().toString()", "attr.data-state": "state()" } }, providers: [
|
|
3263
2998
|
{
|
|
3264
2999
|
provide: NG_VALUE_ACCESSOR,
|
|
3265
3000
|
useExisting: PshSelectComponent,
|
|
3266
3001
|
multi: true
|
|
3267
3002
|
}
|
|
3268
|
-
], ngImport: i0, 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"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
3003
|
+
], ngImport: i0, template: "<div class=\"select-container\">\n @if (label()) {\n <label class=\"select-label\" [attr.for]=\"selectId\" (click)=\"focusSelect()\">\n {{ label() }}\n @if (required()) { <span class=\"required-mark\">*</span> }\n </label>\n }\n\n <div class=\"select-trigger\" [id]=\"selectId\" (click)=\"toggle()\" tabindex=\"0\">\n <div class=\"select-value\">\n <span [class.placeholder]=\"!hasValue()\">\n {{ selectedLabel() }}\n </span>\n </div>\n \n <div class=\"select-actions\">\n @if (clearable() && hasValue() && !disabled()) {\n <button class=\"select-clear\" (click)=\"clear($event)\">\n <i class=\"ph ph-x\"></i>\n </button>\n }\n @if (loading()) {\n <div class=\"select-loader-trigger\"></div>\n } @else {\n <i class=\"ph ph-caret-down select-arrow\"></i>\n }\n </div>\n </div>\n\n @if (isOpen()) {\n <div class=\"select-dropdown\">\n @if (searchable()) {\n <div class=\"select-search\">\n <i class=\"ph ph-magnifying-glass select-search-icon\"></i>\n <input type=\"text\"\n [placeholder]=\"searchConfig().placeholder\"\n [value]=\"searchTerm()\"\n (input)=\"onSearch($event)\"\n (click)=\"$event.stopPropagation()\">\n </div>\n }\n <div class=\"select-options\" (scroll)=\"onScroll($event)\">\n @for (item of filteredOptions(); track getOptionKey(item)) {\n @if (isOptionGroup(item)) {\n <div class=\"select-group\">\n <div class=\"select-group-label\">{{ item.label }}</div>\n @for (opt of item.options; track opt.label) {\n <div class=\"select-option\" \n [class.selected]=\"isSelected(opt)\"\n (click)=\"select(opt)\">\n {{ opt.label }}\n </div>\n }\n </div>\n } @else {\n <div class=\"select-option\" \n [class.selected]=\"isSelected(item)\"\n (click)=\"select(item)\">\n {{ item.label }}\n </div>\n }\n } @empty {\n <div class=\"select-no-results\">Aucun r\u00E9sultat</div>\n }\n </div>\n </div>\n }\n</div>", styles: [":host{display:block;width:100%;max-width:18.75rem}:host.select-full-width{max-width:none}.select-container{position:relative;width:100%}.select-label{display:block;color:var(--text-color);font-size:.875rem;font-weight:500;margin-bottom:.25rem;cursor:pointer}.select-trigger{display:flex;align-items:center;justify-content:space-between;width:100%;height:2.5rem;padding:0 1rem;background:var(--surface-card);border:.0625rem solid var(--surface-border);border-radius:var(--border-radius);cursor:pointer;box-sizing:border-box}.select-trigger:focus{border-color:var(--primary-color);outline:none}.select-actions{display:flex;align-items:center;gap:.5rem}.select-clear{background:none;border:none;cursor:pointer;padding:0;color:var(--text-color-secondary);display:flex}.select-clear:hover{color:var(--danger-color)}.select-loader-trigger{width:1rem;height:1rem;border:2px solid var(--surface-border);border-top-color:var(--primary-color);border-radius:50%;animation:spin .8s linear infinite}.select-arrow{transition:transform .2s;font-size:1rem;color:var(--text-color-secondary)}:host[aria-expanded=true] .select-arrow{transform:rotate(180deg)}.select-dropdown{position:absolute;top:calc(100% + .25rem);left:0;right:0;z-index:1000;background:var(--surface-card);border:.0625rem solid var(--surface-border);border-radius:var(--border-radius);box-shadow:var(--shadow-lg)}.select-search{position:relative;padding:.5rem;border-bottom:.0625rem solid var(--surface-border)}.select-search-icon{position:absolute;left:1.25rem;top:50%;transform:translateY(-50%);color:var(--text-color-secondary);font-size:.875rem;pointer-events:none}.select-search input{width:100%;height:2rem;padding:0 .75rem 0 2rem;background:var(--surface-ground);border:.0625rem solid var(--surface-border);border-radius:var(--border-radius);color:var(--text-color);font-size:.875rem;outline:none;box-sizing:border-box;transition:border-color .15s}.select-search input::placeholder{color:var(--text-color-secondary)}.select-search input:focus{border-color:var(--primary-color)}.select-options{max-height:15rem;overflow-y:auto}.select-group-label{padding:.5rem 1rem;font-size:.75rem;font-weight:600;color:var(--text-color-secondary);background:var(--surface-ground)}.select-option{padding:.625rem 1rem;cursor:pointer}.select-option:hover{background:var(--surface-hover)}.select-option.selected{background:rgba(var(--primary-color-rgb),.1);color:var(--primary-color);font-weight:500}:host.select-small .select-trigger{height:2rem;font-size:.875rem}:host.select-large .select-trigger{height:3rem;font-size:1.125rem}@keyframes spin{to{transform:rotate(360deg)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
3269
3004
|
}
|
|
3270
3005
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: PshSelectComponent, decorators: [{
|
|
3271
3006
|
type: Component,
|
|
@@ -3276,15 +3011,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImpor
|
|
|
3276
3011
|
multi: true
|
|
3277
3012
|
}
|
|
3278
3013
|
], changeDetection: ChangeDetectionStrategy.OnPush, host: {
|
|
3279
|
-
'[class.full-width]': 'fullWidth()',
|
|
3280
|
-
'[class.small]': 'size() === "small"',
|
|
3281
|
-
'[class.large]': 'size() === "large"',
|
|
3282
|
-
'[class.error]': '!!error()',
|
|
3283
|
-
'[class.
|
|
3284
|
-
'[class.
|
|
3285
|
-
'[
|
|
3286
|
-
}, 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"] }]
|
|
3287
|
-
|
|
3014
|
+
'[class.select-full-width]': 'fullWidth()',
|
|
3015
|
+
'[class.select-small]': 'size() === "small"',
|
|
3016
|
+
'[class.select-large]': 'size() === "large"',
|
|
3017
|
+
'[class.select-error]': '!!error()',
|
|
3018
|
+
'[class.select-disabled]': 'disabled()',
|
|
3019
|
+
'[class.select-loading]': 'loading()',
|
|
3020
|
+
'[attr.aria-expanded]': 'isOpen().toString()',
|
|
3021
|
+
'[attr.data-state]': 'state()'
|
|
3022
|
+
}, template: "<div class=\"select-container\">\n @if (label()) {\n <label class=\"select-label\" [attr.for]=\"selectId\" (click)=\"focusSelect()\">\n {{ label() }}\n @if (required()) { <span class=\"required-mark\">*</span> }\n </label>\n }\n\n <div class=\"select-trigger\" [id]=\"selectId\" (click)=\"toggle()\" tabindex=\"0\">\n <div class=\"select-value\">\n <span [class.placeholder]=\"!hasValue()\">\n {{ selectedLabel() }}\n </span>\n </div>\n \n <div class=\"select-actions\">\n @if (clearable() && hasValue() && !disabled()) {\n <button class=\"select-clear\" (click)=\"clear($event)\">\n <i class=\"ph ph-x\"></i>\n </button>\n }\n @if (loading()) {\n <div class=\"select-loader-trigger\"></div>\n } @else {\n <i class=\"ph ph-caret-down select-arrow\"></i>\n }\n </div>\n </div>\n\n @if (isOpen()) {\n <div class=\"select-dropdown\">\n @if (searchable()) {\n <div class=\"select-search\">\n <i class=\"ph ph-magnifying-glass select-search-icon\"></i>\n <input type=\"text\"\n [placeholder]=\"searchConfig().placeholder\"\n [value]=\"searchTerm()\"\n (input)=\"onSearch($event)\"\n (click)=\"$event.stopPropagation()\">\n </div>\n }\n <div class=\"select-options\" (scroll)=\"onScroll($event)\">\n @for (item of filteredOptions(); track getOptionKey(item)) {\n @if (isOptionGroup(item)) {\n <div class=\"select-group\">\n <div class=\"select-group-label\">{{ item.label }}</div>\n @for (opt of item.options; track opt.label) {\n <div class=\"select-option\" \n [class.selected]=\"isSelected(opt)\"\n (click)=\"select(opt)\">\n {{ opt.label }}\n </div>\n }\n </div>\n } @else {\n <div class=\"select-option\" \n [class.selected]=\"isSelected(item)\"\n (click)=\"select(item)\">\n {{ item.label }}\n </div>\n }\n } @empty {\n <div class=\"select-no-results\">Aucun r\u00E9sultat</div>\n }\n </div>\n </div>\n }\n</div>", styles: [":host{display:block;width:100%;max-width:18.75rem}:host.select-full-width{max-width:none}.select-container{position:relative;width:100%}.select-label{display:block;color:var(--text-color);font-size:.875rem;font-weight:500;margin-bottom:.25rem;cursor:pointer}.select-trigger{display:flex;align-items:center;justify-content:space-between;width:100%;height:2.5rem;padding:0 1rem;background:var(--surface-card);border:.0625rem solid var(--surface-border);border-radius:var(--border-radius);cursor:pointer;box-sizing:border-box}.select-trigger:focus{border-color:var(--primary-color);outline:none}.select-actions{display:flex;align-items:center;gap:.5rem}.select-clear{background:none;border:none;cursor:pointer;padding:0;color:var(--text-color-secondary);display:flex}.select-clear:hover{color:var(--danger-color)}.select-loader-trigger{width:1rem;height:1rem;border:2px solid var(--surface-border);border-top-color:var(--primary-color);border-radius:50%;animation:spin .8s linear infinite}.select-arrow{transition:transform .2s;font-size:1rem;color:var(--text-color-secondary)}:host[aria-expanded=true] .select-arrow{transform:rotate(180deg)}.select-dropdown{position:absolute;top:calc(100% + .25rem);left:0;right:0;z-index:1000;background:var(--surface-card);border:.0625rem solid var(--surface-border);border-radius:var(--border-radius);box-shadow:var(--shadow-lg)}.select-search{position:relative;padding:.5rem;border-bottom:.0625rem solid var(--surface-border)}.select-search-icon{position:absolute;left:1.25rem;top:50%;transform:translateY(-50%);color:var(--text-color-secondary);font-size:.875rem;pointer-events:none}.select-search input{width:100%;height:2rem;padding:0 .75rem 0 2rem;background:var(--surface-ground);border:.0625rem solid var(--surface-border);border-radius:var(--border-radius);color:var(--text-color);font-size:.875rem;outline:none;box-sizing:border-box;transition:border-color .15s}.select-search input::placeholder{color:var(--text-color-secondary)}.select-search input:focus{border-color:var(--primary-color)}.select-options{max-height:15rem;overflow-y:auto}.select-group-label{padding:.5rem 1rem;font-size:.75rem;font-weight:600;color:var(--text-color-secondary);background:var(--surface-ground)}.select-option{padding:.625rem 1rem;cursor:pointer}.select-option:hover{background:var(--surface-hover)}.select-option.selected{background:rgba(var(--primary-color-rgb),.1);color:var(--primary-color);font-weight:500}:host.select-small .select-trigger{height:2rem;font-size:.875rem}:host.select-large .select-trigger{height:3rem;font-size:1.125rem}@keyframes spin{to{transform:rotate(360deg)}}\n"] }]
|
|
3023
|
+
}], 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"] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }, { type: i0.Output, args: ["touchedChange"] }], 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 }] }], 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 }] }], compareWith: [{ type: i0.Input, args: [{ isSignal: true, alias: "compareWith", required: false }] }], searchConfig: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchConfig", required: false }] }], opened: [{ type: i0.Output, args: ["opened"] }], closed: [{ type: i0.Output, args: ["closed"] }], searched: [{ type: i0.Output, args: ["searched"] }], scrollEnd: [{ type: i0.Output, args: ["scrollEnd"] }] } });
|
|
3288
3024
|
|
|
3289
3025
|
const SIDEBAR_CONFIG = new InjectionToken('SIDEBAR_CONFIG', {
|
|
3290
3026
|
factory: () => ({
|