@kksdev/ds-angular 1.4.0 → 1.6.0
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/fesm2022/kksdev-ds-angular.mjs +2735 -3
- package/fesm2022/kksdev-ds-angular.mjs.map +1 -1
- package/index.d.ts +926 -4
- package/package.json +2 -2
- package/src/styles/themes/_dark.scss +208 -0
- package/src/styles/themes/_light.scss +208 -0
- package/src/styles/tokens/_primitives.scss +1 -0
- package/src/styles/tokens/_semantic.scss +275 -0
- package/src/styles/tokens/_tokens.scss +229 -0
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { input, Component, output, HostBinding, model, signal, computed, forwardRef, effect, ElementRef, ViewChildren, ViewChild, EventEmitter, inject, HostListener, ContentChild, Output, Directive, DestroyRef, Injectable, ChangeDetectionStrategy, viewChild } from '@angular/core';
|
|
2
|
+
import { input, Component, output, HostBinding, model, signal, computed, forwardRef, effect, ElementRef, ViewChildren, ViewChild, EventEmitter, inject, HostListener, ContentChild, Output, Directive, DestroyRef, Injectable, ChangeDetectionStrategy, viewChild, ViewEncapsulation } from '@angular/core';
|
|
3
3
|
import * as i1 from '@angular/common';
|
|
4
4
|
import { CommonModule, DOCUMENT, NgClass } from '@angular/common';
|
|
5
5
|
import * as i1$1 from '@fortawesome/angular-fontawesome';
|
|
6
6
|
import { FaIconComponent, FontAwesomeModule } from '@fortawesome/angular-fontawesome';
|
|
7
7
|
import * as i1$4 from '@angular/forms';
|
|
8
8
|
import { FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';
|
|
9
|
-
import { faInfoCircle, faTimesCircle, faExclamationTriangle, faCheckCircle, faTimes, faEye, faEyeSlash, faClose, faCircleInfo, faCircleXmark, faCircleExclamation, faCircleCheck, faChevronDown, faChevronLeft, faChevronRight, faAnglesLeft, faAnglesRight, faCheck, faSearch, faXmark, faSpinner, faCalendar, faCloudArrowUp, faFile, faFileImage, faFilePdf, faFileWord, faFileExcel, faInbox, faStar, faStarHalfStroke, faClock, faChevronUp, faFolder, faFolderOpen } from '@fortawesome/free-solid-svg-icons';
|
|
9
|
+
import { faInfoCircle, faTimesCircle, faExclamationTriangle, faCheckCircle, faTimes, faEye, faEyeSlash, faClose, faCircleInfo, faCircleXmark, faCircleExclamation, faCircleCheck, faChevronDown, faChevronLeft, faChevronRight, faAnglesLeft, faAnglesRight, faCheck, faSearch, faXmark, faSpinner, faCalendar, faCloudArrowUp, faFile, faFileImage, faFilePdf, faFileWord, faFileExcel, faInbox, faStar, faStarHalfStroke, faClock, faChevronUp, faFolder, faFolderOpen, faCircle, faCircleHalfStroke, faTriangleExclamation, faMinus, faPlus, faEyeDropper } from '@fortawesome/free-solid-svg-icons';
|
|
10
10
|
import * as i1$2 from '@angular/router';
|
|
11
11
|
import { RouterModule } from '@angular/router';
|
|
12
12
|
import * as i1$3 from '@angular/cdk/overlay';
|
|
@@ -10163,6 +10163,2738 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
|
|
|
10163
10163
|
args: [{ selector: 'ds-tree', standalone: true, imports: [CommonModule, DsTreeNodeComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div [class]=\"containerClasses()\" role=\"tree\">\n @if (processedData().length === 0) {\n <div class=\"ds-tree__empty\">\n <p>No data available</p>\n </div>\n } @else {\n @for (node of processedData(); track node.id) {\n <ds-tree-node\n [node]=\"node\"\n [level]=\"0\"\n [selectable]=\"selectable()\"\n [checkable]=\"checkable()\"\n [showIcon]=\"showIcon()\"\n [selectedNodeId]=\"selectedNodeId()\"\n [expandedNodeIds]=\"expandedNodeIds()\"\n [checkedNodeIds]=\"checkedNodeIds()\"\n [getIndeterminateState]=\"getIndeterminateState.bind(this)\"\n (nodeClick)=\"onNodeClick($event)\"\n (nodeToggle)=\"onNodeToggle($event)\"\n (nodeCheck)=\"onNodeCheck($event.node, $event.checked)\">\n </ds-tree-node>\n }\n }\n</div>\n", styles: [".ds-tree{display:block;width:100%;background-color:var(--tree-bg, var(--white));border:1px solid var(--tree-border, var(--gray-300));border-radius:var(--radius-2);padding:var(--space-2);max-height:400px;overflow-y:auto}.ds-tree__empty{display:flex;align-items:center;justify-content:center;padding:var(--space-8);color:var(--text-muted, var(--gray-500));font-size:var(--font-size-sm)}.ds-tree--sm{font-size:var(--font-size-sm);padding:var(--space-1)}.ds-tree--lg{font-size:var(--font-size-lg);padding:var(--space-3)}.ds-tree::-webkit-scrollbar{width:8px}.ds-tree::-webkit-scrollbar-track{background:var(--gray-100);border-radius:var(--radius-1)}.ds-tree::-webkit-scrollbar-thumb{background:var(--gray-400);border-radius:var(--radius-1)}.ds-tree::-webkit-scrollbar-thumb:hover{background:var(--gray-500)}\n"] }]
|
|
10164
10164
|
}], ctorParameters: () => [], propDecorators: { data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], selectable: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectable", required: false }] }], checkable: [{ type: i0.Input, args: [{ isSignal: true, alias: "checkable", required: false }] }], expandAll: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandAll", required: false }] }], showIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "showIcon", required: false }] }], showLine: [{ type: i0.Input, args: [{ isSignal: true, alias: "showLine", required: false }] }], draggable: [{ type: i0.Input, args: [{ isSignal: true, alias: "draggable", required: false }] }], virtualScroll: [{ type: i0.Input, args: [{ isSignal: true, alias: "virtualScroll", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], loadChildren: [{ type: i0.Input, args: [{ isSignal: true, alias: "loadChildren", required: false }] }], nodeSelect: [{ type: i0.Output, args: ["nodeSelect"] }], nodeExpand: [{ type: i0.Output, args: ["nodeExpand"] }], nodeCheck: [{ type: i0.Output, args: ["nodeCheck"] }] } });
|
|
10165
10165
|
|
|
10166
|
+
/**
|
|
10167
|
+
* # DsPasswordStrength
|
|
10168
|
+
*
|
|
10169
|
+
* Composant indicateur de force de mot de passe avec affichage visuel
|
|
10170
|
+
* (barres de progression) et optionnel des critères de validation.
|
|
10171
|
+
*
|
|
10172
|
+
* ## Usage
|
|
10173
|
+
*
|
|
10174
|
+
* ```html
|
|
10175
|
+
* <ds-password-strength
|
|
10176
|
+
* [password]="userPassword"
|
|
10177
|
+
* [minLength]="8"
|
|
10178
|
+
* [showLabel]="true"
|
|
10179
|
+
* [showCriteria]="true"
|
|
10180
|
+
* (strengthChange)="handleStrengthChange($event)" />
|
|
10181
|
+
* ```
|
|
10182
|
+
*
|
|
10183
|
+
* ## Calcul de la force
|
|
10184
|
+
*
|
|
10185
|
+
* - `none`: Champ vide
|
|
10186
|
+
* - `weak`: Longueur < minLength OU uniquement lettres
|
|
10187
|
+
* - `medium`: Longueur ≥ minLength ET (lettres+chiffres OU lettres+spéciaux)
|
|
10188
|
+
* - `strong`: Longueur ≥ minLength ET majuscules + minuscules + chiffres + spéciaux
|
|
10189
|
+
*
|
|
10190
|
+
* ## Accessibilité
|
|
10191
|
+
*
|
|
10192
|
+
* - Attribut `role="status"` pour annoncer les changements
|
|
10193
|
+
* - Label ARIA dynamique selon la force
|
|
10194
|
+
* - Couleurs sémantiques (error/warning/success)
|
|
10195
|
+
*
|
|
10196
|
+
* @component
|
|
10197
|
+
*/
|
|
10198
|
+
class DsPasswordStrength {
|
|
10199
|
+
/**
|
|
10200
|
+
* Mot de passe à évaluer.
|
|
10201
|
+
* @default ''
|
|
10202
|
+
*/
|
|
10203
|
+
password = input('', ...(ngDevMode ? [{ debugName: "password" }] : []));
|
|
10204
|
+
/**
|
|
10205
|
+
* Longueur minimale requise.
|
|
10206
|
+
* @default 8
|
|
10207
|
+
*/
|
|
10208
|
+
minLength = input(8, ...(ngDevMode ? [{ debugName: "minLength" }] : []));
|
|
10209
|
+
/**
|
|
10210
|
+
* Afficher le label textuel (ex: "Faible", "Moyen", "Fort").
|
|
10211
|
+
* @default true
|
|
10212
|
+
*/
|
|
10213
|
+
showLabel = input(true, ...(ngDevMode ? [{ debugName: "showLabel" }] : []));
|
|
10214
|
+
/**
|
|
10215
|
+
* Afficher les critères détaillés de validation.
|
|
10216
|
+
* @default false
|
|
10217
|
+
*/
|
|
10218
|
+
showCriteria = input(false, ...(ngDevMode ? [{ debugName: "showCriteria" }] : []));
|
|
10219
|
+
/**
|
|
10220
|
+
* Taille du composant.
|
|
10221
|
+
* @default 'md'
|
|
10222
|
+
*/
|
|
10223
|
+
size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : []));
|
|
10224
|
+
/**
|
|
10225
|
+
* Émis lorsque la force du mot de passe change.
|
|
10226
|
+
*/
|
|
10227
|
+
strengthChange = output();
|
|
10228
|
+
/**
|
|
10229
|
+
* Icônes FontAwesome pour les critères.
|
|
10230
|
+
*/
|
|
10231
|
+
faCheck = faCheck;
|
|
10232
|
+
faTimes = faTimes;
|
|
10233
|
+
/**
|
|
10234
|
+
* Regex patterns pour la validation.
|
|
10235
|
+
*/
|
|
10236
|
+
hasUpperCase = /[A-Z]/;
|
|
10237
|
+
hasLowerCase = /[a-z]/;
|
|
10238
|
+
hasNumber = /[0-9]/;
|
|
10239
|
+
hasSpecialChar = /[^A-Za-z0-9]/;
|
|
10240
|
+
/**
|
|
10241
|
+
* Calcul de la force du mot de passe.
|
|
10242
|
+
*/
|
|
10243
|
+
strength = computed(() => {
|
|
10244
|
+
const pwd = this.password();
|
|
10245
|
+
const minLen = this.minLength();
|
|
10246
|
+
if (!pwd || pwd.length === 0) {
|
|
10247
|
+
return 'none';
|
|
10248
|
+
}
|
|
10249
|
+
const hasUpper = this.hasUpperCase.test(pwd);
|
|
10250
|
+
const hasLower = this.hasLowerCase.test(pwd);
|
|
10251
|
+
const hasNum = this.hasNumber.test(pwd);
|
|
10252
|
+
const hasSpecial = this.hasSpecialChar.test(pwd);
|
|
10253
|
+
const lengthValid = pwd.length >= minLen;
|
|
10254
|
+
// Weak: longueur insuffisante OU uniquement lettres
|
|
10255
|
+
if (!lengthValid) {
|
|
10256
|
+
return 'weak';
|
|
10257
|
+
}
|
|
10258
|
+
const hasLetters = hasUpper || hasLower;
|
|
10259
|
+
const hasOnlyLetters = hasLetters && !hasNum && !hasSpecial;
|
|
10260
|
+
if (hasOnlyLetters) {
|
|
10261
|
+
return 'weak';
|
|
10262
|
+
}
|
|
10263
|
+
// Strong: toutes les catégories présentes
|
|
10264
|
+
if (hasUpper && hasLower && hasNum && hasSpecial) {
|
|
10265
|
+
return 'strong';
|
|
10266
|
+
}
|
|
10267
|
+
// Medium: au moins deux catégories
|
|
10268
|
+
return 'medium';
|
|
10269
|
+
}, ...(ngDevMode ? [{ debugName: "strength" }] : []));
|
|
10270
|
+
/**
|
|
10271
|
+
* Label textuel de la force (pour affichage).
|
|
10272
|
+
*/
|
|
10273
|
+
strengthLabel = computed(() => {
|
|
10274
|
+
const labels = {
|
|
10275
|
+
none: '',
|
|
10276
|
+
weak: 'Faible',
|
|
10277
|
+
medium: 'Moyen',
|
|
10278
|
+
strong: 'Fort',
|
|
10279
|
+
};
|
|
10280
|
+
return labels[this.strength()];
|
|
10281
|
+
}, ...(ngDevMode ? [{ debugName: "strengthLabel" }] : []));
|
|
10282
|
+
/**
|
|
10283
|
+
* Label ARIA pour accessibilité.
|
|
10284
|
+
*/
|
|
10285
|
+
ariaLabel = computed(() => {
|
|
10286
|
+
const str = this.strength();
|
|
10287
|
+
if (str === 'none') {
|
|
10288
|
+
return 'Force du mot de passe : non définie';
|
|
10289
|
+
}
|
|
10290
|
+
return `Force du mot de passe : ${this.strengthLabel()}`;
|
|
10291
|
+
}, ...(ngDevMode ? [{ debugName: "ariaLabel" }] : []));
|
|
10292
|
+
/**
|
|
10293
|
+
* Classes CSS calculées pour le conteneur.
|
|
10294
|
+
*/
|
|
10295
|
+
containerClasses = computed(() => {
|
|
10296
|
+
return [
|
|
10297
|
+
'ds-password-strength',
|
|
10298
|
+
`ds-password-strength--${this.size()}`,
|
|
10299
|
+
`ds-password-strength--${this.strength()}`,
|
|
10300
|
+
].filter(Boolean).join(' ');
|
|
10301
|
+
}, ...(ngDevMode ? [{ debugName: "containerClasses" }] : []));
|
|
10302
|
+
/**
|
|
10303
|
+
* Barres indicatrices (3 barres).
|
|
10304
|
+
* Chaque barre est active selon la force.
|
|
10305
|
+
*/
|
|
10306
|
+
bars = computed(() => {
|
|
10307
|
+
const str = this.strength();
|
|
10308
|
+
const barCount = 3;
|
|
10309
|
+
const activeCount = {
|
|
10310
|
+
none: 0,
|
|
10311
|
+
weak: 1,
|
|
10312
|
+
medium: 2,
|
|
10313
|
+
strong: 3,
|
|
10314
|
+
};
|
|
10315
|
+
const count = activeCount[str];
|
|
10316
|
+
return Array.from({ length: barCount }, (_, index) => ({
|
|
10317
|
+
active: index < count,
|
|
10318
|
+
level: str,
|
|
10319
|
+
}));
|
|
10320
|
+
}, ...(ngDevMode ? [{ debugName: "bars" }] : []));
|
|
10321
|
+
/**
|
|
10322
|
+
* Liste des critères de validation (pour affichage détaillé).
|
|
10323
|
+
*/
|
|
10324
|
+
criteria = computed(() => {
|
|
10325
|
+
const pwd = this.password();
|
|
10326
|
+
const minLen = this.minLength();
|
|
10327
|
+
return [
|
|
10328
|
+
{
|
|
10329
|
+
key: 'length',
|
|
10330
|
+
label: `Au moins ${minLen} caractères`,
|
|
10331
|
+
valid: pwd.length >= minLen,
|
|
10332
|
+
},
|
|
10333
|
+
{
|
|
10334
|
+
key: 'uppercase',
|
|
10335
|
+
label: 'Contient des majuscules',
|
|
10336
|
+
valid: this.hasUpperCase.test(pwd),
|
|
10337
|
+
},
|
|
10338
|
+
{
|
|
10339
|
+
key: 'lowercase',
|
|
10340
|
+
label: 'Contient des minuscules',
|
|
10341
|
+
valid: this.hasLowerCase.test(pwd),
|
|
10342
|
+
},
|
|
10343
|
+
{
|
|
10344
|
+
key: 'number',
|
|
10345
|
+
label: 'Contient des chiffres',
|
|
10346
|
+
valid: this.hasNumber.test(pwd),
|
|
10347
|
+
},
|
|
10348
|
+
{
|
|
10349
|
+
key: 'special',
|
|
10350
|
+
label: 'Contient des caractères spéciaux',
|
|
10351
|
+
valid: this.hasSpecialChar.test(pwd),
|
|
10352
|
+
},
|
|
10353
|
+
];
|
|
10354
|
+
}, ...(ngDevMode ? [{ debugName: "criteria" }] : []));
|
|
10355
|
+
/**
|
|
10356
|
+
* Constructeur : émet les changements de force via effect.
|
|
10357
|
+
*/
|
|
10358
|
+
constructor() {
|
|
10359
|
+
let previousStrength = 'none';
|
|
10360
|
+
// Émettre strengthChange à chaque changement
|
|
10361
|
+
effect(() => {
|
|
10362
|
+
const currentStrength = this.strength();
|
|
10363
|
+
if (currentStrength !== previousStrength) {
|
|
10364
|
+
previousStrength = currentStrength;
|
|
10365
|
+
this.strengthChange.emit(currentStrength);
|
|
10366
|
+
}
|
|
10367
|
+
});
|
|
10368
|
+
}
|
|
10369
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DsPasswordStrength, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
10370
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: DsPasswordStrength, isStandalone: true, selector: "ds-password-strength", inputs: { password: { classPropertyName: "password", publicName: "password", isSignal: true, isRequired: false, transformFunction: null }, minLength: { classPropertyName: "minLength", publicName: "minLength", isSignal: true, isRequired: false, transformFunction: null }, showLabel: { classPropertyName: "showLabel", publicName: "showLabel", isSignal: true, isRequired: false, transformFunction: null }, showCriteria: { classPropertyName: "showCriteria", publicName: "showCriteria", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { strengthChange: "strengthChange" }, ngImport: i0, template: "<div [ngClass]=\"containerClasses()\" role=\"status\" [attr.aria-label]=\"ariaLabel()\">\n <!-- Barres indicatrices (3 barres) -->\n <div class=\"ds-password-strength__bars\">\n @for (bar of bars(); track $index) {\n <div\n class=\"ds-password-strength__bar\"\n [class.ds-password-strength__bar--active]=\"bar.active\"\n [class.ds-password-strength__bar--weak]=\"bar.active && bar.level === 'weak'\"\n [class.ds-password-strength__bar--medium]=\"bar.active && bar.level === 'medium'\"\n [class.ds-password-strength__bar--strong]=\"bar.active && bar.level === 'strong'\">\n </div>\n }\n </div>\n\n <!-- Label optionnel -->\n @if (showLabel() && strength() !== 'none') {\n <span\n class=\"ds-password-strength__label\"\n [class]=\"'ds-password-strength__label--' + strength()\">\n {{ strengthLabel() }}\n </span>\n }\n\n <!-- Crit\u00E8res d\u00E9taill\u00E9s optionnels -->\n @if (showCriteria()) {\n <ul class=\"ds-password-strength__criteria\">\n @for (criterion of criteria(); track criterion.key) {\n <li\n class=\"ds-password-strength__criterion\"\n [class.ds-password-strength__criterion--valid]=\"criterion.valid\">\n <fa-icon [icon]=\"criterion.valid ? faCheck : faTimes\" />\n <span>{{ criterion.label }}</span>\n </li>\n }\n </ul>\n }\n</div>\n", styles: ["@charset \"UTF-8\";.ds-password-strength{display:flex;flex-direction:column;gap:var(--password-strength-label-gap)}.ds-password-strength__bars{display:flex;gap:var(--password-strength-bar-gap);align-items:center}.ds-password-strength__bar{flex:1;height:var(--password-strength-bar-height-md);background-color:var(--password-strength-bg);border-radius:var(--password-strength-bar-radius);transition:background-color .3s ease}.ds-password-strength__bar--active.ds-password-strength__bar--weak{background-color:var(--password-strength-weak)}.ds-password-strength__bar--active.ds-password-strength__bar--medium{background-color:var(--password-strength-medium)}.ds-password-strength__bar--active.ds-password-strength__bar--strong{background-color:var(--password-strength-strong)}.ds-password-strength__label{font-size:var(--password-strength-label-font-size);color:var(--password-strength-text);font-weight:var(--font-weight-medium);text-align:right}.ds-password-strength__label--weak{color:var(--password-strength-weak)}.ds-password-strength__label--medium{color:var(--password-strength-medium)}.ds-password-strength__label--strong{color:var(--password-strength-strong)}.ds-password-strength__criteria{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:var(--space-1)}.ds-password-strength__criterion{display:flex;align-items:center;gap:var(--space-2);font-size:var(--font-size-2);color:var(--password-strength-criterion-invalid);transition:color .2s ease}.ds-password-strength__criterion fa-icon{font-size:.875rem}.ds-password-strength__criterion--valid{color:var(--password-strength-criterion-valid)}.ds-password-strength--sm .ds-password-strength__bar{height:var(--password-strength-bar-height-sm)}.ds-password-strength--sm .ds-password-strength__label,.ds-password-strength--sm .ds-password-strength__criterion{font-size:var(--font-size-1)}.ds-password-strength--md .ds-password-strength__bar{height:var(--password-strength-bar-height-md)}.ds-password-strength--md .ds-password-strength__label{font-size:var(--password-strength-label-font-size)}.ds-password-strength--md .ds-password-strength__criterion{font-size:var(--font-size-2)}.ds-password-strength--lg .ds-password-strength__bar{height:var(--password-strength-bar-height-lg)}.ds-password-strength--lg .ds-password-strength__label,.ds-password-strength--lg .ds-password-strength__criterion{font-size:var(--font-size-3)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FontAwesomeModule }, { kind: "component", type: i1$1.FaIconComponent, selector: "fa-icon", inputs: ["icon", "title", "animation", "mask", "flip", "size", "pull", "border", "inverse", "symbol", "rotate", "fixedWidth", "transform", "a11yRole"], outputs: ["iconChange", "titleChange", "animationChange", "maskChange", "flipChange", "sizeChange", "pullChange", "borderChange", "inverseChange", "symbolChange", "rotateChange", "fixedWidthChange", "transformChange", "a11yRoleChange"] }] });
|
|
10371
|
+
}
|
|
10372
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DsPasswordStrength, decorators: [{
|
|
10373
|
+
type: Component,
|
|
10374
|
+
args: [{ selector: 'ds-password-strength', imports: [CommonModule, FontAwesomeModule], template: "<div [ngClass]=\"containerClasses()\" role=\"status\" [attr.aria-label]=\"ariaLabel()\">\n <!-- Barres indicatrices (3 barres) -->\n <div class=\"ds-password-strength__bars\">\n @for (bar of bars(); track $index) {\n <div\n class=\"ds-password-strength__bar\"\n [class.ds-password-strength__bar--active]=\"bar.active\"\n [class.ds-password-strength__bar--weak]=\"bar.active && bar.level === 'weak'\"\n [class.ds-password-strength__bar--medium]=\"bar.active && bar.level === 'medium'\"\n [class.ds-password-strength__bar--strong]=\"bar.active && bar.level === 'strong'\">\n </div>\n }\n </div>\n\n <!-- Label optionnel -->\n @if (showLabel() && strength() !== 'none') {\n <span\n class=\"ds-password-strength__label\"\n [class]=\"'ds-password-strength__label--' + strength()\">\n {{ strengthLabel() }}\n </span>\n }\n\n <!-- Crit\u00E8res d\u00E9taill\u00E9s optionnels -->\n @if (showCriteria()) {\n <ul class=\"ds-password-strength__criteria\">\n @for (criterion of criteria(); track criterion.key) {\n <li\n class=\"ds-password-strength__criterion\"\n [class.ds-password-strength__criterion--valid]=\"criterion.valid\">\n <fa-icon [icon]=\"criterion.valid ? faCheck : faTimes\" />\n <span>{{ criterion.label }}</span>\n </li>\n }\n </ul>\n }\n</div>\n", styles: ["@charset \"UTF-8\";.ds-password-strength{display:flex;flex-direction:column;gap:var(--password-strength-label-gap)}.ds-password-strength__bars{display:flex;gap:var(--password-strength-bar-gap);align-items:center}.ds-password-strength__bar{flex:1;height:var(--password-strength-bar-height-md);background-color:var(--password-strength-bg);border-radius:var(--password-strength-bar-radius);transition:background-color .3s ease}.ds-password-strength__bar--active.ds-password-strength__bar--weak{background-color:var(--password-strength-weak)}.ds-password-strength__bar--active.ds-password-strength__bar--medium{background-color:var(--password-strength-medium)}.ds-password-strength__bar--active.ds-password-strength__bar--strong{background-color:var(--password-strength-strong)}.ds-password-strength__label{font-size:var(--password-strength-label-font-size);color:var(--password-strength-text);font-weight:var(--font-weight-medium);text-align:right}.ds-password-strength__label--weak{color:var(--password-strength-weak)}.ds-password-strength__label--medium{color:var(--password-strength-medium)}.ds-password-strength__label--strong{color:var(--password-strength-strong)}.ds-password-strength__criteria{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:var(--space-1)}.ds-password-strength__criterion{display:flex;align-items:center;gap:var(--space-2);font-size:var(--font-size-2);color:var(--password-strength-criterion-invalid);transition:color .2s ease}.ds-password-strength__criterion fa-icon{font-size:.875rem}.ds-password-strength__criterion--valid{color:var(--password-strength-criterion-valid)}.ds-password-strength--sm .ds-password-strength__bar{height:var(--password-strength-bar-height-sm)}.ds-password-strength--sm .ds-password-strength__label,.ds-password-strength--sm .ds-password-strength__criterion{font-size:var(--font-size-1)}.ds-password-strength--md .ds-password-strength__bar{height:var(--password-strength-bar-height-md)}.ds-password-strength--md .ds-password-strength__label{font-size:var(--password-strength-label-font-size)}.ds-password-strength--md .ds-password-strength__criterion{font-size:var(--font-size-2)}.ds-password-strength--lg .ds-password-strength__bar{height:var(--password-strength-bar-height-lg)}.ds-password-strength--lg .ds-password-strength__label,.ds-password-strength--lg .ds-password-strength__criterion{font-size:var(--font-size-3)}\n"] }]
|
|
10375
|
+
}], ctorParameters: () => [], propDecorators: { password: [{ type: i0.Input, args: [{ isSignal: true, alias: "password", required: false }] }], minLength: [{ type: i0.Input, args: [{ isSignal: true, alias: "minLength", required: false }] }], showLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "showLabel", required: false }] }], showCriteria: [{ type: i0.Input, args: [{ isSignal: true, alias: "showCriteria", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], strengthChange: [{ type: i0.Output, args: ["strengthChange"] }] } });
|
|
10376
|
+
|
|
10377
|
+
/**
|
|
10378
|
+
* # DsTimeline
|
|
10379
|
+
*
|
|
10380
|
+
* Composant pour afficher une liste d'événements dans un ordre chronologique vertical.
|
|
10381
|
+
*
|
|
10382
|
+
* ## Usage
|
|
10383
|
+
*
|
|
10384
|
+
* ```html
|
|
10385
|
+
* <ds-timeline
|
|
10386
|
+
* [items]="events"
|
|
10387
|
+
* mode="left"
|
|
10388
|
+
* size="md"
|
|
10389
|
+
* [pending]="false"
|
|
10390
|
+
* (itemClick)="onItemClick($event)">
|
|
10391
|
+
* </ds-timeline>
|
|
10392
|
+
* ```
|
|
10393
|
+
*
|
|
10394
|
+
* ## Modes
|
|
10395
|
+
*
|
|
10396
|
+
* - `left` : Contenu aligné à droite de la ligne
|
|
10397
|
+
* - `right` : Contenu aligné à gauche de la ligne
|
|
10398
|
+
* - `alternate` : Contenu alterné gauche/droite
|
|
10399
|
+
*
|
|
10400
|
+
* ## Accessibilité
|
|
10401
|
+
*
|
|
10402
|
+
* - Liste sémantique avec `role="list"` et `role="listitem"`
|
|
10403
|
+
* - Dates et contenus avec attributs ARIA
|
|
10404
|
+
* - Navigation clavier supportée
|
|
10405
|
+
*
|
|
10406
|
+
* @component
|
|
10407
|
+
*/
|
|
10408
|
+
class DsTimeline {
|
|
10409
|
+
/**
|
|
10410
|
+
* Liste des événements à afficher.
|
|
10411
|
+
*/
|
|
10412
|
+
items = input.required(...(ngDevMode ? [{ debugName: "items" }] : []));
|
|
10413
|
+
/**
|
|
10414
|
+
* Mode d'affichage (position du contenu).
|
|
10415
|
+
* @default 'left'
|
|
10416
|
+
*/
|
|
10417
|
+
mode = input('left', ...(ngDevMode ? [{ debugName: "mode" }] : []));
|
|
10418
|
+
/**
|
|
10419
|
+
* Taille du composant.
|
|
10420
|
+
* @default 'md'
|
|
10421
|
+
*/
|
|
10422
|
+
size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : []));
|
|
10423
|
+
/**
|
|
10424
|
+
* Affiche un indicateur "en cours" à la fin.
|
|
10425
|
+
* @default false
|
|
10426
|
+
*/
|
|
10427
|
+
pending = input(false, ...(ngDevMode ? [{ debugName: "pending" }] : []));
|
|
10428
|
+
/**
|
|
10429
|
+
* Texte de l'indicateur pending.
|
|
10430
|
+
* @default 'En cours...'
|
|
10431
|
+
*/
|
|
10432
|
+
pendingContent = input('En cours...', ...(ngDevMode ? [{ debugName: "pendingContent" }] : []));
|
|
10433
|
+
/**
|
|
10434
|
+
* Inverse l'ordre d'affichage (plus récent en haut).
|
|
10435
|
+
* @default false
|
|
10436
|
+
*/
|
|
10437
|
+
reverse = input(false, ...(ngDevMode ? [{ debugName: "reverse" }] : []));
|
|
10438
|
+
/**
|
|
10439
|
+
* Événement émis au clic sur un item.
|
|
10440
|
+
*/
|
|
10441
|
+
itemClick = output();
|
|
10442
|
+
/**
|
|
10443
|
+
* Icônes par défaut.
|
|
10444
|
+
*/
|
|
10445
|
+
defaultIcon = faCircle;
|
|
10446
|
+
pendingIcon = faCircleHalfStroke;
|
|
10447
|
+
/**
|
|
10448
|
+
* Items triés (reverse si demandé).
|
|
10449
|
+
*/
|
|
10450
|
+
sortedItems = computed(() => {
|
|
10451
|
+
const items = [...this.items()];
|
|
10452
|
+
return this.reverse() ? items.reverse() : items;
|
|
10453
|
+
}, ...(ngDevMode ? [{ debugName: "sortedItems" }] : []));
|
|
10454
|
+
/**
|
|
10455
|
+
* Classes CSS du conteneur.
|
|
10456
|
+
*/
|
|
10457
|
+
containerClasses = computed(() => {
|
|
10458
|
+
return [
|
|
10459
|
+
'ds-timeline',
|
|
10460
|
+
`ds-timeline--${this.mode()}`,
|
|
10461
|
+
`ds-timeline--${this.size()}`,
|
|
10462
|
+
].filter(Boolean);
|
|
10463
|
+
}, ...(ngDevMode ? [{ debugName: "containerClasses" }] : []));
|
|
10464
|
+
/**
|
|
10465
|
+
* Classes CSS pour un item.
|
|
10466
|
+
*/
|
|
10467
|
+
getItemClasses(item, index) {
|
|
10468
|
+
const position = this.getItemPosition(index);
|
|
10469
|
+
return [
|
|
10470
|
+
'ds-timeline__item',
|
|
10471
|
+
`ds-timeline__item--${position}`,
|
|
10472
|
+
item.color ? `ds-timeline__item--${item.color}` : 'ds-timeline__item--default',
|
|
10473
|
+
].filter(Boolean);
|
|
10474
|
+
}
|
|
10475
|
+
/**
|
|
10476
|
+
* Classes CSS pour le point d'un item.
|
|
10477
|
+
*/
|
|
10478
|
+
getDotClasses(item) {
|
|
10479
|
+
return [
|
|
10480
|
+
'ds-timeline__dot',
|
|
10481
|
+
item.icon ? 'ds-timeline__dot--with-icon' : '',
|
|
10482
|
+
item.color ? `ds-timeline__dot--${item.color}` : 'ds-timeline__dot--default',
|
|
10483
|
+
].filter(Boolean);
|
|
10484
|
+
}
|
|
10485
|
+
/**
|
|
10486
|
+
* Détermine la position d'un item en fonction du mode.
|
|
10487
|
+
*/
|
|
10488
|
+
getItemPosition(index) {
|
|
10489
|
+
const mode = this.mode();
|
|
10490
|
+
if (mode === 'left')
|
|
10491
|
+
return 'right'; // Contenu à droite de la ligne
|
|
10492
|
+
if (mode === 'right')
|
|
10493
|
+
return 'left'; // Contenu à gauche de la ligne
|
|
10494
|
+
// Mode alternate : alterner selon l'index
|
|
10495
|
+
return index % 2 === 0 ? 'right' : 'left';
|
|
10496
|
+
}
|
|
10497
|
+
/**
|
|
10498
|
+
* Gère le clic sur un item.
|
|
10499
|
+
*/
|
|
10500
|
+
handleItemClick(item, index) {
|
|
10501
|
+
this.itemClick.emit({ item, index });
|
|
10502
|
+
}
|
|
10503
|
+
/**
|
|
10504
|
+
* Gère la touche Enter/Space sur un item.
|
|
10505
|
+
*/
|
|
10506
|
+
handleKeydown(event, item, index) {
|
|
10507
|
+
if (event.key === 'Enter' || event.key === ' ') {
|
|
10508
|
+
event.preventDefault();
|
|
10509
|
+
this.handleItemClick(item, index);
|
|
10510
|
+
}
|
|
10511
|
+
}
|
|
10512
|
+
/**
|
|
10513
|
+
* Icône à afficher pour un item.
|
|
10514
|
+
*/
|
|
10515
|
+
getIcon(item) {
|
|
10516
|
+
return item.icon || this.defaultIcon;
|
|
10517
|
+
}
|
|
10518
|
+
/**
|
|
10519
|
+
* Vérifie si c'est le dernier item.
|
|
10520
|
+
*/
|
|
10521
|
+
isLastItem(index) {
|
|
10522
|
+
return index === this.sortedItems().length - 1;
|
|
10523
|
+
}
|
|
10524
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DsTimeline, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
10525
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: DsTimeline, isStandalone: true, selector: "ds-timeline", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, pending: { classPropertyName: "pending", publicName: "pending", isSignal: true, isRequired: false, transformFunction: null }, pendingContent: { classPropertyName: "pendingContent", publicName: "pendingContent", isSignal: true, isRequired: false, transformFunction: null }, reverse: { classPropertyName: "reverse", publicName: "reverse", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { itemClick: "itemClick" }, ngImport: i0, template: "<div [ngClass]=\"containerClasses()\" role=\"list\" aria-label=\"Timeline\">\n @for (item of sortedItems(); track $index) {\n <div\n [ngClass]=\"getItemClasses(item, $index)\"\n role=\"listitem\"\n tabindex=\"0\"\n (click)=\"handleItemClick(item, $index)\"\n (keydown)=\"handleKeydown($event, item, $index)\"\n [class.ds-timeline__item--last]=\"isLastItem($index) && !pending()\">\n\n <!-- Point de la timeline -->\n <div [ngClass]=\"getDotClasses(item)\" [attr.aria-label]=\"item.date || '\u00C9v\u00E9nement'\">\n @if (item.icon) {\n <fa-icon [icon]=\"getIcon(item)\" class=\"ds-timeline__icon\" aria-hidden=\"true\"></fa-icon>\n }\n </div>\n\n <!-- Ligne de connexion -->\n @if (!isLastItem($index) || pending()) {\n <div class=\"ds-timeline__line\" aria-hidden=\"true\"></div>\n }\n\n <!-- Contenu -->\n <div class=\"ds-timeline__content\">\n @if (item.date) {\n <div class=\"ds-timeline__date\">{{ item.date }}</div>\n }\n <div class=\"ds-timeline__text\">{{ item.content }}</div>\n </div>\n </div>\n }\n\n <!-- Indicateur pending -->\n @if (pending()) {\n <div\n class=\"ds-timeline__item ds-timeline__item--pending ds-timeline__item--{{ getItemPosition(sortedItems().length) }}\"\n role=\"listitem\">\n <div class=\"ds-timeline__dot ds-timeline__dot--pending ds-timeline__dot--with-icon\">\n <fa-icon [icon]=\"pendingIcon\" class=\"ds-timeline__icon ds-timeline__icon--pending\" aria-hidden=\"true\"></fa-icon>\n </div>\n <div class=\"ds-timeline__content\">\n <div class=\"ds-timeline__text ds-timeline__text--pending\">{{ pendingContent() }}</div>\n </div>\n </div>\n }\n</div>\n", styles: [".ds-timeline{display:flex;flex-direction:column;position:relative;width:100%}.ds-timeline__item{position:relative;display:grid;padding-bottom:var(--timeline-item-gap);cursor:pointer;transition:opacity .2s ease}.ds-timeline__item:focus{outline:2px solid var(--color-primary);outline-offset:2px;border-radius:var(--radius-1)}.ds-timeline__item:focus-visible{outline:2px solid var(--color-primary)}.ds-timeline__item--last{padding-bottom:0}.ds-timeline__item--pending{cursor:default;animation:pulse 2s ease-in-out infinite}@keyframes pulse{0%,to{opacity:1}50%{opacity:.7}}.ds-timeline--left .ds-timeline__item{grid-template-columns:auto 1fr;grid-template-areas:\"dot content\" \"line content\"}.ds-timeline--right .ds-timeline__item{grid-template-columns:1fr auto;grid-template-areas:\"content dot\" \"content line\";text-align:right}.ds-timeline--right .ds-timeline__item .ds-timeline__content{padding-left:0;padding-right:var(--timeline-content-gap)}.ds-timeline--alternate .ds-timeline__item--left{grid-template-columns:1fr auto;grid-template-areas:\"content dot\" \"content line\";text-align:right}.ds-timeline--alternate .ds-timeline__item--left .ds-timeline__content{padding-left:0;padding-right:var(--timeline-content-gap)}.ds-timeline--alternate .ds-timeline__item--right{grid-template-columns:auto 1fr;grid-template-areas:\"dot content\" \"line content\"}.ds-timeline__dot{grid-area:dot;width:var(--timeline-dot-size);height:var(--timeline-dot-size);border-radius:50%;border:var(--timeline-dot-border-width) solid var(--timeline-dot-border-color);background:var(--timeline-dot-bg);display:flex;align-items:center;justify-content:center;flex-shrink:0;position:relative;z-index:2;transition:all .3s ease}.ds-timeline__dot--default{background:var(--timeline-dot-bg-default);border-color:var(--timeline-dot-border-default)}.ds-timeline__dot--primary{background:var(--timeline-dot-bg-primary);border-color:var(--timeline-dot-border-primary)}.ds-timeline__dot--success{background:var(--timeline-dot-bg-success);border-color:var(--timeline-dot-border-success)}.ds-timeline__dot--warning{background:var(--timeline-dot-bg-warning);border-color:var(--timeline-dot-border-warning)}.ds-timeline__dot--error{background:var(--timeline-dot-bg-error);border-color:var(--timeline-dot-border-error)}.ds-timeline__dot--info{background:var(--timeline-dot-bg-info);border-color:var(--timeline-dot-border-info)}.ds-timeline__dot--pending{background:var(--timeline-dot-bg-pending);border-color:var(--timeline-dot-border-pending)}.ds-timeline__dot--with-icon{background:transparent;border:none}.ds-timeline__item:hover .ds-timeline__dot{transform:scale(1.1)}.ds-timeline__icon{font-size:var(--timeline-icon-size);color:var(--timeline-icon-color)}.ds-timeline__icon--pending{color:var(--timeline-icon-color-pending);animation:spin 2s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.ds-timeline__line{grid-area:line;width:var(--timeline-line-width);background:var(--timeline-line-color);justify-self:center;flex:1;min-height:var(--timeline-item-gap);margin-top:4px}.ds-timeline__content{grid-area:content;padding-left:var(--timeline-content-gap);display:flex;flex-direction:column;gap:var(--timeline-content-inner-gap);min-width:0}.ds-timeline__date{font-size:var(--timeline-date-font-size);color:var(--timeline-date-color);font-weight:500}.ds-timeline__text{font-size:var(--timeline-text-font-size);color:var(--timeline-text-color);line-height:1.5}.ds-timeline__text--pending{color:var(--timeline-text-color-pending);font-style:italic}.ds-timeline--sm{--timeline-dot-size: var(--timeline-dot-size-sm);--timeline-line-width: var(--timeline-line-width-sm);--timeline-item-gap: var(--timeline-item-gap-sm);--timeline-content-gap: var(--timeline-content-gap-sm);--timeline-content-inner-gap: var(--timeline-content-inner-gap-sm);--timeline-date-font-size: var(--timeline-date-font-size-sm);--timeline-text-font-size: var(--timeline-text-font-size-sm);--timeline-icon-size: var(--timeline-icon-size-sm)}.ds-timeline--md{--timeline-dot-size: var(--timeline-dot-size-md);--timeline-line-width: var(--timeline-line-width-md);--timeline-item-gap: var(--timeline-item-gap-md);--timeline-content-gap: var(--timeline-content-gap-md);--timeline-content-inner-gap: var(--timeline-content-inner-gap-md);--timeline-date-font-size: var(--timeline-date-font-size-md);--timeline-text-font-size: var(--timeline-text-font-size-md);--timeline-icon-size: var(--timeline-icon-size-md)}.ds-timeline--lg{--timeline-dot-size: var(--timeline-dot-size-lg);--timeline-line-width: var(--timeline-line-width-lg);--timeline-item-gap: var(--timeline-item-gap-lg);--timeline-content-gap: var(--timeline-content-gap-lg);--timeline-content-inner-gap: var(--timeline-content-inner-gap-lg);--timeline-date-font-size: var(--timeline-date-font-size-lg);--timeline-text-font-size: var(--timeline-text-font-size-lg);--timeline-icon-size: var(--timeline-icon-size-lg)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FontAwesomeModule }, { kind: "component", type: i1$1.FaIconComponent, selector: "fa-icon", inputs: ["icon", "title", "animation", "mask", "flip", "size", "pull", "border", "inverse", "symbol", "rotate", "fixedWidth", "transform", "a11yRole"], outputs: ["iconChange", "titleChange", "animationChange", "maskChange", "flipChange", "sizeChange", "pullChange", "borderChange", "inverseChange", "symbolChange", "rotateChange", "fixedWidthChange", "transformChange", "a11yRoleChange"] }] });
|
|
10526
|
+
}
|
|
10527
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DsTimeline, decorators: [{
|
|
10528
|
+
type: Component,
|
|
10529
|
+
args: [{ selector: 'ds-timeline', imports: [CommonModule, FontAwesomeModule], template: "<div [ngClass]=\"containerClasses()\" role=\"list\" aria-label=\"Timeline\">\n @for (item of sortedItems(); track $index) {\n <div\n [ngClass]=\"getItemClasses(item, $index)\"\n role=\"listitem\"\n tabindex=\"0\"\n (click)=\"handleItemClick(item, $index)\"\n (keydown)=\"handleKeydown($event, item, $index)\"\n [class.ds-timeline__item--last]=\"isLastItem($index) && !pending()\">\n\n <!-- Point de la timeline -->\n <div [ngClass]=\"getDotClasses(item)\" [attr.aria-label]=\"item.date || '\u00C9v\u00E9nement'\">\n @if (item.icon) {\n <fa-icon [icon]=\"getIcon(item)\" class=\"ds-timeline__icon\" aria-hidden=\"true\"></fa-icon>\n }\n </div>\n\n <!-- Ligne de connexion -->\n @if (!isLastItem($index) || pending()) {\n <div class=\"ds-timeline__line\" aria-hidden=\"true\"></div>\n }\n\n <!-- Contenu -->\n <div class=\"ds-timeline__content\">\n @if (item.date) {\n <div class=\"ds-timeline__date\">{{ item.date }}</div>\n }\n <div class=\"ds-timeline__text\">{{ item.content }}</div>\n </div>\n </div>\n }\n\n <!-- Indicateur pending -->\n @if (pending()) {\n <div\n class=\"ds-timeline__item ds-timeline__item--pending ds-timeline__item--{{ getItemPosition(sortedItems().length) }}\"\n role=\"listitem\">\n <div class=\"ds-timeline__dot ds-timeline__dot--pending ds-timeline__dot--with-icon\">\n <fa-icon [icon]=\"pendingIcon\" class=\"ds-timeline__icon ds-timeline__icon--pending\" aria-hidden=\"true\"></fa-icon>\n </div>\n <div class=\"ds-timeline__content\">\n <div class=\"ds-timeline__text ds-timeline__text--pending\">{{ pendingContent() }}</div>\n </div>\n </div>\n }\n</div>\n", styles: [".ds-timeline{display:flex;flex-direction:column;position:relative;width:100%}.ds-timeline__item{position:relative;display:grid;padding-bottom:var(--timeline-item-gap);cursor:pointer;transition:opacity .2s ease}.ds-timeline__item:focus{outline:2px solid var(--color-primary);outline-offset:2px;border-radius:var(--radius-1)}.ds-timeline__item:focus-visible{outline:2px solid var(--color-primary)}.ds-timeline__item--last{padding-bottom:0}.ds-timeline__item--pending{cursor:default;animation:pulse 2s ease-in-out infinite}@keyframes pulse{0%,to{opacity:1}50%{opacity:.7}}.ds-timeline--left .ds-timeline__item{grid-template-columns:auto 1fr;grid-template-areas:\"dot content\" \"line content\"}.ds-timeline--right .ds-timeline__item{grid-template-columns:1fr auto;grid-template-areas:\"content dot\" \"content line\";text-align:right}.ds-timeline--right .ds-timeline__item .ds-timeline__content{padding-left:0;padding-right:var(--timeline-content-gap)}.ds-timeline--alternate .ds-timeline__item--left{grid-template-columns:1fr auto;grid-template-areas:\"content dot\" \"content line\";text-align:right}.ds-timeline--alternate .ds-timeline__item--left .ds-timeline__content{padding-left:0;padding-right:var(--timeline-content-gap)}.ds-timeline--alternate .ds-timeline__item--right{grid-template-columns:auto 1fr;grid-template-areas:\"dot content\" \"line content\"}.ds-timeline__dot{grid-area:dot;width:var(--timeline-dot-size);height:var(--timeline-dot-size);border-radius:50%;border:var(--timeline-dot-border-width) solid var(--timeline-dot-border-color);background:var(--timeline-dot-bg);display:flex;align-items:center;justify-content:center;flex-shrink:0;position:relative;z-index:2;transition:all .3s ease}.ds-timeline__dot--default{background:var(--timeline-dot-bg-default);border-color:var(--timeline-dot-border-default)}.ds-timeline__dot--primary{background:var(--timeline-dot-bg-primary);border-color:var(--timeline-dot-border-primary)}.ds-timeline__dot--success{background:var(--timeline-dot-bg-success);border-color:var(--timeline-dot-border-success)}.ds-timeline__dot--warning{background:var(--timeline-dot-bg-warning);border-color:var(--timeline-dot-border-warning)}.ds-timeline__dot--error{background:var(--timeline-dot-bg-error);border-color:var(--timeline-dot-border-error)}.ds-timeline__dot--info{background:var(--timeline-dot-bg-info);border-color:var(--timeline-dot-border-info)}.ds-timeline__dot--pending{background:var(--timeline-dot-bg-pending);border-color:var(--timeline-dot-border-pending)}.ds-timeline__dot--with-icon{background:transparent;border:none}.ds-timeline__item:hover .ds-timeline__dot{transform:scale(1.1)}.ds-timeline__icon{font-size:var(--timeline-icon-size);color:var(--timeline-icon-color)}.ds-timeline__icon--pending{color:var(--timeline-icon-color-pending);animation:spin 2s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.ds-timeline__line{grid-area:line;width:var(--timeline-line-width);background:var(--timeline-line-color);justify-self:center;flex:1;min-height:var(--timeline-item-gap);margin-top:4px}.ds-timeline__content{grid-area:content;padding-left:var(--timeline-content-gap);display:flex;flex-direction:column;gap:var(--timeline-content-inner-gap);min-width:0}.ds-timeline__date{font-size:var(--timeline-date-font-size);color:var(--timeline-date-color);font-weight:500}.ds-timeline__text{font-size:var(--timeline-text-font-size);color:var(--timeline-text-color);line-height:1.5}.ds-timeline__text--pending{color:var(--timeline-text-color-pending);font-style:italic}.ds-timeline--sm{--timeline-dot-size: var(--timeline-dot-size-sm);--timeline-line-width: var(--timeline-line-width-sm);--timeline-item-gap: var(--timeline-item-gap-sm);--timeline-content-gap: var(--timeline-content-gap-sm);--timeline-content-inner-gap: var(--timeline-content-inner-gap-sm);--timeline-date-font-size: var(--timeline-date-font-size-sm);--timeline-text-font-size: var(--timeline-text-font-size-sm);--timeline-icon-size: var(--timeline-icon-size-sm)}.ds-timeline--md{--timeline-dot-size: var(--timeline-dot-size-md);--timeline-line-width: var(--timeline-line-width-md);--timeline-item-gap: var(--timeline-item-gap-md);--timeline-content-gap: var(--timeline-content-gap-md);--timeline-content-inner-gap: var(--timeline-content-inner-gap-md);--timeline-date-font-size: var(--timeline-date-font-size-md);--timeline-text-font-size: var(--timeline-text-font-size-md);--timeline-icon-size: var(--timeline-icon-size-md)}.ds-timeline--lg{--timeline-dot-size: var(--timeline-dot-size-lg);--timeline-line-width: var(--timeline-line-width-lg);--timeline-item-gap: var(--timeline-item-gap-lg);--timeline-content-gap: var(--timeline-content-gap-lg);--timeline-content-inner-gap: var(--timeline-content-inner-gap-lg);--timeline-date-font-size: var(--timeline-date-font-size-lg);--timeline-text-font-size: var(--timeline-text-font-size-lg);--timeline-icon-size: var(--timeline-icon-size-lg)}\n"] }]
|
|
10530
|
+
}], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: true }] }], mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], pending: [{ type: i0.Input, args: [{ isSignal: true, alias: "pending", required: false }] }], pendingContent: [{ type: i0.Input, args: [{ isSignal: true, alias: "pendingContent", required: false }] }], reverse: [{ type: i0.Input, args: [{ isSignal: true, alias: "reverse", required: false }] }], itemClick: [{ type: i0.Output, args: ["itemClick"] }] } });
|
|
10531
|
+
|
|
10532
|
+
/**
|
|
10533
|
+
* DS Transfer
|
|
10534
|
+
*
|
|
10535
|
+
* Composant permettant de transférer des items entre deux listes (source et cible).
|
|
10536
|
+
* Inclut recherche, sélection multiple, et navigation clavier.
|
|
10537
|
+
*
|
|
10538
|
+
* @example
|
|
10539
|
+
* <ds-transfer
|
|
10540
|
+
* [source]="sourceItems"
|
|
10541
|
+
* [target]="targetItems"
|
|
10542
|
+
* sourceTitle="Disponibles"
|
|
10543
|
+
* targetTitle="Sélectionnés"
|
|
10544
|
+
* [showSearch]="true"
|
|
10545
|
+
* (transferChange)="onTransfer($event)"
|
|
10546
|
+
* />
|
|
10547
|
+
*/
|
|
10548
|
+
class DsTransfer {
|
|
10549
|
+
// Inputs
|
|
10550
|
+
source = input([], ...(ngDevMode ? [{ debugName: "source" }] : []));
|
|
10551
|
+
target = input([], ...(ngDevMode ? [{ debugName: "target" }] : []));
|
|
10552
|
+
sourceTitle = input('Source', ...(ngDevMode ? [{ debugName: "sourceTitle" }] : []));
|
|
10553
|
+
targetTitle = input('Target', ...(ngDevMode ? [{ debugName: "targetTitle" }] : []));
|
|
10554
|
+
showSearch = input(true, ...(ngDevMode ? [{ debugName: "showSearch" }] : []));
|
|
10555
|
+
showSelectAll = input(true, ...(ngDevMode ? [{ debugName: "showSelectAll" }] : []));
|
|
10556
|
+
disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
|
|
10557
|
+
size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : []));
|
|
10558
|
+
// Outputs
|
|
10559
|
+
transferChange = output();
|
|
10560
|
+
// Internal state
|
|
10561
|
+
sourceSelected = signal(new Set(), ...(ngDevMode ? [{ debugName: "sourceSelected" }] : []));
|
|
10562
|
+
targetSelected = signal(new Set(), ...(ngDevMode ? [{ debugName: "targetSelected" }] : []));
|
|
10563
|
+
sourceSearchQuery = signal('', ...(ngDevMode ? [{ debugName: "sourceSearchQuery" }] : []));
|
|
10564
|
+
targetSearchQuery = signal('', ...(ngDevMode ? [{ debugName: "targetSearchQuery" }] : []));
|
|
10565
|
+
// Computed
|
|
10566
|
+
filteredSource = computed(() => {
|
|
10567
|
+
const query = this.sourceSearchQuery().toLowerCase();
|
|
10568
|
+
if (!query)
|
|
10569
|
+
return this.source();
|
|
10570
|
+
return this.source().filter(item => item.label.toLowerCase().includes(query) ||
|
|
10571
|
+
item.description?.toLowerCase().includes(query));
|
|
10572
|
+
}, ...(ngDevMode ? [{ debugName: "filteredSource" }] : []));
|
|
10573
|
+
filteredTarget = computed(() => {
|
|
10574
|
+
const query = this.targetSearchQuery().toLowerCase();
|
|
10575
|
+
if (!query)
|
|
10576
|
+
return this.target();
|
|
10577
|
+
return this.target().filter(item => item.label.toLowerCase().includes(query) ||
|
|
10578
|
+
item.description?.toLowerCase().includes(query));
|
|
10579
|
+
}, ...(ngDevMode ? [{ debugName: "filteredTarget" }] : []));
|
|
10580
|
+
sourceSelectableCount = computed(() => this.filteredSource().filter(item => !item.disabled).length, ...(ngDevMode ? [{ debugName: "sourceSelectableCount" }] : []));
|
|
10581
|
+
targetSelectableCount = computed(() => this.filteredTarget().filter(item => !item.disabled).length, ...(ngDevMode ? [{ debugName: "targetSelectableCount" }] : []));
|
|
10582
|
+
isAllSourceSelected = computed(() => {
|
|
10583
|
+
const count = this.sourceSelectableCount();
|
|
10584
|
+
return count > 0 && this.sourceSelected().size === count;
|
|
10585
|
+
}, ...(ngDevMode ? [{ debugName: "isAllSourceSelected" }] : []));
|
|
10586
|
+
isAllTargetSelected = computed(() => {
|
|
10587
|
+
const count = this.targetSelectableCount();
|
|
10588
|
+
return count > 0 && this.targetSelected().size === count;
|
|
10589
|
+
}, ...(ngDevMode ? [{ debugName: "isAllTargetSelected" }] : []));
|
|
10590
|
+
canTransferToTarget = computed(() => this.sourceSelected().size > 0 && !this.disabled(), ...(ngDevMode ? [{ debugName: "canTransferToTarget" }] : []));
|
|
10591
|
+
canTransferToSource = computed(() => this.targetSelected().size > 0 && !this.disabled(), ...(ngDevMode ? [{ debugName: "canTransferToSource" }] : []));
|
|
10592
|
+
containerClasses = computed(() => ({
|
|
10593
|
+
'ds-transfer': true,
|
|
10594
|
+
'ds-transfer--disabled': this.disabled(),
|
|
10595
|
+
[`ds-transfer--${this.size()}`]: true,
|
|
10596
|
+
}), ...(ngDevMode ? [{ debugName: "containerClasses" }] : []));
|
|
10597
|
+
// Public methods
|
|
10598
|
+
transferToTarget() {
|
|
10599
|
+
if (!this.canTransferToTarget())
|
|
10600
|
+
return;
|
|
10601
|
+
const selectedKeys = Array.from(this.sourceSelected());
|
|
10602
|
+
const itemsToTransfer = this.source().filter(item => selectedKeys.includes(item.key));
|
|
10603
|
+
const newSource = this.source().filter(item => !selectedKeys.includes(item.key));
|
|
10604
|
+
const newTarget = [...this.target(), ...itemsToTransfer];
|
|
10605
|
+
this.sourceSelected.set(new Set());
|
|
10606
|
+
this.emitChange(newSource, newTarget);
|
|
10607
|
+
}
|
|
10608
|
+
transferToSource() {
|
|
10609
|
+
if (!this.canTransferToSource())
|
|
10610
|
+
return;
|
|
10611
|
+
const selectedKeys = Array.from(this.targetSelected());
|
|
10612
|
+
const itemsToTransfer = this.target().filter(item => selectedKeys.includes(item.key));
|
|
10613
|
+
const newTarget = this.target().filter(item => !selectedKeys.includes(item.key));
|
|
10614
|
+
const newSource = [...this.source(), ...itemsToTransfer];
|
|
10615
|
+
this.targetSelected.set(new Set());
|
|
10616
|
+
this.emitChange(newSource, newTarget);
|
|
10617
|
+
}
|
|
10618
|
+
toggleSelectAll(direction) {
|
|
10619
|
+
if (this.disabled())
|
|
10620
|
+
return;
|
|
10621
|
+
const isSource = direction === 'left';
|
|
10622
|
+
const items = isSource ? this.filteredSource() : this.filteredTarget();
|
|
10623
|
+
const selected = isSource ? this.sourceSelected() : this.targetSelected();
|
|
10624
|
+
const isAllSelected = isSource ? this.isAllSourceSelected() : this.isAllTargetSelected();
|
|
10625
|
+
const newSelected = new Set();
|
|
10626
|
+
if (!isAllSelected) {
|
|
10627
|
+
items.forEach(item => {
|
|
10628
|
+
if (!item.disabled) {
|
|
10629
|
+
newSelected.add(item.key);
|
|
10630
|
+
}
|
|
10631
|
+
});
|
|
10632
|
+
}
|
|
10633
|
+
if (isSource) {
|
|
10634
|
+
this.sourceSelected.set(newSelected);
|
|
10635
|
+
}
|
|
10636
|
+
else {
|
|
10637
|
+
this.targetSelected.set(newSelected);
|
|
10638
|
+
}
|
|
10639
|
+
}
|
|
10640
|
+
toggleItemSelection(item, direction) {
|
|
10641
|
+
if (this.disabled() || item.disabled)
|
|
10642
|
+
return;
|
|
10643
|
+
const isSource = direction === 'left';
|
|
10644
|
+
const selected = isSource ? this.sourceSelected() : this.targetSelected();
|
|
10645
|
+
const newSelected = new Set(selected);
|
|
10646
|
+
if (newSelected.has(item.key)) {
|
|
10647
|
+
newSelected.delete(item.key);
|
|
10648
|
+
}
|
|
10649
|
+
else {
|
|
10650
|
+
newSelected.add(item.key);
|
|
10651
|
+
}
|
|
10652
|
+
if (isSource) {
|
|
10653
|
+
this.sourceSelected.set(newSelected);
|
|
10654
|
+
}
|
|
10655
|
+
else {
|
|
10656
|
+
this.targetSelected.set(newSelected);
|
|
10657
|
+
}
|
|
10658
|
+
}
|
|
10659
|
+
isItemSelected(item, direction) {
|
|
10660
|
+
const selected = direction === 'left' ? this.sourceSelected() : this.targetSelected();
|
|
10661
|
+
return selected.has(item.key);
|
|
10662
|
+
}
|
|
10663
|
+
onSearchInput(event, direction) {
|
|
10664
|
+
const input = event.target;
|
|
10665
|
+
const query = input.value;
|
|
10666
|
+
if (direction === 'left') {
|
|
10667
|
+
this.sourceSearchQuery.set(query);
|
|
10668
|
+
}
|
|
10669
|
+
else {
|
|
10670
|
+
this.targetSearchQuery.set(query);
|
|
10671
|
+
}
|
|
10672
|
+
}
|
|
10673
|
+
clearSearch(direction) {
|
|
10674
|
+
if (direction === 'left') {
|
|
10675
|
+
this.sourceSearchQuery.set('');
|
|
10676
|
+
}
|
|
10677
|
+
else {
|
|
10678
|
+
this.targetSearchQuery.set('');
|
|
10679
|
+
}
|
|
10680
|
+
}
|
|
10681
|
+
getSelectedCount(direction) {
|
|
10682
|
+
return direction === 'left'
|
|
10683
|
+
? this.sourceSelected().size
|
|
10684
|
+
: this.targetSelected().size;
|
|
10685
|
+
}
|
|
10686
|
+
getItemCount(direction) {
|
|
10687
|
+
return direction === 'left'
|
|
10688
|
+
? this.filteredSource().length
|
|
10689
|
+
: this.filteredTarget().length;
|
|
10690
|
+
}
|
|
10691
|
+
emitChange(source, target) {
|
|
10692
|
+
this.transferChange.emit({ source, target });
|
|
10693
|
+
}
|
|
10694
|
+
// ARIA helpers
|
|
10695
|
+
getListboxId(direction) {
|
|
10696
|
+
return `ds-transfer-${direction}-listbox`;
|
|
10697
|
+
}
|
|
10698
|
+
getItemId(item, direction) {
|
|
10699
|
+
return `ds-transfer-${direction}-item-${item.key}`;
|
|
10700
|
+
}
|
|
10701
|
+
sourceListboxLabel = computed(() => `${this.sourceTitle()} (${this.getSelectedCount('left')}/${this.getItemCount('left')} sélectionné(s))`, ...(ngDevMode ? [{ debugName: "sourceListboxLabel" }] : []));
|
|
10702
|
+
targetListboxLabel = computed(() => `${this.targetTitle()} (${this.getSelectedCount('right')}/${this.getItemCount('right')} sélectionné(s))`, ...(ngDevMode ? [{ debugName: "targetListboxLabel" }] : []));
|
|
10703
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DsTransfer, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
10704
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: DsTransfer, isStandalone: true, selector: "ds-transfer", inputs: { source: { classPropertyName: "source", publicName: "source", isSignal: true, isRequired: false, transformFunction: null }, target: { classPropertyName: "target", publicName: "target", isSignal: true, isRequired: false, transformFunction: null }, sourceTitle: { classPropertyName: "sourceTitle", publicName: "sourceTitle", isSignal: true, isRequired: false, transformFunction: null }, targetTitle: { classPropertyName: "targetTitle", publicName: "targetTitle", isSignal: true, isRequired: false, transformFunction: null }, showSearch: { classPropertyName: "showSearch", publicName: "showSearch", isSignal: true, isRequired: false, transformFunction: null }, showSelectAll: { classPropertyName: "showSelectAll", publicName: "showSelectAll", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { transferChange: "transferChange" }, ngImport: i0, template: "<div [ngClass]=\"containerClasses()\" role=\"group\" aria-label=\"Transfer component\">\n <!-- Source panel -->\n <div class=\"ds-transfer__panel ds-transfer__panel--source\">\n <!-- Header -->\n <div class=\"ds-transfer__header\">\n <div class=\"ds-transfer__title\">\n <span>{{ sourceTitle() }}</span>\n <span class=\"ds-transfer__count\">\n {{ getSelectedCount('left') }} / {{ source().length }}\n </span>\n </div>\n @if (showSelectAll()) {\n <primitive-checkbox\n [checked]=\"isAllSourceSelected()\"\n [indeterminate]=\"sourceSelected().size > 0 && !isAllSourceSelected()\"\n [disabled]=\"disabled() || sourceSelectableCount() === 0\"\n (checkedChange)=\"toggleSelectAll('left')\"\n size=\"sm\"\n label=\"Tout s\u00E9lectionner\"\n class=\"ds-transfer__select-all\"\n />\n }\n </div>\n\n <!-- Search -->\n @if (showSearch()) {\n <div class=\"ds-transfer__search\">\n <input\n type=\"text\"\n class=\"ds-transfer__search-input\"\n placeholder=\"Rechercher...\"\n [value]=\"sourceSearchQuery()\"\n (input)=\"onSearchInput($event, 'left')\"\n [disabled]=\"disabled()\"\n aria-label=\"Rechercher dans les items source\"\n />\n @if (sourceSearchQuery()) {\n <button\n type=\"button\"\n class=\"ds-transfer__search-clear\"\n (click)=\"clearSearch('left')\"\n aria-label=\"Effacer la recherche\"\n >\n \u2715\n </button>\n }\n </div>\n }\n\n <!-- List -->\n <div\n class=\"ds-transfer__list\"\n role=\"listbox\"\n [attr.aria-label]=\"sourceListboxLabel()\"\n [attr.id]=\"getListboxId('left')\"\n [attr.aria-multiselectable]=\"true\"\n >\n @if (filteredSource().length === 0) {\n <div class=\"ds-transfer__empty\">\n @if (sourceSearchQuery()) {\n Aucun r\u00E9sultat\n } @else {\n Aucun item disponible\n }\n </div>\n } @else {\n @for (item of filteredSource(); track item.key) {\n <div\n class=\"ds-transfer__item\"\n [class.ds-transfer__item--selected]=\"isItemSelected(item, 'left')\"\n [class.ds-transfer__item--disabled]=\"item.disabled\"\n role=\"option\"\n [attr.aria-selected]=\"isItemSelected(item, 'left')\"\n [attr.aria-disabled]=\"item.disabled\"\n [attr.id]=\"getItemId(item, 'left')\"\n (click)=\"toggleItemSelection(item, 'left')\"\n >\n <primitive-checkbox\n [checked]=\"isItemSelected(item, 'left')\"\n [disabled]=\"disabled() || (item.disabled ?? false)\"\n (checkedChange)=\"toggleItemSelection(item, 'left')\"\n size=\"sm\"\n />\n <div class=\"ds-transfer__item-content\">\n <div class=\"ds-transfer__item-label\">{{ item.label }}</div>\n @if (item.description) {\n <div class=\"ds-transfer__item-description\">{{ item.description }}</div>\n }\n </div>\n </div>\n }\n }\n </div>\n </div>\n\n <!-- Transfer buttons -->\n <div class=\"ds-transfer__actions\">\n <ds-button\n variant=\"secondary\"\n size=\"sm\"\n [disabled]=\"!canTransferToTarget()\"\n (click)=\"transferToTarget()\"\n aria-label=\"Transf\u00E9rer les items s\u00E9lectionn\u00E9s vers la droite\"\n >\n \u203A\n </ds-button>\n <ds-button\n variant=\"secondary\"\n size=\"sm\"\n [disabled]=\"!canTransferToSource()\"\n (click)=\"transferToSource()\"\n aria-label=\"Transf\u00E9rer les items s\u00E9lectionn\u00E9s vers la gauche\"\n >\n \u2039\n </ds-button>\n </div>\n\n <!-- Target panel -->\n <div class=\"ds-transfer__panel ds-transfer__panel--target\">\n <!-- Header -->\n <div class=\"ds-transfer__header\">\n <div class=\"ds-transfer__title\">\n <span>{{ targetTitle() }}</span>\n <span class=\"ds-transfer__count\">\n {{ getSelectedCount('right') }} / {{ target().length }}\n </span>\n </div>\n @if (showSelectAll()) {\n <primitive-checkbox\n [checked]=\"isAllTargetSelected()\"\n [indeterminate]=\"targetSelected().size > 0 && !isAllTargetSelected()\"\n [disabled]=\"disabled() || targetSelectableCount() === 0\"\n (checkedChange)=\"toggleSelectAll('right')\"\n size=\"sm\"\n label=\"Tout s\u00E9lectionner\"\n class=\"ds-transfer__select-all\"\n />\n }\n </div>\n\n <!-- Search -->\n @if (showSearch()) {\n <div class=\"ds-transfer__search\">\n <input\n type=\"text\"\n class=\"ds-transfer__search-input\"\n placeholder=\"Rechercher...\"\n [value]=\"targetSearchQuery()\"\n (input)=\"onSearchInput($event, 'right')\"\n [disabled]=\"disabled()\"\n aria-label=\"Rechercher dans les items cible\"\n />\n @if (targetSearchQuery()) {\n <button\n type=\"button\"\n class=\"ds-transfer__search-clear\"\n (click)=\"clearSearch('right')\"\n aria-label=\"Effacer la recherche\"\n >\n \u2715\n </button>\n }\n </div>\n }\n\n <!-- List -->\n <div\n class=\"ds-transfer__list\"\n role=\"listbox\"\n [attr.aria-label]=\"targetListboxLabel()\"\n [attr.id]=\"getListboxId('right')\"\n [attr.aria-multiselectable]=\"true\"\n >\n @if (filteredTarget().length === 0) {\n <div class=\"ds-transfer__empty\">\n @if (targetSearchQuery()) {\n Aucun r\u00E9sultat\n } @else {\n Aucun item s\u00E9lectionn\u00E9\n }\n </div>\n } @else {\n @for (item of filteredTarget(); track item.key) {\n <div\n class=\"ds-transfer__item\"\n [class.ds-transfer__item--selected]=\"isItemSelected(item, 'right')\"\n [class.ds-transfer__item--disabled]=\"item.disabled\"\n role=\"option\"\n [attr.aria-selected]=\"isItemSelected(item, 'right')\"\n [attr.aria-disabled]=\"item.disabled\"\n [attr.id]=\"getItemId(item, 'right')\"\n (click)=\"toggleItemSelection(item, 'right')\"\n >\n <primitive-checkbox\n [checked]=\"isItemSelected(item, 'right')\"\n [disabled]=\"disabled() || (item.disabled ?? false)\"\n (checkedChange)=\"toggleItemSelection(item, 'right')\"\n size=\"sm\"\n />\n <div class=\"ds-transfer__item-content\">\n <div class=\"ds-transfer__item-label\">{{ item.label }}</div>\n @if (item.description) {\n <div class=\"ds-transfer__item-description\">{{ item.description }}</div>\n }\n </div>\n </div>\n }\n }\n </div>\n </div>\n</div>\n", styles: [".ds-transfer{display:flex;align-items:center;gap:var(--transfer-gap, 1rem);width:100%}.ds-transfer__panel{flex:1;display:flex;flex-direction:column;border:1px solid var(--transfer-border-color, var(--gray-300));border-radius:var(--transfer-border-radius, var(--radius-2));background:var(--transfer-bg, var(--white));overflow:hidden}.ds-transfer__header{display:flex;align-items:center;justify-content:space-between;padding:var(--transfer-header-padding, .75rem 1rem);border-bottom:1px solid var(--transfer-header-border-color, var(--gray-200));background:var(--transfer-header-bg, var(--gray-50))}.ds-transfer__title{display:flex;align-items:center;gap:.5rem;font-weight:600;font-size:var(--transfer-title-font-size, var(--font-size-sm));color:var(--transfer-title-color, var(--text-default))}.ds-transfer__count{font-weight:400;font-size:var(--font-size-xs);color:var(--transfer-count-color, var(--text-light))}.ds-transfer__search{position:relative;padding:var(--transfer-search-padding, .75rem 1rem);border-bottom:1px solid var(--transfer-search-border-color, var(--gray-200))}.ds-transfer__search-input{width:100%;padding:var(--transfer-search-input-padding, .5rem 2rem .5rem .75rem);border:1px solid var(--transfer-search-input-border, var(--gray-300));border-radius:var(--transfer-search-input-radius, var(--radius-1));font-size:var(--font-size-sm);color:var(--transfer-search-input-text, var(--text-default));background:var(--transfer-search-input-bg, var(--white))}.ds-transfer__search-input::placeholder{color:var(--transfer-search-placeholder, var(--text-lighter))}.ds-transfer__search-input:focus{outline:none;border-color:var(--transfer-search-input-focus, var(--color-primary));box-shadow:0 0 0 3px var(--transfer-search-input-focus-shadow, rgba(59, 130, 246, .1))}.ds-transfer__search-input:disabled{opacity:.6;cursor:not-allowed;background:var(--transfer-search-input-disabled-bg, var(--gray-50))}.ds-transfer__search-clear{position:absolute;top:50%;right:1.5rem;transform:translateY(-50%);padding:.25rem;border:none;background:transparent;color:var(--transfer-search-clear-color, var(--text-lighter));cursor:pointer;font-size:1rem;line-height:1}.ds-transfer__search-clear:hover{color:var(--transfer-search-clear-hover, var(--text-default))}.ds-transfer__search-clear:focus{outline:2px solid var(--color-primary);outline-offset:2px}.ds-transfer__list{flex:1;overflow-y:auto;min-height:var(--transfer-list-min-height, 300px);max-height:var(--transfer-list-max-height, 400px)}.ds-transfer__empty{display:flex;align-items:center;justify-content:center;height:100%;padding:2rem;color:var(--transfer-empty-color, var(--text-lighter));font-size:var(--font-size-sm);text-align:center}.ds-transfer__item{display:flex;align-items:flex-start;gap:.75rem;padding:var(--transfer-item-padding, .75rem 1rem);border-bottom:1px solid var(--transfer-item-border, var(--gray-100));cursor:pointer;transition:background-color .2s}.ds-transfer__item:hover:not(.ds-transfer__item--disabled){background:var(--transfer-item-hover-bg, var(--gray-50))}.ds-transfer__item--selected{background:var(--transfer-item-selected-bg, var(--blue-50))}.ds-transfer__item--selected:hover:not(.ds-transfer__item--selected--disabled){background:var(--transfer-item-selected-hover-bg, var(--blue-100))}.ds-transfer__item--disabled{opacity:.5;cursor:not-allowed}.ds-transfer__item:last-child{border-bottom:none}.ds-transfer__item-content{flex:1;min-width:0}.ds-transfer__item-label{font-size:var(--transfer-item-font-size, var(--font-size-sm));font-weight:500;color:var(--transfer-item-label-color, var(--text-default));overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ds-transfer__item-description{margin-top:.25rem;font-size:var(--font-size-xs);color:var(--transfer-item-description-color, var(--text-light));overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ds-transfer__actions{display:flex;flex-direction:column;gap:var(--transfer-actions-gap, .5rem);align-self:center}.ds-transfer--sm .ds-transfer__header,.ds-transfer--sm .ds-transfer__search{padding:.5rem .75rem}.ds-transfer--sm .ds-transfer__search-input{padding:.375rem 1.5rem .375rem .5rem;font-size:var(--font-size-xs)}.ds-transfer--sm .ds-transfer__item{padding:.5rem .75rem}.ds-transfer--sm .ds-transfer__item-label{font-size:var(--font-size-xs)}.ds-transfer--sm .ds-transfer__list{min-height:200px;max-height:300px}.ds-transfer--lg .ds-transfer__header,.ds-transfer--lg .ds-transfer__search{padding:1rem 1.25rem}.ds-transfer--lg .ds-transfer__search-input{padding:.625rem 2.5rem .625rem 1rem;font-size:var(--font-size-base)}.ds-transfer--lg .ds-transfer__item{padding:1rem 1.25rem}.ds-transfer--lg .ds-transfer__item-label{font-size:var(--font-size-base)}.ds-transfer--lg .ds-transfer__list{min-height:400px;max-height:500px}.ds-transfer--disabled{opacity:.6;cursor:not-allowed}.ds-transfer--disabled .ds-transfer__panel,.ds-transfer--disabled .ds-transfer__item{pointer-events:none}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }, { kind: "component", type: PrimitiveCheckbox, selector: "primitive-checkbox", inputs: ["checked", "indeterminate", "disabled", "size", "label", "checkboxId"], outputs: ["checkedChange"] }, { kind: "component", type: DsButton, selector: "ds-button", inputs: ["variant", "appearance", "size", "submit", "disabled", "iconStart", "iconEnd", "loading", "block"], outputs: ["clicked"] }] });
|
|
10705
|
+
}
|
|
10706
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DsTransfer, decorators: [{
|
|
10707
|
+
type: Component,
|
|
10708
|
+
args: [{ selector: 'ds-transfer', standalone: true, imports: [CommonModule, FormsModule, PrimitiveCheckbox, DsButton], template: "<div [ngClass]=\"containerClasses()\" role=\"group\" aria-label=\"Transfer component\">\n <!-- Source panel -->\n <div class=\"ds-transfer__panel ds-transfer__panel--source\">\n <!-- Header -->\n <div class=\"ds-transfer__header\">\n <div class=\"ds-transfer__title\">\n <span>{{ sourceTitle() }}</span>\n <span class=\"ds-transfer__count\">\n {{ getSelectedCount('left') }} / {{ source().length }}\n </span>\n </div>\n @if (showSelectAll()) {\n <primitive-checkbox\n [checked]=\"isAllSourceSelected()\"\n [indeterminate]=\"sourceSelected().size > 0 && !isAllSourceSelected()\"\n [disabled]=\"disabled() || sourceSelectableCount() === 0\"\n (checkedChange)=\"toggleSelectAll('left')\"\n size=\"sm\"\n label=\"Tout s\u00E9lectionner\"\n class=\"ds-transfer__select-all\"\n />\n }\n </div>\n\n <!-- Search -->\n @if (showSearch()) {\n <div class=\"ds-transfer__search\">\n <input\n type=\"text\"\n class=\"ds-transfer__search-input\"\n placeholder=\"Rechercher...\"\n [value]=\"sourceSearchQuery()\"\n (input)=\"onSearchInput($event, 'left')\"\n [disabled]=\"disabled()\"\n aria-label=\"Rechercher dans les items source\"\n />\n @if (sourceSearchQuery()) {\n <button\n type=\"button\"\n class=\"ds-transfer__search-clear\"\n (click)=\"clearSearch('left')\"\n aria-label=\"Effacer la recherche\"\n >\n \u2715\n </button>\n }\n </div>\n }\n\n <!-- List -->\n <div\n class=\"ds-transfer__list\"\n role=\"listbox\"\n [attr.aria-label]=\"sourceListboxLabel()\"\n [attr.id]=\"getListboxId('left')\"\n [attr.aria-multiselectable]=\"true\"\n >\n @if (filteredSource().length === 0) {\n <div class=\"ds-transfer__empty\">\n @if (sourceSearchQuery()) {\n Aucun r\u00E9sultat\n } @else {\n Aucun item disponible\n }\n </div>\n } @else {\n @for (item of filteredSource(); track item.key) {\n <div\n class=\"ds-transfer__item\"\n [class.ds-transfer__item--selected]=\"isItemSelected(item, 'left')\"\n [class.ds-transfer__item--disabled]=\"item.disabled\"\n role=\"option\"\n [attr.aria-selected]=\"isItemSelected(item, 'left')\"\n [attr.aria-disabled]=\"item.disabled\"\n [attr.id]=\"getItemId(item, 'left')\"\n (click)=\"toggleItemSelection(item, 'left')\"\n >\n <primitive-checkbox\n [checked]=\"isItemSelected(item, 'left')\"\n [disabled]=\"disabled() || (item.disabled ?? false)\"\n (checkedChange)=\"toggleItemSelection(item, 'left')\"\n size=\"sm\"\n />\n <div class=\"ds-transfer__item-content\">\n <div class=\"ds-transfer__item-label\">{{ item.label }}</div>\n @if (item.description) {\n <div class=\"ds-transfer__item-description\">{{ item.description }}</div>\n }\n </div>\n </div>\n }\n }\n </div>\n </div>\n\n <!-- Transfer buttons -->\n <div class=\"ds-transfer__actions\">\n <ds-button\n variant=\"secondary\"\n size=\"sm\"\n [disabled]=\"!canTransferToTarget()\"\n (click)=\"transferToTarget()\"\n aria-label=\"Transf\u00E9rer les items s\u00E9lectionn\u00E9s vers la droite\"\n >\n \u203A\n </ds-button>\n <ds-button\n variant=\"secondary\"\n size=\"sm\"\n [disabled]=\"!canTransferToSource()\"\n (click)=\"transferToSource()\"\n aria-label=\"Transf\u00E9rer les items s\u00E9lectionn\u00E9s vers la gauche\"\n >\n \u2039\n </ds-button>\n </div>\n\n <!-- Target panel -->\n <div class=\"ds-transfer__panel ds-transfer__panel--target\">\n <!-- Header -->\n <div class=\"ds-transfer__header\">\n <div class=\"ds-transfer__title\">\n <span>{{ targetTitle() }}</span>\n <span class=\"ds-transfer__count\">\n {{ getSelectedCount('right') }} / {{ target().length }}\n </span>\n </div>\n @if (showSelectAll()) {\n <primitive-checkbox\n [checked]=\"isAllTargetSelected()\"\n [indeterminate]=\"targetSelected().size > 0 && !isAllTargetSelected()\"\n [disabled]=\"disabled() || targetSelectableCount() === 0\"\n (checkedChange)=\"toggleSelectAll('right')\"\n size=\"sm\"\n label=\"Tout s\u00E9lectionner\"\n class=\"ds-transfer__select-all\"\n />\n }\n </div>\n\n <!-- Search -->\n @if (showSearch()) {\n <div class=\"ds-transfer__search\">\n <input\n type=\"text\"\n class=\"ds-transfer__search-input\"\n placeholder=\"Rechercher...\"\n [value]=\"targetSearchQuery()\"\n (input)=\"onSearchInput($event, 'right')\"\n [disabled]=\"disabled()\"\n aria-label=\"Rechercher dans les items cible\"\n />\n @if (targetSearchQuery()) {\n <button\n type=\"button\"\n class=\"ds-transfer__search-clear\"\n (click)=\"clearSearch('right')\"\n aria-label=\"Effacer la recherche\"\n >\n \u2715\n </button>\n }\n </div>\n }\n\n <!-- List -->\n <div\n class=\"ds-transfer__list\"\n role=\"listbox\"\n [attr.aria-label]=\"targetListboxLabel()\"\n [attr.id]=\"getListboxId('right')\"\n [attr.aria-multiselectable]=\"true\"\n >\n @if (filteredTarget().length === 0) {\n <div class=\"ds-transfer__empty\">\n @if (targetSearchQuery()) {\n Aucun r\u00E9sultat\n } @else {\n Aucun item s\u00E9lectionn\u00E9\n }\n </div>\n } @else {\n @for (item of filteredTarget(); track item.key) {\n <div\n class=\"ds-transfer__item\"\n [class.ds-transfer__item--selected]=\"isItemSelected(item, 'right')\"\n [class.ds-transfer__item--disabled]=\"item.disabled\"\n role=\"option\"\n [attr.aria-selected]=\"isItemSelected(item, 'right')\"\n [attr.aria-disabled]=\"item.disabled\"\n [attr.id]=\"getItemId(item, 'right')\"\n (click)=\"toggleItemSelection(item, 'right')\"\n >\n <primitive-checkbox\n [checked]=\"isItemSelected(item, 'right')\"\n [disabled]=\"disabled() || (item.disabled ?? false)\"\n (checkedChange)=\"toggleItemSelection(item, 'right')\"\n size=\"sm\"\n />\n <div class=\"ds-transfer__item-content\">\n <div class=\"ds-transfer__item-label\">{{ item.label }}</div>\n @if (item.description) {\n <div class=\"ds-transfer__item-description\">{{ item.description }}</div>\n }\n </div>\n </div>\n }\n }\n </div>\n </div>\n</div>\n", styles: [".ds-transfer{display:flex;align-items:center;gap:var(--transfer-gap, 1rem);width:100%}.ds-transfer__panel{flex:1;display:flex;flex-direction:column;border:1px solid var(--transfer-border-color, var(--gray-300));border-radius:var(--transfer-border-radius, var(--radius-2));background:var(--transfer-bg, var(--white));overflow:hidden}.ds-transfer__header{display:flex;align-items:center;justify-content:space-between;padding:var(--transfer-header-padding, .75rem 1rem);border-bottom:1px solid var(--transfer-header-border-color, var(--gray-200));background:var(--transfer-header-bg, var(--gray-50))}.ds-transfer__title{display:flex;align-items:center;gap:.5rem;font-weight:600;font-size:var(--transfer-title-font-size, var(--font-size-sm));color:var(--transfer-title-color, var(--text-default))}.ds-transfer__count{font-weight:400;font-size:var(--font-size-xs);color:var(--transfer-count-color, var(--text-light))}.ds-transfer__search{position:relative;padding:var(--transfer-search-padding, .75rem 1rem);border-bottom:1px solid var(--transfer-search-border-color, var(--gray-200))}.ds-transfer__search-input{width:100%;padding:var(--transfer-search-input-padding, .5rem 2rem .5rem .75rem);border:1px solid var(--transfer-search-input-border, var(--gray-300));border-radius:var(--transfer-search-input-radius, var(--radius-1));font-size:var(--font-size-sm);color:var(--transfer-search-input-text, var(--text-default));background:var(--transfer-search-input-bg, var(--white))}.ds-transfer__search-input::placeholder{color:var(--transfer-search-placeholder, var(--text-lighter))}.ds-transfer__search-input:focus{outline:none;border-color:var(--transfer-search-input-focus, var(--color-primary));box-shadow:0 0 0 3px var(--transfer-search-input-focus-shadow, rgba(59, 130, 246, .1))}.ds-transfer__search-input:disabled{opacity:.6;cursor:not-allowed;background:var(--transfer-search-input-disabled-bg, var(--gray-50))}.ds-transfer__search-clear{position:absolute;top:50%;right:1.5rem;transform:translateY(-50%);padding:.25rem;border:none;background:transparent;color:var(--transfer-search-clear-color, var(--text-lighter));cursor:pointer;font-size:1rem;line-height:1}.ds-transfer__search-clear:hover{color:var(--transfer-search-clear-hover, var(--text-default))}.ds-transfer__search-clear:focus{outline:2px solid var(--color-primary);outline-offset:2px}.ds-transfer__list{flex:1;overflow-y:auto;min-height:var(--transfer-list-min-height, 300px);max-height:var(--transfer-list-max-height, 400px)}.ds-transfer__empty{display:flex;align-items:center;justify-content:center;height:100%;padding:2rem;color:var(--transfer-empty-color, var(--text-lighter));font-size:var(--font-size-sm);text-align:center}.ds-transfer__item{display:flex;align-items:flex-start;gap:.75rem;padding:var(--transfer-item-padding, .75rem 1rem);border-bottom:1px solid var(--transfer-item-border, var(--gray-100));cursor:pointer;transition:background-color .2s}.ds-transfer__item:hover:not(.ds-transfer__item--disabled){background:var(--transfer-item-hover-bg, var(--gray-50))}.ds-transfer__item--selected{background:var(--transfer-item-selected-bg, var(--blue-50))}.ds-transfer__item--selected:hover:not(.ds-transfer__item--selected--disabled){background:var(--transfer-item-selected-hover-bg, var(--blue-100))}.ds-transfer__item--disabled{opacity:.5;cursor:not-allowed}.ds-transfer__item:last-child{border-bottom:none}.ds-transfer__item-content{flex:1;min-width:0}.ds-transfer__item-label{font-size:var(--transfer-item-font-size, var(--font-size-sm));font-weight:500;color:var(--transfer-item-label-color, var(--text-default));overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ds-transfer__item-description{margin-top:.25rem;font-size:var(--font-size-xs);color:var(--transfer-item-description-color, var(--text-light));overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ds-transfer__actions{display:flex;flex-direction:column;gap:var(--transfer-actions-gap, .5rem);align-self:center}.ds-transfer--sm .ds-transfer__header,.ds-transfer--sm .ds-transfer__search{padding:.5rem .75rem}.ds-transfer--sm .ds-transfer__search-input{padding:.375rem 1.5rem .375rem .5rem;font-size:var(--font-size-xs)}.ds-transfer--sm .ds-transfer__item{padding:.5rem .75rem}.ds-transfer--sm .ds-transfer__item-label{font-size:var(--font-size-xs)}.ds-transfer--sm .ds-transfer__list{min-height:200px;max-height:300px}.ds-transfer--lg .ds-transfer__header,.ds-transfer--lg .ds-transfer__search{padding:1rem 1.25rem}.ds-transfer--lg .ds-transfer__search-input{padding:.625rem 2.5rem .625rem 1rem;font-size:var(--font-size-base)}.ds-transfer--lg .ds-transfer__item{padding:1rem 1.25rem}.ds-transfer--lg .ds-transfer__item-label{font-size:var(--font-size-base)}.ds-transfer--lg .ds-transfer__list{min-height:400px;max-height:500px}.ds-transfer--disabled{opacity:.6;cursor:not-allowed}.ds-transfer--disabled .ds-transfer__panel,.ds-transfer--disabled .ds-transfer__item{pointer-events:none}\n"] }]
|
|
10709
|
+
}], propDecorators: { source: [{ type: i0.Input, args: [{ isSignal: true, alias: "source", required: false }] }], target: [{ type: i0.Input, args: [{ isSignal: true, alias: "target", required: false }] }], sourceTitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "sourceTitle", required: false }] }], targetTitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "targetTitle", required: false }] }], showSearch: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSearch", required: false }] }], showSelectAll: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSelectAll", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], transferChange: [{ type: i0.Output, args: ["transferChange"] }] } });
|
|
10710
|
+
|
|
10711
|
+
class DsCarousel {
|
|
10712
|
+
// Config
|
|
10713
|
+
slides = input([], ...(ngDevMode ? [{ debugName: "slides" }] : []));
|
|
10714
|
+
autoplay = input(false, ...(ngDevMode ? [{ debugName: "autoplay" }] : []));
|
|
10715
|
+
autoplaySpeed = input(3000, ...(ngDevMode ? [{ debugName: "autoplaySpeed" }] : []));
|
|
10716
|
+
effect = input('slide', ...(ngDevMode ? [{ debugName: "effect" }] : []));
|
|
10717
|
+
dots = input(true, ...(ngDevMode ? [{ debugName: "dots" }] : []));
|
|
10718
|
+
dotsPosition = input('bottom', ...(ngDevMode ? [{ debugName: "dotsPosition" }] : []));
|
|
10719
|
+
arrows = input(true, ...(ngDevMode ? [{ debugName: "arrows" }] : []));
|
|
10720
|
+
infinite = input(true, ...(ngDevMode ? [{ debugName: "infinite" }] : []));
|
|
10721
|
+
pauseOnHover = input(true, ...(ngDevMode ? [{ debugName: "pauseOnHover" }] : []));
|
|
10722
|
+
activeIndex = input(0, ...(ngDevMode ? [{ debugName: "activeIndex" }] : []));
|
|
10723
|
+
// Events
|
|
10724
|
+
slideChange = output();
|
|
10725
|
+
// ViewChild
|
|
10726
|
+
trackElement;
|
|
10727
|
+
slideElements;
|
|
10728
|
+
// Icons
|
|
10729
|
+
icons = {
|
|
10730
|
+
left: faChevronLeft,
|
|
10731
|
+
right: faChevronRight,
|
|
10732
|
+
};
|
|
10733
|
+
// Internal state
|
|
10734
|
+
internalActiveIndex = signal(0, ...(ngDevMode ? [{ debugName: "internalActiveIndex" }] : []));
|
|
10735
|
+
isPaused = signal(false, ...(ngDevMode ? [{ debugName: "isPaused" }] : []));
|
|
10736
|
+
isTransitioning = signal(false, ...(ngDevMode ? [{ debugName: "isTransitioning" }] : []));
|
|
10737
|
+
autoplayTimer = null;
|
|
10738
|
+
startX = 0;
|
|
10739
|
+
startY = 0;
|
|
10740
|
+
isDragging = false;
|
|
10741
|
+
constructor() {
|
|
10742
|
+
// Sync external activeIndex with internal
|
|
10743
|
+
effect(() => {
|
|
10744
|
+
const extIndex = this.activeIndex();
|
|
10745
|
+
const totalSlides = this.slides().length;
|
|
10746
|
+
if (totalSlides > 0 && extIndex >= 0 && extIndex < totalSlides) {
|
|
10747
|
+
this.internalActiveIndex.set(extIndex);
|
|
10748
|
+
}
|
|
10749
|
+
});
|
|
10750
|
+
// Autoplay effect
|
|
10751
|
+
effect(() => {
|
|
10752
|
+
if (this.autoplay() && !this.isPaused()) {
|
|
10753
|
+
this.startAutoplay();
|
|
10754
|
+
}
|
|
10755
|
+
else {
|
|
10756
|
+
this.stopAutoplay();
|
|
10757
|
+
}
|
|
10758
|
+
});
|
|
10759
|
+
}
|
|
10760
|
+
ngAfterViewInit() {
|
|
10761
|
+
// Initialiser l'index actif
|
|
10762
|
+
const initialIndex = this.activeIndex();
|
|
10763
|
+
if (initialIndex >= 0 && initialIndex < this.slides().length) {
|
|
10764
|
+
this.internalActiveIndex.set(initialIndex);
|
|
10765
|
+
}
|
|
10766
|
+
}
|
|
10767
|
+
ngOnDestroy() {
|
|
10768
|
+
this.stopAutoplay();
|
|
10769
|
+
}
|
|
10770
|
+
containerClasses = computed(() => {
|
|
10771
|
+
const classes = ['ds-carousel'];
|
|
10772
|
+
classes.push(`ds-carousel--${this.effect()}`);
|
|
10773
|
+
classes.push(`ds-carousel--dots-${this.dotsPosition()}`);
|
|
10774
|
+
if (this.isTransitioning())
|
|
10775
|
+
classes.push('ds-carousel--transitioning');
|
|
10776
|
+
return classes.join(' ');
|
|
10777
|
+
}, ...(ngDevMode ? [{ debugName: "containerClasses" }] : []));
|
|
10778
|
+
trackStyle = computed(() => {
|
|
10779
|
+
if (this.effect() === 'slide') {
|
|
10780
|
+
const offset = -this.internalActiveIndex() * 100;
|
|
10781
|
+
return { transform: `translateX(${offset}%)` };
|
|
10782
|
+
}
|
|
10783
|
+
return {};
|
|
10784
|
+
}, ...(ngDevMode ? [{ debugName: "trackStyle" }] : []));
|
|
10785
|
+
slideClasses(index) {
|
|
10786
|
+
const classes = ['ds-carousel__slide'];
|
|
10787
|
+
const active = this.internalActiveIndex();
|
|
10788
|
+
if (index === active) {
|
|
10789
|
+
classes.push('ds-carousel__slide--active');
|
|
10790
|
+
}
|
|
10791
|
+
if (this.effect() === 'fade') {
|
|
10792
|
+
classes.push('ds-carousel__slide--fade');
|
|
10793
|
+
}
|
|
10794
|
+
return classes.join(' ');
|
|
10795
|
+
}
|
|
10796
|
+
dotClasses(index) {
|
|
10797
|
+
const classes = ['ds-carousel__dot'];
|
|
10798
|
+
if (index === this.internalActiveIndex()) {
|
|
10799
|
+
classes.push('ds-carousel__dot--active');
|
|
10800
|
+
}
|
|
10801
|
+
return classes.join(' ');
|
|
10802
|
+
}
|
|
10803
|
+
// Public methods
|
|
10804
|
+
next() {
|
|
10805
|
+
const totalSlides = this.slides().length;
|
|
10806
|
+
if (totalSlides === 0)
|
|
10807
|
+
return;
|
|
10808
|
+
const currentIndex = this.internalActiveIndex();
|
|
10809
|
+
let nextIndex = currentIndex + 1;
|
|
10810
|
+
if (nextIndex >= totalSlides) {
|
|
10811
|
+
nextIndex = this.infinite() ? 0 : currentIndex;
|
|
10812
|
+
}
|
|
10813
|
+
if (nextIndex !== currentIndex) {
|
|
10814
|
+
this.goTo(nextIndex);
|
|
10815
|
+
}
|
|
10816
|
+
}
|
|
10817
|
+
prev() {
|
|
10818
|
+
const totalSlides = this.slides().length;
|
|
10819
|
+
if (totalSlides === 0)
|
|
10820
|
+
return;
|
|
10821
|
+
const currentIndex = this.internalActiveIndex();
|
|
10822
|
+
let prevIndex = currentIndex - 1;
|
|
10823
|
+
if (prevIndex < 0) {
|
|
10824
|
+
prevIndex = this.infinite() ? totalSlides - 1 : currentIndex;
|
|
10825
|
+
}
|
|
10826
|
+
if (prevIndex !== currentIndex) {
|
|
10827
|
+
this.goTo(prevIndex);
|
|
10828
|
+
}
|
|
10829
|
+
}
|
|
10830
|
+
goTo(index) {
|
|
10831
|
+
const totalSlides = this.slides().length;
|
|
10832
|
+
if (index < 0 || index >= totalSlides || index === this.internalActiveIndex()) {
|
|
10833
|
+
return;
|
|
10834
|
+
}
|
|
10835
|
+
this.isTransitioning.set(true);
|
|
10836
|
+
this.internalActiveIndex.set(index);
|
|
10837
|
+
const slide = this.slides()[index];
|
|
10838
|
+
this.slideChange.emit({ index, slide });
|
|
10839
|
+
// Reset transitioning flag
|
|
10840
|
+
setTimeout(() => {
|
|
10841
|
+
this.isTransitioning.set(false);
|
|
10842
|
+
}, 300);
|
|
10843
|
+
// Reset autoplay
|
|
10844
|
+
if (this.autoplay()) {
|
|
10845
|
+
this.stopAutoplay();
|
|
10846
|
+
this.startAutoplay();
|
|
10847
|
+
}
|
|
10848
|
+
}
|
|
10849
|
+
pause() {
|
|
10850
|
+
this.isPaused.set(true);
|
|
10851
|
+
this.stopAutoplay();
|
|
10852
|
+
}
|
|
10853
|
+
play() {
|
|
10854
|
+
this.isPaused.set(false);
|
|
10855
|
+
if (this.autoplay()) {
|
|
10856
|
+
this.startAutoplay();
|
|
10857
|
+
}
|
|
10858
|
+
}
|
|
10859
|
+
onMouseEnter() {
|
|
10860
|
+
if (this.pauseOnHover() && this.autoplay()) {
|
|
10861
|
+
this.pause();
|
|
10862
|
+
}
|
|
10863
|
+
}
|
|
10864
|
+
onMouseLeave() {
|
|
10865
|
+
if (this.pauseOnHover() && this.autoplay()) {
|
|
10866
|
+
this.play();
|
|
10867
|
+
}
|
|
10868
|
+
}
|
|
10869
|
+
onKeydown(event) {
|
|
10870
|
+
switch (event.key) {
|
|
10871
|
+
case 'ArrowLeft':
|
|
10872
|
+
event.preventDefault();
|
|
10873
|
+
this.prev();
|
|
10874
|
+
break;
|
|
10875
|
+
case 'ArrowRight':
|
|
10876
|
+
event.preventDefault();
|
|
10877
|
+
this.next();
|
|
10878
|
+
break;
|
|
10879
|
+
case 'Home':
|
|
10880
|
+
event.preventDefault();
|
|
10881
|
+
this.goTo(0);
|
|
10882
|
+
break;
|
|
10883
|
+
case 'End':
|
|
10884
|
+
event.preventDefault();
|
|
10885
|
+
this.goTo(this.slides().length - 1);
|
|
10886
|
+
break;
|
|
10887
|
+
}
|
|
10888
|
+
}
|
|
10889
|
+
// Touch/swipe handlers
|
|
10890
|
+
onTouchStart(event) {
|
|
10891
|
+
this.startX = event.touches[0].clientX;
|
|
10892
|
+
this.startY = event.touches[0].clientY;
|
|
10893
|
+
this.isDragging = false;
|
|
10894
|
+
}
|
|
10895
|
+
onTouchMove(event) {
|
|
10896
|
+
if (!this.isDragging) {
|
|
10897
|
+
const deltaX = Math.abs(event.touches[0].clientX - this.startX);
|
|
10898
|
+
const deltaY = Math.abs(event.touches[0].clientY - this.startY);
|
|
10899
|
+
// Detect horizontal swipe
|
|
10900
|
+
if (deltaX > deltaY && deltaX > 10) {
|
|
10901
|
+
this.isDragging = true;
|
|
10902
|
+
}
|
|
10903
|
+
}
|
|
10904
|
+
}
|
|
10905
|
+
onTouchEnd(event) {
|
|
10906
|
+
if (!this.isDragging)
|
|
10907
|
+
return;
|
|
10908
|
+
const endX = event.changedTouches[0].clientX;
|
|
10909
|
+
const deltaX = endX - this.startX;
|
|
10910
|
+
if (Math.abs(deltaX) > 50) {
|
|
10911
|
+
if (deltaX > 0) {
|
|
10912
|
+
this.prev();
|
|
10913
|
+
}
|
|
10914
|
+
else {
|
|
10915
|
+
this.next();
|
|
10916
|
+
}
|
|
10917
|
+
}
|
|
10918
|
+
this.isDragging = false;
|
|
10919
|
+
}
|
|
10920
|
+
startAutoplay() {
|
|
10921
|
+
this.stopAutoplay();
|
|
10922
|
+
this.autoplayTimer = setInterval(() => {
|
|
10923
|
+
this.next();
|
|
10924
|
+
}, this.autoplaySpeed());
|
|
10925
|
+
}
|
|
10926
|
+
stopAutoplay() {
|
|
10927
|
+
if (this.autoplayTimer) {
|
|
10928
|
+
clearInterval(this.autoplayTimer);
|
|
10929
|
+
this.autoplayTimer = null;
|
|
10930
|
+
}
|
|
10931
|
+
}
|
|
10932
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DsCarousel, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
10933
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: DsCarousel, isStandalone: true, selector: "ds-carousel", inputs: { slides: { classPropertyName: "slides", publicName: "slides", isSignal: true, isRequired: false, transformFunction: null }, autoplay: { classPropertyName: "autoplay", publicName: "autoplay", isSignal: true, isRequired: false, transformFunction: null }, autoplaySpeed: { classPropertyName: "autoplaySpeed", publicName: "autoplaySpeed", isSignal: true, isRequired: false, transformFunction: null }, effect: { classPropertyName: "effect", publicName: "effect", isSignal: true, isRequired: false, transformFunction: null }, dots: { classPropertyName: "dots", publicName: "dots", isSignal: true, isRequired: false, transformFunction: null }, dotsPosition: { classPropertyName: "dotsPosition", publicName: "dotsPosition", isSignal: true, isRequired: false, transformFunction: null }, arrows: { classPropertyName: "arrows", publicName: "arrows", isSignal: true, isRequired: false, transformFunction: null }, infinite: { classPropertyName: "infinite", publicName: "infinite", isSignal: true, isRequired: false, transformFunction: null }, pauseOnHover: { classPropertyName: "pauseOnHover", publicName: "pauseOnHover", isSignal: true, isRequired: false, transformFunction: null }, activeIndex: { classPropertyName: "activeIndex", publicName: "activeIndex", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { slideChange: "slideChange" }, viewQueries: [{ propertyName: "trackElement", first: true, predicate: ["track"], descendants: true }, { propertyName: "slideElements", predicate: ["slideElement"], descendants: true }], ngImport: i0, template: "<div\n [class]=\"containerClasses()\"\n (mouseenter)=\"onMouseEnter()\"\n (mouseleave)=\"onMouseLeave()\"\n (keydown)=\"onKeydown($event)\"\n (touchstart)=\"onTouchStart($event)\"\n (touchmove)=\"onTouchMove($event)\"\n (touchend)=\"onTouchEnd($event)\"\n tabindex=\"0\"\n role=\"region\"\n aria-roledescription=\"carousel\"\n [attr.aria-label]=\"'Carousel with ' + slides().length + ' slides'\"\n>\n <!-- Arrows -->\n @if (arrows() && slides().length > 1) {\n <button\n class=\"ds-carousel__arrow ds-carousel__arrow--left\"\n (click)=\"prev()\"\n [attr.aria-label]=\"'Previous slide'\"\n type=\"button\"\n >\n <fa-icon [icon]=\"icons.left\" />\n </button>\n\n <button\n class=\"ds-carousel__arrow ds-carousel__arrow--right\"\n (click)=\"next()\"\n [attr.aria-label]=\"'Next slide'\"\n type=\"button\"\n >\n <fa-icon [icon]=\"icons.right\" />\n </button>\n }\n\n <!-- Slides container -->\n <div class=\"ds-carousel__container\">\n <div\n class=\"ds-carousel__track\"\n #track\n [ngStyle]=\"trackStyle()\"\n role=\"list\"\n >\n @for (slide of slides(); track slide.id; let i = $index) {\n <div\n class=\"{{ slideClasses(i) }}\"\n #slideElement\n role=\"listitem\"\n [attr.aria-hidden]=\"i !== internalActiveIndex()\"\n [attr.aria-label]=\"'Slide ' + (i + 1) + ' of ' + slides().length\"\n >\n @if (slide.image) {\n <img\n [src]=\"slide.image\"\n [alt]=\"slide.alt || slide.title || 'Slide ' + (i + 1)\"\n class=\"ds-carousel__image\"\n />\n }\n\n @if (slide.title || slide.description) {\n <div class=\"ds-carousel__content\">\n @if (slide.title) {\n <h3 class=\"ds-carousel__title\">{{ slide.title }}</h3>\n }\n @if (slide.description) {\n <p class=\"ds-carousel__description\">{{ slide.description }}</p>\n }\n </div>\n }\n\n <!-- Content projection for custom slides -->\n <ng-content select=\"[carousel-slide]\" />\n </div>\n }\n </div>\n </div>\n\n <!-- Dots -->\n @if (dots() && slides().length > 1) {\n <div\n class=\"ds-carousel__dots\"\n role=\"tablist\"\n [attr.aria-label]=\"'Carousel navigation'\"\n >\n @for (slide of slides(); track slide.id; let i = $index) {\n <button\n type=\"button\"\n [class]=\"dotClasses(i)\"\n (click)=\"goTo(i)\"\n role=\"tab\"\n [attr.aria-selected]=\"i === internalActiveIndex()\"\n [attr.aria-label]=\"'Go to slide ' + (i + 1)\"\n [attr.aria-controls]=\"'carousel-slide-' + i\"\n >\n <span class=\"ds-carousel__dot-inner\"></span>\n </button>\n }\n </div>\n }\n</div>\n", styles: [".ds-carousel{position:relative;width:100%;overflow:hidden;background-color:var(--carousel-bg, var(--gray-50));border-radius:var(--carousel-radius, var(--radius-2));outline:none}.ds-carousel__container{position:relative;width:100%;height:400px;overflow:hidden}.ds-carousel__track{display:flex;height:100%;transition:transform .3s ease-in-out}.ds-carousel__slide{position:relative;flex:0 0 100%;width:100%;height:100%;display:flex;align-items:center;justify-content:center;opacity:1;transition:opacity .3s ease-in-out}.ds-carousel__slide--fade{position:absolute;top:0;left:0;opacity:0;transition:opacity .5s ease-in-out}.ds-carousel__slide--fade.ds-carousel__slide--active{opacity:1;z-index:1}.ds-carousel__image{width:100%;height:100%;object-fit:cover;display:block}.ds-carousel__content{position:absolute;bottom:0;left:0;right:0;padding:var(--carousel-content-padding, var(--space-6));background:var(--carousel-content-bg, linear-gradient(to top, rgba(0, 0, 0, .7), transparent));color:var(--carousel-content-text, var(--white))}.ds-carousel__title{margin:0 0 var(--space-2) 0;font-size:var(--carousel-title-size, var(--font-size-5));font-weight:var(--font-weight-bold, 700);line-height:1.2}.ds-carousel__description{margin:0;font-size:var(--carousel-description-size, var(--font-size-3));line-height:1.5;opacity:.95}.ds-carousel__arrow{position:absolute;top:50%;transform:translateY(-50%);z-index:10;display:flex;align-items:center;justify-content:center;width:var(--carousel-arrow-size, 40px);height:var(--carousel-arrow-size, 40px);padding:0;background-color:var(--carousel-arrow-bg, rgba(255, 255, 255, .9));color:var(--carousel-arrow-color, var(--gray-800));border:none;border-radius:var(--carousel-arrow-radius, 50%);cursor:pointer;transition:all .2s ease;box-shadow:var(--carousel-arrow-shadow, var(--shadow-md))}.ds-carousel__arrow:hover{background-color:var(--carousel-arrow-bg-hover, var(--white));color:var(--carousel-arrow-color-hover, var(--color-primary));transform:translateY(-50%) scale(1.1)}.ds-carousel__arrow:active{transform:translateY(-50%) scale(.95)}.ds-carousel__arrow:focus-visible{outline:2px solid var(--carousel-arrow-focus, var(--color-primary));outline-offset:2px}.ds-carousel__arrow--left{left:var(--carousel-arrow-offset, var(--space-4))}.ds-carousel__arrow--right{right:var(--carousel-arrow-offset, var(--space-4))}.ds-carousel__arrow fa-icon{font-size:var(--carousel-arrow-icon-size, var(--font-size-4))}.ds-carousel__dots{position:absolute;z-index:10;display:flex;gap:var(--carousel-dots-gap, var(--space-2));padding:var(--carousel-dots-padding, var(--space-4))}.ds-carousel--dots-bottom .ds-carousel__dots{bottom:0;left:50%;transform:translate(-50%);flex-direction:row}.ds-carousel--dots-top .ds-carousel__dots{top:0;left:50%;transform:translate(-50%);flex-direction:row}.ds-carousel--dots-left .ds-carousel__dots{top:50%;left:0;transform:translateY(-50%);flex-direction:column}.ds-carousel--dots-right .ds-carousel__dots{top:50%;right:0;transform:translateY(-50%);flex-direction:column}.ds-carousel__dot{padding:0;border:none;background:transparent;cursor:pointer;transition:all .3s ease}.ds-carousel__dot:focus-visible{outline:2px solid var(--carousel-dot-focus, var(--color-primary));outline-offset:2px;border-radius:50%}.ds-carousel__dot-inner{display:block;width:var(--carousel-dot-size, 10px);height:var(--carousel-dot-size, 10px);background-color:var(--carousel-dot-bg, rgba(255, 255, 255, .5));border-radius:50%;transition:all .3s ease}.ds-carousel__dot--active .ds-carousel__dot-inner{background-color:var(--carousel-dot-bg-active, var(--white));width:var(--carousel-dot-size-active, 12px);height:var(--carousel-dot-size-active, 12px)}.ds-carousel__dot:hover .ds-carousel__dot-inner{background-color:var(--carousel-dot-bg-hover, rgba(255, 255, 255, .8));transform:scale(1.2)}.ds-carousel--fade .ds-carousel__track{position:relative}.ds-carousel--fade .ds-carousel__slide{position:absolute;top:0;left:0}.ds-carousel--transitioning{-webkit-user-select:none;user-select:none}@media (max-width: 768px){.ds-carousel__container{height:300px}.ds-carousel__content{padding:var(--space-4)}.ds-carousel__title{font-size:var(--font-size-4)}.ds-carousel__description{font-size:var(--font-size-2)}.ds-carousel__arrow{width:32px;height:32px}.ds-carousel__arrow fa-icon{font-size:var(--font-size-3)}.ds-carousel__arrow--left,.ds-carousel__arrow--right{--carousel-arrow-offset: var(--space-2)}}@media (max-width: 480px){.ds-carousel__container{height:250px}.ds-carousel__arrow{width:28px;height:28px}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: FontAwesomeModule }, { kind: "component", type: i1$1.FaIconComponent, selector: "fa-icon", inputs: ["icon", "title", "animation", "mask", "flip", "size", "pull", "border", "inverse", "symbol", "rotate", "fixedWidth", "transform", "a11yRole"], outputs: ["iconChange", "titleChange", "animationChange", "maskChange", "flipChange", "sizeChange", "pullChange", "borderChange", "inverseChange", "symbolChange", "rotateChange", "fixedWidthChange", "transformChange", "a11yRoleChange"] }] });
|
|
10934
|
+
}
|
|
10935
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DsCarousel, decorators: [{
|
|
10936
|
+
type: Component,
|
|
10937
|
+
args: [{ selector: 'ds-carousel', imports: [CommonModule, FontAwesomeModule], template: "<div\n [class]=\"containerClasses()\"\n (mouseenter)=\"onMouseEnter()\"\n (mouseleave)=\"onMouseLeave()\"\n (keydown)=\"onKeydown($event)\"\n (touchstart)=\"onTouchStart($event)\"\n (touchmove)=\"onTouchMove($event)\"\n (touchend)=\"onTouchEnd($event)\"\n tabindex=\"0\"\n role=\"region\"\n aria-roledescription=\"carousel\"\n [attr.aria-label]=\"'Carousel with ' + slides().length + ' slides'\"\n>\n <!-- Arrows -->\n @if (arrows() && slides().length > 1) {\n <button\n class=\"ds-carousel__arrow ds-carousel__arrow--left\"\n (click)=\"prev()\"\n [attr.aria-label]=\"'Previous slide'\"\n type=\"button\"\n >\n <fa-icon [icon]=\"icons.left\" />\n </button>\n\n <button\n class=\"ds-carousel__arrow ds-carousel__arrow--right\"\n (click)=\"next()\"\n [attr.aria-label]=\"'Next slide'\"\n type=\"button\"\n >\n <fa-icon [icon]=\"icons.right\" />\n </button>\n }\n\n <!-- Slides container -->\n <div class=\"ds-carousel__container\">\n <div\n class=\"ds-carousel__track\"\n #track\n [ngStyle]=\"trackStyle()\"\n role=\"list\"\n >\n @for (slide of slides(); track slide.id; let i = $index) {\n <div\n class=\"{{ slideClasses(i) }}\"\n #slideElement\n role=\"listitem\"\n [attr.aria-hidden]=\"i !== internalActiveIndex()\"\n [attr.aria-label]=\"'Slide ' + (i + 1) + ' of ' + slides().length\"\n >\n @if (slide.image) {\n <img\n [src]=\"slide.image\"\n [alt]=\"slide.alt || slide.title || 'Slide ' + (i + 1)\"\n class=\"ds-carousel__image\"\n />\n }\n\n @if (slide.title || slide.description) {\n <div class=\"ds-carousel__content\">\n @if (slide.title) {\n <h3 class=\"ds-carousel__title\">{{ slide.title }}</h3>\n }\n @if (slide.description) {\n <p class=\"ds-carousel__description\">{{ slide.description }}</p>\n }\n </div>\n }\n\n <!-- Content projection for custom slides -->\n <ng-content select=\"[carousel-slide]\" />\n </div>\n }\n </div>\n </div>\n\n <!-- Dots -->\n @if (dots() && slides().length > 1) {\n <div\n class=\"ds-carousel__dots\"\n role=\"tablist\"\n [attr.aria-label]=\"'Carousel navigation'\"\n >\n @for (slide of slides(); track slide.id; let i = $index) {\n <button\n type=\"button\"\n [class]=\"dotClasses(i)\"\n (click)=\"goTo(i)\"\n role=\"tab\"\n [attr.aria-selected]=\"i === internalActiveIndex()\"\n [attr.aria-label]=\"'Go to slide ' + (i + 1)\"\n [attr.aria-controls]=\"'carousel-slide-' + i\"\n >\n <span class=\"ds-carousel__dot-inner\"></span>\n </button>\n }\n </div>\n }\n</div>\n", styles: [".ds-carousel{position:relative;width:100%;overflow:hidden;background-color:var(--carousel-bg, var(--gray-50));border-radius:var(--carousel-radius, var(--radius-2));outline:none}.ds-carousel__container{position:relative;width:100%;height:400px;overflow:hidden}.ds-carousel__track{display:flex;height:100%;transition:transform .3s ease-in-out}.ds-carousel__slide{position:relative;flex:0 0 100%;width:100%;height:100%;display:flex;align-items:center;justify-content:center;opacity:1;transition:opacity .3s ease-in-out}.ds-carousel__slide--fade{position:absolute;top:0;left:0;opacity:0;transition:opacity .5s ease-in-out}.ds-carousel__slide--fade.ds-carousel__slide--active{opacity:1;z-index:1}.ds-carousel__image{width:100%;height:100%;object-fit:cover;display:block}.ds-carousel__content{position:absolute;bottom:0;left:0;right:0;padding:var(--carousel-content-padding, var(--space-6));background:var(--carousel-content-bg, linear-gradient(to top, rgba(0, 0, 0, .7), transparent));color:var(--carousel-content-text, var(--white))}.ds-carousel__title{margin:0 0 var(--space-2) 0;font-size:var(--carousel-title-size, var(--font-size-5));font-weight:var(--font-weight-bold, 700);line-height:1.2}.ds-carousel__description{margin:0;font-size:var(--carousel-description-size, var(--font-size-3));line-height:1.5;opacity:.95}.ds-carousel__arrow{position:absolute;top:50%;transform:translateY(-50%);z-index:10;display:flex;align-items:center;justify-content:center;width:var(--carousel-arrow-size, 40px);height:var(--carousel-arrow-size, 40px);padding:0;background-color:var(--carousel-arrow-bg, rgba(255, 255, 255, .9));color:var(--carousel-arrow-color, var(--gray-800));border:none;border-radius:var(--carousel-arrow-radius, 50%);cursor:pointer;transition:all .2s ease;box-shadow:var(--carousel-arrow-shadow, var(--shadow-md))}.ds-carousel__arrow:hover{background-color:var(--carousel-arrow-bg-hover, var(--white));color:var(--carousel-arrow-color-hover, var(--color-primary));transform:translateY(-50%) scale(1.1)}.ds-carousel__arrow:active{transform:translateY(-50%) scale(.95)}.ds-carousel__arrow:focus-visible{outline:2px solid var(--carousel-arrow-focus, var(--color-primary));outline-offset:2px}.ds-carousel__arrow--left{left:var(--carousel-arrow-offset, var(--space-4))}.ds-carousel__arrow--right{right:var(--carousel-arrow-offset, var(--space-4))}.ds-carousel__arrow fa-icon{font-size:var(--carousel-arrow-icon-size, var(--font-size-4))}.ds-carousel__dots{position:absolute;z-index:10;display:flex;gap:var(--carousel-dots-gap, var(--space-2));padding:var(--carousel-dots-padding, var(--space-4))}.ds-carousel--dots-bottom .ds-carousel__dots{bottom:0;left:50%;transform:translate(-50%);flex-direction:row}.ds-carousel--dots-top .ds-carousel__dots{top:0;left:50%;transform:translate(-50%);flex-direction:row}.ds-carousel--dots-left .ds-carousel__dots{top:50%;left:0;transform:translateY(-50%);flex-direction:column}.ds-carousel--dots-right .ds-carousel__dots{top:50%;right:0;transform:translateY(-50%);flex-direction:column}.ds-carousel__dot{padding:0;border:none;background:transparent;cursor:pointer;transition:all .3s ease}.ds-carousel__dot:focus-visible{outline:2px solid var(--carousel-dot-focus, var(--color-primary));outline-offset:2px;border-radius:50%}.ds-carousel__dot-inner{display:block;width:var(--carousel-dot-size, 10px);height:var(--carousel-dot-size, 10px);background-color:var(--carousel-dot-bg, rgba(255, 255, 255, .5));border-radius:50%;transition:all .3s ease}.ds-carousel__dot--active .ds-carousel__dot-inner{background-color:var(--carousel-dot-bg-active, var(--white));width:var(--carousel-dot-size-active, 12px);height:var(--carousel-dot-size-active, 12px)}.ds-carousel__dot:hover .ds-carousel__dot-inner{background-color:var(--carousel-dot-bg-hover, rgba(255, 255, 255, .8));transform:scale(1.2)}.ds-carousel--fade .ds-carousel__track{position:relative}.ds-carousel--fade .ds-carousel__slide{position:absolute;top:0;left:0}.ds-carousel--transitioning{-webkit-user-select:none;user-select:none}@media (max-width: 768px){.ds-carousel__container{height:300px}.ds-carousel__content{padding:var(--space-4)}.ds-carousel__title{font-size:var(--font-size-4)}.ds-carousel__description{font-size:var(--font-size-2)}.ds-carousel__arrow{width:32px;height:32px}.ds-carousel__arrow fa-icon{font-size:var(--font-size-3)}.ds-carousel__arrow--left,.ds-carousel__arrow--right{--carousel-arrow-offset: var(--space-2)}}@media (max-width: 480px){.ds-carousel__container{height:250px}.ds-carousel__arrow{width:28px;height:28px}}\n"] }]
|
|
10938
|
+
}], ctorParameters: () => [], propDecorators: { slides: [{ type: i0.Input, args: [{ isSignal: true, alias: "slides", required: false }] }], autoplay: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoplay", required: false }] }], autoplaySpeed: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoplaySpeed", required: false }] }], effect: [{ type: i0.Input, args: [{ isSignal: true, alias: "effect", required: false }] }], dots: [{ type: i0.Input, args: [{ isSignal: true, alias: "dots", required: false }] }], dotsPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "dotsPosition", required: false }] }], arrows: [{ type: i0.Input, args: [{ isSignal: true, alias: "arrows", required: false }] }], infinite: [{ type: i0.Input, args: [{ isSignal: true, alias: "infinite", required: false }] }], pauseOnHover: [{ type: i0.Input, args: [{ isSignal: true, alias: "pauseOnHover", required: false }] }], activeIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeIndex", required: false }] }], slideChange: [{ type: i0.Output, args: ["slideChange"] }], trackElement: [{
|
|
10939
|
+
type: ViewChild,
|
|
10940
|
+
args: ['track', { static: false }]
|
|
10941
|
+
}], slideElements: [{
|
|
10942
|
+
type: ViewChildren,
|
|
10943
|
+
args: ['slideElement']
|
|
10944
|
+
}] } });
|
|
10945
|
+
|
|
10946
|
+
class DsNotificationService {
|
|
10947
|
+
notifications = signal([], ...(ngDevMode ? [{ debugName: "notifications" }] : []));
|
|
10948
|
+
nextId = 1;
|
|
10949
|
+
notifications$ = this.notifications.asReadonly();
|
|
10950
|
+
open(config) {
|
|
10951
|
+
const id = config.id || `notification-${this.nextId++}`;
|
|
10952
|
+
const notification = {
|
|
10953
|
+
...config,
|
|
10954
|
+
id,
|
|
10955
|
+
timestamp: Date.now(),
|
|
10956
|
+
closable: config.closable ?? true,
|
|
10957
|
+
duration: config.duration ?? 4500
|
|
10958
|
+
};
|
|
10959
|
+
// Set default icons based on type
|
|
10960
|
+
if (!notification.icon && notification.type) {
|
|
10961
|
+
notification.icon = this.getDefaultIcon(notification.type);
|
|
10962
|
+
}
|
|
10963
|
+
this.notifications.update(items => [...items, notification]);
|
|
10964
|
+
// Auto-dismiss if duration > 0
|
|
10965
|
+
if (notification.duration && notification.duration > 0) {
|
|
10966
|
+
setTimeout(() => {
|
|
10967
|
+
this.close(id);
|
|
10968
|
+
}, notification.duration);
|
|
10969
|
+
}
|
|
10970
|
+
return id;
|
|
10971
|
+
}
|
|
10972
|
+
info(title, message, config) {
|
|
10973
|
+
return this.open({
|
|
10974
|
+
...config,
|
|
10975
|
+
title,
|
|
10976
|
+
message,
|
|
10977
|
+
type: 'info'
|
|
10978
|
+
});
|
|
10979
|
+
}
|
|
10980
|
+
success(title, message, config) {
|
|
10981
|
+
return this.open({
|
|
10982
|
+
...config,
|
|
10983
|
+
title,
|
|
10984
|
+
message,
|
|
10985
|
+
type: 'success'
|
|
10986
|
+
});
|
|
10987
|
+
}
|
|
10988
|
+
warning(title, message, config) {
|
|
10989
|
+
return this.open({
|
|
10990
|
+
...config,
|
|
10991
|
+
title,
|
|
10992
|
+
message,
|
|
10993
|
+
type: 'warning'
|
|
10994
|
+
});
|
|
10995
|
+
}
|
|
10996
|
+
error(title, message, config) {
|
|
10997
|
+
return this.open({
|
|
10998
|
+
...config,
|
|
10999
|
+
title,
|
|
11000
|
+
message,
|
|
11001
|
+
type: 'error'
|
|
11002
|
+
});
|
|
11003
|
+
}
|
|
11004
|
+
close(id) {
|
|
11005
|
+
this.notifications.update(items => items.filter(item => item.id !== id));
|
|
11006
|
+
}
|
|
11007
|
+
closeAll() {
|
|
11008
|
+
this.notifications.set([]);
|
|
11009
|
+
}
|
|
11010
|
+
getDefaultIcon(type) {
|
|
11011
|
+
switch (type) {
|
|
11012
|
+
case 'info':
|
|
11013
|
+
return faCircleInfo;
|
|
11014
|
+
case 'success':
|
|
11015
|
+
return faCircleCheck;
|
|
11016
|
+
case 'warning':
|
|
11017
|
+
return faTriangleExclamation;
|
|
11018
|
+
case 'error':
|
|
11019
|
+
return faCircleXmark;
|
|
11020
|
+
default:
|
|
11021
|
+
return faCircleInfo;
|
|
11022
|
+
}
|
|
11023
|
+
}
|
|
11024
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DsNotificationService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
11025
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DsNotificationService, providedIn: 'root' });
|
|
11026
|
+
}
|
|
11027
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DsNotificationService, decorators: [{
|
|
11028
|
+
type: Injectable,
|
|
11029
|
+
args: [{
|
|
11030
|
+
providedIn: 'root'
|
|
11031
|
+
}]
|
|
11032
|
+
}] });
|
|
11033
|
+
|
|
11034
|
+
class DsNotificationItemComponent {
|
|
11035
|
+
notification = input.required(...(ngDevMode ? [{ debugName: "notification" }] : []));
|
|
11036
|
+
closeClick = output();
|
|
11037
|
+
actionClick = output();
|
|
11038
|
+
closeIcon = faXmark;
|
|
11039
|
+
notificationClasses = () => {
|
|
11040
|
+
const classes = ['ds-notification'];
|
|
11041
|
+
const notification = this.notification();
|
|
11042
|
+
if (notification.type) {
|
|
11043
|
+
classes.push(`ds-notification--${notification.type}`);
|
|
11044
|
+
}
|
|
11045
|
+
return classes;
|
|
11046
|
+
};
|
|
11047
|
+
onClose() {
|
|
11048
|
+
this.closeClick.emit(this.notification().id);
|
|
11049
|
+
}
|
|
11050
|
+
onActionClick(index) {
|
|
11051
|
+
const notification = this.notification();
|
|
11052
|
+
if (notification.actions && notification.actions[index]) {
|
|
11053
|
+
notification.actions[index].handler();
|
|
11054
|
+
this.actionClick.emit({ id: notification.id, actionIndex: index });
|
|
11055
|
+
}
|
|
11056
|
+
}
|
|
11057
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DsNotificationItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
11058
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: DsNotificationItemComponent, isStandalone: true, selector: "ds-notification-item", inputs: { notification: { classPropertyName: "notification", publicName: "notification", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { closeClick: "closeClick", actionClick: "actionClick" }, ngImport: i0, template: "<div\n [class]=\"notificationClasses().join(' ')\"\n role=\"alert\"\n [attr.aria-live]=\"notification().type === 'error' ? 'assertive' : 'polite'\"\n [attr.aria-atomic]=\"true\"\n>\n <div class=\"ds-notification__header\">\n <div class=\"ds-notification__icon-title\">\n @if (notification().icon) {\n <fa-icon\n [icon]=\"notification().icon\"\n class=\"ds-notification__icon\"\n [attr.aria-hidden]=\"true\"\n />\n }\n <h4 class=\"ds-notification__title\">{{ notification().title }}</h4>\n </div>\n @if (notification().closable) {\n <button\n type=\"button\"\n class=\"ds-notification__close\"\n (click)=\"onClose()\"\n [attr.aria-label]=\"'Fermer la notification'\"\n >\n <fa-icon [icon]=\"closeIcon\" />\n </button>\n }\n </div>\n\n <div class=\"ds-notification__body\">\n <p class=\"ds-notification__message\">{{ notification().message }}</p>\n </div>\n\n @if (notification().actions && notification().actions!.length > 0) {\n <div class=\"ds-notification__actions\">\n @for (action of notification().actions!; track $index) {\n <button\n type=\"button\"\n class=\"ds-notification__action ds-notification__action--{{ action.variant || 'secondary' }}\"\n (click)=\"onActionClick($index)\"\n >\n {{ action.label }}\n </button>\n }\n </div>\n }\n</div>\n", styles: [".ds-notification-container{position:fixed;z-index:var(--notification-z-index, 1050);pointer-events:none;display:flex;flex-direction:column;gap:var(--notification-gap, var(--space-3, .75rem));max-width:var(--notification-max-width, 384px);width:100%}.ds-notification-container--topRight{top:var(--notification-offset-y, var(--space-6, 1.5rem));right:var(--notification-offset-x, var(--space-6, 1.5rem))}.ds-notification-container--topLeft{top:var(--notification-offset-y, var(--space-6, 1.5rem));left:var(--notification-offset-x, var(--space-6, 1.5rem))}.ds-notification-container--bottomRight{bottom:var(--notification-offset-y, var(--space-6, 1.5rem));right:var(--notification-offset-x, var(--space-6, 1.5rem))}.ds-notification-container--bottomLeft{bottom:var(--notification-offset-y, var(--space-6, 1.5rem));left:var(--notification-offset-x, var(--space-6, 1.5rem))}.ds-notification-wrapper{pointer-events:auto;animation:var(--notification-animation-in, slideInRight .3s ease-out)}@keyframes slideInRight{0%{transform:translate(100%);opacity:0}to{transform:translate(0);opacity:1}}@keyframes slideInLeft{0%{transform:translate(-100%);opacity:0}to{transform:translate(0);opacity:1}}.ds-notification{background:var(--notification-bg, var(--color-white, #ffffff));border:var(--notification-border-width, 1px) solid var(--notification-border-color, var(--gray-300, #d1d5db));border-radius:var(--notification-radius, var(--radius-2, .5rem));box-shadow:var(--notification-shadow, var(--shadow-lg, 0 10px 15px -3px rgba(0, 0, 0, .1)));padding:var(--notification-padding, var(--space-4, 1rem));display:flex;flex-direction:column;gap:var(--notification-gap-inner, var(--space-3, .75rem));width:100%}.ds-notification__header{display:flex;justify-content:space-between;align-items:flex-start;gap:var(--space-2, .5rem)}.ds-notification__icon-title{display:flex;align-items:center;gap:var(--notification-icon-gap, var(--space-2, .5rem));flex:1}.ds-notification__icon{font-size:var(--notification-icon-size, 1.25rem);flex-shrink:0;color:var(--notification-icon-color, var(--gray-500, #6b7280))}.ds-notification__title{margin:0;font-size:var(--notification-title-size, var(--font-size-base, 1rem));font-weight:var(--notification-title-weight, 600);color:var(--notification-title-color, var(--gray-900, #111827));line-height:1.4}.ds-notification__close{background:transparent;border:none;padding:var(--space-1, .25rem);cursor:pointer;color:var(--notification-close-color, var(--gray-400, #9ca3af));line-height:1;transition:color .2s ease;flex-shrink:0}.ds-notification__close:hover{color:var(--notification-close-hover-color, var(--gray-600, #4b5563))}.ds-notification__close:focus-visible{outline:2px solid var(--color-primary, #3b82f6);outline-offset:2px;border-radius:var(--radius-1, .25rem)}.ds-notification__body{padding-left:calc(var(--notification-icon-size, 1.25rem) + var(--notification-icon-gap, var(--space-2, .5rem)))}.ds-notification__message{margin:0;font-size:var(--notification-message-size, var(--font-size-sm, .875rem));color:var(--notification-message-color, var(--gray-600, #4b5563));line-height:1.5}.ds-notification__actions{display:flex;gap:var(--space-2, .5rem);padding-left:calc(var(--notification-icon-size, 1.25rem) + var(--notification-icon-gap, var(--space-2, .5rem)))}.ds-notification__action{padding:var(--space-2, .5rem) var(--space-3, .75rem);font-size:var(--font-size-sm, .875rem);font-weight:500;border-radius:var(--radius-1, .25rem);cursor:pointer;transition:all .2s ease;border:1px solid transparent}.ds-notification__action--primary{background:var(--color-primary, #3b82f6);color:var(--color-white, #ffffff);border-color:var(--color-primary, #3b82f6)}.ds-notification__action--primary:hover{background:var(--primary-600, #2563eb);border-color:var(--primary-600, #2563eb)}.ds-notification__action--secondary{background:var(--gray-100, #f3f4f6);color:var(--gray-700, #374151);border-color:var(--gray-300, #d1d5db)}.ds-notification__action--secondary:hover{background:var(--gray-200, #e5e7eb)}.ds-notification__action--ghost{background:transparent;color:var(--color-primary, #3b82f6)}.ds-notification__action--ghost:hover{background:var(--primary-50, #eff6ff)}.ds-notification__action:focus-visible{outline:2px solid var(--color-primary, #3b82f6);outline-offset:2px}.ds-notification--info .ds-notification__icon{color:var(--notification-info-icon, var(--color-primary, #3b82f6))}.ds-notification--success .ds-notification__icon{color:var(--notification-success-icon, var(--success, #10b981))}.ds-notification--warning .ds-notification__icon{color:var(--notification-warning-icon, var(--warning, #f59e0b))}.ds-notification--error .ds-notification__icon{color:var(--notification-error-icon, var(--error, #ef4444))}.ds-notification-container--topLeft .ds-notification-wrapper,.ds-notification-container--bottomLeft .ds-notification-wrapper{animation:slideInLeft .3s ease-out}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FontAwesomeModule }, { kind: "component", type: i1$1.FaIconComponent, selector: "fa-icon", inputs: ["icon", "title", "animation", "mask", "flip", "size", "pull", "border", "inverse", "symbol", "rotate", "fixedWidth", "transform", "a11yRole"], outputs: ["iconChange", "titleChange", "animationChange", "maskChange", "flipChange", "sizeChange", "pullChange", "borderChange", "inverseChange", "symbolChange", "rotateChange", "fixedWidthChange", "transformChange", "a11yRoleChange"] }] });
|
|
11059
|
+
}
|
|
11060
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DsNotificationItemComponent, decorators: [{
|
|
11061
|
+
type: Component,
|
|
11062
|
+
args: [{ selector: 'ds-notification-item', standalone: true, imports: [CommonModule, FontAwesomeModule], template: "<div\n [class]=\"notificationClasses().join(' ')\"\n role=\"alert\"\n [attr.aria-live]=\"notification().type === 'error' ? 'assertive' : 'polite'\"\n [attr.aria-atomic]=\"true\"\n>\n <div class=\"ds-notification__header\">\n <div class=\"ds-notification__icon-title\">\n @if (notification().icon) {\n <fa-icon\n [icon]=\"notification().icon\"\n class=\"ds-notification__icon\"\n [attr.aria-hidden]=\"true\"\n />\n }\n <h4 class=\"ds-notification__title\">{{ notification().title }}</h4>\n </div>\n @if (notification().closable) {\n <button\n type=\"button\"\n class=\"ds-notification__close\"\n (click)=\"onClose()\"\n [attr.aria-label]=\"'Fermer la notification'\"\n >\n <fa-icon [icon]=\"closeIcon\" />\n </button>\n }\n </div>\n\n <div class=\"ds-notification__body\">\n <p class=\"ds-notification__message\">{{ notification().message }}</p>\n </div>\n\n @if (notification().actions && notification().actions!.length > 0) {\n <div class=\"ds-notification__actions\">\n @for (action of notification().actions!; track $index) {\n <button\n type=\"button\"\n class=\"ds-notification__action ds-notification__action--{{ action.variant || 'secondary' }}\"\n (click)=\"onActionClick($index)\"\n >\n {{ action.label }}\n </button>\n }\n </div>\n }\n</div>\n", styles: [".ds-notification-container{position:fixed;z-index:var(--notification-z-index, 1050);pointer-events:none;display:flex;flex-direction:column;gap:var(--notification-gap, var(--space-3, .75rem));max-width:var(--notification-max-width, 384px);width:100%}.ds-notification-container--topRight{top:var(--notification-offset-y, var(--space-6, 1.5rem));right:var(--notification-offset-x, var(--space-6, 1.5rem))}.ds-notification-container--topLeft{top:var(--notification-offset-y, var(--space-6, 1.5rem));left:var(--notification-offset-x, var(--space-6, 1.5rem))}.ds-notification-container--bottomRight{bottom:var(--notification-offset-y, var(--space-6, 1.5rem));right:var(--notification-offset-x, var(--space-6, 1.5rem))}.ds-notification-container--bottomLeft{bottom:var(--notification-offset-y, var(--space-6, 1.5rem));left:var(--notification-offset-x, var(--space-6, 1.5rem))}.ds-notification-wrapper{pointer-events:auto;animation:var(--notification-animation-in, slideInRight .3s ease-out)}@keyframes slideInRight{0%{transform:translate(100%);opacity:0}to{transform:translate(0);opacity:1}}@keyframes slideInLeft{0%{transform:translate(-100%);opacity:0}to{transform:translate(0);opacity:1}}.ds-notification{background:var(--notification-bg, var(--color-white, #ffffff));border:var(--notification-border-width, 1px) solid var(--notification-border-color, var(--gray-300, #d1d5db));border-radius:var(--notification-radius, var(--radius-2, .5rem));box-shadow:var(--notification-shadow, var(--shadow-lg, 0 10px 15px -3px rgba(0, 0, 0, .1)));padding:var(--notification-padding, var(--space-4, 1rem));display:flex;flex-direction:column;gap:var(--notification-gap-inner, var(--space-3, .75rem));width:100%}.ds-notification__header{display:flex;justify-content:space-between;align-items:flex-start;gap:var(--space-2, .5rem)}.ds-notification__icon-title{display:flex;align-items:center;gap:var(--notification-icon-gap, var(--space-2, .5rem));flex:1}.ds-notification__icon{font-size:var(--notification-icon-size, 1.25rem);flex-shrink:0;color:var(--notification-icon-color, var(--gray-500, #6b7280))}.ds-notification__title{margin:0;font-size:var(--notification-title-size, var(--font-size-base, 1rem));font-weight:var(--notification-title-weight, 600);color:var(--notification-title-color, var(--gray-900, #111827));line-height:1.4}.ds-notification__close{background:transparent;border:none;padding:var(--space-1, .25rem);cursor:pointer;color:var(--notification-close-color, var(--gray-400, #9ca3af));line-height:1;transition:color .2s ease;flex-shrink:0}.ds-notification__close:hover{color:var(--notification-close-hover-color, var(--gray-600, #4b5563))}.ds-notification__close:focus-visible{outline:2px solid var(--color-primary, #3b82f6);outline-offset:2px;border-radius:var(--radius-1, .25rem)}.ds-notification__body{padding-left:calc(var(--notification-icon-size, 1.25rem) + var(--notification-icon-gap, var(--space-2, .5rem)))}.ds-notification__message{margin:0;font-size:var(--notification-message-size, var(--font-size-sm, .875rem));color:var(--notification-message-color, var(--gray-600, #4b5563));line-height:1.5}.ds-notification__actions{display:flex;gap:var(--space-2, .5rem);padding-left:calc(var(--notification-icon-size, 1.25rem) + var(--notification-icon-gap, var(--space-2, .5rem)))}.ds-notification__action{padding:var(--space-2, .5rem) var(--space-3, .75rem);font-size:var(--font-size-sm, .875rem);font-weight:500;border-radius:var(--radius-1, .25rem);cursor:pointer;transition:all .2s ease;border:1px solid transparent}.ds-notification__action--primary{background:var(--color-primary, #3b82f6);color:var(--color-white, #ffffff);border-color:var(--color-primary, #3b82f6)}.ds-notification__action--primary:hover{background:var(--primary-600, #2563eb);border-color:var(--primary-600, #2563eb)}.ds-notification__action--secondary{background:var(--gray-100, #f3f4f6);color:var(--gray-700, #374151);border-color:var(--gray-300, #d1d5db)}.ds-notification__action--secondary:hover{background:var(--gray-200, #e5e7eb)}.ds-notification__action--ghost{background:transparent;color:var(--color-primary, #3b82f6)}.ds-notification__action--ghost:hover{background:var(--primary-50, #eff6ff)}.ds-notification__action:focus-visible{outline:2px solid var(--color-primary, #3b82f6);outline-offset:2px}.ds-notification--info .ds-notification__icon{color:var(--notification-info-icon, var(--color-primary, #3b82f6))}.ds-notification--success .ds-notification__icon{color:var(--notification-success-icon, var(--success, #10b981))}.ds-notification--warning .ds-notification__icon{color:var(--notification-warning-icon, var(--warning, #f59e0b))}.ds-notification--error .ds-notification__icon{color:var(--notification-error-icon, var(--error, #ef4444))}.ds-notification-container--topLeft .ds-notification-wrapper,.ds-notification-container--bottomLeft .ds-notification-wrapper{animation:slideInLeft .3s ease-out}\n"] }]
|
|
11063
|
+
}], propDecorators: { notification: [{ type: i0.Input, args: [{ isSignal: true, alias: "notification", required: true }] }], closeClick: [{ type: i0.Output, args: ["closeClick"] }], actionClick: [{ type: i0.Output, args: ["actionClick"] }] } });
|
|
11064
|
+
|
|
11065
|
+
class DsNotificationContainerComponent {
|
|
11066
|
+
notificationService = inject(DsNotificationService);
|
|
11067
|
+
placement = input('topRight', ...(ngDevMode ? [{ debugName: "placement" }] : []));
|
|
11068
|
+
maxStack = input(5, ...(ngDevMode ? [{ debugName: "maxStack" }] : []));
|
|
11069
|
+
notifications = this.notificationService.notifications$;
|
|
11070
|
+
visibleNotifications = computed(() => {
|
|
11071
|
+
const all = this.notifications();
|
|
11072
|
+
const max = this.maxStack();
|
|
11073
|
+
return all.slice(-max);
|
|
11074
|
+
}, ...(ngDevMode ? [{ debugName: "visibleNotifications" }] : []));
|
|
11075
|
+
containerClasses = computed(() => {
|
|
11076
|
+
const classes = ['ds-notification-container'];
|
|
11077
|
+
classes.push(`ds-notification-container--${this.placement()}`);
|
|
11078
|
+
return classes.join(' ');
|
|
11079
|
+
}, ...(ngDevMode ? [{ debugName: "containerClasses" }] : []));
|
|
11080
|
+
onClose(id) {
|
|
11081
|
+
this.notificationService.close(id);
|
|
11082
|
+
}
|
|
11083
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DsNotificationContainerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
11084
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: DsNotificationContainerComponent, isStandalone: true, selector: "ds-notification-container", inputs: { placement: { classPropertyName: "placement", publicName: "placement", isSignal: true, isRequired: false, transformFunction: null }, maxStack: { classPropertyName: "maxStack", publicName: "maxStack", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
|
|
11085
|
+
<div [class]="containerClasses()">
|
|
11086
|
+
@for (notification of visibleNotifications(); track notification.id) {
|
|
11087
|
+
<ds-notification-item
|
|
11088
|
+
[notification]="notification"
|
|
11089
|
+
(closeClick)="onClose($event)"
|
|
11090
|
+
class="ds-notification-wrapper"
|
|
11091
|
+
/>
|
|
11092
|
+
}
|
|
11093
|
+
</div>
|
|
11094
|
+
`, isInline: true, styles: [".ds-notification-container{position:fixed;z-index:var(--notification-z-index, 1050);pointer-events:none;display:flex;flex-direction:column;gap:var(--notification-gap, var(--space-3, .75rem));max-width:var(--notification-max-width, 384px);width:100%}.ds-notification-container--topRight{top:var(--notification-offset-y, var(--space-6, 1.5rem));right:var(--notification-offset-x, var(--space-6, 1.5rem))}.ds-notification-container--topLeft{top:var(--notification-offset-y, var(--space-6, 1.5rem));left:var(--notification-offset-x, var(--space-6, 1.5rem))}.ds-notification-container--bottomRight{bottom:var(--notification-offset-y, var(--space-6, 1.5rem));right:var(--notification-offset-x, var(--space-6, 1.5rem))}.ds-notification-container--bottomLeft{bottom:var(--notification-offset-y, var(--space-6, 1.5rem));left:var(--notification-offset-x, var(--space-6, 1.5rem))}.ds-notification-wrapper{pointer-events:auto;animation:var(--notification-animation-in, slideInRight .3s ease-out)}@keyframes slideInRight{0%{transform:translate(100%);opacity:0}to{transform:translate(0);opacity:1}}@keyframes slideInLeft{0%{transform:translate(-100%);opacity:0}to{transform:translate(0);opacity:1}}.ds-notification{background:var(--notification-bg, var(--color-white, #ffffff));border:var(--notification-border-width, 1px) solid var(--notification-border-color, var(--gray-300, #d1d5db));border-radius:var(--notification-radius, var(--radius-2, .5rem));box-shadow:var(--notification-shadow, var(--shadow-lg, 0 10px 15px -3px rgba(0, 0, 0, .1)));padding:var(--notification-padding, var(--space-4, 1rem));display:flex;flex-direction:column;gap:var(--notification-gap-inner, var(--space-3, .75rem));width:100%}.ds-notification__header{display:flex;justify-content:space-between;align-items:flex-start;gap:var(--space-2, .5rem)}.ds-notification__icon-title{display:flex;align-items:center;gap:var(--notification-icon-gap, var(--space-2, .5rem));flex:1}.ds-notification__icon{font-size:var(--notification-icon-size, 1.25rem);flex-shrink:0;color:var(--notification-icon-color, var(--gray-500, #6b7280))}.ds-notification__title{margin:0;font-size:var(--notification-title-size, var(--font-size-base, 1rem));font-weight:var(--notification-title-weight, 600);color:var(--notification-title-color, var(--gray-900, #111827));line-height:1.4}.ds-notification__close{background:transparent;border:none;padding:var(--space-1, .25rem);cursor:pointer;color:var(--notification-close-color, var(--gray-400, #9ca3af));line-height:1;transition:color .2s ease;flex-shrink:0}.ds-notification__close:hover{color:var(--notification-close-hover-color, var(--gray-600, #4b5563))}.ds-notification__close:focus-visible{outline:2px solid var(--color-primary, #3b82f6);outline-offset:2px;border-radius:var(--radius-1, .25rem)}.ds-notification__body{padding-left:calc(var(--notification-icon-size, 1.25rem) + var(--notification-icon-gap, var(--space-2, .5rem)))}.ds-notification__message{margin:0;font-size:var(--notification-message-size, var(--font-size-sm, .875rem));color:var(--notification-message-color, var(--gray-600, #4b5563));line-height:1.5}.ds-notification__actions{display:flex;gap:var(--space-2, .5rem);padding-left:calc(var(--notification-icon-size, 1.25rem) + var(--notification-icon-gap, var(--space-2, .5rem)))}.ds-notification__action{padding:var(--space-2, .5rem) var(--space-3, .75rem);font-size:var(--font-size-sm, .875rem);font-weight:500;border-radius:var(--radius-1, .25rem);cursor:pointer;transition:all .2s ease;border:1px solid transparent}.ds-notification__action--primary{background:var(--color-primary, #3b82f6);color:var(--color-white, #ffffff);border-color:var(--color-primary, #3b82f6)}.ds-notification__action--primary:hover{background:var(--primary-600, #2563eb);border-color:var(--primary-600, #2563eb)}.ds-notification__action--secondary{background:var(--gray-100, #f3f4f6);color:var(--gray-700, #374151);border-color:var(--gray-300, #d1d5db)}.ds-notification__action--secondary:hover{background:var(--gray-200, #e5e7eb)}.ds-notification__action--ghost{background:transparent;color:var(--color-primary, #3b82f6)}.ds-notification__action--ghost:hover{background:var(--primary-50, #eff6ff)}.ds-notification__action:focus-visible{outline:2px solid var(--color-primary, #3b82f6);outline-offset:2px}.ds-notification--info .ds-notification__icon{color:var(--notification-info-icon, var(--color-primary, #3b82f6))}.ds-notification--success .ds-notification__icon{color:var(--notification-success-icon, var(--success, #10b981))}.ds-notification--warning .ds-notification__icon{color:var(--notification-warning-icon, var(--warning, #f59e0b))}.ds-notification--error .ds-notification__icon{color:var(--notification-error-icon, var(--error, #ef4444))}.ds-notification-container--topLeft .ds-notification-wrapper,.ds-notification-container--bottomLeft .ds-notification-wrapper{animation:slideInLeft .3s ease-out}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: DsNotificationItemComponent, selector: "ds-notification-item", inputs: ["notification"], outputs: ["closeClick", "actionClick"] }] });
|
|
11095
|
+
}
|
|
11096
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DsNotificationContainerComponent, decorators: [{
|
|
11097
|
+
type: Component,
|
|
11098
|
+
args: [{ selector: 'ds-notification-container', standalone: true, imports: [CommonModule, DsNotificationItemComponent], template: `
|
|
11099
|
+
<div [class]="containerClasses()">
|
|
11100
|
+
@for (notification of visibleNotifications(); track notification.id) {
|
|
11101
|
+
<ds-notification-item
|
|
11102
|
+
[notification]="notification"
|
|
11103
|
+
(closeClick)="onClose($event)"
|
|
11104
|
+
class="ds-notification-wrapper"
|
|
11105
|
+
/>
|
|
11106
|
+
}
|
|
11107
|
+
</div>
|
|
11108
|
+
`, styles: [".ds-notification-container{position:fixed;z-index:var(--notification-z-index, 1050);pointer-events:none;display:flex;flex-direction:column;gap:var(--notification-gap, var(--space-3, .75rem));max-width:var(--notification-max-width, 384px);width:100%}.ds-notification-container--topRight{top:var(--notification-offset-y, var(--space-6, 1.5rem));right:var(--notification-offset-x, var(--space-6, 1.5rem))}.ds-notification-container--topLeft{top:var(--notification-offset-y, var(--space-6, 1.5rem));left:var(--notification-offset-x, var(--space-6, 1.5rem))}.ds-notification-container--bottomRight{bottom:var(--notification-offset-y, var(--space-6, 1.5rem));right:var(--notification-offset-x, var(--space-6, 1.5rem))}.ds-notification-container--bottomLeft{bottom:var(--notification-offset-y, var(--space-6, 1.5rem));left:var(--notification-offset-x, var(--space-6, 1.5rem))}.ds-notification-wrapper{pointer-events:auto;animation:var(--notification-animation-in, slideInRight .3s ease-out)}@keyframes slideInRight{0%{transform:translate(100%);opacity:0}to{transform:translate(0);opacity:1}}@keyframes slideInLeft{0%{transform:translate(-100%);opacity:0}to{transform:translate(0);opacity:1}}.ds-notification{background:var(--notification-bg, var(--color-white, #ffffff));border:var(--notification-border-width, 1px) solid var(--notification-border-color, var(--gray-300, #d1d5db));border-radius:var(--notification-radius, var(--radius-2, .5rem));box-shadow:var(--notification-shadow, var(--shadow-lg, 0 10px 15px -3px rgba(0, 0, 0, .1)));padding:var(--notification-padding, var(--space-4, 1rem));display:flex;flex-direction:column;gap:var(--notification-gap-inner, var(--space-3, .75rem));width:100%}.ds-notification__header{display:flex;justify-content:space-between;align-items:flex-start;gap:var(--space-2, .5rem)}.ds-notification__icon-title{display:flex;align-items:center;gap:var(--notification-icon-gap, var(--space-2, .5rem));flex:1}.ds-notification__icon{font-size:var(--notification-icon-size, 1.25rem);flex-shrink:0;color:var(--notification-icon-color, var(--gray-500, #6b7280))}.ds-notification__title{margin:0;font-size:var(--notification-title-size, var(--font-size-base, 1rem));font-weight:var(--notification-title-weight, 600);color:var(--notification-title-color, var(--gray-900, #111827));line-height:1.4}.ds-notification__close{background:transparent;border:none;padding:var(--space-1, .25rem);cursor:pointer;color:var(--notification-close-color, var(--gray-400, #9ca3af));line-height:1;transition:color .2s ease;flex-shrink:0}.ds-notification__close:hover{color:var(--notification-close-hover-color, var(--gray-600, #4b5563))}.ds-notification__close:focus-visible{outline:2px solid var(--color-primary, #3b82f6);outline-offset:2px;border-radius:var(--radius-1, .25rem)}.ds-notification__body{padding-left:calc(var(--notification-icon-size, 1.25rem) + var(--notification-icon-gap, var(--space-2, .5rem)))}.ds-notification__message{margin:0;font-size:var(--notification-message-size, var(--font-size-sm, .875rem));color:var(--notification-message-color, var(--gray-600, #4b5563));line-height:1.5}.ds-notification__actions{display:flex;gap:var(--space-2, .5rem);padding-left:calc(var(--notification-icon-size, 1.25rem) + var(--notification-icon-gap, var(--space-2, .5rem)))}.ds-notification__action{padding:var(--space-2, .5rem) var(--space-3, .75rem);font-size:var(--font-size-sm, .875rem);font-weight:500;border-radius:var(--radius-1, .25rem);cursor:pointer;transition:all .2s ease;border:1px solid transparent}.ds-notification__action--primary{background:var(--color-primary, #3b82f6);color:var(--color-white, #ffffff);border-color:var(--color-primary, #3b82f6)}.ds-notification__action--primary:hover{background:var(--primary-600, #2563eb);border-color:var(--primary-600, #2563eb)}.ds-notification__action--secondary{background:var(--gray-100, #f3f4f6);color:var(--gray-700, #374151);border-color:var(--gray-300, #d1d5db)}.ds-notification__action--secondary:hover{background:var(--gray-200, #e5e7eb)}.ds-notification__action--ghost{background:transparent;color:var(--color-primary, #3b82f6)}.ds-notification__action--ghost:hover{background:var(--primary-50, #eff6ff)}.ds-notification__action:focus-visible{outline:2px solid var(--color-primary, #3b82f6);outline-offset:2px}.ds-notification--info .ds-notification__icon{color:var(--notification-info-icon, var(--color-primary, #3b82f6))}.ds-notification--success .ds-notification__icon{color:var(--notification-success-icon, var(--success, #10b981))}.ds-notification--warning .ds-notification__icon{color:var(--notification-warning-icon, var(--warning, #f59e0b))}.ds-notification--error .ds-notification__icon{color:var(--notification-error-icon, var(--error, #ef4444))}.ds-notification-container--topLeft .ds-notification-wrapper,.ds-notification-container--bottomLeft .ds-notification-wrapper{animation:slideInLeft .3s ease-out}\n"] }]
|
|
11109
|
+
}], propDecorators: { placement: [{ type: i0.Input, args: [{ isSignal: true, alias: "placement", required: false }] }], maxStack: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxStack", required: false }] }] } });
|
|
11110
|
+
|
|
11111
|
+
/**
|
|
11112
|
+
* DsCalendar - Composant calendrier mensuel/annuel avec gestion d'événements
|
|
11113
|
+
*
|
|
11114
|
+
* @example
|
|
11115
|
+
* ```html
|
|
11116
|
+
* <ds-calendar
|
|
11117
|
+
* [value]="currentDate"
|
|
11118
|
+
* [events]="calendarEvents"
|
|
11119
|
+
* (dateSelect)="onDateSelect($event)"
|
|
11120
|
+
* (eventClick)="onEventClick($event)">
|
|
11121
|
+
* </ds-calendar>
|
|
11122
|
+
* ```
|
|
11123
|
+
*/
|
|
11124
|
+
class DsCalendar {
|
|
11125
|
+
// =========================================================================
|
|
11126
|
+
// INPUTS (Signals Angular 20)
|
|
11127
|
+
// =========================================================================
|
|
11128
|
+
/**
|
|
11129
|
+
* Date courante affichée
|
|
11130
|
+
*/
|
|
11131
|
+
value = input(new Date(), ...(ngDevMode ? [{ debugName: "value" }] : []));
|
|
11132
|
+
/**
|
|
11133
|
+
* Mode d'affichage (month ou year)
|
|
11134
|
+
*/
|
|
11135
|
+
mode = input('month', ...(ngDevMode ? [{ debugName: "mode" }] : []));
|
|
11136
|
+
/**
|
|
11137
|
+
* Événements à afficher dans le calendrier
|
|
11138
|
+
*/
|
|
11139
|
+
events = input([], ...(ngDevMode ? [{ debugName: "events" }] : []));
|
|
11140
|
+
/**
|
|
11141
|
+
* Taille du calendrier
|
|
11142
|
+
*/
|
|
11143
|
+
size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : []));
|
|
11144
|
+
/**
|
|
11145
|
+
* Locale pour les noms de jours et mois
|
|
11146
|
+
*/
|
|
11147
|
+
locale = input('fr-FR', ...(ngDevMode ? [{ debugName: "locale" }] : []));
|
|
11148
|
+
/**
|
|
11149
|
+
* Premier jour de la semaine (0=dimanche, 1=lundi)
|
|
11150
|
+
*/
|
|
11151
|
+
firstDayOfWeek = input(1, ...(ngDevMode ? [{ debugName: "firstDayOfWeek" }] : []));
|
|
11152
|
+
/**
|
|
11153
|
+
* Fonction pour désactiver certaines dates
|
|
11154
|
+
*/
|
|
11155
|
+
disabledDate = input(undefined, ...(ngDevMode ? [{ debugName: "disabledDate" }] : []));
|
|
11156
|
+
// =========================================================================
|
|
11157
|
+
// OUTPUTS
|
|
11158
|
+
// =========================================================================
|
|
11159
|
+
/**
|
|
11160
|
+
* Émis lors de la sélection d'une date
|
|
11161
|
+
*/
|
|
11162
|
+
dateSelect = output();
|
|
11163
|
+
/**
|
|
11164
|
+
* Émis lors du changement de mois
|
|
11165
|
+
*/
|
|
11166
|
+
monthChange = output();
|
|
11167
|
+
/**
|
|
11168
|
+
* Émis lors du changement de mode
|
|
11169
|
+
*/
|
|
11170
|
+
modeChange = output();
|
|
11171
|
+
/**
|
|
11172
|
+
* Émis lors du clic sur un événement
|
|
11173
|
+
*/
|
|
11174
|
+
eventClick = output();
|
|
11175
|
+
// =========================================================================
|
|
11176
|
+
// ÉTAT INTERNE
|
|
11177
|
+
// =========================================================================
|
|
11178
|
+
/**
|
|
11179
|
+
* Date actuellement affichée (mois/année)
|
|
11180
|
+
*/
|
|
11181
|
+
displayDate = signal(new Date(), ...(ngDevMode ? [{ debugName: "displayDate" }] : []));
|
|
11182
|
+
/**
|
|
11183
|
+
* Mode actuel (interne)
|
|
11184
|
+
*/
|
|
11185
|
+
currentMode = signal('month', ...(ngDevMode ? [{ debugName: "currentMode" }] : []));
|
|
11186
|
+
// =========================================================================
|
|
11187
|
+
// ICÔNES FONTAWESOME
|
|
11188
|
+
// =========================================================================
|
|
11189
|
+
icons = {
|
|
11190
|
+
chevronLeft: faChevronLeft,
|
|
11191
|
+
chevronRight: faChevronRight,
|
|
11192
|
+
};
|
|
11193
|
+
// =========================================================================
|
|
11194
|
+
// COMPUTED SIGNALS
|
|
11195
|
+
// =========================================================================
|
|
11196
|
+
/**
|
|
11197
|
+
* Classes CSS de l'hôte
|
|
11198
|
+
*/
|
|
11199
|
+
hostClasses = computed(() => {
|
|
11200
|
+
const classes = ['ds-calendar'];
|
|
11201
|
+
classes.push(`ds-calendar--${this.size()}`);
|
|
11202
|
+
classes.push(`ds-calendar--${this.currentMode()}`);
|
|
11203
|
+
return classes.join(' ');
|
|
11204
|
+
}, ...(ngDevMode ? [{ debugName: "hostClasses" }] : []));
|
|
11205
|
+
/**
|
|
11206
|
+
* Titre du calendrier (mois + année)
|
|
11207
|
+
*/
|
|
11208
|
+
calendarTitle = computed(() => {
|
|
11209
|
+
const date = this.displayDate();
|
|
11210
|
+
const locale = this.locale();
|
|
11211
|
+
if (this.currentMode() === 'year') {
|
|
11212
|
+
return date.getFullYear().toString();
|
|
11213
|
+
}
|
|
11214
|
+
const monthName = date.toLocaleDateString(locale, { month: 'long' });
|
|
11215
|
+
const year = date.getFullYear();
|
|
11216
|
+
return `${monthName.charAt(0).toUpperCase() + monthName.slice(1)} ${year}`;
|
|
11217
|
+
}, ...(ngDevMode ? [{ debugName: "calendarTitle" }] : []));
|
|
11218
|
+
/**
|
|
11219
|
+
* Noms des jours de la semaine
|
|
11220
|
+
*/
|
|
11221
|
+
weekDays = computed(() => {
|
|
11222
|
+
const locale = this.locale();
|
|
11223
|
+
const firstDay = this.firstDayOfWeek();
|
|
11224
|
+
const days = [];
|
|
11225
|
+
// Générer les noms des jours à partir du premier jour de la semaine
|
|
11226
|
+
for (let i = 0; i < 7; i++) {
|
|
11227
|
+
const date = new Date(2024, 0, firstDay + i); // Année 2024 (lundi = 1er janvier)
|
|
11228
|
+
const dayName = date.toLocaleDateString(locale, { weekday: 'short' });
|
|
11229
|
+
days.push(dayName.charAt(0).toUpperCase() + dayName.slice(1));
|
|
11230
|
+
}
|
|
11231
|
+
return days;
|
|
11232
|
+
}, ...(ngDevMode ? [{ debugName: "weekDays" }] : []));
|
|
11233
|
+
/**
|
|
11234
|
+
* Grille des jours du mois (6 semaines)
|
|
11235
|
+
*/
|
|
11236
|
+
calendarGrid = computed(() => {
|
|
11237
|
+
const date = this.displayDate();
|
|
11238
|
+
const firstDay = this.firstDayOfWeek();
|
|
11239
|
+
const events = this.events();
|
|
11240
|
+
const disabledFn = this.disabledDate();
|
|
11241
|
+
const today = new Date();
|
|
11242
|
+
today.setHours(0, 0, 0, 0);
|
|
11243
|
+
const year = date.getFullYear();
|
|
11244
|
+
const month = date.getMonth();
|
|
11245
|
+
// Premier jour du mois
|
|
11246
|
+
const firstDayOfMonth = new Date(year, month, 1);
|
|
11247
|
+
let startDay = firstDayOfMonth.getDay() - firstDay;
|
|
11248
|
+
if (startDay < 0)
|
|
11249
|
+
startDay += 7;
|
|
11250
|
+
// Calculer la date de début de la grille (peut être dans le mois précédent)
|
|
11251
|
+
const startDate = new Date(year, month, 1 - startDay);
|
|
11252
|
+
const days = [];
|
|
11253
|
+
// Générer 42 jours (6 semaines x 7 jours)
|
|
11254
|
+
for (let i = 0; i < 42; i++) {
|
|
11255
|
+
const currentDate = new Date(startDate);
|
|
11256
|
+
currentDate.setDate(startDate.getDate() + i);
|
|
11257
|
+
currentDate.setHours(0, 0, 0, 0);
|
|
11258
|
+
const isCurrentMonth = currentDate.getMonth() === month;
|
|
11259
|
+
const isToday = currentDate.getTime() === today.getTime();
|
|
11260
|
+
const isDisabled = disabledFn ? disabledFn(currentDate) : false;
|
|
11261
|
+
// Trouver les événements pour ce jour
|
|
11262
|
+
const dayEvents = events.filter((event) => {
|
|
11263
|
+
const eventDate = new Date(event.date);
|
|
11264
|
+
eventDate.setHours(0, 0, 0, 0);
|
|
11265
|
+
return eventDate.getTime() === currentDate.getTime();
|
|
11266
|
+
});
|
|
11267
|
+
days.push({
|
|
11268
|
+
date: currentDate,
|
|
11269
|
+
isCurrentMonth,
|
|
11270
|
+
isToday,
|
|
11271
|
+
isDisabled,
|
|
11272
|
+
events: dayEvents,
|
|
11273
|
+
});
|
|
11274
|
+
}
|
|
11275
|
+
return days;
|
|
11276
|
+
}, ...(ngDevMode ? [{ debugName: "calendarGrid" }] : []));
|
|
11277
|
+
/**
|
|
11278
|
+
* Grille des mois (vue année)
|
|
11279
|
+
*/
|
|
11280
|
+
monthGrid = computed(() => {
|
|
11281
|
+
const date = this.displayDate();
|
|
11282
|
+
const locale = this.locale();
|
|
11283
|
+
const currentMonth = new Date().getMonth();
|
|
11284
|
+
const currentYear = new Date().getFullYear();
|
|
11285
|
+
const displayYear = date.getFullYear();
|
|
11286
|
+
const months = [];
|
|
11287
|
+
for (let i = 0; i < 12; i++) {
|
|
11288
|
+
const monthDate = new Date(displayYear, i, 1);
|
|
11289
|
+
const monthName = monthDate.toLocaleDateString(locale, { month: 'long' });
|
|
11290
|
+
months.push({
|
|
11291
|
+
monthIndex: i,
|
|
11292
|
+
label: monthName.charAt(0).toUpperCase() + monthName.slice(1),
|
|
11293
|
+
isCurrentMonth: i === currentMonth && displayYear === currentYear,
|
|
11294
|
+
});
|
|
11295
|
+
}
|
|
11296
|
+
return months;
|
|
11297
|
+
}, ...(ngDevMode ? [{ debugName: "monthGrid" }] : []));
|
|
11298
|
+
// =========================================================================
|
|
11299
|
+
// EFFECTS
|
|
11300
|
+
// =========================================================================
|
|
11301
|
+
constructor() {
|
|
11302
|
+
// Synchroniser displayDate avec value au démarrage
|
|
11303
|
+
effect(() => {
|
|
11304
|
+
const value = this.value();
|
|
11305
|
+
this.displayDate.set(new Date(value));
|
|
11306
|
+
}, { allowSignalWrites: true });
|
|
11307
|
+
// Synchroniser currentMode avec mode
|
|
11308
|
+
effect(() => {
|
|
11309
|
+
this.currentMode.set(this.mode());
|
|
11310
|
+
}, { allowSignalWrites: true });
|
|
11311
|
+
}
|
|
11312
|
+
// =========================================================================
|
|
11313
|
+
// MÉTHODES PUBLIQUES
|
|
11314
|
+
// =========================================================================
|
|
11315
|
+
/**
|
|
11316
|
+
* Navigue vers le mois précédent
|
|
11317
|
+
*/
|
|
11318
|
+
previousMonth() {
|
|
11319
|
+
const current = this.displayDate();
|
|
11320
|
+
const newDate = new Date(current.getFullYear(), current.getMonth() - 1, 1);
|
|
11321
|
+
this.displayDate.set(newDate);
|
|
11322
|
+
this.monthChange.emit(newDate);
|
|
11323
|
+
}
|
|
11324
|
+
/**
|
|
11325
|
+
* Navigue vers le mois suivant
|
|
11326
|
+
*/
|
|
11327
|
+
nextMonth() {
|
|
11328
|
+
const current = this.displayDate();
|
|
11329
|
+
const newDate = new Date(current.getFullYear(), current.getMonth() + 1, 1);
|
|
11330
|
+
this.displayDate.set(newDate);
|
|
11331
|
+
this.monthChange.emit(newDate);
|
|
11332
|
+
}
|
|
11333
|
+
/**
|
|
11334
|
+
* Navigue vers l'année précédente
|
|
11335
|
+
*/
|
|
11336
|
+
previousYear() {
|
|
11337
|
+
const current = this.displayDate();
|
|
11338
|
+
const newDate = new Date(current.getFullYear() - 1, current.getMonth(), 1);
|
|
11339
|
+
this.displayDate.set(newDate);
|
|
11340
|
+
this.monthChange.emit(newDate);
|
|
11341
|
+
}
|
|
11342
|
+
/**
|
|
11343
|
+
* Navigue vers l'année suivante
|
|
11344
|
+
*/
|
|
11345
|
+
nextYear() {
|
|
11346
|
+
const current = this.displayDate();
|
|
11347
|
+
const newDate = new Date(current.getFullYear() + 1, current.getMonth(), 1);
|
|
11348
|
+
this.displayDate.set(newDate);
|
|
11349
|
+
this.monthChange.emit(newDate);
|
|
11350
|
+
}
|
|
11351
|
+
/**
|
|
11352
|
+
* Sélectionne une date
|
|
11353
|
+
*/
|
|
11354
|
+
selectDate(day) {
|
|
11355
|
+
if (day.isDisabled)
|
|
11356
|
+
return;
|
|
11357
|
+
this.dateSelect.emit(new Date(day.date));
|
|
11358
|
+
}
|
|
11359
|
+
/**
|
|
11360
|
+
* Sélectionne un mois (en mode année)
|
|
11361
|
+
*/
|
|
11362
|
+
selectMonth(month) {
|
|
11363
|
+
const current = this.displayDate();
|
|
11364
|
+
const newDate = new Date(current.getFullYear(), month.monthIndex, 1);
|
|
11365
|
+
this.displayDate.set(newDate);
|
|
11366
|
+
this.currentMode.set('month');
|
|
11367
|
+
this.modeChange.emit('month');
|
|
11368
|
+
}
|
|
11369
|
+
/**
|
|
11370
|
+
* Toggle entre mode mois et année
|
|
11371
|
+
*/
|
|
11372
|
+
toggleMode() {
|
|
11373
|
+
const newMode = this.currentMode() === 'month' ? 'year' : 'month';
|
|
11374
|
+
this.currentMode.set(newMode);
|
|
11375
|
+
this.modeChange.emit(newMode);
|
|
11376
|
+
}
|
|
11377
|
+
/**
|
|
11378
|
+
* Gère le clic sur un événement
|
|
11379
|
+
*/
|
|
11380
|
+
onEventClick(event, mouseEvent) {
|
|
11381
|
+
mouseEvent.stopPropagation();
|
|
11382
|
+
this.eventClick.emit(event);
|
|
11383
|
+
}
|
|
11384
|
+
/**
|
|
11385
|
+
* Retourne les classes CSS d'un jour
|
|
11386
|
+
*/
|
|
11387
|
+
getDayClasses(day) {
|
|
11388
|
+
const classes = ['ds-calendar__day'];
|
|
11389
|
+
if (!day.isCurrentMonth) {
|
|
11390
|
+
classes.push('ds-calendar__day--other-month');
|
|
11391
|
+
}
|
|
11392
|
+
if (day.isToday) {
|
|
11393
|
+
classes.push('ds-calendar__day--today');
|
|
11394
|
+
}
|
|
11395
|
+
if (day.isDisabled) {
|
|
11396
|
+
classes.push('ds-calendar__day--disabled');
|
|
11397
|
+
}
|
|
11398
|
+
if (day.events.length > 0) {
|
|
11399
|
+
classes.push('ds-calendar__day--has-events');
|
|
11400
|
+
}
|
|
11401
|
+
return classes.join(' ');
|
|
11402
|
+
}
|
|
11403
|
+
/**
|
|
11404
|
+
* Retourne les classes CSS d'un mois
|
|
11405
|
+
*/
|
|
11406
|
+
getMonthClasses(month) {
|
|
11407
|
+
const classes = ['ds-calendar__month'];
|
|
11408
|
+
if (month.isCurrentMonth) {
|
|
11409
|
+
classes.push('ds-calendar__month--current');
|
|
11410
|
+
}
|
|
11411
|
+
return classes.join(' ');
|
|
11412
|
+
}
|
|
11413
|
+
/**
|
|
11414
|
+
* Retourne les classes CSS d'un événement
|
|
11415
|
+
*/
|
|
11416
|
+
getEventClasses(event) {
|
|
11417
|
+
const classes = ['ds-calendar__event'];
|
|
11418
|
+
if (event.type) {
|
|
11419
|
+
classes.push(`ds-calendar__event--${event.type}`);
|
|
11420
|
+
}
|
|
11421
|
+
return classes.join(' ');
|
|
11422
|
+
}
|
|
11423
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DsCalendar, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
11424
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: DsCalendar, isStandalone: true, selector: "ds-calendar", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, events: { classPropertyName: "events", publicName: "events", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null }, firstDayOfWeek: { classPropertyName: "firstDayOfWeek", publicName: "firstDayOfWeek", isSignal: true, isRequired: false, transformFunction: null }, disabledDate: { classPropertyName: "disabledDate", publicName: "disabledDate", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { dateSelect: "dateSelect", monthChange: "monthChange", modeChange: "modeChange", eventClick: "eventClick" }, host: { properties: { "class": "hostClasses()" }, classAttribute: "ds-calendar" }, ngImport: i0, template: "<div class=\"ds-calendar__container\">\n <!-- Header avec navigation et s\u00E9lecteur mode -->\n <div class=\"ds-calendar__header\">\n <div class=\"ds-calendar__nav\">\n @if (currentMode() === 'month') {\n <button\n type=\"button\"\n class=\"ds-calendar__nav-btn\"\n (click)=\"previousMonth()\"\n aria-label=\"Mois pr\u00E9c\u00E9dent\"\n >\n <fa-icon [icon]=\"icons.chevronLeft\"></fa-icon>\n </button>\n } @else {\n <button\n type=\"button\"\n class=\"ds-calendar__nav-btn\"\n (click)=\"previousYear()\"\n aria-label=\"Ann\u00E9e pr\u00E9c\u00E9dente\"\n >\n <fa-icon [icon]=\"icons.chevronLeft\"></fa-icon>\n </button>\n }\n\n <button\n type=\"button\"\n class=\"ds-calendar__title\"\n (click)=\"toggleMode()\"\n [attr.aria-label]=\"currentMode() === 'month' ? 'Voir l\\'ann\u00E9e' : 'Voir le mois'\"\n >\n {{ calendarTitle() }}\n </button>\n\n @if (currentMode() === 'month') {\n <button\n type=\"button\"\n class=\"ds-calendar__nav-btn\"\n (click)=\"nextMonth()\"\n aria-label=\"Mois suivant\"\n >\n <fa-icon [icon]=\"icons.chevronRight\"></fa-icon>\n </button>\n } @else {\n <button\n type=\"button\"\n class=\"ds-calendar__nav-btn\"\n (click)=\"nextYear()\"\n aria-label=\"Ann\u00E9e suivante\"\n >\n <fa-icon [icon]=\"icons.chevronRight\"></fa-icon>\n </button>\n }\n </div>\n\n <div class=\"ds-calendar__mode-selector\">\n <button\n type=\"button\"\n class=\"ds-calendar__mode-btn\"\n [class.ds-calendar__mode-btn--active]=\"currentMode() === 'month'\"\n (click)=\"currentMode() === 'year' && toggleMode()\"\n >\n Mois\n </button>\n <button\n type=\"button\"\n class=\"ds-calendar__mode-btn\"\n [class.ds-calendar__mode-btn--active]=\"currentMode() === 'year'\"\n (click)=\"currentMode() === 'month' && toggleMode()\"\n >\n Ann\u00E9e\n </button>\n </div>\n </div>\n\n <!-- Vue mois -->\n @if (currentMode() === 'month') {\n <div class=\"ds-calendar__month-view\">\n <!-- Noms des jours de la semaine -->\n <div class=\"ds-calendar__weekdays\">\n @for (day of weekDays(); track day) {\n <div class=\"ds-calendar__weekday\">{{ day }}</div>\n }\n </div>\n\n <!-- Grille des jours -->\n <div class=\"ds-calendar__grid\">\n @for (day of calendarGrid(); track day.date.getTime()) {\n <button\n type=\"button\"\n [class]=\"getDayClasses(day)\"\n [disabled]=\"day.isDisabled\"\n (click)=\"selectDate(day)\"\n [attr.aria-label]=\"day.date.toLocaleDateString(locale())\"\n [attr.aria-current]=\"day.isToday ? 'date' : null\"\n >\n <span class=\"ds-calendar__day-number\">{{ day.date.getDate() }}</span>\n\n @if (day.events.length > 0) {\n <div class=\"ds-calendar__events\">\n @for (event of day.events; track event.id) {\n <div\n [class]=\"getEventClasses(event)\"\n [title]=\"event.title\"\n (click)=\"onEventClick(event, $event)\"\n role=\"button\"\n [attr.aria-label]=\"event.title\"\n >\n <span class=\"ds-calendar__event-dot\"></span>\n @if (size() === 'lg') {\n <span class=\"ds-calendar__event-title\">{{ event.title }}</span>\n }\n </div>\n }\n </div>\n }\n </button>\n }\n </div>\n </div>\n }\n\n <!-- Vue ann\u00E9e -->\n @if (currentMode() === 'year') {\n <div class=\"ds-calendar__year-view\">\n <div class=\"ds-calendar__months-grid\">\n @for (month of monthGrid(); track month.monthIndex) {\n <button\n type=\"button\"\n [class]=\"getMonthClasses(month)\"\n (click)=\"selectMonth(month)\"\n [attr.aria-label]=\"month.label\"\n [attr.aria-current]=\"month.isCurrentMonth ? 'true' : null\"\n >\n {{ month.label }}\n </button>\n }\n </div>\n </div>\n }\n</div>\n", styles: [".ds-calendar{display:block;width:100%}.ds-calendar__container{background:var(--calendar-bg, var(--white));border:1px solid var(--calendar-border, var(--gray-200));border-radius:var(--calendar-radius, var(--radius-2));overflow:hidden}.ds-calendar__header{display:flex;align-items:center;justify-content:space-between;padding:var(--calendar-header-padding, var(--space-4));border-bottom:1px solid var(--calendar-border, var(--gray-200));background:var(--calendar-header-bg, var(--gray-50))}.ds-calendar__nav{display:flex;align-items:center;gap:var(--calendar-nav-gap, var(--space-2))}.ds-calendar__nav-btn{display:inline-flex;align-items:center;justify-content:center;width:var(--calendar-nav-btn-size, 32px);height:var(--calendar-nav-btn-size, 32px);padding:0;background:transparent;border:1px solid var(--calendar-nav-btn-border, var(--gray-300));border-radius:var(--calendar-nav-btn-radius, var(--radius-1));color:var(--calendar-nav-btn-color, var(--gray-700));font-size:var(--calendar-nav-btn-font-size, var(--font-size-3));cursor:pointer;transition:all .2s ease}.ds-calendar__nav-btn:hover:not(:disabled){background:var(--calendar-nav-btn-hover-bg, var(--gray-100));border-color:var(--calendar-nav-btn-hover-border, var(--gray-400));color:var(--calendar-nav-btn-hover-color, var(--gray-900))}.ds-calendar__nav-btn:active:not(:disabled){transform:scale(.95)}.ds-calendar__nav-btn:disabled{opacity:.5;cursor:not-allowed}.ds-calendar__title{padding:var(--calendar-title-padding, var(--space-2) var(--space-3));background:transparent;border:1px solid transparent;border-radius:var(--calendar-title-radius, var(--radius-1));color:var(--calendar-title-color, var(--gray-900));font-size:var(--calendar-title-font-size, var(--font-size-4));font-weight:var(--calendar-title-font-weight, 600);cursor:pointer;transition:all .2s ease}.ds-calendar__title:hover{background:var(--calendar-title-hover-bg, var(--gray-100));border-color:var(--calendar-title-hover-border, var(--gray-300))}.ds-calendar__mode-selector{display:flex;gap:var(--calendar-mode-gap, var(--space-1));background:var(--calendar-mode-bg, var(--white));border:1px solid var(--calendar-mode-border, var(--gray-300));border-radius:var(--calendar-mode-radius, var(--radius-1));padding:var(--calendar-mode-padding, 2px)}.ds-calendar__mode-btn{padding:var(--calendar-mode-btn-padding, var(--space-1) var(--space-3));background:transparent;border:none;border-radius:var(--calendar-mode-btn-radius, var(--radius-1));color:var(--calendar-mode-btn-color, var(--gray-700));font-size:var(--calendar-mode-btn-font-size, var(--font-size-2));cursor:pointer;transition:all .2s ease}.ds-calendar__mode-btn:hover{color:var(--calendar-mode-btn-hover-color, var(--gray-900))}.ds-calendar__mode-btn--active{background:var(--calendar-mode-btn-active-bg, var(--color-primary));color:var(--calendar-mode-btn-active-color, var(--white))}.ds-calendar__month-view{padding:var(--calendar-month-view-padding, var(--space-4))}.ds-calendar__weekdays{display:grid;grid-template-columns:repeat(7,1fr);gap:var(--calendar-weekday-gap, var(--space-1));margin-bottom:var(--calendar-weekday-margin, var(--space-2))}.ds-calendar__weekday{text-align:center;color:var(--calendar-weekday-color, var(--gray-600));font-size:var(--calendar-weekday-font-size, var(--font-size-2));font-weight:var(--calendar-weekday-font-weight, 600);text-transform:uppercase;padding:var(--calendar-weekday-padding, var(--space-2) 0)}.ds-calendar__grid{display:grid;grid-template-columns:repeat(7,1fr);gap:var(--calendar-grid-gap, var(--space-1))}.ds-calendar__day{position:relative;aspect-ratio:1;display:flex;flex-direction:column;align-items:center;justify-content:flex-start;padding:var(--calendar-day-padding, var(--space-2));background:var(--calendar-day-bg, transparent);border:1px solid var(--calendar-day-border, transparent);border-radius:var(--calendar-day-radius, var(--radius-1));color:var(--calendar-day-color, var(--gray-900));font-size:var(--calendar-day-font-size, var(--font-size-3));cursor:pointer;transition:all .2s ease}.ds-calendar__day:hover:not(:disabled){background:var(--calendar-day-hover-bg, var(--gray-100));border-color:var(--calendar-day-hover-border, var(--gray-300))}.ds-calendar__day--other-month{color:var(--calendar-day-other-month-color, var(--gray-400))}.ds-calendar__day--today{background:var(--calendar-day-today-bg, var(--blue-50));border-color:var(--calendar-day-today-border, var(--color-primary));color:var(--calendar-day-today-color, var(--color-primary));font-weight:600}.ds-calendar__day--disabled{opacity:.4;cursor:not-allowed;background:var(--calendar-day-disabled-bg, var(--gray-50))}.ds-calendar__day--has-events .ds-calendar__day-number{font-weight:600}.ds-calendar__day-number{line-height:1;margin-bottom:var(--calendar-day-number-margin, var(--space-1))}.ds-calendar__events{display:flex;flex-direction:column;gap:var(--calendar-events-gap, 2px);width:100%;margin-top:auto}.ds-calendar__event{display:flex;align-items:center;gap:var(--calendar-event-gap, var(--space-1));padding:var(--calendar-event-padding, 2px);border-radius:var(--calendar-event-radius, var(--radius-1));cursor:pointer;transition:all .2s ease}.ds-calendar__event:hover{transform:scale(1.05)}.ds-calendar__event-dot{width:var(--calendar-event-dot-size, 6px);height:var(--calendar-event-dot-size, 6px);border-radius:50%;background:var(--calendar-event-dot-color, var(--gray-500));flex-shrink:0}.ds-calendar__event-title{font-size:var(--calendar-event-title-font-size, var(--font-size-1));color:var(--calendar-event-title-color, var(--gray-700));white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.ds-calendar__event--success .ds-calendar__event-dot{background:var(--calendar-event-success-color, var(--success))}.ds-calendar__event--warning .ds-calendar__event-dot{background:var(--calendar-event-warning-color, var(--warning))}.ds-calendar__event--error .ds-calendar__event-dot{background:var(--calendar-event-error-color, var(--error))}.ds-calendar__year-view{padding:var(--calendar-year-view-padding, var(--space-4))}.ds-calendar__months-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:var(--calendar-months-gap, var(--space-3))}.ds-calendar__month{padding:var(--calendar-month-padding, var(--space-4));background:var(--calendar-month-bg, transparent);border:1px solid var(--calendar-month-border, var(--gray-200));border-radius:var(--calendar-month-radius, var(--radius-2));color:var(--calendar-month-color, var(--gray-900));font-size:var(--calendar-month-font-size, var(--font-size-3));font-weight:500;cursor:pointer;transition:all .2s ease;text-align:center}.ds-calendar__month:hover{background:var(--calendar-month-hover-bg, var(--gray-50));border-color:var(--calendar-month-hover-border, var(--gray-300))}.ds-calendar__month--current{background:var(--calendar-month-current-bg, var(--blue-50));border-color:var(--calendar-month-current-border, var(--color-primary));color:var(--calendar-month-current-color, var(--color-primary));font-weight:600}.ds-calendar--sm .ds-calendar__header{padding:var(--calendar-header-padding-sm, var(--space-2))}.ds-calendar--sm .ds-calendar__title{font-size:var(--calendar-title-font-size-sm, var(--font-size-3))}.ds-calendar--sm .ds-calendar__weekday{font-size:var(--calendar-weekday-font-size-sm, var(--font-size-1))}.ds-calendar--sm .ds-calendar__day{padding:var(--calendar-day-padding-sm, var(--space-1));font-size:var(--calendar-day-font-size-sm, var(--font-size-2))}.ds-calendar--sm .ds-calendar__month{padding:var(--calendar-month-padding-sm, var(--space-2));font-size:var(--calendar-month-font-size-sm, var(--font-size-2))}.ds-calendar--lg .ds-calendar__header{padding:var(--calendar-header-padding-lg, var(--space-6))}.ds-calendar--lg .ds-calendar__title{font-size:var(--calendar-title-font-size-lg, var(--font-size-5))}.ds-calendar--lg .ds-calendar__weekday{font-size:var(--calendar-weekday-font-size-lg, var(--font-size-3))}.ds-calendar--lg .ds-calendar__day{padding:var(--calendar-day-padding-lg, var(--space-3));font-size:var(--calendar-day-font-size-lg, var(--font-size-4))}.ds-calendar--lg .ds-calendar__month{padding:var(--calendar-month-padding-lg, var(--space-6));font-size:var(--calendar-month-font-size-lg, var(--font-size-4))}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FontAwesomeModule }, { kind: "component", type: i1$1.FaIconComponent, selector: "fa-icon", inputs: ["icon", "title", "animation", "mask", "flip", "size", "pull", "border", "inverse", "symbol", "rotate", "fixedWidth", "transform", "a11yRole"], outputs: ["iconChange", "titleChange", "animationChange", "maskChange", "flipChange", "sizeChange", "pullChange", "borderChange", "inverseChange", "symbolChange", "rotateChange", "fixedWidthChange", "transformChange", "a11yRoleChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
11425
|
+
}
|
|
11426
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DsCalendar, decorators: [{
|
|
11427
|
+
type: Component,
|
|
11428
|
+
args: [{ selector: 'ds-calendar', standalone: true, imports: [CommonModule, FontAwesomeModule], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: {
|
|
11429
|
+
class: 'ds-calendar',
|
|
11430
|
+
'[class]': 'hostClasses()',
|
|
11431
|
+
}, template: "<div class=\"ds-calendar__container\">\n <!-- Header avec navigation et s\u00E9lecteur mode -->\n <div class=\"ds-calendar__header\">\n <div class=\"ds-calendar__nav\">\n @if (currentMode() === 'month') {\n <button\n type=\"button\"\n class=\"ds-calendar__nav-btn\"\n (click)=\"previousMonth()\"\n aria-label=\"Mois pr\u00E9c\u00E9dent\"\n >\n <fa-icon [icon]=\"icons.chevronLeft\"></fa-icon>\n </button>\n } @else {\n <button\n type=\"button\"\n class=\"ds-calendar__nav-btn\"\n (click)=\"previousYear()\"\n aria-label=\"Ann\u00E9e pr\u00E9c\u00E9dente\"\n >\n <fa-icon [icon]=\"icons.chevronLeft\"></fa-icon>\n </button>\n }\n\n <button\n type=\"button\"\n class=\"ds-calendar__title\"\n (click)=\"toggleMode()\"\n [attr.aria-label]=\"currentMode() === 'month' ? 'Voir l\\'ann\u00E9e' : 'Voir le mois'\"\n >\n {{ calendarTitle() }}\n </button>\n\n @if (currentMode() === 'month') {\n <button\n type=\"button\"\n class=\"ds-calendar__nav-btn\"\n (click)=\"nextMonth()\"\n aria-label=\"Mois suivant\"\n >\n <fa-icon [icon]=\"icons.chevronRight\"></fa-icon>\n </button>\n } @else {\n <button\n type=\"button\"\n class=\"ds-calendar__nav-btn\"\n (click)=\"nextYear()\"\n aria-label=\"Ann\u00E9e suivante\"\n >\n <fa-icon [icon]=\"icons.chevronRight\"></fa-icon>\n </button>\n }\n </div>\n\n <div class=\"ds-calendar__mode-selector\">\n <button\n type=\"button\"\n class=\"ds-calendar__mode-btn\"\n [class.ds-calendar__mode-btn--active]=\"currentMode() === 'month'\"\n (click)=\"currentMode() === 'year' && toggleMode()\"\n >\n Mois\n </button>\n <button\n type=\"button\"\n class=\"ds-calendar__mode-btn\"\n [class.ds-calendar__mode-btn--active]=\"currentMode() === 'year'\"\n (click)=\"currentMode() === 'month' && toggleMode()\"\n >\n Ann\u00E9e\n </button>\n </div>\n </div>\n\n <!-- Vue mois -->\n @if (currentMode() === 'month') {\n <div class=\"ds-calendar__month-view\">\n <!-- Noms des jours de la semaine -->\n <div class=\"ds-calendar__weekdays\">\n @for (day of weekDays(); track day) {\n <div class=\"ds-calendar__weekday\">{{ day }}</div>\n }\n </div>\n\n <!-- Grille des jours -->\n <div class=\"ds-calendar__grid\">\n @for (day of calendarGrid(); track day.date.getTime()) {\n <button\n type=\"button\"\n [class]=\"getDayClasses(day)\"\n [disabled]=\"day.isDisabled\"\n (click)=\"selectDate(day)\"\n [attr.aria-label]=\"day.date.toLocaleDateString(locale())\"\n [attr.aria-current]=\"day.isToday ? 'date' : null\"\n >\n <span class=\"ds-calendar__day-number\">{{ day.date.getDate() }}</span>\n\n @if (day.events.length > 0) {\n <div class=\"ds-calendar__events\">\n @for (event of day.events; track event.id) {\n <div\n [class]=\"getEventClasses(event)\"\n [title]=\"event.title\"\n (click)=\"onEventClick(event, $event)\"\n role=\"button\"\n [attr.aria-label]=\"event.title\"\n >\n <span class=\"ds-calendar__event-dot\"></span>\n @if (size() === 'lg') {\n <span class=\"ds-calendar__event-title\">{{ event.title }}</span>\n }\n </div>\n }\n </div>\n }\n </button>\n }\n </div>\n </div>\n }\n\n <!-- Vue ann\u00E9e -->\n @if (currentMode() === 'year') {\n <div class=\"ds-calendar__year-view\">\n <div class=\"ds-calendar__months-grid\">\n @for (month of monthGrid(); track month.monthIndex) {\n <button\n type=\"button\"\n [class]=\"getMonthClasses(month)\"\n (click)=\"selectMonth(month)\"\n [attr.aria-label]=\"month.label\"\n [attr.aria-current]=\"month.isCurrentMonth ? 'true' : null\"\n >\n {{ month.label }}\n </button>\n }\n </div>\n </div>\n }\n</div>\n", styles: [".ds-calendar{display:block;width:100%}.ds-calendar__container{background:var(--calendar-bg, var(--white));border:1px solid var(--calendar-border, var(--gray-200));border-radius:var(--calendar-radius, var(--radius-2));overflow:hidden}.ds-calendar__header{display:flex;align-items:center;justify-content:space-between;padding:var(--calendar-header-padding, var(--space-4));border-bottom:1px solid var(--calendar-border, var(--gray-200));background:var(--calendar-header-bg, var(--gray-50))}.ds-calendar__nav{display:flex;align-items:center;gap:var(--calendar-nav-gap, var(--space-2))}.ds-calendar__nav-btn{display:inline-flex;align-items:center;justify-content:center;width:var(--calendar-nav-btn-size, 32px);height:var(--calendar-nav-btn-size, 32px);padding:0;background:transparent;border:1px solid var(--calendar-nav-btn-border, var(--gray-300));border-radius:var(--calendar-nav-btn-radius, var(--radius-1));color:var(--calendar-nav-btn-color, var(--gray-700));font-size:var(--calendar-nav-btn-font-size, var(--font-size-3));cursor:pointer;transition:all .2s ease}.ds-calendar__nav-btn:hover:not(:disabled){background:var(--calendar-nav-btn-hover-bg, var(--gray-100));border-color:var(--calendar-nav-btn-hover-border, var(--gray-400));color:var(--calendar-nav-btn-hover-color, var(--gray-900))}.ds-calendar__nav-btn:active:not(:disabled){transform:scale(.95)}.ds-calendar__nav-btn:disabled{opacity:.5;cursor:not-allowed}.ds-calendar__title{padding:var(--calendar-title-padding, var(--space-2) var(--space-3));background:transparent;border:1px solid transparent;border-radius:var(--calendar-title-radius, var(--radius-1));color:var(--calendar-title-color, var(--gray-900));font-size:var(--calendar-title-font-size, var(--font-size-4));font-weight:var(--calendar-title-font-weight, 600);cursor:pointer;transition:all .2s ease}.ds-calendar__title:hover{background:var(--calendar-title-hover-bg, var(--gray-100));border-color:var(--calendar-title-hover-border, var(--gray-300))}.ds-calendar__mode-selector{display:flex;gap:var(--calendar-mode-gap, var(--space-1));background:var(--calendar-mode-bg, var(--white));border:1px solid var(--calendar-mode-border, var(--gray-300));border-radius:var(--calendar-mode-radius, var(--radius-1));padding:var(--calendar-mode-padding, 2px)}.ds-calendar__mode-btn{padding:var(--calendar-mode-btn-padding, var(--space-1) var(--space-3));background:transparent;border:none;border-radius:var(--calendar-mode-btn-radius, var(--radius-1));color:var(--calendar-mode-btn-color, var(--gray-700));font-size:var(--calendar-mode-btn-font-size, var(--font-size-2));cursor:pointer;transition:all .2s ease}.ds-calendar__mode-btn:hover{color:var(--calendar-mode-btn-hover-color, var(--gray-900))}.ds-calendar__mode-btn--active{background:var(--calendar-mode-btn-active-bg, var(--color-primary));color:var(--calendar-mode-btn-active-color, var(--white))}.ds-calendar__month-view{padding:var(--calendar-month-view-padding, var(--space-4))}.ds-calendar__weekdays{display:grid;grid-template-columns:repeat(7,1fr);gap:var(--calendar-weekday-gap, var(--space-1));margin-bottom:var(--calendar-weekday-margin, var(--space-2))}.ds-calendar__weekday{text-align:center;color:var(--calendar-weekday-color, var(--gray-600));font-size:var(--calendar-weekday-font-size, var(--font-size-2));font-weight:var(--calendar-weekday-font-weight, 600);text-transform:uppercase;padding:var(--calendar-weekday-padding, var(--space-2) 0)}.ds-calendar__grid{display:grid;grid-template-columns:repeat(7,1fr);gap:var(--calendar-grid-gap, var(--space-1))}.ds-calendar__day{position:relative;aspect-ratio:1;display:flex;flex-direction:column;align-items:center;justify-content:flex-start;padding:var(--calendar-day-padding, var(--space-2));background:var(--calendar-day-bg, transparent);border:1px solid var(--calendar-day-border, transparent);border-radius:var(--calendar-day-radius, var(--radius-1));color:var(--calendar-day-color, var(--gray-900));font-size:var(--calendar-day-font-size, var(--font-size-3));cursor:pointer;transition:all .2s ease}.ds-calendar__day:hover:not(:disabled){background:var(--calendar-day-hover-bg, var(--gray-100));border-color:var(--calendar-day-hover-border, var(--gray-300))}.ds-calendar__day--other-month{color:var(--calendar-day-other-month-color, var(--gray-400))}.ds-calendar__day--today{background:var(--calendar-day-today-bg, var(--blue-50));border-color:var(--calendar-day-today-border, var(--color-primary));color:var(--calendar-day-today-color, var(--color-primary));font-weight:600}.ds-calendar__day--disabled{opacity:.4;cursor:not-allowed;background:var(--calendar-day-disabled-bg, var(--gray-50))}.ds-calendar__day--has-events .ds-calendar__day-number{font-weight:600}.ds-calendar__day-number{line-height:1;margin-bottom:var(--calendar-day-number-margin, var(--space-1))}.ds-calendar__events{display:flex;flex-direction:column;gap:var(--calendar-events-gap, 2px);width:100%;margin-top:auto}.ds-calendar__event{display:flex;align-items:center;gap:var(--calendar-event-gap, var(--space-1));padding:var(--calendar-event-padding, 2px);border-radius:var(--calendar-event-radius, var(--radius-1));cursor:pointer;transition:all .2s ease}.ds-calendar__event:hover{transform:scale(1.05)}.ds-calendar__event-dot{width:var(--calendar-event-dot-size, 6px);height:var(--calendar-event-dot-size, 6px);border-radius:50%;background:var(--calendar-event-dot-color, var(--gray-500));flex-shrink:0}.ds-calendar__event-title{font-size:var(--calendar-event-title-font-size, var(--font-size-1));color:var(--calendar-event-title-color, var(--gray-700));white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.ds-calendar__event--success .ds-calendar__event-dot{background:var(--calendar-event-success-color, var(--success))}.ds-calendar__event--warning .ds-calendar__event-dot{background:var(--calendar-event-warning-color, var(--warning))}.ds-calendar__event--error .ds-calendar__event-dot{background:var(--calendar-event-error-color, var(--error))}.ds-calendar__year-view{padding:var(--calendar-year-view-padding, var(--space-4))}.ds-calendar__months-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:var(--calendar-months-gap, var(--space-3))}.ds-calendar__month{padding:var(--calendar-month-padding, var(--space-4));background:var(--calendar-month-bg, transparent);border:1px solid var(--calendar-month-border, var(--gray-200));border-radius:var(--calendar-month-radius, var(--radius-2));color:var(--calendar-month-color, var(--gray-900));font-size:var(--calendar-month-font-size, var(--font-size-3));font-weight:500;cursor:pointer;transition:all .2s ease;text-align:center}.ds-calendar__month:hover{background:var(--calendar-month-hover-bg, var(--gray-50));border-color:var(--calendar-month-hover-border, var(--gray-300))}.ds-calendar__month--current{background:var(--calendar-month-current-bg, var(--blue-50));border-color:var(--calendar-month-current-border, var(--color-primary));color:var(--calendar-month-current-color, var(--color-primary));font-weight:600}.ds-calendar--sm .ds-calendar__header{padding:var(--calendar-header-padding-sm, var(--space-2))}.ds-calendar--sm .ds-calendar__title{font-size:var(--calendar-title-font-size-sm, var(--font-size-3))}.ds-calendar--sm .ds-calendar__weekday{font-size:var(--calendar-weekday-font-size-sm, var(--font-size-1))}.ds-calendar--sm .ds-calendar__day{padding:var(--calendar-day-padding-sm, var(--space-1));font-size:var(--calendar-day-font-size-sm, var(--font-size-2))}.ds-calendar--sm .ds-calendar__month{padding:var(--calendar-month-padding-sm, var(--space-2));font-size:var(--calendar-month-font-size-sm, var(--font-size-2))}.ds-calendar--lg .ds-calendar__header{padding:var(--calendar-header-padding-lg, var(--space-6))}.ds-calendar--lg .ds-calendar__title{font-size:var(--calendar-title-font-size-lg, var(--font-size-5))}.ds-calendar--lg .ds-calendar__weekday{font-size:var(--calendar-weekday-font-size-lg, var(--font-size-3))}.ds-calendar--lg .ds-calendar__day{padding:var(--calendar-day-padding-lg, var(--space-3));font-size:var(--calendar-day-font-size-lg, var(--font-size-4))}.ds-calendar--lg .ds-calendar__month{padding:var(--calendar-month-padding-lg, var(--space-6));font-size:var(--calendar-month-font-size-lg, var(--font-size-4))}\n"] }]
|
|
11432
|
+
}], ctorParameters: () => [], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], events: [{ type: i0.Input, args: [{ isSignal: true, alias: "events", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: false }] }], firstDayOfWeek: [{ type: i0.Input, args: [{ isSignal: true, alias: "firstDayOfWeek", required: false }] }], disabledDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabledDate", required: false }] }], dateSelect: [{ type: i0.Output, args: ["dateSelect"] }], monthChange: [{ type: i0.Output, args: ["monthChange"] }], modeChange: [{ type: i0.Output, args: ["modeChange"] }], eventClick: [{ type: i0.Output, args: ["eventClick"] }] } });
|
|
11433
|
+
|
|
11434
|
+
class DsInputNumber {
|
|
11435
|
+
// Config
|
|
11436
|
+
min = input(-Infinity, ...(ngDevMode ? [{ debugName: "min" }] : []));
|
|
11437
|
+
max = input(Infinity, ...(ngDevMode ? [{ debugName: "max" }] : []));
|
|
11438
|
+
step = input(1, ...(ngDevMode ? [{ debugName: "step" }] : []));
|
|
11439
|
+
disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
|
|
11440
|
+
readonly = input(false, ...(ngDevMode ? [{ debugName: "readonly" }] : []));
|
|
11441
|
+
required = input(false, ...(ngDevMode ? [{ debugName: "required" }] : []));
|
|
11442
|
+
size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : []));
|
|
11443
|
+
placeholder = input('', ...(ngDevMode ? [{ debugName: "placeholder" }] : []));
|
|
11444
|
+
prefix = input(undefined, ...(ngDevMode ? [{ debugName: "prefix" }] : []));
|
|
11445
|
+
suffix = input(undefined, ...(ngDevMode ? [{ debugName: "suffix" }] : []));
|
|
11446
|
+
precision = input(0, ...(ngDevMode ? [{ debugName: "precision" }] : []));
|
|
11447
|
+
controls = input(true, ...(ngDevMode ? [{ debugName: "controls" }] : []));
|
|
11448
|
+
controlsPosition = input('both', ...(ngDevMode ? [{ debugName: "controlsPosition" }] : []));
|
|
11449
|
+
// Accessibility
|
|
11450
|
+
ariaLabel = input(undefined, ...(ngDevMode ? [{ debugName: "ariaLabel" }] : []));
|
|
11451
|
+
id = input(crypto.randomUUID(), ...(ngDevMode ? [{ debugName: "id" }] : []));
|
|
11452
|
+
name = input(undefined, ...(ngDevMode ? [{ debugName: "name" }] : []));
|
|
11453
|
+
// Events
|
|
11454
|
+
valueChange = output();
|
|
11455
|
+
// ViewChild
|
|
11456
|
+
inputElement;
|
|
11457
|
+
// Icons
|
|
11458
|
+
faMinus = faMinus;
|
|
11459
|
+
faPlus = faPlus;
|
|
11460
|
+
// Internal state
|
|
11461
|
+
disabledState = signal(false, ...(ngDevMode ? [{ debugName: "disabledState" }] : []));
|
|
11462
|
+
internalValue = signal(null, ...(ngDevMode ? [{ debugName: "internalValue" }] : []));
|
|
11463
|
+
focused = signal(false, ...(ngDevMode ? [{ debugName: "focused" }] : []));
|
|
11464
|
+
displayValue = signal('', ...(ngDevMode ? [{ debugName: "displayValue" }] : []));
|
|
11465
|
+
constructor() {
|
|
11466
|
+
// Effect pour formater l'affichage
|
|
11467
|
+
effect(() => {
|
|
11468
|
+
const val = this.internalValue();
|
|
11469
|
+
if (val === null) {
|
|
11470
|
+
this.displayValue.set('');
|
|
11471
|
+
return;
|
|
11472
|
+
}
|
|
11473
|
+
const formatted = this.formatValue(val);
|
|
11474
|
+
this.displayValue.set(formatted);
|
|
11475
|
+
});
|
|
11476
|
+
}
|
|
11477
|
+
isDisabled = computed(() => this.disabled() || this.disabledState(), ...(ngDevMode ? [{ debugName: "isDisabled" }] : []));
|
|
11478
|
+
isReadonly = computed(() => this.readonly(), ...(ngDevMode ? [{ debugName: "isReadonly" }] : []));
|
|
11479
|
+
showControls = computed(() => this.controls() && !this.isDisabled() && !this.isReadonly(), ...(ngDevMode ? [{ debugName: "showControls" }] : []));
|
|
11480
|
+
controlsOnRight = computed(() => this.controlsPosition() === 'right', ...(ngDevMode ? [{ debugName: "controlsOnRight" }] : []));
|
|
11481
|
+
controlsOnBoth = computed(() => this.controlsPosition() === 'both', ...(ngDevMode ? [{ debugName: "controlsOnBoth" }] : []));
|
|
11482
|
+
containerClasses = computed(() => {
|
|
11483
|
+
const classes = ['ds-input-number'];
|
|
11484
|
+
classes.push(`ds-input-number--${this.size()}`);
|
|
11485
|
+
if (this.isDisabled())
|
|
11486
|
+
classes.push('ds-input-number--disabled');
|
|
11487
|
+
if (this.isReadonly())
|
|
11488
|
+
classes.push('ds-input-number--readonly');
|
|
11489
|
+
if (this.focused())
|
|
11490
|
+
classes.push('ds-input-number--focused');
|
|
11491
|
+
if (this.controlsOnRight())
|
|
11492
|
+
classes.push('ds-input-number--controls-right');
|
|
11493
|
+
if (this.controlsOnBoth())
|
|
11494
|
+
classes.push('ds-input-number--controls-both');
|
|
11495
|
+
if (this.prefix())
|
|
11496
|
+
classes.push('ds-input-number--has-prefix');
|
|
11497
|
+
if (this.suffix())
|
|
11498
|
+
classes.push('ds-input-number--has-suffix');
|
|
11499
|
+
return classes.join(' ');
|
|
11500
|
+
}, ...(ngDevMode ? [{ debugName: "containerClasses" }] : []));
|
|
11501
|
+
canDecrement = computed(() => {
|
|
11502
|
+
if (!this.showControls())
|
|
11503
|
+
return false;
|
|
11504
|
+
const val = this.internalValue();
|
|
11505
|
+
if (val === null)
|
|
11506
|
+
return true;
|
|
11507
|
+
return val > this.min();
|
|
11508
|
+
}, ...(ngDevMode ? [{ debugName: "canDecrement" }] : []));
|
|
11509
|
+
canIncrement = computed(() => {
|
|
11510
|
+
if (!this.showControls())
|
|
11511
|
+
return false;
|
|
11512
|
+
const val = this.internalValue();
|
|
11513
|
+
if (val === null)
|
|
11514
|
+
return true;
|
|
11515
|
+
return val < this.max();
|
|
11516
|
+
}, ...(ngDevMode ? [{ debugName: "canIncrement" }] : []));
|
|
11517
|
+
// ControlValueAccessor
|
|
11518
|
+
onChange = () => { };
|
|
11519
|
+
onTouched = () => { };
|
|
11520
|
+
writeValue(value) {
|
|
11521
|
+
this.internalValue.set(value);
|
|
11522
|
+
}
|
|
11523
|
+
registerOnChange(fn) {
|
|
11524
|
+
this.onChange = fn;
|
|
11525
|
+
}
|
|
11526
|
+
registerOnTouched(fn) {
|
|
11527
|
+
this.onTouched = fn;
|
|
11528
|
+
}
|
|
11529
|
+
setDisabledState(isDisabled) {
|
|
11530
|
+
this.disabledState.set(isDisabled);
|
|
11531
|
+
}
|
|
11532
|
+
// Helpers
|
|
11533
|
+
formatValue(value) {
|
|
11534
|
+
const prec = this.precision();
|
|
11535
|
+
return prec > 0 ? value.toFixed(prec) : Math.floor(value).toString();
|
|
11536
|
+
}
|
|
11537
|
+
parseValue(input) {
|
|
11538
|
+
if (input === '' || input === '-')
|
|
11539
|
+
return null;
|
|
11540
|
+
const parsed = parseFloat(input);
|
|
11541
|
+
if (isNaN(parsed))
|
|
11542
|
+
return null;
|
|
11543
|
+
return parsed;
|
|
11544
|
+
}
|
|
11545
|
+
clampValue(value) {
|
|
11546
|
+
return Math.max(this.min(), Math.min(this.max(), value));
|
|
11547
|
+
}
|
|
11548
|
+
roundToPrecision(value) {
|
|
11549
|
+
const prec = this.precision();
|
|
11550
|
+
if (prec === 0)
|
|
11551
|
+
return Math.round(value);
|
|
11552
|
+
const multiplier = Math.pow(10, prec);
|
|
11553
|
+
return Math.round(value * multiplier) / multiplier;
|
|
11554
|
+
}
|
|
11555
|
+
emitValue(value) {
|
|
11556
|
+
this.onChange(value);
|
|
11557
|
+
if (value !== null) {
|
|
11558
|
+
this.valueChange.emit(value);
|
|
11559
|
+
}
|
|
11560
|
+
}
|
|
11561
|
+
// Event handlers
|
|
11562
|
+
onInputChange(event) {
|
|
11563
|
+
if (this.isDisabled() || this.isReadonly())
|
|
11564
|
+
return;
|
|
11565
|
+
const target = event.target;
|
|
11566
|
+
const parsed = this.parseValue(target.value);
|
|
11567
|
+
if (parsed === null) {
|
|
11568
|
+
this.internalValue.set(null);
|
|
11569
|
+
this.emitValue(null);
|
|
11570
|
+
return;
|
|
11571
|
+
}
|
|
11572
|
+
const clamped = this.clampValue(parsed);
|
|
11573
|
+
const rounded = this.roundToPrecision(clamped);
|
|
11574
|
+
this.internalValue.set(rounded);
|
|
11575
|
+
this.emitValue(rounded);
|
|
11576
|
+
}
|
|
11577
|
+
onInputBlur() {
|
|
11578
|
+
this.focused.set(false);
|
|
11579
|
+
this.onTouched();
|
|
11580
|
+
// Formater la valeur au blur
|
|
11581
|
+
const val = this.internalValue();
|
|
11582
|
+
if (val !== null) {
|
|
11583
|
+
const clamped = this.clampValue(val);
|
|
11584
|
+
const rounded = this.roundToPrecision(clamped);
|
|
11585
|
+
if (rounded !== val) {
|
|
11586
|
+
this.internalValue.set(rounded);
|
|
11587
|
+
this.emitValue(rounded);
|
|
11588
|
+
}
|
|
11589
|
+
}
|
|
11590
|
+
}
|
|
11591
|
+
onInputFocus() {
|
|
11592
|
+
this.focused.set(true);
|
|
11593
|
+
}
|
|
11594
|
+
onKeyDown(event) {
|
|
11595
|
+
if (this.isDisabled() || this.isReadonly())
|
|
11596
|
+
return;
|
|
11597
|
+
const stepVal = this.step();
|
|
11598
|
+
let handled = false;
|
|
11599
|
+
switch (event.key) {
|
|
11600
|
+
case 'ArrowUp':
|
|
11601
|
+
this.increment();
|
|
11602
|
+
handled = true;
|
|
11603
|
+
break;
|
|
11604
|
+
case 'ArrowDown':
|
|
11605
|
+
this.decrement();
|
|
11606
|
+
handled = true;
|
|
11607
|
+
break;
|
|
11608
|
+
case 'Home':
|
|
11609
|
+
this.setToMin();
|
|
11610
|
+
handled = true;
|
|
11611
|
+
break;
|
|
11612
|
+
case 'End':
|
|
11613
|
+
this.setToMax();
|
|
11614
|
+
handled = true;
|
|
11615
|
+
break;
|
|
11616
|
+
case 'PageUp':
|
|
11617
|
+
this.incrementBy(stepVal * 10);
|
|
11618
|
+
handled = true;
|
|
11619
|
+
break;
|
|
11620
|
+
case 'PageDown':
|
|
11621
|
+
this.decrementBy(stepVal * 10);
|
|
11622
|
+
handled = true;
|
|
11623
|
+
break;
|
|
11624
|
+
}
|
|
11625
|
+
if (handled) {
|
|
11626
|
+
event.preventDefault();
|
|
11627
|
+
}
|
|
11628
|
+
}
|
|
11629
|
+
increment() {
|
|
11630
|
+
if (!this.canIncrement())
|
|
11631
|
+
return;
|
|
11632
|
+
this.incrementBy(this.step());
|
|
11633
|
+
}
|
|
11634
|
+
decrement() {
|
|
11635
|
+
if (!this.canDecrement())
|
|
11636
|
+
return;
|
|
11637
|
+
this.decrementBy(this.step());
|
|
11638
|
+
}
|
|
11639
|
+
incrementBy(delta) {
|
|
11640
|
+
const current = this.internalValue() ?? this.min();
|
|
11641
|
+
const newValue = this.clampValue(this.roundToPrecision(current + delta));
|
|
11642
|
+
this.internalValue.set(newValue);
|
|
11643
|
+
this.emitValue(newValue);
|
|
11644
|
+
this.inputElement?.nativeElement.focus();
|
|
11645
|
+
}
|
|
11646
|
+
decrementBy(delta) {
|
|
11647
|
+
const current = this.internalValue() ?? this.max();
|
|
11648
|
+
const newValue = this.clampValue(this.roundToPrecision(current - delta));
|
|
11649
|
+
this.internalValue.set(newValue);
|
|
11650
|
+
this.emitValue(newValue);
|
|
11651
|
+
this.inputElement?.nativeElement.focus();
|
|
11652
|
+
}
|
|
11653
|
+
setToMin() {
|
|
11654
|
+
const newValue = this.min();
|
|
11655
|
+
this.internalValue.set(newValue);
|
|
11656
|
+
this.emitValue(newValue);
|
|
11657
|
+
}
|
|
11658
|
+
setToMax() {
|
|
11659
|
+
const newValue = this.max();
|
|
11660
|
+
this.internalValue.set(newValue);
|
|
11661
|
+
this.emitValue(newValue);
|
|
11662
|
+
}
|
|
11663
|
+
// ARIA helpers
|
|
11664
|
+
ariaValueMin = computed(() => this.min(), ...(ngDevMode ? [{ debugName: "ariaValueMin" }] : []));
|
|
11665
|
+
ariaValueMax = computed(() => this.max(), ...(ngDevMode ? [{ debugName: "ariaValueMax" }] : []));
|
|
11666
|
+
ariaValueNow = computed(() => this.internalValue() ?? undefined, ...(ngDevMode ? [{ debugName: "ariaValueNow" }] : []));
|
|
11667
|
+
ariaValueText = computed(() => {
|
|
11668
|
+
const val = this.internalValue();
|
|
11669
|
+
if (val === null)
|
|
11670
|
+
return undefined;
|
|
11671
|
+
const prefixStr = this.prefix() ?? '';
|
|
11672
|
+
const suffixStr = this.suffix() ?? '';
|
|
11673
|
+
return `${prefixStr}${this.formatValue(val)}${suffixStr}`;
|
|
11674
|
+
}, ...(ngDevMode ? [{ debugName: "ariaValueText" }] : []));
|
|
11675
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DsInputNumber, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
11676
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: DsInputNumber, isStandalone: true, selector: "ds-input-number", inputs: { min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, step: { classPropertyName: "step", publicName: "step", 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 }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, prefix: { classPropertyName: "prefix", publicName: "prefix", isSignal: true, isRequired: false, transformFunction: null }, suffix: { classPropertyName: "suffix", publicName: "suffix", isSignal: true, isRequired: false, transformFunction: null }, precision: { classPropertyName: "precision", publicName: "precision", isSignal: true, isRequired: false, transformFunction: null }, controls: { classPropertyName: "controls", publicName: "controls", isSignal: true, isRequired: false, transformFunction: null }, controlsPosition: { classPropertyName: "controlsPosition", publicName: "controlsPosition", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueChange: "valueChange" }, providers: [
|
|
11677
|
+
{
|
|
11678
|
+
provide: NG_VALUE_ACCESSOR,
|
|
11679
|
+
useExisting: forwardRef(() => DsInputNumber),
|
|
11680
|
+
multi: true,
|
|
11681
|
+
},
|
|
11682
|
+
], viewQueries: [{ propertyName: "inputElement", first: true, predicate: ["inputElement"], descendants: true }], ngImport: i0, template: "<div [class]=\"containerClasses()\">\n <!-- Bouton d\u00E9cr\u00E9mentation (position both) -->\n @if (showControls() && controlsOnBoth()) {\n <button\n type=\"button\"\n class=\"ds-input-number__btn ds-input-number__btn--decrement\"\n [disabled]=\"!canDecrement()\"\n (click)=\"decrement()\"\n [attr.aria-label]=\"'Decrement value'\"\n tabindex=\"-1\"\n >\n <fa-icon [icon]=\"faMinus\" />\n </button>\n }\n\n <!-- Wrapper pour input + prefix/suffix -->\n <div class=\"ds-input-number__input-wrapper\">\n @if (prefix()) {\n <span class=\"ds-input-number__prefix\">{{ prefix() }}</span>\n }\n\n <input\n #inputElement\n type=\"text\"\n class=\"ds-input-number__input\"\n [id]=\"id()\"\n [name]=\"name()\"\n [value]=\"displayValue()\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"isDisabled()\"\n [readonly]=\"isReadonly()\"\n [required]=\"required()\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-valuemin]=\"ariaValueMin()\"\n [attr.aria-valuemax]=\"ariaValueMax()\"\n [attr.aria-valuenow]=\"ariaValueNow()\"\n [attr.aria-valuetext]=\"ariaValueText()\"\n role=\"spinbutton\"\n (input)=\"onInputChange($event)\"\n (blur)=\"onInputBlur()\"\n (focus)=\"onInputFocus()\"\n (keydown)=\"onKeyDown($event)\"\n />\n\n @if (suffix()) {\n <span class=\"ds-input-number__suffix\">{{ suffix() }}</span>\n }\n </div>\n\n <!-- Boutons position right -->\n @if (showControls() && controlsOnRight()) {\n <div class=\"ds-input-number__controls-right\">\n <button\n type=\"button\"\n class=\"ds-input-number__btn ds-input-number__btn--increment-right\"\n [disabled]=\"!canIncrement()\"\n (click)=\"increment()\"\n [attr.aria-label]=\"'Increment value'\"\n tabindex=\"-1\"\n >\n <fa-icon [icon]=\"faPlus\" />\n </button>\n <button\n type=\"button\"\n class=\"ds-input-number__btn ds-input-number__btn--decrement-right\"\n [disabled]=\"!canDecrement()\"\n (click)=\"decrement()\"\n [attr.aria-label]=\"'Decrement value'\"\n tabindex=\"-1\"\n >\n <fa-icon [icon]=\"faMinus\" />\n </button>\n </div>\n }\n\n <!-- Bouton incr\u00E9mentation (position both) -->\n @if (showControls() && controlsOnBoth()) {\n <button\n type=\"button\"\n class=\"ds-input-number__btn ds-input-number__btn--increment\"\n [disabled]=\"!canIncrement()\"\n (click)=\"increment()\"\n [attr.aria-label]=\"'Increment value'\"\n tabindex=\"-1\"\n >\n <fa-icon [icon]=\"faPlus\" />\n </button>\n }\n</div>\n", styles: [".ds-input-number{display:inline-flex;align-items:stretch;position:relative;vertical-align:middle;width:100%;max-width:200px}.ds-input-number__input-wrapper{display:flex;align-items:center;flex:1;position:relative;background-color:var(--input-bg, var(--gray-50));border:1px solid var(--input-border-color, var(--gray-300));border-radius:var(--input-border-radius, var(--radius-2));transition:all .2s ease;overflow:hidden}.ds-input-number--focused .ds-input-number__input-wrapper{border-color:var(--input-focus-border, var(--color-primary));box-shadow:0 0 0 3px var(--input-focus-ring, rgba(37, 99, 235, .1))}.ds-input-number--disabled .ds-input-number__input-wrapper{background-color:var(--input-bg-disabled, var(--gray-100));border-color:var(--input-border-disabled, var(--gray-200));cursor:not-allowed}.ds-input-number--readonly .ds-input-number__input-wrapper{background-color:var(--input-bg-readonly, var(--gray-50));border-color:var(--input-border-color, var(--gray-300))}.ds-input-number__input{flex:1;border:none;outline:none;background:transparent;color:var(--input-text-color, var(--gray-900));font-family:inherit;text-align:center;padding:0 var(--space-2, .5rem)}.ds-input-number__input::placeholder{color:var(--input-placeholder, var(--gray-500))}.ds-input-number__input:disabled{cursor:not-allowed;color:var(--input-text-disabled, var(--gray-500))}.ds-input-number--readonly .ds-input-number__input{cursor:default}.ds-input-number__input::-webkit-outer-spin-button,.ds-input-number__input::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}.ds-input-number__input[type=number]{-moz-appearance:textfield}.ds-input-number__prefix,.ds-input-number__suffix{display:inline-flex;align-items:center;color:var(--input-placeholder, var(--gray-500));font-size:inherit;padding:0 var(--space-2, .5rem);-webkit-user-select:none;user-select:none}.ds-input-number__prefix{padding-right:0}.ds-input-number__suffix{padding-left:0}.ds-input-number__btn{display:inline-flex;align-items:center;justify-content:center;border:none;outline:none;cursor:pointer;background-color:var(--input-number-btn-bg, var(--gray-100));color:var(--input-text-color, var(--gray-900));transition:all .15s ease;-webkit-user-select:none;user-select:none}.ds-input-number__btn:hover:not(:disabled){background-color:var(--input-number-btn-hover, var(--gray-200))}.ds-input-number__btn:active:not(:disabled){background-color:var(--input-number-btn-active, var(--gray-300))}.ds-input-number__btn:disabled{cursor:not-allowed;background-color:var(--input-number-btn-disabled, var(--gray-50));color:var(--input-text-disabled, var(--gray-400))}.ds-input-number__btn fa-icon{font-size:.875em}.ds-input-number--controls-both .ds-input-number__btn--decrement{border-right:1px solid var(--input-border-color, var(--gray-300));border-top-left-radius:var(--input-border-radius, var(--radius-2));border-bottom-left-radius:var(--input-border-radius, var(--radius-2))}.ds-input-number--controls-both .ds-input-number__btn--increment{border-left:1px solid var(--input-border-color, var(--gray-300));border-top-right-radius:var(--input-border-radius, var(--radius-2));border-bottom-right-radius:var(--input-border-radius, var(--radius-2))}.ds-input-number--controls-both .ds-input-number__input-wrapper{border-radius:0}.ds-input-number--controls-right .ds-input-number__controls-right{display:flex;flex-direction:column;border-left:1px solid var(--input-border-color, var(--gray-300))}.ds-input-number--controls-right .ds-input-number__btn--increment-right,.ds-input-number--controls-right .ds-input-number__btn--decrement-right{flex:1;width:var(--input-number-btn-size-md, 24px)}.ds-input-number--controls-right .ds-input-number__btn--increment-right{border-bottom:1px solid var(--input-border-color, var(--gray-300));border-top-right-radius:var(--input-border-radius, var(--radius-2))}.ds-input-number--controls-right .ds-input-number__btn--decrement-right{border-bottom-right-radius:var(--input-border-radius, var(--radius-2))}.ds-input-number--controls-right .ds-input-number__input-wrapper{border-top-right-radius:0;border-bottom-right-radius:0}.ds-input-number--sm{font-size:var(--font-size-sm, .875rem)}.ds-input-number--sm .ds-input-number__input-wrapper{height:var(--input-number-height-sm, 32px)}.ds-input-number--sm .ds-input-number__btn{width:var(--input-number-btn-size-sm, 28px);height:var(--input-number-btn-size-sm, 28px)}.ds-input-number--sm.ds-input-number--controls-right .ds-input-number__btn{width:var(--input-number-btn-size-sm, 20px);height:calc(var(--input-number-height-sm, 32px) / 2)}.ds-input-number--md{font-size:var(--font-size-base, 1rem)}.ds-input-number--md .ds-input-number__input-wrapper{height:var(--input-number-height-md, 40px)}.ds-input-number--md .ds-input-number__btn{width:var(--input-number-btn-size-md, 36px);height:var(--input-number-btn-size-md, 36px)}.ds-input-number--md.ds-input-number--controls-right .ds-input-number__btn{width:var(--input-number-btn-size-md, 24px);height:calc(var(--input-number-height-md, 40px) / 2)}.ds-input-number--lg{font-size:var(--font-size-lg, 1.125rem)}.ds-input-number--lg .ds-input-number__input-wrapper{height:var(--input-number-height-lg, 48px)}.ds-input-number--lg .ds-input-number__btn{width:var(--input-number-btn-size-lg, 44px);height:var(--input-number-btn-size-lg, 44px)}.ds-input-number--lg.ds-input-number--controls-right .ds-input-number__btn{width:var(--input-number-btn-size-lg, 28px);height:calc(var(--input-number-height-lg, 48px) / 2)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: FaIconComponent, selector: "fa-icon", inputs: ["icon", "title", "animation", "mask", "flip", "size", "pull", "border", "inverse", "symbol", "rotate", "fixedWidth", "transform", "a11yRole"], outputs: ["iconChange", "titleChange", "animationChange", "maskChange", "flipChange", "sizeChange", "pullChange", "borderChange", "inverseChange", "symbolChange", "rotateChange", "fixedWidthChange", "transformChange", "a11yRoleChange"] }] });
|
|
11683
|
+
}
|
|
11684
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DsInputNumber, decorators: [{
|
|
11685
|
+
type: Component,
|
|
11686
|
+
args: [{ selector: 'ds-input-number', imports: [CommonModule, FaIconComponent], providers: [
|
|
11687
|
+
{
|
|
11688
|
+
provide: NG_VALUE_ACCESSOR,
|
|
11689
|
+
useExisting: forwardRef(() => DsInputNumber),
|
|
11690
|
+
multi: true,
|
|
11691
|
+
},
|
|
11692
|
+
], template: "<div [class]=\"containerClasses()\">\n <!-- Bouton d\u00E9cr\u00E9mentation (position both) -->\n @if (showControls() && controlsOnBoth()) {\n <button\n type=\"button\"\n class=\"ds-input-number__btn ds-input-number__btn--decrement\"\n [disabled]=\"!canDecrement()\"\n (click)=\"decrement()\"\n [attr.aria-label]=\"'Decrement value'\"\n tabindex=\"-1\"\n >\n <fa-icon [icon]=\"faMinus\" />\n </button>\n }\n\n <!-- Wrapper pour input + prefix/suffix -->\n <div class=\"ds-input-number__input-wrapper\">\n @if (prefix()) {\n <span class=\"ds-input-number__prefix\">{{ prefix() }}</span>\n }\n\n <input\n #inputElement\n type=\"text\"\n class=\"ds-input-number__input\"\n [id]=\"id()\"\n [name]=\"name()\"\n [value]=\"displayValue()\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"isDisabled()\"\n [readonly]=\"isReadonly()\"\n [required]=\"required()\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-valuemin]=\"ariaValueMin()\"\n [attr.aria-valuemax]=\"ariaValueMax()\"\n [attr.aria-valuenow]=\"ariaValueNow()\"\n [attr.aria-valuetext]=\"ariaValueText()\"\n role=\"spinbutton\"\n (input)=\"onInputChange($event)\"\n (blur)=\"onInputBlur()\"\n (focus)=\"onInputFocus()\"\n (keydown)=\"onKeyDown($event)\"\n />\n\n @if (suffix()) {\n <span class=\"ds-input-number__suffix\">{{ suffix() }}</span>\n }\n </div>\n\n <!-- Boutons position right -->\n @if (showControls() && controlsOnRight()) {\n <div class=\"ds-input-number__controls-right\">\n <button\n type=\"button\"\n class=\"ds-input-number__btn ds-input-number__btn--increment-right\"\n [disabled]=\"!canIncrement()\"\n (click)=\"increment()\"\n [attr.aria-label]=\"'Increment value'\"\n tabindex=\"-1\"\n >\n <fa-icon [icon]=\"faPlus\" />\n </button>\n <button\n type=\"button\"\n class=\"ds-input-number__btn ds-input-number__btn--decrement-right\"\n [disabled]=\"!canDecrement()\"\n (click)=\"decrement()\"\n [attr.aria-label]=\"'Decrement value'\"\n tabindex=\"-1\"\n >\n <fa-icon [icon]=\"faMinus\" />\n </button>\n </div>\n }\n\n <!-- Bouton incr\u00E9mentation (position both) -->\n @if (showControls() && controlsOnBoth()) {\n <button\n type=\"button\"\n class=\"ds-input-number__btn ds-input-number__btn--increment\"\n [disabled]=\"!canIncrement()\"\n (click)=\"increment()\"\n [attr.aria-label]=\"'Increment value'\"\n tabindex=\"-1\"\n >\n <fa-icon [icon]=\"faPlus\" />\n </button>\n }\n</div>\n", styles: [".ds-input-number{display:inline-flex;align-items:stretch;position:relative;vertical-align:middle;width:100%;max-width:200px}.ds-input-number__input-wrapper{display:flex;align-items:center;flex:1;position:relative;background-color:var(--input-bg, var(--gray-50));border:1px solid var(--input-border-color, var(--gray-300));border-radius:var(--input-border-radius, var(--radius-2));transition:all .2s ease;overflow:hidden}.ds-input-number--focused .ds-input-number__input-wrapper{border-color:var(--input-focus-border, var(--color-primary));box-shadow:0 0 0 3px var(--input-focus-ring, rgba(37, 99, 235, .1))}.ds-input-number--disabled .ds-input-number__input-wrapper{background-color:var(--input-bg-disabled, var(--gray-100));border-color:var(--input-border-disabled, var(--gray-200));cursor:not-allowed}.ds-input-number--readonly .ds-input-number__input-wrapper{background-color:var(--input-bg-readonly, var(--gray-50));border-color:var(--input-border-color, var(--gray-300))}.ds-input-number__input{flex:1;border:none;outline:none;background:transparent;color:var(--input-text-color, var(--gray-900));font-family:inherit;text-align:center;padding:0 var(--space-2, .5rem)}.ds-input-number__input::placeholder{color:var(--input-placeholder, var(--gray-500))}.ds-input-number__input:disabled{cursor:not-allowed;color:var(--input-text-disabled, var(--gray-500))}.ds-input-number--readonly .ds-input-number__input{cursor:default}.ds-input-number__input::-webkit-outer-spin-button,.ds-input-number__input::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}.ds-input-number__input[type=number]{-moz-appearance:textfield}.ds-input-number__prefix,.ds-input-number__suffix{display:inline-flex;align-items:center;color:var(--input-placeholder, var(--gray-500));font-size:inherit;padding:0 var(--space-2, .5rem);-webkit-user-select:none;user-select:none}.ds-input-number__prefix{padding-right:0}.ds-input-number__suffix{padding-left:0}.ds-input-number__btn{display:inline-flex;align-items:center;justify-content:center;border:none;outline:none;cursor:pointer;background-color:var(--input-number-btn-bg, var(--gray-100));color:var(--input-text-color, var(--gray-900));transition:all .15s ease;-webkit-user-select:none;user-select:none}.ds-input-number__btn:hover:not(:disabled){background-color:var(--input-number-btn-hover, var(--gray-200))}.ds-input-number__btn:active:not(:disabled){background-color:var(--input-number-btn-active, var(--gray-300))}.ds-input-number__btn:disabled{cursor:not-allowed;background-color:var(--input-number-btn-disabled, var(--gray-50));color:var(--input-text-disabled, var(--gray-400))}.ds-input-number__btn fa-icon{font-size:.875em}.ds-input-number--controls-both .ds-input-number__btn--decrement{border-right:1px solid var(--input-border-color, var(--gray-300));border-top-left-radius:var(--input-border-radius, var(--radius-2));border-bottom-left-radius:var(--input-border-radius, var(--radius-2))}.ds-input-number--controls-both .ds-input-number__btn--increment{border-left:1px solid var(--input-border-color, var(--gray-300));border-top-right-radius:var(--input-border-radius, var(--radius-2));border-bottom-right-radius:var(--input-border-radius, var(--radius-2))}.ds-input-number--controls-both .ds-input-number__input-wrapper{border-radius:0}.ds-input-number--controls-right .ds-input-number__controls-right{display:flex;flex-direction:column;border-left:1px solid var(--input-border-color, var(--gray-300))}.ds-input-number--controls-right .ds-input-number__btn--increment-right,.ds-input-number--controls-right .ds-input-number__btn--decrement-right{flex:1;width:var(--input-number-btn-size-md, 24px)}.ds-input-number--controls-right .ds-input-number__btn--increment-right{border-bottom:1px solid var(--input-border-color, var(--gray-300));border-top-right-radius:var(--input-border-radius, var(--radius-2))}.ds-input-number--controls-right .ds-input-number__btn--decrement-right{border-bottom-right-radius:var(--input-border-radius, var(--radius-2))}.ds-input-number--controls-right .ds-input-number__input-wrapper{border-top-right-radius:0;border-bottom-right-radius:0}.ds-input-number--sm{font-size:var(--font-size-sm, .875rem)}.ds-input-number--sm .ds-input-number__input-wrapper{height:var(--input-number-height-sm, 32px)}.ds-input-number--sm .ds-input-number__btn{width:var(--input-number-btn-size-sm, 28px);height:var(--input-number-btn-size-sm, 28px)}.ds-input-number--sm.ds-input-number--controls-right .ds-input-number__btn{width:var(--input-number-btn-size-sm, 20px);height:calc(var(--input-number-height-sm, 32px) / 2)}.ds-input-number--md{font-size:var(--font-size-base, 1rem)}.ds-input-number--md .ds-input-number__input-wrapper{height:var(--input-number-height-md, 40px)}.ds-input-number--md .ds-input-number__btn{width:var(--input-number-btn-size-md, 36px);height:var(--input-number-btn-size-md, 36px)}.ds-input-number--md.ds-input-number--controls-right .ds-input-number__btn{width:var(--input-number-btn-size-md, 24px);height:calc(var(--input-number-height-md, 40px) / 2)}.ds-input-number--lg{font-size:var(--font-size-lg, 1.125rem)}.ds-input-number--lg .ds-input-number__input-wrapper{height:var(--input-number-height-lg, 48px)}.ds-input-number--lg .ds-input-number__btn{width:var(--input-number-btn-size-lg, 44px);height:var(--input-number-btn-size-lg, 44px)}.ds-input-number--lg.ds-input-number--controls-right .ds-input-number__btn{width:var(--input-number-btn-size-lg, 28px);height:calc(var(--input-number-height-lg, 48px) / 2)}\n"] }]
|
|
11693
|
+
}], ctorParameters: () => [], propDecorators: { min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], step: [{ type: i0.Input, args: [{ isSignal: true, alias: "step", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], prefix: [{ type: i0.Input, args: [{ isSignal: true, alias: "prefix", required: false }] }], suffix: [{ type: i0.Input, args: [{ isSignal: true, alias: "suffix", required: false }] }], precision: [{ type: i0.Input, args: [{ isSignal: true, alias: "precision", required: false }] }], controls: [{ type: i0.Input, args: [{ isSignal: true, alias: "controls", required: false }] }], controlsPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "controlsPosition", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], valueChange: [{ type: i0.Output, args: ["valueChange"] }], inputElement: [{
|
|
11694
|
+
type: ViewChild,
|
|
11695
|
+
args: ['inputElement', { static: false }]
|
|
11696
|
+
}] } });
|
|
11697
|
+
|
|
11698
|
+
/**
|
|
11699
|
+
* DS Segmented Control
|
|
11700
|
+
*
|
|
11701
|
+
* Composant groupe de boutons mutuellement exclusifs visuellement connectés.
|
|
11702
|
+
* Alternative stylisée aux boutons radio pour basculer entre vues, modes ou options.
|
|
11703
|
+
*
|
|
11704
|
+
* @example
|
|
11705
|
+
* // Formulaire réactif
|
|
11706
|
+
* <ds-segmented-control
|
|
11707
|
+
* formControlName="view"
|
|
11708
|
+
* [options]="viewOptions"
|
|
11709
|
+
* size="md"
|
|
11710
|
+
* fullWidth
|
|
11711
|
+
* />
|
|
11712
|
+
*
|
|
11713
|
+
* @example
|
|
11714
|
+
* // Template-driven
|
|
11715
|
+
* <ds-segmented-control
|
|
11716
|
+
* [(ngModel)]="selectedView"
|
|
11717
|
+
* [options]="[
|
|
11718
|
+
* { value: 'list', label: 'Liste', icon: 'fas-list' },
|
|
11719
|
+
* { value: 'grid', label: 'Grille', icon: 'fas-grid' },
|
|
11720
|
+
* { value: 'map', label: 'Carte', icon: 'fas-map' }
|
|
11721
|
+
* ]"
|
|
11722
|
+
* color="neutral"
|
|
11723
|
+
* />
|
|
11724
|
+
*/
|
|
11725
|
+
class DsSegmentedControl {
|
|
11726
|
+
/**
|
|
11727
|
+
* Liste des options du segmented control
|
|
11728
|
+
*/
|
|
11729
|
+
options = input.required(...(ngDevMode ? [{ debugName: "options" }] : []));
|
|
11730
|
+
/**
|
|
11731
|
+
* Taille du segmented control (sm, md, lg)
|
|
11732
|
+
*/
|
|
11733
|
+
size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : []));
|
|
11734
|
+
/**
|
|
11735
|
+
* État désactivé global
|
|
11736
|
+
*/
|
|
11737
|
+
disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
|
|
11738
|
+
/**
|
|
11739
|
+
* Prend toute la largeur du conteneur
|
|
11740
|
+
*/
|
|
11741
|
+
fullWidth = input(false, ...(ngDevMode ? [{ debugName: "fullWidth" }] : []));
|
|
11742
|
+
/**
|
|
11743
|
+
* Orientation (horizontal, vertical)
|
|
11744
|
+
*/
|
|
11745
|
+
orientation = input('horizontal', ...(ngDevMode ? [{ debugName: "orientation" }] : []));
|
|
11746
|
+
/**
|
|
11747
|
+
* Couleur du segment actif (primary, neutral)
|
|
11748
|
+
*/
|
|
11749
|
+
color = input('primary', ...(ngDevMode ? [{ debugName: "color" }] : []));
|
|
11750
|
+
// Internal state
|
|
11751
|
+
disabledState = signal(false, ...(ngDevMode ? [{ debugName: "disabledState" }] : []));
|
|
11752
|
+
internalValue = signal(null, ...(ngDevMode ? [{ debugName: "internalValue" }] : []));
|
|
11753
|
+
// Computed properties
|
|
11754
|
+
isDisabled = computed(() => this.disabled() || this.disabledState(), ...(ngDevMode ? [{ debugName: "isDisabled" }] : []));
|
|
11755
|
+
containerClasses = computed(() => ({
|
|
11756
|
+
'ds-segmented-control': true,
|
|
11757
|
+
[`ds-segmented-control--${this.size()}`]: true,
|
|
11758
|
+
[`ds-segmented-control--${this.orientation()}`]: true,
|
|
11759
|
+
[`ds-segmented-control--${this.color()}`]: true,
|
|
11760
|
+
'ds-segmented-control--full-width': this.fullWidth(),
|
|
11761
|
+
'ds-segmented-control--disabled': this.isDisabled(),
|
|
11762
|
+
}), ...(ngDevMode ? [{ debugName: "containerClasses" }] : []));
|
|
11763
|
+
activeIndex = computed(() => {
|
|
11764
|
+
const value = this.internalValue();
|
|
11765
|
+
if (!value)
|
|
11766
|
+
return -1;
|
|
11767
|
+
return this.options().findIndex((opt) => opt.value === value);
|
|
11768
|
+
}, ...(ngDevMode ? [{ debugName: "activeIndex" }] : []));
|
|
11769
|
+
/**
|
|
11770
|
+
* Vérifie si une option est sélectionnée
|
|
11771
|
+
*/
|
|
11772
|
+
isOptionSelected(option) {
|
|
11773
|
+
return this.internalValue() === option.value;
|
|
11774
|
+
}
|
|
11775
|
+
/**
|
|
11776
|
+
* Vérifie si une option est désactivée
|
|
11777
|
+
*/
|
|
11778
|
+
isOptionDisabled(option) {
|
|
11779
|
+
return this.isDisabled() || !!option.disabled;
|
|
11780
|
+
}
|
|
11781
|
+
/**
|
|
11782
|
+
* Classes CSS pour un segment
|
|
11783
|
+
*/
|
|
11784
|
+
getSegmentClasses(option) {
|
|
11785
|
+
return {
|
|
11786
|
+
'ds-segmented-control__segment': true,
|
|
11787
|
+
'ds-segmented-control__segment--active': this.isOptionSelected(option),
|
|
11788
|
+
'ds-segmented-control__segment--disabled': this.isOptionDisabled(option),
|
|
11789
|
+
};
|
|
11790
|
+
}
|
|
11791
|
+
// ControlValueAccessor implementation
|
|
11792
|
+
onChange = () => { };
|
|
11793
|
+
onTouched = () => { };
|
|
11794
|
+
writeValue(value) {
|
|
11795
|
+
this.internalValue.set(value);
|
|
11796
|
+
}
|
|
11797
|
+
registerOnChange(fn) {
|
|
11798
|
+
this.onChange = fn;
|
|
11799
|
+
}
|
|
11800
|
+
registerOnTouched(fn) {
|
|
11801
|
+
this.onTouched = fn;
|
|
11802
|
+
}
|
|
11803
|
+
setDisabledState(isDisabled) {
|
|
11804
|
+
this.disabledState.set(isDisabled);
|
|
11805
|
+
}
|
|
11806
|
+
// Event handlers
|
|
11807
|
+
onSegmentClick(option) {
|
|
11808
|
+
if (this.isOptionDisabled(option)) {
|
|
11809
|
+
return;
|
|
11810
|
+
}
|
|
11811
|
+
this.internalValue.set(option.value);
|
|
11812
|
+
this.onChange(option.value);
|
|
11813
|
+
this.onTouched();
|
|
11814
|
+
}
|
|
11815
|
+
onKeydown(event) {
|
|
11816
|
+
const target = event.target;
|
|
11817
|
+
if (target.getAttribute('role') !== 'radio')
|
|
11818
|
+
return;
|
|
11819
|
+
const currentIndex = this.activeIndex();
|
|
11820
|
+
const optionsArray = this.options();
|
|
11821
|
+
const isHorizontal = this.orientation() === 'horizontal';
|
|
11822
|
+
let nextIndex = currentIndex;
|
|
11823
|
+
switch (event.key) {
|
|
11824
|
+
case 'ArrowLeft':
|
|
11825
|
+
if (!isHorizontal)
|
|
11826
|
+
return;
|
|
11827
|
+
event.preventDefault();
|
|
11828
|
+
nextIndex = this.findPreviousEnabledOption(currentIndex);
|
|
11829
|
+
break;
|
|
11830
|
+
case 'ArrowRight':
|
|
11831
|
+
if (!isHorizontal)
|
|
11832
|
+
return;
|
|
11833
|
+
event.preventDefault();
|
|
11834
|
+
nextIndex = this.findNextEnabledOption(currentIndex);
|
|
11835
|
+
break;
|
|
11836
|
+
case 'ArrowUp':
|
|
11837
|
+
if (isHorizontal)
|
|
11838
|
+
return;
|
|
11839
|
+
event.preventDefault();
|
|
11840
|
+
nextIndex = this.findPreviousEnabledOption(currentIndex);
|
|
11841
|
+
break;
|
|
11842
|
+
case 'ArrowDown':
|
|
11843
|
+
if (isHorizontal)
|
|
11844
|
+
return;
|
|
11845
|
+
event.preventDefault();
|
|
11846
|
+
nextIndex = this.findNextEnabledOption(currentIndex);
|
|
11847
|
+
break;
|
|
11848
|
+
case 'Home':
|
|
11849
|
+
event.preventDefault();
|
|
11850
|
+
nextIndex = this.findNextEnabledOption(-1);
|
|
11851
|
+
break;
|
|
11852
|
+
case 'End':
|
|
11853
|
+
event.preventDefault();
|
|
11854
|
+
nextIndex = this.findPreviousEnabledOption(optionsArray.length);
|
|
11855
|
+
break;
|
|
11856
|
+
default:
|
|
11857
|
+
return;
|
|
11858
|
+
}
|
|
11859
|
+
if (nextIndex !== currentIndex && nextIndex !== -1) {
|
|
11860
|
+
this.onSegmentClick(optionsArray[nextIndex]);
|
|
11861
|
+
this.focusSegment(nextIndex);
|
|
11862
|
+
}
|
|
11863
|
+
}
|
|
11864
|
+
findNextEnabledOption(startIndex) {
|
|
11865
|
+
const optionsArray = this.options();
|
|
11866
|
+
for (let i = startIndex + 1; i < optionsArray.length; i++) {
|
|
11867
|
+
if (!optionsArray[i].disabled)
|
|
11868
|
+
return i;
|
|
11869
|
+
}
|
|
11870
|
+
return startIndex === -1 ? 0 : startIndex;
|
|
11871
|
+
}
|
|
11872
|
+
findPreviousEnabledOption(startIndex) {
|
|
11873
|
+
const optionsArray = this.options();
|
|
11874
|
+
for (let i = startIndex - 1; i >= 0; i--) {
|
|
11875
|
+
if (!optionsArray[i].disabled)
|
|
11876
|
+
return i;
|
|
11877
|
+
}
|
|
11878
|
+
return startIndex === optionsArray.length ? optionsArray.length - 1 : startIndex;
|
|
11879
|
+
}
|
|
11880
|
+
focusSegment(index) {
|
|
11881
|
+
setTimeout(() => {
|
|
11882
|
+
const segment = document.querySelector(`.ds-segmented-control__segment[data-index="${index}"]`);
|
|
11883
|
+
segment?.focus();
|
|
11884
|
+
}, 0);
|
|
11885
|
+
}
|
|
11886
|
+
// Track function for @for
|
|
11887
|
+
trackByValue(_index, option) {
|
|
11888
|
+
return option.value;
|
|
11889
|
+
}
|
|
11890
|
+
/**
|
|
11891
|
+
* Parse l'icône depuis le format string vers le format FontAwesome
|
|
11892
|
+
* @param iconName - Nom de l'icône (ex: 'fas-list', 'list', 'fa-solid fa-list')
|
|
11893
|
+
* @returns Tuple [prefix, iconName] pour FontAwesome
|
|
11894
|
+
*/
|
|
11895
|
+
parseIcon(iconName) {
|
|
11896
|
+
// Format: 'fas-list' ou 'far-check'
|
|
11897
|
+
if (iconName.includes('-')) {
|
|
11898
|
+
const parts = iconName.split('-');
|
|
11899
|
+
if (parts[0] === 'fas' || parts[0] === 'far' || parts[0] === 'fab') {
|
|
11900
|
+
return [parts[0], parts.slice(1).join('-')];
|
|
11901
|
+
}
|
|
11902
|
+
}
|
|
11903
|
+
// Par défaut, utiliser 'fas' comme préfixe
|
|
11904
|
+
return ['fas', iconName];
|
|
11905
|
+
}
|
|
11906
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DsSegmentedControl, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
11907
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: DsSegmentedControl, isStandalone: true, selector: "ds-segmented-control", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: true, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, fullWidth: { classPropertyName: "fullWidth", publicName: "fullWidth", isSignal: true, isRequired: false, transformFunction: null }, orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "keydown": "onKeydown($event)" } }, providers: [
|
|
11908
|
+
{
|
|
11909
|
+
provide: NG_VALUE_ACCESSOR,
|
|
11910
|
+
useExisting: forwardRef(() => DsSegmentedControl),
|
|
11911
|
+
multi: true,
|
|
11912
|
+
},
|
|
11913
|
+
], ngImport: i0, template: "<div\n [ngClass]=\"containerClasses()\"\n role=\"radiogroup\"\n [attr.aria-disabled]=\"isDisabled()\"\n>\n @for (option of options(); track trackByValue($index, option)) {\n <button\n type=\"button\"\n role=\"radio\"\n [ngClass]=\"getSegmentClasses(option)\"\n [attr.data-index]=\"$index\"\n [attr.aria-checked]=\"isOptionSelected(option)\"\n [attr.aria-disabled]=\"isOptionDisabled(option)\"\n [disabled]=\"isOptionDisabled(option)\"\n [tabindex]=\"isOptionSelected(option) ? 0 : -1\"\n (click)=\"onSegmentClick(option)\"\n >\n @if (option.icon) {\n <fa-icon\n class=\"ds-segmented-control__icon\"\n [icon]=\"parseIcon(option.icon)\"\n />\n }\n <span class=\"ds-segmented-control__label\">{{ option.label }}</span>\n </button>\n }\n</div>\n", styles: [".ds-segmented-control{display:inline-flex;background:var(--segmented-bg);border-radius:var(--segmented-border-radius);padding:var(--segmented-gap);gap:var(--segmented-gap);box-shadow:inset 0 0 0 1px var(--segmented-border-color)}.ds-segmented-control--horizontal{flex-direction:row}.ds-segmented-control--vertical{flex-direction:column}.ds-segmented-control--full-width{display:flex;width:100%}.ds-segmented-control--full-width .ds-segmented-control__segment{flex:1}.ds-segmented-control--disabled{opacity:.5;cursor:not-allowed}.ds-segmented-control--sm .ds-segmented-control__segment{height:var(--segmented-height-sm);padding:0 var(--segmented-padding-sm);font-size:var(--segmented-font-size-sm);border-radius:calc(var(--segmented-border-radius) - var(--segmented-gap))}.ds-segmented-control--sm .ds-segmented-control__icon{font-size:var(--segmented-icon-size-sm)}.ds-segmented-control--md .ds-segmented-control__segment{height:var(--segmented-height-md);padding:0 var(--segmented-padding-md);font-size:var(--segmented-font-size-md);border-radius:calc(var(--segmented-border-radius) - var(--segmented-gap))}.ds-segmented-control--md .ds-segmented-control__icon{font-size:var(--segmented-icon-size-md)}.ds-segmented-control--lg .ds-segmented-control__segment{height:var(--segmented-height-lg);padding:0 var(--segmented-padding-lg);font-size:var(--segmented-font-size-lg);border-radius:calc(var(--segmented-border-radius) - var(--segmented-gap))}.ds-segmented-control--lg .ds-segmented-control__icon{font-size:var(--segmented-icon-size-lg)}.ds-segmented-control__segment{display:inline-flex;align-items:center;justify-content:center;gap:var(--segmented-segment-gap);border:none;background:transparent;color:var(--segmented-text);font-weight:500;cursor:pointer;transition:all .2s ease;white-space:nowrap;-webkit-user-select:none;user-select:none}.ds-segmented-control__segment:hover:not(.ds-segmented-control__segment--disabled):not(.ds-segmented-control__segment--active){background:var(--segmented-hover-bg)}.ds-segmented-control__segment:focus-visible{outline:2px solid var(--color-primary);outline-offset:2px}.ds-segmented-control__segment--active{background:var(--segmented-active-bg);color:var(--segmented-active-text);box-shadow:var(--segmented-active-shadow);font-weight:600}.ds-segmented-control__segment--disabled{cursor:not-allowed;opacity:.4}.ds-segmented-control__icon{display:inline-flex;flex-shrink:0}.ds-segmented-control__label{display:inline-flex}.ds-segmented-control--primary .ds-segmented-control__segment--active{background:var(--segmented-active-bg-primary);color:var(--segmented-active-text-primary)}.ds-segmented-control--neutral .ds-segmented-control__segment--active{background:var(--segmented-active-bg-neutral);color:var(--segmented-active-text-neutral)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FontAwesomeModule }, { kind: "component", type: i1$1.FaIconComponent, selector: "fa-icon", inputs: ["icon", "title", "animation", "mask", "flip", "size", "pull", "border", "inverse", "symbol", "rotate", "fixedWidth", "transform", "a11yRole"], outputs: ["iconChange", "titleChange", "animationChange", "maskChange", "flipChange", "sizeChange", "pullChange", "borderChange", "inverseChange", "symbolChange", "rotateChange", "fixedWidthChange", "transformChange", "a11yRoleChange"] }] });
|
|
11914
|
+
}
|
|
11915
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DsSegmentedControl, decorators: [{
|
|
11916
|
+
type: Component,
|
|
11917
|
+
args: [{ selector: 'ds-segmented-control', standalone: true, imports: [CommonModule, FontAwesomeModule], providers: [
|
|
11918
|
+
{
|
|
11919
|
+
provide: NG_VALUE_ACCESSOR,
|
|
11920
|
+
useExisting: forwardRef(() => DsSegmentedControl),
|
|
11921
|
+
multi: true,
|
|
11922
|
+
},
|
|
11923
|
+
], template: "<div\n [ngClass]=\"containerClasses()\"\n role=\"radiogroup\"\n [attr.aria-disabled]=\"isDisabled()\"\n>\n @for (option of options(); track trackByValue($index, option)) {\n <button\n type=\"button\"\n role=\"radio\"\n [ngClass]=\"getSegmentClasses(option)\"\n [attr.data-index]=\"$index\"\n [attr.aria-checked]=\"isOptionSelected(option)\"\n [attr.aria-disabled]=\"isOptionDisabled(option)\"\n [disabled]=\"isOptionDisabled(option)\"\n [tabindex]=\"isOptionSelected(option) ? 0 : -1\"\n (click)=\"onSegmentClick(option)\"\n >\n @if (option.icon) {\n <fa-icon\n class=\"ds-segmented-control__icon\"\n [icon]=\"parseIcon(option.icon)\"\n />\n }\n <span class=\"ds-segmented-control__label\">{{ option.label }}</span>\n </button>\n }\n</div>\n", styles: [".ds-segmented-control{display:inline-flex;background:var(--segmented-bg);border-radius:var(--segmented-border-radius);padding:var(--segmented-gap);gap:var(--segmented-gap);box-shadow:inset 0 0 0 1px var(--segmented-border-color)}.ds-segmented-control--horizontal{flex-direction:row}.ds-segmented-control--vertical{flex-direction:column}.ds-segmented-control--full-width{display:flex;width:100%}.ds-segmented-control--full-width .ds-segmented-control__segment{flex:1}.ds-segmented-control--disabled{opacity:.5;cursor:not-allowed}.ds-segmented-control--sm .ds-segmented-control__segment{height:var(--segmented-height-sm);padding:0 var(--segmented-padding-sm);font-size:var(--segmented-font-size-sm);border-radius:calc(var(--segmented-border-radius) - var(--segmented-gap))}.ds-segmented-control--sm .ds-segmented-control__icon{font-size:var(--segmented-icon-size-sm)}.ds-segmented-control--md .ds-segmented-control__segment{height:var(--segmented-height-md);padding:0 var(--segmented-padding-md);font-size:var(--segmented-font-size-md);border-radius:calc(var(--segmented-border-radius) - var(--segmented-gap))}.ds-segmented-control--md .ds-segmented-control__icon{font-size:var(--segmented-icon-size-md)}.ds-segmented-control--lg .ds-segmented-control__segment{height:var(--segmented-height-lg);padding:0 var(--segmented-padding-lg);font-size:var(--segmented-font-size-lg);border-radius:calc(var(--segmented-border-radius) - var(--segmented-gap))}.ds-segmented-control--lg .ds-segmented-control__icon{font-size:var(--segmented-icon-size-lg)}.ds-segmented-control__segment{display:inline-flex;align-items:center;justify-content:center;gap:var(--segmented-segment-gap);border:none;background:transparent;color:var(--segmented-text);font-weight:500;cursor:pointer;transition:all .2s ease;white-space:nowrap;-webkit-user-select:none;user-select:none}.ds-segmented-control__segment:hover:not(.ds-segmented-control__segment--disabled):not(.ds-segmented-control__segment--active){background:var(--segmented-hover-bg)}.ds-segmented-control__segment:focus-visible{outline:2px solid var(--color-primary);outline-offset:2px}.ds-segmented-control__segment--active{background:var(--segmented-active-bg);color:var(--segmented-active-text);box-shadow:var(--segmented-active-shadow);font-weight:600}.ds-segmented-control__segment--disabled{cursor:not-allowed;opacity:.4}.ds-segmented-control__icon{display:inline-flex;flex-shrink:0}.ds-segmented-control__label{display:inline-flex}.ds-segmented-control--primary .ds-segmented-control__segment--active{background:var(--segmented-active-bg-primary);color:var(--segmented-active-text-primary)}.ds-segmented-control--neutral .ds-segmented-control__segment--active{background:var(--segmented-active-bg-neutral);color:var(--segmented-active-text-neutral)}\n"] }]
|
|
11924
|
+
}], propDecorators: { options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: true }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], fullWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "fullWidth", required: false }] }], orientation: [{ type: i0.Input, args: [{ isSignal: true, alias: "orientation", required: false }] }], color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], onKeydown: [{
|
|
11925
|
+
type: HostListener,
|
|
11926
|
+
args: ['keydown', ['$event']]
|
|
11927
|
+
}] } });
|
|
11928
|
+
|
|
11929
|
+
class DsColorPickerPanelComponent {
|
|
11930
|
+
spectrumCanvas;
|
|
11931
|
+
// Config (set by parent)
|
|
11932
|
+
value = '';
|
|
11933
|
+
showAlpha = false;
|
|
11934
|
+
presetColors = [];
|
|
11935
|
+
recentColors = [];
|
|
11936
|
+
showRecentColors = false;
|
|
11937
|
+
format = 'hex';
|
|
11938
|
+
// Outputs
|
|
11939
|
+
colorSelected = output();
|
|
11940
|
+
closed = output();
|
|
11941
|
+
// Icons
|
|
11942
|
+
checkIcon = faCheck;
|
|
11943
|
+
// State
|
|
11944
|
+
hue = signal(0, ...(ngDevMode ? [{ debugName: "hue" }] : []));
|
|
11945
|
+
saturation = signal(100, ...(ngDevMode ? [{ debugName: "saturation" }] : []));
|
|
11946
|
+
lightness = signal(50, ...(ngDevMode ? [{ debugName: "lightness" }] : []));
|
|
11947
|
+
alpha = signal(1, ...(ngDevMode ? [{ debugName: "alpha" }] : []));
|
|
11948
|
+
cursorX = signal(null, ...(ngDevMode ? [{ debugName: "cursorX" }] : []));
|
|
11949
|
+
cursorY = signal(null, ...(ngDevMode ? [{ debugName: "cursorY" }] : []));
|
|
11950
|
+
isDragging = signal(false, ...(ngDevMode ? [{ debugName: "isDragging" }] : []));
|
|
11951
|
+
// Computed
|
|
11952
|
+
rgb = computed(() => this.hslToRGB(this.hue(), this.saturation(), this.lightness()), ...(ngDevMode ? [{ debugName: "rgb" }] : []));
|
|
11953
|
+
hexValue = computed(() => {
|
|
11954
|
+
const rgb = this.rgb();
|
|
11955
|
+
const r = rgb.r.toString(16).padStart(2, '0');
|
|
11956
|
+
const g = rgb.g.toString(16).padStart(2, '0');
|
|
11957
|
+
const b = rgb.b.toString(16).padStart(2, '0');
|
|
11958
|
+
return `#${r}${g}${b}`;
|
|
11959
|
+
}, ...(ngDevMode ? [{ debugName: "hexValue" }] : []));
|
|
11960
|
+
currentColor = computed(() => {
|
|
11961
|
+
if (this.showAlpha && this.alpha() < 1) {
|
|
11962
|
+
const rgb = this.rgb();
|
|
11963
|
+
return `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${this.alpha()})`;
|
|
11964
|
+
}
|
|
11965
|
+
return this.hexValue();
|
|
11966
|
+
}, ...(ngDevMode ? [{ debugName: "currentColor" }] : []));
|
|
11967
|
+
constructor() {
|
|
11968
|
+
// Observer les changements de couleur
|
|
11969
|
+
effect(() => {
|
|
11970
|
+
const color = this.currentColor();
|
|
11971
|
+
if (color !== this.value) {
|
|
11972
|
+
this.colorSelected.emit(color);
|
|
11973
|
+
}
|
|
11974
|
+
});
|
|
11975
|
+
}
|
|
11976
|
+
ngAfterViewInit() {
|
|
11977
|
+
this.initializeFromValue();
|
|
11978
|
+
this.renderSpectrum();
|
|
11979
|
+
}
|
|
11980
|
+
initializeFromValue() {
|
|
11981
|
+
if (!this.value) {
|
|
11982
|
+
this.updateCursor();
|
|
11983
|
+
return;
|
|
11984
|
+
}
|
|
11985
|
+
const rgb = this.parseColor(this.value);
|
|
11986
|
+
if (rgb) {
|
|
11987
|
+
const hsl = this.rgbToHSL(rgb.r, rgb.g, rgb.b);
|
|
11988
|
+
this.hue.set(hsl.h);
|
|
11989
|
+
this.saturation.set(hsl.s);
|
|
11990
|
+
this.lightness.set(hsl.l);
|
|
11991
|
+
if (rgb.a !== undefined) {
|
|
11992
|
+
this.alpha.set(rgb.a);
|
|
11993
|
+
}
|
|
11994
|
+
this.updateCursor();
|
|
11995
|
+
}
|
|
11996
|
+
}
|
|
11997
|
+
renderSpectrum() {
|
|
11998
|
+
if (!this.spectrumCanvas)
|
|
11999
|
+
return;
|
|
12000
|
+
const canvas = this.spectrumCanvas.nativeElement;
|
|
12001
|
+
const ctx = canvas.getContext('2d');
|
|
12002
|
+
if (!ctx)
|
|
12003
|
+
return;
|
|
12004
|
+
const width = canvas.width;
|
|
12005
|
+
const height = canvas.height;
|
|
12006
|
+
// Gradient de saturation (horizontal)
|
|
12007
|
+
const satGradient = ctx.createLinearGradient(0, 0, width, 0);
|
|
12008
|
+
satGradient.addColorStop(0, 'white');
|
|
12009
|
+
satGradient.addColorStop(1, `hsl(${this.hue()}, 100%, 50%)`);
|
|
12010
|
+
ctx.fillStyle = satGradient;
|
|
12011
|
+
ctx.fillRect(0, 0, width, height);
|
|
12012
|
+
// Gradient de luminosité (vertical)
|
|
12013
|
+
const lightGradient = ctx.createLinearGradient(0, 0, 0, height);
|
|
12014
|
+
lightGradient.addColorStop(0, 'transparent');
|
|
12015
|
+
lightGradient.addColorStop(1, 'black');
|
|
12016
|
+
ctx.fillStyle = lightGradient;
|
|
12017
|
+
ctx.fillRect(0, 0, width, height);
|
|
12018
|
+
}
|
|
12019
|
+
updateCursor() {
|
|
12020
|
+
if (!this.spectrumCanvas)
|
|
12021
|
+
return;
|
|
12022
|
+
const canvas = this.spectrumCanvas.nativeElement;
|
|
12023
|
+
const x = (this.saturation() / 100) * canvas.width;
|
|
12024
|
+
const y = ((100 - this.lightness()) / 100) * canvas.height;
|
|
12025
|
+
this.cursorX.set(x);
|
|
12026
|
+
this.cursorY.set(y);
|
|
12027
|
+
}
|
|
12028
|
+
onHueChange(event) {
|
|
12029
|
+
const target = event.target;
|
|
12030
|
+
this.hue.set(parseInt(target.value, 10));
|
|
12031
|
+
this.renderSpectrum();
|
|
12032
|
+
}
|
|
12033
|
+
onAlphaChange(event) {
|
|
12034
|
+
const target = event.target;
|
|
12035
|
+
this.alpha.set(parseInt(target.value, 10) / 100);
|
|
12036
|
+
}
|
|
12037
|
+
onSpectrumMouseDown(event) {
|
|
12038
|
+
this.isDragging.set(true);
|
|
12039
|
+
this.updateColorFromSpectrum(event);
|
|
12040
|
+
}
|
|
12041
|
+
onSpectrumMouseMove(event) {
|
|
12042
|
+
if (this.isDragging()) {
|
|
12043
|
+
this.updateColorFromSpectrum(event);
|
|
12044
|
+
}
|
|
12045
|
+
}
|
|
12046
|
+
onSpectrumMouseUp() {
|
|
12047
|
+
this.isDragging.set(false);
|
|
12048
|
+
}
|
|
12049
|
+
updateColorFromSpectrum(event) {
|
|
12050
|
+
if (!this.spectrumCanvas)
|
|
12051
|
+
return;
|
|
12052
|
+
const canvas = this.spectrumCanvas.nativeElement;
|
|
12053
|
+
const rect = canvas.getBoundingClientRect();
|
|
12054
|
+
const x = Math.max(0, Math.min(event.clientX - rect.left, canvas.width));
|
|
12055
|
+
const y = Math.max(0, Math.min(event.clientY - rect.top, canvas.height));
|
|
12056
|
+
const saturation = (x / canvas.width) * 100;
|
|
12057
|
+
const lightness = 100 - (y / canvas.height) * 100;
|
|
12058
|
+
this.saturation.set(Math.round(saturation));
|
|
12059
|
+
this.lightness.set(Math.round(lightness));
|
|
12060
|
+
this.cursorX.set(x);
|
|
12061
|
+
this.cursorY.set(y);
|
|
12062
|
+
}
|
|
12063
|
+
onHexInput(event) {
|
|
12064
|
+
const target = event.target;
|
|
12065
|
+
const hex = target.value;
|
|
12066
|
+
if (!hex.startsWith('#')) {
|
|
12067
|
+
target.value = '#' + hex;
|
|
12068
|
+
return;
|
|
12069
|
+
}
|
|
12070
|
+
const rgb = this.parseColor(hex);
|
|
12071
|
+
if (rgb) {
|
|
12072
|
+
const hsl = this.rgbToHSL(rgb.r, rgb.g, rgb.b);
|
|
12073
|
+
this.hue.set(hsl.h);
|
|
12074
|
+
this.saturation.set(hsl.s);
|
|
12075
|
+
this.lightness.set(hsl.l);
|
|
12076
|
+
this.renderSpectrum();
|
|
12077
|
+
this.updateCursor();
|
|
12078
|
+
}
|
|
12079
|
+
}
|
|
12080
|
+
onRGBInput(channel, event) {
|
|
12081
|
+
const target = event.target;
|
|
12082
|
+
const value = parseInt(target.value, 10);
|
|
12083
|
+
if (isNaN(value) || value < 0 || value > 255)
|
|
12084
|
+
return;
|
|
12085
|
+
const currentRGB = this.rgb();
|
|
12086
|
+
const newRGB = { ...currentRGB, [channel]: value };
|
|
12087
|
+
const hsl = this.rgbToHSL(newRGB.r, newRGB.g, newRGB.b);
|
|
12088
|
+
this.hue.set(hsl.h);
|
|
12089
|
+
this.saturation.set(hsl.s);
|
|
12090
|
+
this.lightness.set(hsl.l);
|
|
12091
|
+
this.renderSpectrum();
|
|
12092
|
+
this.updateCursor();
|
|
12093
|
+
}
|
|
12094
|
+
onAlphaInputManual(event) {
|
|
12095
|
+
const target = event.target;
|
|
12096
|
+
const value = parseFloat(target.value);
|
|
12097
|
+
if (isNaN(value) || value < 0 || value > 1)
|
|
12098
|
+
return;
|
|
12099
|
+
this.alpha.set(value);
|
|
12100
|
+
}
|
|
12101
|
+
selectPreset(color) {
|
|
12102
|
+
const rgb = this.parseColor(color);
|
|
12103
|
+
if (rgb) {
|
|
12104
|
+
const hsl = this.rgbToHSL(rgb.r, rgb.g, rgb.b);
|
|
12105
|
+
this.hue.set(hsl.h);
|
|
12106
|
+
this.saturation.set(hsl.s);
|
|
12107
|
+
this.lightness.set(hsl.l);
|
|
12108
|
+
if (rgb.a !== undefined) {
|
|
12109
|
+
this.alpha.set(rgb.a);
|
|
12110
|
+
}
|
|
12111
|
+
this.renderSpectrum();
|
|
12112
|
+
this.updateCursor();
|
|
12113
|
+
}
|
|
12114
|
+
}
|
|
12115
|
+
// === Conversions de couleurs ===
|
|
12116
|
+
hslToRGB(h, s, l) {
|
|
12117
|
+
h = h / 360;
|
|
12118
|
+
s = s / 100;
|
|
12119
|
+
l = l / 100;
|
|
12120
|
+
let r, g, b;
|
|
12121
|
+
if (s === 0) {
|
|
12122
|
+
r = g = b = l;
|
|
12123
|
+
}
|
|
12124
|
+
else {
|
|
12125
|
+
const hue2rgb = (p, q, t) => {
|
|
12126
|
+
if (t < 0)
|
|
12127
|
+
t += 1;
|
|
12128
|
+
if (t > 1)
|
|
12129
|
+
t -= 1;
|
|
12130
|
+
if (t < 1 / 6)
|
|
12131
|
+
return p + (q - p) * 6 * t;
|
|
12132
|
+
if (t < 1 / 2)
|
|
12133
|
+
return q;
|
|
12134
|
+
if (t < 2 / 3)
|
|
12135
|
+
return p + (q - p) * (2 / 3 - t) * 6;
|
|
12136
|
+
return p;
|
|
12137
|
+
};
|
|
12138
|
+
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
|
12139
|
+
const p = 2 * l - q;
|
|
12140
|
+
r = hue2rgb(p, q, h + 1 / 3);
|
|
12141
|
+
g = hue2rgb(p, q, h);
|
|
12142
|
+
b = hue2rgb(p, q, h - 1 / 3);
|
|
12143
|
+
}
|
|
12144
|
+
return {
|
|
12145
|
+
r: Math.round(r * 255),
|
|
12146
|
+
g: Math.round(g * 255),
|
|
12147
|
+
b: Math.round(b * 255),
|
|
12148
|
+
};
|
|
12149
|
+
}
|
|
12150
|
+
rgbToHSL(r, g, b) {
|
|
12151
|
+
r /= 255;
|
|
12152
|
+
g /= 255;
|
|
12153
|
+
b /= 255;
|
|
12154
|
+
const max = Math.max(r, g, b);
|
|
12155
|
+
const min = Math.min(r, g, b);
|
|
12156
|
+
let h = 0;
|
|
12157
|
+
let s = 0;
|
|
12158
|
+
const l = (max + min) / 2;
|
|
12159
|
+
if (max !== min) {
|
|
12160
|
+
const d = max - min;
|
|
12161
|
+
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
|
|
12162
|
+
switch (max) {
|
|
12163
|
+
case r:
|
|
12164
|
+
h = ((g - b) / d + (g < b ? 6 : 0)) / 6;
|
|
12165
|
+
break;
|
|
12166
|
+
case g:
|
|
12167
|
+
h = ((b - r) / d + 2) / 6;
|
|
12168
|
+
break;
|
|
12169
|
+
case b:
|
|
12170
|
+
h = ((r - g) / d + 4) / 6;
|
|
12171
|
+
break;
|
|
12172
|
+
}
|
|
12173
|
+
}
|
|
12174
|
+
return {
|
|
12175
|
+
h: Math.round(h * 360),
|
|
12176
|
+
s: Math.round(s * 100),
|
|
12177
|
+
l: Math.round(l * 100),
|
|
12178
|
+
};
|
|
12179
|
+
}
|
|
12180
|
+
parseColor(color) {
|
|
12181
|
+
// Parse HEX
|
|
12182
|
+
if (color.startsWith('#')) {
|
|
12183
|
+
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})?$/i.exec(color);
|
|
12184
|
+
if (!result)
|
|
12185
|
+
return null;
|
|
12186
|
+
return {
|
|
12187
|
+
r: parseInt(result[1], 16),
|
|
12188
|
+
g: parseInt(result[2], 16),
|
|
12189
|
+
b: parseInt(result[3], 16),
|
|
12190
|
+
a: result[4] ? parseInt(result[4], 16) / 255 : undefined,
|
|
12191
|
+
};
|
|
12192
|
+
}
|
|
12193
|
+
// Parse RGB/RGBA
|
|
12194
|
+
if (color.startsWith('rgb')) {
|
|
12195
|
+
const match = color.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*([\d.]+))?\)/);
|
|
12196
|
+
if (!match)
|
|
12197
|
+
return null;
|
|
12198
|
+
return {
|
|
12199
|
+
r: parseInt(match[1], 10),
|
|
12200
|
+
g: parseInt(match[2], 10),
|
|
12201
|
+
b: parseInt(match[3], 10),
|
|
12202
|
+
a: match[4] ? parseFloat(match[4]) : undefined,
|
|
12203
|
+
};
|
|
12204
|
+
}
|
|
12205
|
+
return null;
|
|
12206
|
+
}
|
|
12207
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DsColorPickerPanelComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
12208
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: DsColorPickerPanelComponent, isStandalone: true, selector: "ds-color-picker-panel", outputs: { colorSelected: "colorSelected", closed: "closed" }, viewQueries: [{ propertyName: "spectrumCanvas", first: true, predicate: ["spectrumCanvas"], descendants: true }], ngImport: i0, template: `
|
|
12209
|
+
<div class="ds-color-picker-panel" role="dialog" aria-label="Color picker">
|
|
12210
|
+
<!-- Spectre de couleurs -->
|
|
12211
|
+
<div class="ds-color-picker-panel__spectrum">
|
|
12212
|
+
<canvas
|
|
12213
|
+
#spectrumCanvas
|
|
12214
|
+
class="ds-color-picker-panel__spectrum-canvas"
|
|
12215
|
+
width="280"
|
|
12216
|
+
height="180"
|
|
12217
|
+
(mousedown)="onSpectrumMouseDown($event)"
|
|
12218
|
+
(mousemove)="onSpectrumMouseMove($event)"
|
|
12219
|
+
(mouseup)="onSpectrumMouseUp()"
|
|
12220
|
+
(mouseleave)="onSpectrumMouseUp()">
|
|
12221
|
+
</canvas>
|
|
12222
|
+
|
|
12223
|
+
<!-- Curseur de sélection -->
|
|
12224
|
+
@if (cursorX() !== null && cursorY() !== null) {
|
|
12225
|
+
<div
|
|
12226
|
+
class="ds-color-picker-panel__cursor"
|
|
12227
|
+
[style.left.px]="cursorX()"
|
|
12228
|
+
[style.top.px]="cursorY()">
|
|
12229
|
+
</div>
|
|
12230
|
+
}
|
|
12231
|
+
</div>
|
|
12232
|
+
|
|
12233
|
+
<!-- Slider de teinte -->
|
|
12234
|
+
<div class="ds-color-picker-panel__hue-slider">
|
|
12235
|
+
<input
|
|
12236
|
+
type="range"
|
|
12237
|
+
class="ds-color-picker-panel__slider"
|
|
12238
|
+
min="0"
|
|
12239
|
+
max="360"
|
|
12240
|
+
step="1"
|
|
12241
|
+
[value]="hue()"
|
|
12242
|
+
(input)="onHueChange($event)"
|
|
12243
|
+
aria-label="Hue" />
|
|
12244
|
+
</div>
|
|
12245
|
+
|
|
12246
|
+
<!-- Slider alpha (optionnel) -->
|
|
12247
|
+
@if (showAlpha) {
|
|
12248
|
+
<div class="ds-color-picker-panel__alpha-slider">
|
|
12249
|
+
<div class="ds-color-picker-panel__alpha-bg"></div>
|
|
12250
|
+
<input
|
|
12251
|
+
type="range"
|
|
12252
|
+
class="ds-color-picker-panel__slider ds-color-picker-panel__slider--alpha"
|
|
12253
|
+
min="0"
|
|
12254
|
+
max="100"
|
|
12255
|
+
step="1"
|
|
12256
|
+
[value]="alpha() * 100"
|
|
12257
|
+
(input)="onAlphaChange($event)"
|
|
12258
|
+
aria-label="Alpha" />
|
|
12259
|
+
</div>
|
|
12260
|
+
}
|
|
12261
|
+
|
|
12262
|
+
<!-- Inputs manuels -->
|
|
12263
|
+
<div class="ds-color-picker-panel__inputs">
|
|
12264
|
+
@if (format === 'hex') {
|
|
12265
|
+
<div class="ds-color-picker-panel__input-group">
|
|
12266
|
+
<label class="ds-color-picker-panel__label">HEX</label>
|
|
12267
|
+
<input
|
|
12268
|
+
type="text"
|
|
12269
|
+
class="ds-color-picker-panel__input"
|
|
12270
|
+
[value]="hexValue()"
|
|
12271
|
+
(input)="onHexInput($event)"
|
|
12272
|
+
maxlength="7"
|
|
12273
|
+
placeholder="#000000" />
|
|
12274
|
+
</div>
|
|
12275
|
+
}
|
|
12276
|
+
|
|
12277
|
+
@if (format === 'rgb') {
|
|
12278
|
+
<div class="ds-color-picker-panel__input-group">
|
|
12279
|
+
<label class="ds-color-picker-panel__label">R</label>
|
|
12280
|
+
<input
|
|
12281
|
+
type="number"
|
|
12282
|
+
class="ds-color-picker-panel__input"
|
|
12283
|
+
min="0"
|
|
12284
|
+
max="255"
|
|
12285
|
+
[value]="rgb().r"
|
|
12286
|
+
(input)="onRGBInput('r', $event)" />
|
|
12287
|
+
</div>
|
|
12288
|
+
<div class="ds-color-picker-panel__input-group">
|
|
12289
|
+
<label class="ds-color-picker-panel__label">G</label>
|
|
12290
|
+
<input
|
|
12291
|
+
type="number"
|
|
12292
|
+
class="ds-color-picker-panel__input"
|
|
12293
|
+
min="0"
|
|
12294
|
+
max="255"
|
|
12295
|
+
[value]="rgb().g"
|
|
12296
|
+
(input)="onRGBInput('g', $event)" />
|
|
12297
|
+
</div>
|
|
12298
|
+
<div class="ds-color-picker-panel__input-group">
|
|
12299
|
+
<label class="ds-color-picker-panel__label">B</label>
|
|
12300
|
+
<input
|
|
12301
|
+
type="number"
|
|
12302
|
+
class="ds-color-picker-panel__input"
|
|
12303
|
+
min="0"
|
|
12304
|
+
max="255"
|
|
12305
|
+
[value]="rgb().b"
|
|
12306
|
+
(input)="onRGBInput('b', $event)" />
|
|
12307
|
+
</div>
|
|
12308
|
+
@if (showAlpha) {
|
|
12309
|
+
<div class="ds-color-picker-panel__input-group">
|
|
12310
|
+
<label class="ds-color-picker-panel__label">A</label>
|
|
12311
|
+
<input
|
|
12312
|
+
type="number"
|
|
12313
|
+
class="ds-color-picker-panel__input"
|
|
12314
|
+
min="0"
|
|
12315
|
+
max="1"
|
|
12316
|
+
step="0.01"
|
|
12317
|
+
[value]="alpha()"
|
|
12318
|
+
(input)="onAlphaInputManual($event)" />
|
|
12319
|
+
</div>
|
|
12320
|
+
}
|
|
12321
|
+
}
|
|
12322
|
+
</div>
|
|
12323
|
+
|
|
12324
|
+
<!-- Couleurs prédéfinies -->
|
|
12325
|
+
@if (presetColors.length > 0) {
|
|
12326
|
+
<div class="ds-color-picker-panel__presets">
|
|
12327
|
+
<div class="ds-color-picker-panel__presets-label">Presets</div>
|
|
12328
|
+
<div class="ds-color-picker-panel__presets-grid">
|
|
12329
|
+
@for (color of presetColors; track color) {
|
|
12330
|
+
<button
|
|
12331
|
+
type="button"
|
|
12332
|
+
class="ds-color-picker-panel__preset"
|
|
12333
|
+
[style.background-color]="color"
|
|
12334
|
+
[class.ds-color-picker-panel__preset--selected]="color === value"
|
|
12335
|
+
(click)="selectPreset(color)"
|
|
12336
|
+
[attr.aria-label]="'Select ' + color">
|
|
12337
|
+
@if (color === value) {
|
|
12338
|
+
<fa-icon [icon]="checkIcon" class="ds-color-picker-panel__preset-check"></fa-icon>
|
|
12339
|
+
}
|
|
12340
|
+
</button>
|
|
12341
|
+
}
|
|
12342
|
+
</div>
|
|
12343
|
+
</div>
|
|
12344
|
+
}
|
|
12345
|
+
|
|
12346
|
+
<!-- Couleurs récentes -->
|
|
12347
|
+
@if (showRecentColors && recentColors.length > 0) {
|
|
12348
|
+
<div class="ds-color-picker-panel__recent">
|
|
12349
|
+
<div class="ds-color-picker-panel__recent-label">Recent</div>
|
|
12350
|
+
<div class="ds-color-picker-panel__recent-grid">
|
|
12351
|
+
@for (color of recentColors; track color) {
|
|
12352
|
+
<button
|
|
12353
|
+
type="button"
|
|
12354
|
+
class="ds-color-picker-panel__preset"
|
|
12355
|
+
[style.background-color]="color"
|
|
12356
|
+
[class.ds-color-picker-panel__preset--selected]="color === value"
|
|
12357
|
+
(click)="selectPreset(color)"
|
|
12358
|
+
[attr.aria-label]="'Select ' + color">
|
|
12359
|
+
@if (color === value) {
|
|
12360
|
+
<fa-icon [icon]="checkIcon" class="ds-color-picker-panel__preset-check"></fa-icon>
|
|
12361
|
+
}
|
|
12362
|
+
</button>
|
|
12363
|
+
}
|
|
12364
|
+
</div>
|
|
12365
|
+
</div>
|
|
12366
|
+
}
|
|
12367
|
+
</div>
|
|
12368
|
+
`, isInline: true, styles: [".ds-color-picker-panel{position:relative;display:flex;flex-direction:column;gap:var(--space-3);width:300px;padding:var(--space-4);background:var(--colorpicker-panel-bg, var(--background-main));border:1px solid var(--colorpicker-panel-border, var(--border-default));border-radius:var(--colorpicker-panel-radius, var(--radius-2));box-shadow:var(--colorpicker-panel-shadow, var(--shadow-3))}.ds-color-picker-panel__spectrum{position:relative;width:100%;height:180px;border-radius:var(--radius-1);overflow:hidden;cursor:crosshair;border:1px solid var(--border-default)}.ds-color-picker-panel__spectrum-canvas{display:block;width:100%;height:100%}.ds-color-picker-panel__cursor{position:absolute;width:16px;height:16px;border:2px solid white;border-radius:50%;box-shadow:0 0 0 1px #0000004d,0 2px 4px #0003;transform:translate(-50%,-50%);pointer-events:none}.ds-color-picker-panel__hue-slider,.ds-color-picker-panel__alpha-slider{position:relative;width:100%;height:12px;border-radius:var(--radius-1);overflow:hidden}.ds-color-picker-panel__hue-slider{background:linear-gradient(to right,red,#ff0,#0f0,#0ff,#00f,#f0f,red)}.ds-color-picker-panel__alpha-slider .ds-color-picker-panel__alpha-bg{position:absolute;inset:0;background-image:linear-gradient(45deg,#ccc 25%,transparent 25%),linear-gradient(-45deg,#ccc 25%,transparent 25%),linear-gradient(45deg,transparent 75%,#ccc 75%),linear-gradient(-45deg,transparent 75%,#ccc 75%);background-size:8px 8px;background-position:0 0,0 4px,4px -4px,-4px 0}.ds-color-picker-panel__slider{position:relative;width:100%;height:100%;-webkit-appearance:none;appearance:none;background:transparent;cursor:pointer;z-index:1}.ds-color-picker-panel__slider::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;width:16px;height:16px;border:2px solid white;border-radius:50%;background:transparent;box-shadow:0 0 0 1px #0000004d,0 2px 4px #0003;cursor:pointer}.ds-color-picker-panel__slider::-moz-range-thumb{width:16px;height:16px;border:2px solid white;border-radius:50%;background:transparent;box-shadow:0 0 0 1px #0000004d,0 2px 4px #0003;cursor:pointer}.ds-color-picker-panel__slider:focus-visible{outline:2px solid var(--color-primary);outline-offset:2px}.ds-color-picker-panel__slider--alpha{background:linear-gradient(to right,transparent 0%,currentColor 100%)}.ds-color-picker-panel__inputs{display:flex;gap:var(--space-2)}.ds-color-picker-panel__input-group{display:flex;flex-direction:column;gap:var(--space-1);flex:1}.ds-color-picker-panel__label{font-size:var(--font-size-1);font-weight:600;color:var(--text-muted);text-transform:uppercase}.ds-color-picker-panel__input{width:100%;padding:var(--space-1) var(--space-2);background:var(--colorpicker-input-bg, var(--background-main));border:1px solid var(--colorpicker-input-border, var(--border-default));border-radius:var(--radius-1);color:var(--colorpicker-input-text, var(--text-default));font-size:var(--font-size-2);font-family:monospace;text-align:center;outline:none;transition:border-color var(--duration-fast, .15s) ease}.ds-color-picker-panel__input:focus{border-color:var(--color-primary)}.ds-color-picker-panel__input:hover:not(:focus){border-color:var(--border-strong)}.ds-color-picker-panel__input[type=number]{-moz-appearance:textfield}.ds-color-picker-panel__input[type=number]::-webkit-outer-spin-button,.ds-color-picker-panel__input[type=number]::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}.ds-color-picker-panel__presets,.ds-color-picker-panel__recent{display:flex;flex-direction:column;gap:var(--space-2)}.ds-color-picker-panel__presets-label,.ds-color-picker-panel__recent-label{font-size:var(--font-size-2);font-weight:600;color:var(--text-muted)}.ds-color-picker-panel__presets-grid,.ds-color-picker-panel__recent-grid{display:grid;grid-template-columns:repeat(8,1fr);gap:var(--space-2)}.ds-color-picker-panel__preset{position:relative;width:28px;height:28px;padding:0;background:currentColor;border:2px solid var(--colorpicker-preset-border, var(--border-default));border-radius:var(--radius-1);cursor:pointer;transition:transform var(--duration-fast, .15s) ease,border-color var(--duration-fast, .15s) ease;background-image:linear-gradient(45deg,#ccc 25%,transparent 25%),linear-gradient(-45deg,#ccc 25%,transparent 25%),linear-gradient(45deg,transparent 75%,#ccc 75%),linear-gradient(-45deg,transparent 75%,#ccc 75%);background-size:8px 8px;background-position:0 0,0 4px,4px -4px,-4px 0}.ds-color-picker-panel__preset:after{content:\"\";position:absolute;inset:0;background-color:currentColor;border-radius:inherit}.ds-color-picker-panel__preset:hover:not(:disabled){transform:scale(1.1);border-color:var(--color-primary)}.ds-color-picker-panel__preset:focus-visible{outline:2px solid var(--color-primary);outline-offset:2px}.ds-color-picker-panel__preset--selected{border-color:var(--color-primary);border-width:3px}.ds-color-picker-panel__preset-check{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);color:#fff;filter:drop-shadow(0 1px 2px rgba(0,0,0,.5));font-size:var(--font-size-2);z-index:1}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: FontAwesomeModule }, { kind: "component", type: i1$1.FaIconComponent, selector: "fa-icon", inputs: ["icon", "title", "animation", "mask", "flip", "size", "pull", "border", "inverse", "symbol", "rotate", "fixedWidth", "transform", "a11yRole"], outputs: ["iconChange", "titleChange", "animationChange", "maskChange", "flipChange", "sizeChange", "pullChange", "borderChange", "inverseChange", "symbolChange", "rotateChange", "fixedWidthChange", "transformChange", "a11yRoleChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
12369
|
+
}
|
|
12370
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DsColorPickerPanelComponent, decorators: [{
|
|
12371
|
+
type: Component,
|
|
12372
|
+
args: [{ selector: 'ds-color-picker-panel', standalone: true, imports: [CommonModule, FormsModule, FontAwesomeModule], template: `
|
|
12373
|
+
<div class="ds-color-picker-panel" role="dialog" aria-label="Color picker">
|
|
12374
|
+
<!-- Spectre de couleurs -->
|
|
12375
|
+
<div class="ds-color-picker-panel__spectrum">
|
|
12376
|
+
<canvas
|
|
12377
|
+
#spectrumCanvas
|
|
12378
|
+
class="ds-color-picker-panel__spectrum-canvas"
|
|
12379
|
+
width="280"
|
|
12380
|
+
height="180"
|
|
12381
|
+
(mousedown)="onSpectrumMouseDown($event)"
|
|
12382
|
+
(mousemove)="onSpectrumMouseMove($event)"
|
|
12383
|
+
(mouseup)="onSpectrumMouseUp()"
|
|
12384
|
+
(mouseleave)="onSpectrumMouseUp()">
|
|
12385
|
+
</canvas>
|
|
12386
|
+
|
|
12387
|
+
<!-- Curseur de sélection -->
|
|
12388
|
+
@if (cursorX() !== null && cursorY() !== null) {
|
|
12389
|
+
<div
|
|
12390
|
+
class="ds-color-picker-panel__cursor"
|
|
12391
|
+
[style.left.px]="cursorX()"
|
|
12392
|
+
[style.top.px]="cursorY()">
|
|
12393
|
+
</div>
|
|
12394
|
+
}
|
|
12395
|
+
</div>
|
|
12396
|
+
|
|
12397
|
+
<!-- Slider de teinte -->
|
|
12398
|
+
<div class="ds-color-picker-panel__hue-slider">
|
|
12399
|
+
<input
|
|
12400
|
+
type="range"
|
|
12401
|
+
class="ds-color-picker-panel__slider"
|
|
12402
|
+
min="0"
|
|
12403
|
+
max="360"
|
|
12404
|
+
step="1"
|
|
12405
|
+
[value]="hue()"
|
|
12406
|
+
(input)="onHueChange($event)"
|
|
12407
|
+
aria-label="Hue" />
|
|
12408
|
+
</div>
|
|
12409
|
+
|
|
12410
|
+
<!-- Slider alpha (optionnel) -->
|
|
12411
|
+
@if (showAlpha) {
|
|
12412
|
+
<div class="ds-color-picker-panel__alpha-slider">
|
|
12413
|
+
<div class="ds-color-picker-panel__alpha-bg"></div>
|
|
12414
|
+
<input
|
|
12415
|
+
type="range"
|
|
12416
|
+
class="ds-color-picker-panel__slider ds-color-picker-panel__slider--alpha"
|
|
12417
|
+
min="0"
|
|
12418
|
+
max="100"
|
|
12419
|
+
step="1"
|
|
12420
|
+
[value]="alpha() * 100"
|
|
12421
|
+
(input)="onAlphaChange($event)"
|
|
12422
|
+
aria-label="Alpha" />
|
|
12423
|
+
</div>
|
|
12424
|
+
}
|
|
12425
|
+
|
|
12426
|
+
<!-- Inputs manuels -->
|
|
12427
|
+
<div class="ds-color-picker-panel__inputs">
|
|
12428
|
+
@if (format === 'hex') {
|
|
12429
|
+
<div class="ds-color-picker-panel__input-group">
|
|
12430
|
+
<label class="ds-color-picker-panel__label">HEX</label>
|
|
12431
|
+
<input
|
|
12432
|
+
type="text"
|
|
12433
|
+
class="ds-color-picker-panel__input"
|
|
12434
|
+
[value]="hexValue()"
|
|
12435
|
+
(input)="onHexInput($event)"
|
|
12436
|
+
maxlength="7"
|
|
12437
|
+
placeholder="#000000" />
|
|
12438
|
+
</div>
|
|
12439
|
+
}
|
|
12440
|
+
|
|
12441
|
+
@if (format === 'rgb') {
|
|
12442
|
+
<div class="ds-color-picker-panel__input-group">
|
|
12443
|
+
<label class="ds-color-picker-panel__label">R</label>
|
|
12444
|
+
<input
|
|
12445
|
+
type="number"
|
|
12446
|
+
class="ds-color-picker-panel__input"
|
|
12447
|
+
min="0"
|
|
12448
|
+
max="255"
|
|
12449
|
+
[value]="rgb().r"
|
|
12450
|
+
(input)="onRGBInput('r', $event)" />
|
|
12451
|
+
</div>
|
|
12452
|
+
<div class="ds-color-picker-panel__input-group">
|
|
12453
|
+
<label class="ds-color-picker-panel__label">G</label>
|
|
12454
|
+
<input
|
|
12455
|
+
type="number"
|
|
12456
|
+
class="ds-color-picker-panel__input"
|
|
12457
|
+
min="0"
|
|
12458
|
+
max="255"
|
|
12459
|
+
[value]="rgb().g"
|
|
12460
|
+
(input)="onRGBInput('g', $event)" />
|
|
12461
|
+
</div>
|
|
12462
|
+
<div class="ds-color-picker-panel__input-group">
|
|
12463
|
+
<label class="ds-color-picker-panel__label">B</label>
|
|
12464
|
+
<input
|
|
12465
|
+
type="number"
|
|
12466
|
+
class="ds-color-picker-panel__input"
|
|
12467
|
+
min="0"
|
|
12468
|
+
max="255"
|
|
12469
|
+
[value]="rgb().b"
|
|
12470
|
+
(input)="onRGBInput('b', $event)" />
|
|
12471
|
+
</div>
|
|
12472
|
+
@if (showAlpha) {
|
|
12473
|
+
<div class="ds-color-picker-panel__input-group">
|
|
12474
|
+
<label class="ds-color-picker-panel__label">A</label>
|
|
12475
|
+
<input
|
|
12476
|
+
type="number"
|
|
12477
|
+
class="ds-color-picker-panel__input"
|
|
12478
|
+
min="0"
|
|
12479
|
+
max="1"
|
|
12480
|
+
step="0.01"
|
|
12481
|
+
[value]="alpha()"
|
|
12482
|
+
(input)="onAlphaInputManual($event)" />
|
|
12483
|
+
</div>
|
|
12484
|
+
}
|
|
12485
|
+
}
|
|
12486
|
+
</div>
|
|
12487
|
+
|
|
12488
|
+
<!-- Couleurs prédéfinies -->
|
|
12489
|
+
@if (presetColors.length > 0) {
|
|
12490
|
+
<div class="ds-color-picker-panel__presets">
|
|
12491
|
+
<div class="ds-color-picker-panel__presets-label">Presets</div>
|
|
12492
|
+
<div class="ds-color-picker-panel__presets-grid">
|
|
12493
|
+
@for (color of presetColors; track color) {
|
|
12494
|
+
<button
|
|
12495
|
+
type="button"
|
|
12496
|
+
class="ds-color-picker-panel__preset"
|
|
12497
|
+
[style.background-color]="color"
|
|
12498
|
+
[class.ds-color-picker-panel__preset--selected]="color === value"
|
|
12499
|
+
(click)="selectPreset(color)"
|
|
12500
|
+
[attr.aria-label]="'Select ' + color">
|
|
12501
|
+
@if (color === value) {
|
|
12502
|
+
<fa-icon [icon]="checkIcon" class="ds-color-picker-panel__preset-check"></fa-icon>
|
|
12503
|
+
}
|
|
12504
|
+
</button>
|
|
12505
|
+
}
|
|
12506
|
+
</div>
|
|
12507
|
+
</div>
|
|
12508
|
+
}
|
|
12509
|
+
|
|
12510
|
+
<!-- Couleurs récentes -->
|
|
12511
|
+
@if (showRecentColors && recentColors.length > 0) {
|
|
12512
|
+
<div class="ds-color-picker-panel__recent">
|
|
12513
|
+
<div class="ds-color-picker-panel__recent-label">Recent</div>
|
|
12514
|
+
<div class="ds-color-picker-panel__recent-grid">
|
|
12515
|
+
@for (color of recentColors; track color) {
|
|
12516
|
+
<button
|
|
12517
|
+
type="button"
|
|
12518
|
+
class="ds-color-picker-panel__preset"
|
|
12519
|
+
[style.background-color]="color"
|
|
12520
|
+
[class.ds-color-picker-panel__preset--selected]="color === value"
|
|
12521
|
+
(click)="selectPreset(color)"
|
|
12522
|
+
[attr.aria-label]="'Select ' + color">
|
|
12523
|
+
@if (color === value) {
|
|
12524
|
+
<fa-icon [icon]="checkIcon" class="ds-color-picker-panel__preset-check"></fa-icon>
|
|
12525
|
+
}
|
|
12526
|
+
</button>
|
|
12527
|
+
}
|
|
12528
|
+
</div>
|
|
12529
|
+
</div>
|
|
12530
|
+
}
|
|
12531
|
+
</div>
|
|
12532
|
+
`, changeDetection: ChangeDetectionStrategy.OnPush, styles: [".ds-color-picker-panel{position:relative;display:flex;flex-direction:column;gap:var(--space-3);width:300px;padding:var(--space-4);background:var(--colorpicker-panel-bg, var(--background-main));border:1px solid var(--colorpicker-panel-border, var(--border-default));border-radius:var(--colorpicker-panel-radius, var(--radius-2));box-shadow:var(--colorpicker-panel-shadow, var(--shadow-3))}.ds-color-picker-panel__spectrum{position:relative;width:100%;height:180px;border-radius:var(--radius-1);overflow:hidden;cursor:crosshair;border:1px solid var(--border-default)}.ds-color-picker-panel__spectrum-canvas{display:block;width:100%;height:100%}.ds-color-picker-panel__cursor{position:absolute;width:16px;height:16px;border:2px solid white;border-radius:50%;box-shadow:0 0 0 1px #0000004d,0 2px 4px #0003;transform:translate(-50%,-50%);pointer-events:none}.ds-color-picker-panel__hue-slider,.ds-color-picker-panel__alpha-slider{position:relative;width:100%;height:12px;border-radius:var(--radius-1);overflow:hidden}.ds-color-picker-panel__hue-slider{background:linear-gradient(to right,red,#ff0,#0f0,#0ff,#00f,#f0f,red)}.ds-color-picker-panel__alpha-slider .ds-color-picker-panel__alpha-bg{position:absolute;inset:0;background-image:linear-gradient(45deg,#ccc 25%,transparent 25%),linear-gradient(-45deg,#ccc 25%,transparent 25%),linear-gradient(45deg,transparent 75%,#ccc 75%),linear-gradient(-45deg,transparent 75%,#ccc 75%);background-size:8px 8px;background-position:0 0,0 4px,4px -4px,-4px 0}.ds-color-picker-panel__slider{position:relative;width:100%;height:100%;-webkit-appearance:none;appearance:none;background:transparent;cursor:pointer;z-index:1}.ds-color-picker-panel__slider::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;width:16px;height:16px;border:2px solid white;border-radius:50%;background:transparent;box-shadow:0 0 0 1px #0000004d,0 2px 4px #0003;cursor:pointer}.ds-color-picker-panel__slider::-moz-range-thumb{width:16px;height:16px;border:2px solid white;border-radius:50%;background:transparent;box-shadow:0 0 0 1px #0000004d,0 2px 4px #0003;cursor:pointer}.ds-color-picker-panel__slider:focus-visible{outline:2px solid var(--color-primary);outline-offset:2px}.ds-color-picker-panel__slider--alpha{background:linear-gradient(to right,transparent 0%,currentColor 100%)}.ds-color-picker-panel__inputs{display:flex;gap:var(--space-2)}.ds-color-picker-panel__input-group{display:flex;flex-direction:column;gap:var(--space-1);flex:1}.ds-color-picker-panel__label{font-size:var(--font-size-1);font-weight:600;color:var(--text-muted);text-transform:uppercase}.ds-color-picker-panel__input{width:100%;padding:var(--space-1) var(--space-2);background:var(--colorpicker-input-bg, var(--background-main));border:1px solid var(--colorpicker-input-border, var(--border-default));border-radius:var(--radius-1);color:var(--colorpicker-input-text, var(--text-default));font-size:var(--font-size-2);font-family:monospace;text-align:center;outline:none;transition:border-color var(--duration-fast, .15s) ease}.ds-color-picker-panel__input:focus{border-color:var(--color-primary)}.ds-color-picker-panel__input:hover:not(:focus){border-color:var(--border-strong)}.ds-color-picker-panel__input[type=number]{-moz-appearance:textfield}.ds-color-picker-panel__input[type=number]::-webkit-outer-spin-button,.ds-color-picker-panel__input[type=number]::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}.ds-color-picker-panel__presets,.ds-color-picker-panel__recent{display:flex;flex-direction:column;gap:var(--space-2)}.ds-color-picker-panel__presets-label,.ds-color-picker-panel__recent-label{font-size:var(--font-size-2);font-weight:600;color:var(--text-muted)}.ds-color-picker-panel__presets-grid,.ds-color-picker-panel__recent-grid{display:grid;grid-template-columns:repeat(8,1fr);gap:var(--space-2)}.ds-color-picker-panel__preset{position:relative;width:28px;height:28px;padding:0;background:currentColor;border:2px solid var(--colorpicker-preset-border, var(--border-default));border-radius:var(--radius-1);cursor:pointer;transition:transform var(--duration-fast, .15s) ease,border-color var(--duration-fast, .15s) ease;background-image:linear-gradient(45deg,#ccc 25%,transparent 25%),linear-gradient(-45deg,#ccc 25%,transparent 25%),linear-gradient(45deg,transparent 75%,#ccc 75%),linear-gradient(-45deg,transparent 75%,#ccc 75%);background-size:8px 8px;background-position:0 0,0 4px,4px -4px,-4px 0}.ds-color-picker-panel__preset:after{content:\"\";position:absolute;inset:0;background-color:currentColor;border-radius:inherit}.ds-color-picker-panel__preset:hover:not(:disabled){transform:scale(1.1);border-color:var(--color-primary)}.ds-color-picker-panel__preset:focus-visible{outline:2px solid var(--color-primary);outline-offset:2px}.ds-color-picker-panel__preset--selected{border-color:var(--color-primary);border-width:3px}.ds-color-picker-panel__preset-check{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);color:#fff;filter:drop-shadow(0 1px 2px rgba(0,0,0,.5));font-size:var(--font-size-2);z-index:1}\n"] }]
|
|
12533
|
+
}], ctorParameters: () => [], propDecorators: { spectrumCanvas: [{
|
|
12534
|
+
type: ViewChild,
|
|
12535
|
+
args: ['spectrumCanvas']
|
|
12536
|
+
}], colorSelected: [{ type: i0.Output, args: ["colorSelected"] }], closed: [{ type: i0.Output, args: ["closed"] }] } });
|
|
12537
|
+
|
|
12538
|
+
/**
|
|
12539
|
+
* DsColorPicker - Composant de sélection de couleur
|
|
12540
|
+
*
|
|
12541
|
+
* @description
|
|
12542
|
+
* Sélecteur de couleur avec palette prédéfinie, spectre de couleurs,
|
|
12543
|
+
* support RGB/HSL, alpha channel optionnel, et intégration formulaires.
|
|
12544
|
+
*
|
|
12545
|
+
* @example
|
|
12546
|
+
* ```html
|
|
12547
|
+
* <ds-color-picker
|
|
12548
|
+
* [value]="'#3b82f6'"
|
|
12549
|
+
* [showAlpha]="true"
|
|
12550
|
+
* (colorChange)="onColorChange($event)">
|
|
12551
|
+
* </ds-color-picker>
|
|
12552
|
+
* ```
|
|
12553
|
+
*/
|
|
12554
|
+
class DsColorPicker {
|
|
12555
|
+
overlay;
|
|
12556
|
+
elementRef;
|
|
12557
|
+
// Inputs
|
|
12558
|
+
value = input('', ...(ngDevMode ? [{ debugName: "value" }] : []));
|
|
12559
|
+
size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : []));
|
|
12560
|
+
disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
|
|
12561
|
+
showAlpha = input(false, ...(ngDevMode ? [{ debugName: "showAlpha" }] : []));
|
|
12562
|
+
presetColors = input([], ...(ngDevMode ? [{ debugName: "presetColors" }] : []));
|
|
12563
|
+
format = input('hex', ...(ngDevMode ? [{ debugName: "format" }] : []));
|
|
12564
|
+
placeholder = input('Select color', ...(ngDevMode ? [{ debugName: "placeholder" }] : []));
|
|
12565
|
+
allowClear = input(true, ...(ngDevMode ? [{ debugName: "allowClear" }] : []));
|
|
12566
|
+
showRecentColors = input(true, ...(ngDevMode ? [{ debugName: "showRecentColors" }] : []));
|
|
12567
|
+
maxRecentColors = input(8, ...(ngDevMode ? [{ debugName: "maxRecentColors" }] : []));
|
|
12568
|
+
// Outputs
|
|
12569
|
+
colorChange = output();
|
|
12570
|
+
// Icons
|
|
12571
|
+
pickerIcon = faEyeDropper;
|
|
12572
|
+
clearIcon = faTimes;
|
|
12573
|
+
checkIcon = faCheck;
|
|
12574
|
+
// State
|
|
12575
|
+
isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : []));
|
|
12576
|
+
internalValue = signal('', ...(ngDevMode ? [{ debugName: "internalValue" }] : []));
|
|
12577
|
+
isFocused = signal(false, ...(ngDevMode ? [{ debugName: "isFocused" }] : []));
|
|
12578
|
+
recentColors = signal([], ...(ngDevMode ? [{ debugName: "recentColors" }] : []));
|
|
12579
|
+
// Overlay
|
|
12580
|
+
overlayRef = null;
|
|
12581
|
+
// Computed
|
|
12582
|
+
containerClasses = computed(() => {
|
|
12583
|
+
const classes = ['ds-color-picker'];
|
|
12584
|
+
classes.push(`ds-color-picker--${this.size()}`);
|
|
12585
|
+
if (this.disabled())
|
|
12586
|
+
classes.push('ds-color-picker--disabled');
|
|
12587
|
+
if (this.isFocused())
|
|
12588
|
+
classes.push('ds-color-picker--focused');
|
|
12589
|
+
if (this.isOpen())
|
|
12590
|
+
classes.push('ds-color-picker--open');
|
|
12591
|
+
return classes.join(' ');
|
|
12592
|
+
}, ...(ngDevMode ? [{ debugName: "containerClasses" }] : []));
|
|
12593
|
+
displayValue = computed(() => {
|
|
12594
|
+
const val = this.internalValue();
|
|
12595
|
+
if (!val)
|
|
12596
|
+
return '';
|
|
12597
|
+
// Convertir selon le format demandé
|
|
12598
|
+
const format = this.format();
|
|
12599
|
+
if (format === 'hex') {
|
|
12600
|
+
return this.toHex(val);
|
|
12601
|
+
}
|
|
12602
|
+
else if (format === 'rgb') {
|
|
12603
|
+
return this.toRGB(val);
|
|
12604
|
+
}
|
|
12605
|
+
else if (format === 'hsl') {
|
|
12606
|
+
return this.toHSL(val);
|
|
12607
|
+
}
|
|
12608
|
+
return val;
|
|
12609
|
+
}, ...(ngDevMode ? [{ debugName: "displayValue" }] : []));
|
|
12610
|
+
previewColor = computed(() => {
|
|
12611
|
+
return this.internalValue() || 'transparent';
|
|
12612
|
+
}, ...(ngDevMode ? [{ debugName: "previewColor" }] : []));
|
|
12613
|
+
effectivePresets = computed(() => {
|
|
12614
|
+
const custom = this.presetColors();
|
|
12615
|
+
if (custom.length > 0)
|
|
12616
|
+
return custom;
|
|
12617
|
+
// Palette par défaut
|
|
12618
|
+
return [
|
|
12619
|
+
'#000000', '#ffffff', '#f87171', '#fb923c', '#fbbf24', '#facc15',
|
|
12620
|
+
'#a3e635', '#4ade80', '#34d399', '#2dd4bf', '#22d3ee', '#38bdf8',
|
|
12621
|
+
'#60a5fa', '#818cf8', '#a78bfa', '#c084fc', '#e879f9', '#f472b6',
|
|
12622
|
+
'#fb7185', '#f43f5e', '#ef4444', '#dc2626', '#b91c1c', '#991b1b',
|
|
12623
|
+
];
|
|
12624
|
+
}, ...(ngDevMode ? [{ debugName: "effectivePresets" }] : []));
|
|
12625
|
+
// ControlValueAccessor
|
|
12626
|
+
onChange = () => { };
|
|
12627
|
+
onTouched = () => { };
|
|
12628
|
+
constructor(overlay, elementRef) {
|
|
12629
|
+
this.overlay = overlay;
|
|
12630
|
+
this.elementRef = elementRef;
|
|
12631
|
+
// Sync external value with internal
|
|
12632
|
+
effect(() => {
|
|
12633
|
+
const val = this.value();
|
|
12634
|
+
if (val !== this.internalValue()) {
|
|
12635
|
+
this.internalValue.set(val);
|
|
12636
|
+
}
|
|
12637
|
+
});
|
|
12638
|
+
// Charger les couleurs récentes depuis localStorage
|
|
12639
|
+
this.loadRecentColors();
|
|
12640
|
+
}
|
|
12641
|
+
writeValue(value) {
|
|
12642
|
+
this.internalValue.set(value || '');
|
|
12643
|
+
}
|
|
12644
|
+
registerOnChange(fn) {
|
|
12645
|
+
this.onChange = fn;
|
|
12646
|
+
}
|
|
12647
|
+
registerOnTouched(fn) {
|
|
12648
|
+
this.onTouched = fn;
|
|
12649
|
+
}
|
|
12650
|
+
setDisabledState(isDisabled) {
|
|
12651
|
+
// Géré par input disabled
|
|
12652
|
+
}
|
|
12653
|
+
toggle() {
|
|
12654
|
+
if (this.disabled())
|
|
12655
|
+
return;
|
|
12656
|
+
if (this.isOpen()) {
|
|
12657
|
+
this.close();
|
|
12658
|
+
}
|
|
12659
|
+
else {
|
|
12660
|
+
this.open();
|
|
12661
|
+
}
|
|
12662
|
+
}
|
|
12663
|
+
open() {
|
|
12664
|
+
if (this.disabled() || this.isOpen())
|
|
12665
|
+
return;
|
|
12666
|
+
this.isOpen.set(true);
|
|
12667
|
+
this.createOverlay();
|
|
12668
|
+
}
|
|
12669
|
+
close() {
|
|
12670
|
+
if (!this.isOpen())
|
|
12671
|
+
return;
|
|
12672
|
+
this.isOpen.set(false);
|
|
12673
|
+
this.destroyOverlay();
|
|
12674
|
+
this.onTouched();
|
|
12675
|
+
}
|
|
12676
|
+
onFocus() {
|
|
12677
|
+
if (!this.disabled()) {
|
|
12678
|
+
this.isFocused.set(true);
|
|
12679
|
+
}
|
|
12680
|
+
}
|
|
12681
|
+
onBlur() {
|
|
12682
|
+
this.isFocused.set(false);
|
|
12683
|
+
if (!this.isOpen()) {
|
|
12684
|
+
this.onTouched();
|
|
12685
|
+
}
|
|
12686
|
+
}
|
|
12687
|
+
clear() {
|
|
12688
|
+
if (this.disabled())
|
|
12689
|
+
return;
|
|
12690
|
+
this.updateValue('');
|
|
12691
|
+
}
|
|
12692
|
+
onColorSelected(color) {
|
|
12693
|
+
this.updateValue(color);
|
|
12694
|
+
this.addToRecentColors(color);
|
|
12695
|
+
}
|
|
12696
|
+
updateValue(value) {
|
|
12697
|
+
this.internalValue.set(value);
|
|
12698
|
+
this.onChange(value);
|
|
12699
|
+
this.colorChange.emit(value);
|
|
12700
|
+
}
|
|
12701
|
+
createOverlay() {
|
|
12702
|
+
if (this.overlayRef)
|
|
12703
|
+
return;
|
|
12704
|
+
const positionStrategy = this.overlay
|
|
12705
|
+
.position()
|
|
12706
|
+
.flexibleConnectedTo(this.elementRef.nativeElement.querySelector('.ds-color-picker__trigger'))
|
|
12707
|
+
.withPositions([
|
|
12708
|
+
{
|
|
12709
|
+
originX: 'start',
|
|
12710
|
+
originY: 'bottom',
|
|
12711
|
+
overlayX: 'start',
|
|
12712
|
+
overlayY: 'top',
|
|
12713
|
+
offsetY: 8,
|
|
12714
|
+
},
|
|
12715
|
+
{
|
|
12716
|
+
originX: 'start',
|
|
12717
|
+
originY: 'top',
|
|
12718
|
+
overlayX: 'start',
|
|
12719
|
+
overlayY: 'bottom',
|
|
12720
|
+
offsetY: -8,
|
|
12721
|
+
},
|
|
12722
|
+
]);
|
|
12723
|
+
this.overlayRef = this.overlay.create({
|
|
12724
|
+
positionStrategy,
|
|
12725
|
+
hasBackdrop: true,
|
|
12726
|
+
backdropClass: 'cdk-overlay-transparent-backdrop',
|
|
12727
|
+
scrollStrategy: this.overlay.scrollStrategies.reposition(),
|
|
12728
|
+
});
|
|
12729
|
+
const portal = new ComponentPortal(DsColorPickerPanelComponent);
|
|
12730
|
+
const componentRef = this.overlayRef.attach(portal);
|
|
12731
|
+
// Configuration du panel
|
|
12732
|
+
componentRef.instance.value = this.internalValue();
|
|
12733
|
+
componentRef.instance.showAlpha = this.showAlpha();
|
|
12734
|
+
componentRef.instance.presetColors = this.effectivePresets();
|
|
12735
|
+
componentRef.instance.recentColors = this.recentColors();
|
|
12736
|
+
componentRef.instance.showRecentColors = this.showRecentColors();
|
|
12737
|
+
componentRef.instance.format = this.format();
|
|
12738
|
+
// Écouter les événements
|
|
12739
|
+
componentRef.instance.colorSelected.subscribe((color) => {
|
|
12740
|
+
this.onColorSelected(color);
|
|
12741
|
+
});
|
|
12742
|
+
componentRef.instance.closed.subscribe(() => {
|
|
12743
|
+
this.close();
|
|
12744
|
+
});
|
|
12745
|
+
// Fermer au clic sur backdrop
|
|
12746
|
+
this.overlayRef.backdropClick().subscribe(() => {
|
|
12747
|
+
this.close();
|
|
12748
|
+
});
|
|
12749
|
+
}
|
|
12750
|
+
destroyOverlay() {
|
|
12751
|
+
if (this.overlayRef) {
|
|
12752
|
+
this.overlayRef.dispose();
|
|
12753
|
+
this.overlayRef = null;
|
|
12754
|
+
}
|
|
12755
|
+
}
|
|
12756
|
+
addToRecentColors(color) {
|
|
12757
|
+
if (!this.showRecentColors() || !color)
|
|
12758
|
+
return;
|
|
12759
|
+
const recent = this.recentColors();
|
|
12760
|
+
const filtered = recent.filter(c => c !== color);
|
|
12761
|
+
const updated = [color, ...filtered].slice(0, this.maxRecentColors());
|
|
12762
|
+
this.recentColors.set(updated);
|
|
12763
|
+
this.saveRecentColors(updated);
|
|
12764
|
+
}
|
|
12765
|
+
loadRecentColors() {
|
|
12766
|
+
try {
|
|
12767
|
+
const stored = localStorage.getItem('ds-color-picker-recent');
|
|
12768
|
+
if (stored) {
|
|
12769
|
+
const colors = JSON.parse(stored);
|
|
12770
|
+
if (Array.isArray(colors)) {
|
|
12771
|
+
this.recentColors.set(colors.slice(0, this.maxRecentColors()));
|
|
12772
|
+
}
|
|
12773
|
+
}
|
|
12774
|
+
}
|
|
12775
|
+
catch (e) {
|
|
12776
|
+
// Ignorer les erreurs de parsing
|
|
12777
|
+
}
|
|
12778
|
+
}
|
|
12779
|
+
saveRecentColors(colors) {
|
|
12780
|
+
try {
|
|
12781
|
+
localStorage.setItem('ds-color-picker-recent', JSON.stringify(colors));
|
|
12782
|
+
}
|
|
12783
|
+
catch (e) {
|
|
12784
|
+
// Ignorer les erreurs de stockage
|
|
12785
|
+
}
|
|
12786
|
+
}
|
|
12787
|
+
// === Conversions de couleurs ===
|
|
12788
|
+
toHex(color) {
|
|
12789
|
+
if (color.startsWith('#'))
|
|
12790
|
+
return color;
|
|
12791
|
+
const rgb = this.parseRGB(color);
|
|
12792
|
+
if (rgb) {
|
|
12793
|
+
const r = rgb.r.toString(16).padStart(2, '0');
|
|
12794
|
+
const g = rgb.g.toString(16).padStart(2, '0');
|
|
12795
|
+
const b = rgb.b.toString(16).padStart(2, '0');
|
|
12796
|
+
return `#${r}${g}${b}`;
|
|
12797
|
+
}
|
|
12798
|
+
return color;
|
|
12799
|
+
}
|
|
12800
|
+
toRGB(color) {
|
|
12801
|
+
if (color.startsWith('rgb'))
|
|
12802
|
+
return color;
|
|
12803
|
+
const rgb = this.hexToRGB(color);
|
|
12804
|
+
if (rgb) {
|
|
12805
|
+
if (rgb.a !== undefined) {
|
|
12806
|
+
return `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${rgb.a})`;
|
|
12807
|
+
}
|
|
12808
|
+
return `rgb(${rgb.r}, ${rgb.g}, ${rgb.b})`;
|
|
12809
|
+
}
|
|
12810
|
+
return color;
|
|
12811
|
+
}
|
|
12812
|
+
toHSL(color) {
|
|
12813
|
+
if (color.startsWith('hsl'))
|
|
12814
|
+
return color;
|
|
12815
|
+
const rgb = this.hexToRGB(color);
|
|
12816
|
+
if (rgb) {
|
|
12817
|
+
const hsl = this.rgbToHSL(rgb);
|
|
12818
|
+
if (hsl.a !== undefined) {
|
|
12819
|
+
return `hsla(${hsl.h}, ${hsl.s}%, ${hsl.l}%, ${hsl.a})`;
|
|
12820
|
+
}
|
|
12821
|
+
return `hsl(${hsl.h}, ${hsl.s}%, ${hsl.l}%)`;
|
|
12822
|
+
}
|
|
12823
|
+
return color;
|
|
12824
|
+
}
|
|
12825
|
+
hexToRGB(hex) {
|
|
12826
|
+
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})?$/i.exec(hex);
|
|
12827
|
+
if (!result)
|
|
12828
|
+
return null;
|
|
12829
|
+
return {
|
|
12830
|
+
r: parseInt(result[1], 16),
|
|
12831
|
+
g: parseInt(result[2], 16),
|
|
12832
|
+
b: parseInt(result[3], 16),
|
|
12833
|
+
a: result[4] ? parseInt(result[4], 16) / 255 : undefined,
|
|
12834
|
+
};
|
|
12835
|
+
}
|
|
12836
|
+
parseRGB(rgb) {
|
|
12837
|
+
const match = rgb.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*([\d.]+))?\)/);
|
|
12838
|
+
if (!match)
|
|
12839
|
+
return null;
|
|
12840
|
+
return {
|
|
12841
|
+
r: parseInt(match[1], 10),
|
|
12842
|
+
g: parseInt(match[2], 10),
|
|
12843
|
+
b: parseInt(match[3], 10),
|
|
12844
|
+
a: match[4] ? parseFloat(match[4]) : undefined,
|
|
12845
|
+
};
|
|
12846
|
+
}
|
|
12847
|
+
rgbToHSL(rgb) {
|
|
12848
|
+
const r = rgb.r / 255;
|
|
12849
|
+
const g = rgb.g / 255;
|
|
12850
|
+
const b = rgb.b / 255;
|
|
12851
|
+
const max = Math.max(r, g, b);
|
|
12852
|
+
const min = Math.min(r, g, b);
|
|
12853
|
+
let h = 0;
|
|
12854
|
+
let s = 0;
|
|
12855
|
+
const l = (max + min) / 2;
|
|
12856
|
+
if (max !== min) {
|
|
12857
|
+
const d = max - min;
|
|
12858
|
+
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
|
|
12859
|
+
switch (max) {
|
|
12860
|
+
case r:
|
|
12861
|
+
h = ((g - b) / d + (g < b ? 6 : 0)) / 6;
|
|
12862
|
+
break;
|
|
12863
|
+
case g:
|
|
12864
|
+
h = ((b - r) / d + 2) / 6;
|
|
12865
|
+
break;
|
|
12866
|
+
case b:
|
|
12867
|
+
h = ((r - g) / d + 4) / 6;
|
|
12868
|
+
break;
|
|
12869
|
+
}
|
|
12870
|
+
}
|
|
12871
|
+
return {
|
|
12872
|
+
h: Math.round(h * 360),
|
|
12873
|
+
s: Math.round(s * 100),
|
|
12874
|
+
l: Math.round(l * 100),
|
|
12875
|
+
a: rgb.a,
|
|
12876
|
+
};
|
|
12877
|
+
}
|
|
12878
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DsColorPicker, deps: [{ token: i1$3.Overlay }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
12879
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: DsColorPicker, isStandalone: true, selector: "ds-color-picker", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, showAlpha: { classPropertyName: "showAlpha", publicName: "showAlpha", isSignal: true, isRequired: false, transformFunction: null }, presetColors: { classPropertyName: "presetColors", publicName: "presetColors", isSignal: true, isRequired: false, transformFunction: null }, format: { classPropertyName: "format", publicName: "format", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, allowClear: { classPropertyName: "allowClear", publicName: "allowClear", isSignal: true, isRequired: false, transformFunction: null }, showRecentColors: { classPropertyName: "showRecentColors", publicName: "showRecentColors", isSignal: true, isRequired: false, transformFunction: null }, maxRecentColors: { classPropertyName: "maxRecentColors", publicName: "maxRecentColors", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { colorChange: "colorChange" }, providers: [
|
|
12880
|
+
{
|
|
12881
|
+
provide: NG_VALUE_ACCESSOR,
|
|
12882
|
+
useExisting: forwardRef(() => DsColorPicker),
|
|
12883
|
+
multi: true,
|
|
12884
|
+
},
|
|
12885
|
+
], ngImport: i0, template: "<div [class]=\"containerClasses()\">\n <div class=\"ds-color-picker__trigger\" (click)=\"toggle()\">\n <!-- Preview de la couleur -->\n <div\n class=\"ds-color-picker__preview\"\n [style.background-color]=\"previewColor()\"\n [attr.aria-label]=\"'Color: ' + displayValue()\">\n </div>\n\n <!-- Input texte -->\n <input\n type=\"text\"\n class=\"ds-color-picker__input\"\n [value]=\"displayValue()\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"disabled()\"\n readonly\n (focus)=\"onFocus()\"\n (blur)=\"onBlur()\"\n [attr.aria-label]=\"placeholder()\" />\n\n <!-- Actions -->\n <div class=\"ds-color-picker__actions\">\n @if (allowClear() && internalValue()) {\n <button\n type=\"button\"\n class=\"ds-color-picker__action ds-color-picker__action--clear\"\n [disabled]=\"disabled()\"\n (click)=\"clear(); $event.stopPropagation()\"\n [attr.aria-label]=\"'Clear color'\">\n <fa-icon [icon]=\"clearIcon\" aria-hidden=\"true\"></fa-icon>\n </button>\n }\n\n <button\n type=\"button\"\n class=\"ds-color-picker__action ds-color-picker__action--picker\"\n [disabled]=\"disabled()\"\n [attr.aria-label]=\"'Open color picker'\">\n <fa-icon [icon]=\"pickerIcon\" aria-hidden=\"true\"></fa-icon>\n </button>\n </div>\n </div>\n</div>\n", styles: [".ds-color-picker{position:relative;display:inline-flex;width:100%}.ds-color-picker__trigger{position:relative;display:flex;align-items:center;gap:var(--colorpicker-gap, var(--space-2));width:100%;background:var(--colorpicker-bg, var(--background-main));border:1px solid var(--colorpicker-border, var(--border-default));border-radius:var(--colorpicker-radius, var(--radius-2));padding:var(--colorpicker-padding, var(--space-2));cursor:pointer;transition:border-color var(--duration-fast, .15s) ease,box-shadow var(--duration-fast, .15s) ease}.ds-color-picker__trigger:hover:not([disabled]){border-color:var(--colorpicker-border-hover, var(--border-strong))}.ds-color-picker__preview{flex-shrink:0;width:var(--colorpicker-preview-size, 28px);height:var(--colorpicker-preview-size, 28px);border:2px solid var(--colorpicker-preview-border, var(--border-default));border-radius:var(--radius-1);background-image:linear-gradient(45deg,#ccc 25%,transparent 25%),linear-gradient(-45deg,#ccc 25%,transparent 25%),linear-gradient(45deg,transparent 75%,#ccc 75%),linear-gradient(-45deg,transparent 75%,#ccc 75%);background-size:8px 8px;background-position:0 0,0 4px,4px -4px,-4px 0;position:relative}.ds-color-picker__preview:after{content:\"\";position:absolute;inset:0;background-color:currentColor;border-radius:inherit}.ds-color-picker__input{flex:1;min-width:0;background:transparent;border:none;color:var(--colorpicker-text, var(--text-default));font-size:var(--colorpicker-font-size, var(--font-size-3));outline:none;cursor:pointer}.ds-color-picker__input::placeholder{color:var(--colorpicker-placeholder, var(--text-muted))}.ds-color-picker__input:disabled{cursor:not-allowed}.ds-color-picker__actions{display:flex;align-items:center;gap:var(--space-1)}.ds-color-picker__action{display:flex;align-items:center;justify-content:center;width:var(--colorpicker-action-size, 24px);height:var(--colorpicker-action-size, 24px);padding:0;background:transparent;border:none;border-radius:var(--radius-1);color:var(--colorpicker-icon, var(--text-muted));cursor:pointer;transition:background-color var(--duration-fast, .15s) ease,color var(--duration-fast, .15s) ease}.ds-color-picker__action:hover:not(:disabled){background:var(--colorpicker-action-hover-bg, var(--surface-hover));color:var(--text-default)}.ds-color-picker__action:focus-visible{outline:2px solid var(--color-primary);outline-offset:1px}.ds-color-picker__action:disabled{opacity:.5;cursor:not-allowed}.ds-color-picker__action--clear{color:var(--colorpicker-clear-icon, var(--text-muted))}.ds-color-picker__action--clear:hover:not(:disabled){color:var(--error)}.ds-color-picker--sm .ds-color-picker__trigger{padding:var(--colorpicker-padding-sm, var(--space-1) var(--space-2));height:var(--colorpicker-height-sm, 32px)}.ds-color-picker--sm .ds-color-picker__preview{width:var(--colorpicker-preview-size-sm, 20px);height:var(--colorpicker-preview-size-sm, 20px)}.ds-color-picker--sm .ds-color-picker__input{font-size:var(--colorpicker-font-size-sm, var(--font-size-2))}.ds-color-picker--sm .ds-color-picker__action{width:var(--colorpicker-action-size-sm, 20px);height:var(--colorpicker-action-size-sm, 20px);font-size:var(--font-size-2)}.ds-color-picker--md .ds-color-picker__trigger{padding:var(--colorpicker-padding-md, var(--space-2));height:var(--colorpicker-height-md, 40px)}.ds-color-picker--md .ds-color-picker__preview{width:var(--colorpicker-preview-size-md, 28px);height:var(--colorpicker-preview-size-md, 28px)}.ds-color-picker--md .ds-color-picker__input{font-size:var(--colorpicker-font-size-md, var(--font-size-3))}.ds-color-picker--md .ds-color-picker__action{width:var(--colorpicker-action-size-md, 24px);height:var(--colorpicker-action-size-md, 24px);font-size:var(--font-size-3)}.ds-color-picker--lg .ds-color-picker__trigger{padding:var(--colorpicker-padding-lg, var(--space-3));height:var(--colorpicker-height-lg, 48px)}.ds-color-picker--lg .ds-color-picker__preview{width:var(--colorpicker-preview-size-lg, 36px);height:var(--colorpicker-preview-size-lg, 36px)}.ds-color-picker--lg .ds-color-picker__input{font-size:var(--colorpicker-font-size-lg, var(--font-size-4))}.ds-color-picker--lg .ds-color-picker__action{width:var(--colorpicker-action-size-lg, 28px);height:var(--colorpicker-action-size-lg, 28px);font-size:var(--font-size-4)}.ds-color-picker--focused .ds-color-picker__trigger{border-color:var(--color-primary);box-shadow:0 0 0 3px var(--colorpicker-focus-shadow, rgba(59, 130, 246, .25))}.ds-color-picker--open .ds-color-picker__trigger{border-color:var(--color-primary)}.ds-color-picker--disabled{opacity:.6;pointer-events:none;cursor:not-allowed}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FontAwesomeModule }, { kind: "component", type: i1$1.FaIconComponent, selector: "fa-icon", inputs: ["icon", "title", "animation", "mask", "flip", "size", "pull", "border", "inverse", "symbol", "rotate", "fixedWidth", "transform", "a11yRole"], outputs: ["iconChange", "titleChange", "animationChange", "maskChange", "flipChange", "sizeChange", "pullChange", "borderChange", "inverseChange", "symbolChange", "rotateChange", "fixedWidthChange", "transformChange", "a11yRoleChange"] }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: OverlayModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
12886
|
+
}
|
|
12887
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DsColorPicker, decorators: [{
|
|
12888
|
+
type: Component,
|
|
12889
|
+
args: [{ selector: 'ds-color-picker', standalone: true, imports: [CommonModule, FontAwesomeModule, FormsModule, OverlayModule], changeDetection: ChangeDetectionStrategy.OnPush, providers: [
|
|
12890
|
+
{
|
|
12891
|
+
provide: NG_VALUE_ACCESSOR,
|
|
12892
|
+
useExisting: forwardRef(() => DsColorPicker),
|
|
12893
|
+
multi: true,
|
|
12894
|
+
},
|
|
12895
|
+
], template: "<div [class]=\"containerClasses()\">\n <div class=\"ds-color-picker__trigger\" (click)=\"toggle()\">\n <!-- Preview de la couleur -->\n <div\n class=\"ds-color-picker__preview\"\n [style.background-color]=\"previewColor()\"\n [attr.aria-label]=\"'Color: ' + displayValue()\">\n </div>\n\n <!-- Input texte -->\n <input\n type=\"text\"\n class=\"ds-color-picker__input\"\n [value]=\"displayValue()\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"disabled()\"\n readonly\n (focus)=\"onFocus()\"\n (blur)=\"onBlur()\"\n [attr.aria-label]=\"placeholder()\" />\n\n <!-- Actions -->\n <div class=\"ds-color-picker__actions\">\n @if (allowClear() && internalValue()) {\n <button\n type=\"button\"\n class=\"ds-color-picker__action ds-color-picker__action--clear\"\n [disabled]=\"disabled()\"\n (click)=\"clear(); $event.stopPropagation()\"\n [attr.aria-label]=\"'Clear color'\">\n <fa-icon [icon]=\"clearIcon\" aria-hidden=\"true\"></fa-icon>\n </button>\n }\n\n <button\n type=\"button\"\n class=\"ds-color-picker__action ds-color-picker__action--picker\"\n [disabled]=\"disabled()\"\n [attr.aria-label]=\"'Open color picker'\">\n <fa-icon [icon]=\"pickerIcon\" aria-hidden=\"true\"></fa-icon>\n </button>\n </div>\n </div>\n</div>\n", styles: [".ds-color-picker{position:relative;display:inline-flex;width:100%}.ds-color-picker__trigger{position:relative;display:flex;align-items:center;gap:var(--colorpicker-gap, var(--space-2));width:100%;background:var(--colorpicker-bg, var(--background-main));border:1px solid var(--colorpicker-border, var(--border-default));border-radius:var(--colorpicker-radius, var(--radius-2));padding:var(--colorpicker-padding, var(--space-2));cursor:pointer;transition:border-color var(--duration-fast, .15s) ease,box-shadow var(--duration-fast, .15s) ease}.ds-color-picker__trigger:hover:not([disabled]){border-color:var(--colorpicker-border-hover, var(--border-strong))}.ds-color-picker__preview{flex-shrink:0;width:var(--colorpicker-preview-size, 28px);height:var(--colorpicker-preview-size, 28px);border:2px solid var(--colorpicker-preview-border, var(--border-default));border-radius:var(--radius-1);background-image:linear-gradient(45deg,#ccc 25%,transparent 25%),linear-gradient(-45deg,#ccc 25%,transparent 25%),linear-gradient(45deg,transparent 75%,#ccc 75%),linear-gradient(-45deg,transparent 75%,#ccc 75%);background-size:8px 8px;background-position:0 0,0 4px,4px -4px,-4px 0;position:relative}.ds-color-picker__preview:after{content:\"\";position:absolute;inset:0;background-color:currentColor;border-radius:inherit}.ds-color-picker__input{flex:1;min-width:0;background:transparent;border:none;color:var(--colorpicker-text, var(--text-default));font-size:var(--colorpicker-font-size, var(--font-size-3));outline:none;cursor:pointer}.ds-color-picker__input::placeholder{color:var(--colorpicker-placeholder, var(--text-muted))}.ds-color-picker__input:disabled{cursor:not-allowed}.ds-color-picker__actions{display:flex;align-items:center;gap:var(--space-1)}.ds-color-picker__action{display:flex;align-items:center;justify-content:center;width:var(--colorpicker-action-size, 24px);height:var(--colorpicker-action-size, 24px);padding:0;background:transparent;border:none;border-radius:var(--radius-1);color:var(--colorpicker-icon, var(--text-muted));cursor:pointer;transition:background-color var(--duration-fast, .15s) ease,color var(--duration-fast, .15s) ease}.ds-color-picker__action:hover:not(:disabled){background:var(--colorpicker-action-hover-bg, var(--surface-hover));color:var(--text-default)}.ds-color-picker__action:focus-visible{outline:2px solid var(--color-primary);outline-offset:1px}.ds-color-picker__action:disabled{opacity:.5;cursor:not-allowed}.ds-color-picker__action--clear{color:var(--colorpicker-clear-icon, var(--text-muted))}.ds-color-picker__action--clear:hover:not(:disabled){color:var(--error)}.ds-color-picker--sm .ds-color-picker__trigger{padding:var(--colorpicker-padding-sm, var(--space-1) var(--space-2));height:var(--colorpicker-height-sm, 32px)}.ds-color-picker--sm .ds-color-picker__preview{width:var(--colorpicker-preview-size-sm, 20px);height:var(--colorpicker-preview-size-sm, 20px)}.ds-color-picker--sm .ds-color-picker__input{font-size:var(--colorpicker-font-size-sm, var(--font-size-2))}.ds-color-picker--sm .ds-color-picker__action{width:var(--colorpicker-action-size-sm, 20px);height:var(--colorpicker-action-size-sm, 20px);font-size:var(--font-size-2)}.ds-color-picker--md .ds-color-picker__trigger{padding:var(--colorpicker-padding-md, var(--space-2));height:var(--colorpicker-height-md, 40px)}.ds-color-picker--md .ds-color-picker__preview{width:var(--colorpicker-preview-size-md, 28px);height:var(--colorpicker-preview-size-md, 28px)}.ds-color-picker--md .ds-color-picker__input{font-size:var(--colorpicker-font-size-md, var(--font-size-3))}.ds-color-picker--md .ds-color-picker__action{width:var(--colorpicker-action-size-md, 24px);height:var(--colorpicker-action-size-md, 24px);font-size:var(--font-size-3)}.ds-color-picker--lg .ds-color-picker__trigger{padding:var(--colorpicker-padding-lg, var(--space-3));height:var(--colorpicker-height-lg, 48px)}.ds-color-picker--lg .ds-color-picker__preview{width:var(--colorpicker-preview-size-lg, 36px);height:var(--colorpicker-preview-size-lg, 36px)}.ds-color-picker--lg .ds-color-picker__input{font-size:var(--colorpicker-font-size-lg, var(--font-size-4))}.ds-color-picker--lg .ds-color-picker__action{width:var(--colorpicker-action-size-lg, 28px);height:var(--colorpicker-action-size-lg, 28px);font-size:var(--font-size-4)}.ds-color-picker--focused .ds-color-picker__trigger{border-color:var(--color-primary);box-shadow:0 0 0 3px var(--colorpicker-focus-shadow, rgba(59, 130, 246, .25))}.ds-color-picker--open .ds-color-picker__trigger{border-color:var(--color-primary)}.ds-color-picker--disabled{opacity:.6;pointer-events:none;cursor:not-allowed}\n"] }]
|
|
12896
|
+
}], ctorParameters: () => [{ type: i1$3.Overlay }, { type: i0.ElementRef }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], showAlpha: [{ type: i0.Input, args: [{ isSignal: true, alias: "showAlpha", required: false }] }], presetColors: [{ type: i0.Input, args: [{ isSignal: true, alias: "presetColors", required: false }] }], format: [{ type: i0.Input, args: [{ isSignal: true, alias: "format", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], allowClear: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowClear", required: false }] }], showRecentColors: [{ type: i0.Input, args: [{ isSignal: true, alias: "showRecentColors", required: false }] }], maxRecentColors: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxRecentColors", required: false }] }], colorChange: [{ type: i0.Output, args: ["colorChange"] }] } });
|
|
12897
|
+
|
|
10166
12898
|
/*
|
|
10167
12899
|
* Components barrel export
|
|
10168
12900
|
*/
|
|
@@ -10734,5 +13466,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
|
|
|
10734
13466
|
* Generated bundle index. Do not edit.
|
|
10735
13467
|
*/
|
|
10736
13468
|
|
|
10737
|
-
export { AUTOCOMPLETE_POSITIONS, BUTTON_APPEARANCE_OPTIONS, BUTTON_SIZE_OPTIONS, BUTTON_VARIANT_OPTIONS, DROPDOWN_POSITIONS, DsAccordion, DsAlert, DsAvatar, DsBadge, DsBreadcrumb, DsButton, DsCard, DsCheckbox, DsChip, DsCombobox, DsContainer, DsDatePicker, DsDivider, DsDrawer, DsDropdown, DsEmpty, DsFileUpload, DsI18nService, DsInputField, DsInputTextarea, DsMenu, DsModalComponent, DsPagination, DsPopover, DsPopoverComponent, DsProgressBar, DsRadioGroup, DsRating, DsSearchInput, DsSelect, DsSkeleton, DsSlider, DsStepper, DsTable, DsTabs, DsTimePicker, DsToastComponent, DsToastContainerComponent, DsToastService, DsToggle, DsTooltip, DsTooltipComponent, DsTree, IconRegistryService, POPOVER_POSITIONS, PrimitiveBadge, PrimitiveButton, PrimitiveCheckbox, PrimitiveInput, PrimitiveRadio, PrimitiveTextarea, PrimitiveToggle, TOOLTIP_POSITIONS, buildButtonArgTypes, buildButtonArgs, createSizeRender, createVariantRender };
|
|
13469
|
+
export { AUTOCOMPLETE_POSITIONS, BUTTON_APPEARANCE_OPTIONS, BUTTON_SIZE_OPTIONS, BUTTON_VARIANT_OPTIONS, DROPDOWN_POSITIONS, DsAccordion, DsAlert, DsAvatar, DsBadge, DsBreadcrumb, DsButton, DsCalendar, DsCard, DsCarousel, DsCheckbox, DsChip, DsColorPicker, DsCombobox, DsContainer, DsDatePicker, DsDivider, DsDrawer, DsDropdown, DsEmpty, DsFileUpload, DsI18nService, DsInputField, DsInputNumber, DsInputTextarea, DsMenu, DsModalComponent, DsNotificationContainerComponent, DsNotificationItemComponent, DsNotificationService, DsPagination, DsPasswordStrength, DsPopover, DsPopoverComponent, DsProgressBar, DsRadioGroup, DsRating, DsSearchInput, DsSegmentedControl, DsSelect, DsSkeleton, DsSlider, DsStepper, DsTable, DsTabs, DsTimePicker, DsTimeline, DsToastComponent, DsToastContainerComponent, DsToastService, DsToggle, DsTooltip, DsTooltipComponent, DsTransfer, DsTree, IconRegistryService, POPOVER_POSITIONS, PrimitiveBadge, PrimitiveButton, PrimitiveCheckbox, PrimitiveInput, PrimitiveRadio, PrimitiveTextarea, PrimitiveToggle, TOOLTIP_POSITIONS, buildButtonArgTypes, buildButtonArgs, createSizeRender, createVariantRender };
|
|
10738
13470
|
//# sourceMappingURL=kksdev-ds-angular.mjs.map
|