@kksdev/ds-angular 1.7.2 → 1.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/kksdev-ds-angular.mjs +794 -8
- package/fesm2022/kksdev-ds-angular.mjs.map +1 -1
- package/index.d.ts +303 -5
- package/package.json +2 -2
|
@@ -1,7 +1,7 @@
|
|
|
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, Input, ViewEncapsulation } 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, contentChildren, ChangeDetectionStrategy, viewChild, Input, ViewEncapsulation } from '@angular/core';
|
|
3
3
|
import * as i1 from '@angular/common';
|
|
4
|
-
import { CommonModule, DOCUMENT, NgClass } from '@angular/common';
|
|
4
|
+
import { CommonModule, DOCUMENT, NgClass, NgTemplateOutlet } 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';
|
|
@@ -5215,6 +5215,82 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
|
|
|
5215
5215
|
args: ['blur']
|
|
5216
5216
|
}] } });
|
|
5217
5217
|
|
|
5218
|
+
let accordionItemIdCounter = 0;
|
|
5219
|
+
/**
|
|
5220
|
+
* # DsAccordionItem
|
|
5221
|
+
*
|
|
5222
|
+
* Composant enfant pour le mode template-driven de DsAccordion.
|
|
5223
|
+
* Permet d'injecter du contenu Angular riche (composants, HTML, etc.).
|
|
5224
|
+
*
|
|
5225
|
+
* ## Usage
|
|
5226
|
+
*
|
|
5227
|
+
* ```html
|
|
5228
|
+
* <ds-accordion [multiple]="true">
|
|
5229
|
+
* <ds-accordion-item header="Section 1" [badge]="items.length">
|
|
5230
|
+
* <div>Contenu riche ici</div>
|
|
5231
|
+
* <my-component />
|
|
5232
|
+
* </ds-accordion-item>
|
|
5233
|
+
* </ds-accordion>
|
|
5234
|
+
* ```
|
|
5235
|
+
*
|
|
5236
|
+
* @component
|
|
5237
|
+
*/
|
|
5238
|
+
class DsAccordionItem {
|
|
5239
|
+
/**
|
|
5240
|
+
* Texte du header.
|
|
5241
|
+
*/
|
|
5242
|
+
header = input('', ...(ngDevMode ? [{ debugName: "header" }] : []));
|
|
5243
|
+
/**
|
|
5244
|
+
* Badge optionnel affiché à côté du header (ex: compteur).
|
|
5245
|
+
*/
|
|
5246
|
+
badge = input(undefined, ...(ngDevMode ? [{ debugName: "badge" }] : []));
|
|
5247
|
+
/**
|
|
5248
|
+
* ID unique de l'item. Auto-généré si non fourni.
|
|
5249
|
+
*/
|
|
5250
|
+
id = input(`accordion-item-${++accordionItemIdCounter}`, ...(ngDevMode ? [{ debugName: "id" }] : []));
|
|
5251
|
+
/**
|
|
5252
|
+
* Désactiver cet item.
|
|
5253
|
+
* @default false
|
|
5254
|
+
*/
|
|
5255
|
+
disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
|
|
5256
|
+
/**
|
|
5257
|
+
* Template du contenu projeté.
|
|
5258
|
+
* @internal
|
|
5259
|
+
*/
|
|
5260
|
+
contentTemplate;
|
|
5261
|
+
/**
|
|
5262
|
+
* État d'expansion (contrôlé par le parent DsAccordion).
|
|
5263
|
+
* @internal
|
|
5264
|
+
*/
|
|
5265
|
+
_expanded = signal(false, ...(ngDevMode ? [{ debugName: "_expanded" }] : []));
|
|
5266
|
+
/**
|
|
5267
|
+
* Index dans la liste (injecté par le parent).
|
|
5268
|
+
* @internal
|
|
5269
|
+
*/
|
|
5270
|
+
_index = signal(0, ...(ngDevMode ? [{ debugName: "_index" }] : []));
|
|
5271
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DsAccordionItem, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
5272
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.15", type: DsAccordionItem, isStandalone: true, selector: "ds-accordion-item", inputs: { header: { classPropertyName: "header", publicName: "header", isSignal: true, isRequired: false, transformFunction: null }, badge: { classPropertyName: "badge", publicName: "badge", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "contentTemplate", first: true, predicate: ["contentTemplate"], descendants: true, static: true }], ngImport: i0, template: `
|
|
5273
|
+
<ng-template #contentTemplate>
|
|
5274
|
+
<ng-content />
|
|
5275
|
+
</ng-template>
|
|
5276
|
+
`, isInline: true });
|
|
5277
|
+
}
|
|
5278
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DsAccordionItem, decorators: [{
|
|
5279
|
+
type: Component,
|
|
5280
|
+
args: [{
|
|
5281
|
+
selector: 'ds-accordion-item',
|
|
5282
|
+
standalone: true,
|
|
5283
|
+
template: `
|
|
5284
|
+
<ng-template #contentTemplate>
|
|
5285
|
+
<ng-content />
|
|
5286
|
+
</ng-template>
|
|
5287
|
+
`,
|
|
5288
|
+
}]
|
|
5289
|
+
}], propDecorators: { header: [{ type: i0.Input, args: [{ isSignal: true, alias: "header", required: false }] }], badge: [{ type: i0.Input, args: [{ isSignal: true, alias: "badge", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], contentTemplate: [{
|
|
5290
|
+
type: ViewChild,
|
|
5291
|
+
args: ['contentTemplate', { static: true }]
|
|
5292
|
+
}] } });
|
|
5293
|
+
|
|
5218
5294
|
/**
|
|
5219
5295
|
* # DsAccordion
|
|
5220
5296
|
*
|
|
@@ -5242,9 +5318,11 @@ class DsAccordion {
|
|
|
5242
5318
|
// Icône FontAwesome
|
|
5243
5319
|
faChevronDown = faChevronDown;
|
|
5244
5320
|
/**
|
|
5245
|
-
* Liste des items de l'accordion.
|
|
5321
|
+
* Liste des items de l'accordion (mode data-driven).
|
|
5322
|
+
* Laisser vide pour utiliser le mode template-driven avec <ds-accordion-item>.
|
|
5323
|
+
* @default []
|
|
5246
5324
|
*/
|
|
5247
|
-
items = input
|
|
5325
|
+
items = input([], ...(ngDevMode ? [{ debugName: "items" }] : []));
|
|
5248
5326
|
/**
|
|
5249
5327
|
* Permettre l'expansion de plusieurs items simultanément.
|
|
5250
5328
|
* @default false
|
|
@@ -5274,6 +5352,19 @@ class DsAccordion {
|
|
|
5274
5352
|
* Événement émis lors du changement d'état d'un item.
|
|
5275
5353
|
*/
|
|
5276
5354
|
itemChange = output();
|
|
5355
|
+
/**
|
|
5356
|
+
* Items enfants en mode template-driven.
|
|
5357
|
+
* @internal
|
|
5358
|
+
*/
|
|
5359
|
+
accordionItems = contentChildren(DsAccordionItem, ...(ngDevMode ? [{ debugName: "accordionItems" }] : []));
|
|
5360
|
+
/**
|
|
5361
|
+
* Mode de fonctionnement (auto-détecté).
|
|
5362
|
+
* - 'data' : si [items] est fourni et non vide
|
|
5363
|
+
* - 'template' : si des <ds-accordion-item> enfants sont présents
|
|
5364
|
+
*/
|
|
5365
|
+
mode = computed(() => {
|
|
5366
|
+
return this.items().length > 0 ? 'data' : 'template';
|
|
5367
|
+
}, ...(ngDevMode ? [{ debugName: "mode" }] : []));
|
|
5277
5368
|
/**
|
|
5278
5369
|
* État interne des items ouverts.
|
|
5279
5370
|
*/
|
|
@@ -5413,13 +5504,103 @@ class DsAccordion {
|
|
|
5413
5504
|
getContentId(item) {
|
|
5414
5505
|
return `accordion-content-${item.id}`;
|
|
5415
5506
|
}
|
|
5507
|
+
// ==========================================
|
|
5508
|
+
// Mode template-driven
|
|
5509
|
+
// ==========================================
|
|
5510
|
+
/**
|
|
5511
|
+
* Initialiser les index des items enfants.
|
|
5512
|
+
*/
|
|
5513
|
+
ngAfterContentInit() {
|
|
5514
|
+
this.updateTemplateItemsIndex();
|
|
5515
|
+
}
|
|
5516
|
+
/**
|
|
5517
|
+
* Mettre à jour les index des items template.
|
|
5518
|
+
*/
|
|
5519
|
+
updateTemplateItemsIndex() {
|
|
5520
|
+
this.accordionItems().forEach((item, index) => {
|
|
5521
|
+
item._index.set(index);
|
|
5522
|
+
});
|
|
5523
|
+
}
|
|
5524
|
+
/**
|
|
5525
|
+
* Toggle un item en mode template-driven.
|
|
5526
|
+
*/
|
|
5527
|
+
toggleTemplateItem(item) {
|
|
5528
|
+
if (this.disabled() || item.disabled())
|
|
5529
|
+
return;
|
|
5530
|
+
const itemId = item.id();
|
|
5531
|
+
const isCurrentlyExpanded = this.isExpanded(itemId);
|
|
5532
|
+
if (isCurrentlyExpanded) {
|
|
5533
|
+
this._expandedIds.update((set) => {
|
|
5534
|
+
const newSet = new Set(set);
|
|
5535
|
+
newSet.delete(itemId);
|
|
5536
|
+
return newSet;
|
|
5537
|
+
});
|
|
5538
|
+
}
|
|
5539
|
+
else {
|
|
5540
|
+
if (!this.multiple()) {
|
|
5541
|
+
this._expandedIds.set(new Set([itemId]));
|
|
5542
|
+
}
|
|
5543
|
+
else {
|
|
5544
|
+
this._expandedIds.update((set) => {
|
|
5545
|
+
const newSet = new Set(set);
|
|
5546
|
+
newSet.add(itemId);
|
|
5547
|
+
return newSet;
|
|
5548
|
+
});
|
|
5549
|
+
}
|
|
5550
|
+
}
|
|
5551
|
+
item._expanded.set(!isCurrentlyExpanded);
|
|
5552
|
+
this.itemChange.emit({
|
|
5553
|
+
itemId,
|
|
5554
|
+
expanded: !isCurrentlyExpanded,
|
|
5555
|
+
expandedItems: Array.from(this._expandedIds()),
|
|
5556
|
+
});
|
|
5557
|
+
}
|
|
5558
|
+
/**
|
|
5559
|
+
* Gestion du clavier en mode template-driven.
|
|
5560
|
+
*/
|
|
5561
|
+
onTemplateKeydown(event, item, index) {
|
|
5562
|
+
const items = this.accordionItems();
|
|
5563
|
+
switch (event.key) {
|
|
5564
|
+
case 'Enter':
|
|
5565
|
+
case ' ':
|
|
5566
|
+
event.preventDefault();
|
|
5567
|
+
this.toggleTemplateItem(item);
|
|
5568
|
+
break;
|
|
5569
|
+
case 'ArrowDown':
|
|
5570
|
+
event.preventDefault();
|
|
5571
|
+
this.focusItem(Math.min(index + 1, items.length - 1));
|
|
5572
|
+
break;
|
|
5573
|
+
case 'ArrowUp':
|
|
5574
|
+
event.preventDefault();
|
|
5575
|
+
this.focusItem(Math.max(index - 1, 0));
|
|
5576
|
+
break;
|
|
5577
|
+
case 'Home':
|
|
5578
|
+
event.preventDefault();
|
|
5579
|
+
this.focusItem(0);
|
|
5580
|
+
break;
|
|
5581
|
+
case 'End':
|
|
5582
|
+
event.preventDefault();
|
|
5583
|
+
this.focusItem(items.length - 1);
|
|
5584
|
+
break;
|
|
5585
|
+
}
|
|
5586
|
+
}
|
|
5587
|
+
/**
|
|
5588
|
+
* Classes CSS pour un item template-driven.
|
|
5589
|
+
*/
|
|
5590
|
+
getTemplateItemClasses(item) {
|
|
5591
|
+
return [
|
|
5592
|
+
'ds-accordion__item',
|
|
5593
|
+
this.isExpanded(item.id()) ? 'ds-accordion__item--expanded' : '',
|
|
5594
|
+
item.disabled() ? 'ds-accordion__item--disabled' : '',
|
|
5595
|
+
].filter(Boolean);
|
|
5596
|
+
}
|
|
5416
5597
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DsAccordion, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
5417
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: DsAccordion, isStandalone: true, selector: "ds-accordion", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired:
|
|
5598
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: DsAccordion, isStandalone: true, selector: "ds-accordion", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, expandedIds: { classPropertyName: "expandedIds", publicName: "expandedIds", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { itemChange: "itemChange" }, queries: [{ propertyName: "accordionItems", predicate: DsAccordionItem, isSignal: true }], ngImport: i0, template: "<div [ngClass]=\"containerClasses()\">\n <!-- Mode data-driven (r\u00E9trocompatible) -->\n @if (mode() === 'data') {\n @for (item of items(); track item.id; let i = $index) {\n <div [ngClass]=\"getItemClasses(item)\">\n <!-- Header -->\n <button\n type=\"button\"\n class=\"ds-accordion__header\"\n [id]=\"getHeaderId(item)\"\n [attr.aria-expanded]=\"isExpanded(item.id)\"\n [attr.aria-controls]=\"getContentId(item)\"\n [disabled]=\"disabled() || item.disabled\"\n (click)=\"toggleItem(item)\"\n (keydown)=\"onKeydown($event, item, i)\">\n <span class=\"ds-accordion__title\">{{ item.header }}</span>\n <fa-icon\n class=\"ds-accordion__icon\"\n [icon]=\"faChevronDown\"\n [class.ds-accordion__icon--rotated]=\"isExpanded(item.id)\"\n aria-hidden=\"true\">\n </fa-icon>\n </button>\n\n <!-- Contenu -->\n <div\n class=\"ds-accordion__content\"\n [id]=\"getContentId(item)\"\n role=\"region\"\n [attr.aria-labelledby]=\"getHeaderId(item)\"\n [attr.aria-hidden]=\"!isExpanded(item.id)\"\n [class.ds-accordion__content--expanded]=\"isExpanded(item.id)\">\n <div class=\"ds-accordion__body\">\n {{ item.content }}\n </div>\n </div>\n </div>\n }\n }\n\n <!-- Mode template-driven (contenu riche) -->\n @if (mode() === 'template') {\n @for (item of accordionItems(); track item.id(); let i = $index) {\n <div [ngClass]=\"getTemplateItemClasses(item)\">\n <!-- Header -->\n <button\n type=\"button\"\n class=\"ds-accordion__header\"\n [id]=\"'accordion-header-' + item.id()\"\n [attr.aria-expanded]=\"isExpanded(item.id())\"\n [attr.aria-controls]=\"'accordion-content-' + item.id()\"\n [disabled]=\"disabled() || item.disabled()\"\n (click)=\"toggleTemplateItem(item)\"\n (keydown)=\"onTemplateKeydown($event, item, i)\">\n <span class=\"ds-accordion__title\">{{ item.header() }}</span>\n @if (item.badge() !== undefined) {\n <ds-badge class=\"ds-accordion__badge\" size=\"sm\" type=\"neutral\">\n {{ item.badge() }}\n </ds-badge>\n }\n <fa-icon\n class=\"ds-accordion__icon\"\n [icon]=\"faChevronDown\"\n [class.ds-accordion__icon--rotated]=\"isExpanded(item.id())\"\n aria-hidden=\"true\">\n </fa-icon>\n </button>\n\n <!-- Contenu -->\n <div\n class=\"ds-accordion__content\"\n [id]=\"'accordion-content-' + item.id()\"\n role=\"region\"\n [attr.aria-labelledby]=\"'accordion-header-' + item.id()\"\n [attr.aria-hidden]=\"!isExpanded(item.id())\"\n [class.ds-accordion__content--expanded]=\"isExpanded(item.id())\">\n <div class=\"ds-accordion__body\">\n <ng-container *ngTemplateOutlet=\"item.contentTemplate\" />\n </div>\n </div>\n </div>\n }\n }\n</div>\n", styles: ["@charset \"UTF-8\";.ds-accordion{font-family:var(--font-family-base)}.ds-accordion__item--disabled{opacity:.5;pointer-events:none}.ds-accordion__header{display:flex;align-items:center;justify-content:space-between;width:100%;padding:var(--accordion-header-padding-md, var(--space-4));background-color:var(--accordion-header-bg, var(--background-main));border:none;cursor:pointer;text-align:left;font-family:inherit;font-size:var(--accordion-header-font-size-md, var(--font-size-3));font-weight:var(--font-weight-medium);color:var(--accordion-header-text, var(--text-default));border-radius:0;transition:background-color var(--duration-fast) var(--easing-default),color var(--duration-fast) var(--easing-default)}.ds-accordion__header:hover:not(:disabled){background-color:var(--accordion-header-hover-bg, var(--surface-hover))}.ds-accordion__header:focus-visible{outline:none;box-shadow:inset 0 0 0 2px var(--accordion-focus-color, var(--color-primary))}.ds-accordion__header:active:not(:disabled){transform:scale(.995)}.ds-accordion__header:disabled{cursor:not-allowed}.ds-accordion__title{flex:1}.ds-accordion__icon{flex-shrink:0;transition:transform var(--duration-normal) var(--easing-default);color:var(--accordion-icon-color, var(--text-muted))}.ds-accordion__icon--rotated{transform:rotate(180deg)}.ds-accordion__badge{margin-left:var(--space-2);margin-right:var(--space-2);flex-shrink:0}.ds-accordion__content{max-height:0;overflow:hidden;transition:max-height var(--duration-normal) var(--easing-default)}.ds-accordion__content--expanded{max-height:var(--accordion-content-max-height)}.ds-accordion__body{padding:var(--accordion-body-padding-md, var(--space-4));color:var(--accordion-body-text, var(--text-muted));font-size:var(--accordion-body-font-size-md, var(--font-size-2));line-height:var(--line-height-relaxed)}.ds-accordion--default .ds-accordion__item{border-bottom:var(--accordion-border-width) solid var(--accordion-border-color, var(--border-color))}.ds-accordion--default .ds-accordion__item:last-child{border-bottom:none}.ds-accordion--bordered{border:var(--accordion-border-width) solid var(--accordion-border-color, var(--border-color));border-radius:var(--accordion-radius, var(--radius-2));overflow:hidden}.ds-accordion--bordered .ds-accordion__item{border-bottom:var(--accordion-border-width) solid var(--accordion-border-color, var(--border-color))}.ds-accordion--bordered .ds-accordion__item:last-child{border-bottom:none}.ds-accordion--separated .ds-accordion__item{margin-bottom:var(--accordion-item-gap, var(--space-2));border:var(--accordion-border-width) solid var(--accordion-border-color, var(--border-color));border-radius:var(--accordion-radius, var(--radius-2));overflow:hidden}.ds-accordion--separated .ds-accordion__item:last-child{margin-bottom:0}.ds-accordion--separated .ds-accordion__item--expanded{border-color:var(--accordion-expanded-border-color, var(--color-primary))}.ds-accordion--sm .ds-accordion__header{padding:var(--accordion-header-padding-sm, var(--space-2) var(--space-3));font-size:var(--accordion-header-font-size-sm, var(--font-size-2))}.ds-accordion--sm .ds-accordion__body{padding:var(--accordion-body-padding-sm, var(--space-2) var(--space-3));font-size:var(--accordion-body-font-size-sm, var(--font-size-1))}.ds-accordion--lg .ds-accordion__header{padding:var(--accordion-header-padding-lg, var(--space-5) var(--space-6));font-size:var(--accordion-header-font-size-lg, var(--font-size-4))}.ds-accordion--lg .ds-accordion__body{padding:var(--accordion-body-padding-lg, var(--space-5) var(--space-6));font-size:var(--accordion-body-font-size-lg, var(--font-size-3))}.ds-accordion--disabled{opacity:.5;pointer-events:none}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { 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: "component", type: DsBadge, selector: "ds-badge", inputs: ["type", "size", "iconStart", "iconEnd", "variant", "shape", "color"] }] });
|
|
5418
5599
|
}
|
|
5419
5600
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DsAccordion, decorators: [{
|
|
5420
5601
|
type: Component,
|
|
5421
|
-
args: [{ selector: 'ds-accordion', imports: [CommonModule, FontAwesomeModule], template: "<div [ngClass]=\"containerClasses()\">\n @for (item of items(); track item.id; let i = $index) {\n
|
|
5422
|
-
}], ctorParameters: () => [], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required:
|
|
5602
|
+
args: [{ selector: 'ds-accordion', imports: [CommonModule, FontAwesomeModule, NgTemplateOutlet, DsBadge], template: "<div [ngClass]=\"containerClasses()\">\n <!-- Mode data-driven (r\u00E9trocompatible) -->\n @if (mode() === 'data') {\n @for (item of items(); track item.id; let i = $index) {\n <div [ngClass]=\"getItemClasses(item)\">\n <!-- Header -->\n <button\n type=\"button\"\n class=\"ds-accordion__header\"\n [id]=\"getHeaderId(item)\"\n [attr.aria-expanded]=\"isExpanded(item.id)\"\n [attr.aria-controls]=\"getContentId(item)\"\n [disabled]=\"disabled() || item.disabled\"\n (click)=\"toggleItem(item)\"\n (keydown)=\"onKeydown($event, item, i)\">\n <span class=\"ds-accordion__title\">{{ item.header }}</span>\n <fa-icon\n class=\"ds-accordion__icon\"\n [icon]=\"faChevronDown\"\n [class.ds-accordion__icon--rotated]=\"isExpanded(item.id)\"\n aria-hidden=\"true\">\n </fa-icon>\n </button>\n\n <!-- Contenu -->\n <div\n class=\"ds-accordion__content\"\n [id]=\"getContentId(item)\"\n role=\"region\"\n [attr.aria-labelledby]=\"getHeaderId(item)\"\n [attr.aria-hidden]=\"!isExpanded(item.id)\"\n [class.ds-accordion__content--expanded]=\"isExpanded(item.id)\">\n <div class=\"ds-accordion__body\">\n {{ item.content }}\n </div>\n </div>\n </div>\n }\n }\n\n <!-- Mode template-driven (contenu riche) -->\n @if (mode() === 'template') {\n @for (item of accordionItems(); track item.id(); let i = $index) {\n <div [ngClass]=\"getTemplateItemClasses(item)\">\n <!-- Header -->\n <button\n type=\"button\"\n class=\"ds-accordion__header\"\n [id]=\"'accordion-header-' + item.id()\"\n [attr.aria-expanded]=\"isExpanded(item.id())\"\n [attr.aria-controls]=\"'accordion-content-' + item.id()\"\n [disabled]=\"disabled() || item.disabled()\"\n (click)=\"toggleTemplateItem(item)\"\n (keydown)=\"onTemplateKeydown($event, item, i)\">\n <span class=\"ds-accordion__title\">{{ item.header() }}</span>\n @if (item.badge() !== undefined) {\n <ds-badge class=\"ds-accordion__badge\" size=\"sm\" type=\"neutral\">\n {{ item.badge() }}\n </ds-badge>\n }\n <fa-icon\n class=\"ds-accordion__icon\"\n [icon]=\"faChevronDown\"\n [class.ds-accordion__icon--rotated]=\"isExpanded(item.id())\"\n aria-hidden=\"true\">\n </fa-icon>\n </button>\n\n <!-- Contenu -->\n <div\n class=\"ds-accordion__content\"\n [id]=\"'accordion-content-' + item.id()\"\n role=\"region\"\n [attr.aria-labelledby]=\"'accordion-header-' + item.id()\"\n [attr.aria-hidden]=\"!isExpanded(item.id())\"\n [class.ds-accordion__content--expanded]=\"isExpanded(item.id())\">\n <div class=\"ds-accordion__body\">\n <ng-container *ngTemplateOutlet=\"item.contentTemplate\" />\n </div>\n </div>\n </div>\n }\n }\n</div>\n", styles: ["@charset \"UTF-8\";.ds-accordion{font-family:var(--font-family-base)}.ds-accordion__item--disabled{opacity:.5;pointer-events:none}.ds-accordion__header{display:flex;align-items:center;justify-content:space-between;width:100%;padding:var(--accordion-header-padding-md, var(--space-4));background-color:var(--accordion-header-bg, var(--background-main));border:none;cursor:pointer;text-align:left;font-family:inherit;font-size:var(--accordion-header-font-size-md, var(--font-size-3));font-weight:var(--font-weight-medium);color:var(--accordion-header-text, var(--text-default));border-radius:0;transition:background-color var(--duration-fast) var(--easing-default),color var(--duration-fast) var(--easing-default)}.ds-accordion__header:hover:not(:disabled){background-color:var(--accordion-header-hover-bg, var(--surface-hover))}.ds-accordion__header:focus-visible{outline:none;box-shadow:inset 0 0 0 2px var(--accordion-focus-color, var(--color-primary))}.ds-accordion__header:active:not(:disabled){transform:scale(.995)}.ds-accordion__header:disabled{cursor:not-allowed}.ds-accordion__title{flex:1}.ds-accordion__icon{flex-shrink:0;transition:transform var(--duration-normal) var(--easing-default);color:var(--accordion-icon-color, var(--text-muted))}.ds-accordion__icon--rotated{transform:rotate(180deg)}.ds-accordion__badge{margin-left:var(--space-2);margin-right:var(--space-2);flex-shrink:0}.ds-accordion__content{max-height:0;overflow:hidden;transition:max-height var(--duration-normal) var(--easing-default)}.ds-accordion__content--expanded{max-height:var(--accordion-content-max-height)}.ds-accordion__body{padding:var(--accordion-body-padding-md, var(--space-4));color:var(--accordion-body-text, var(--text-muted));font-size:var(--accordion-body-font-size-md, var(--font-size-2));line-height:var(--line-height-relaxed)}.ds-accordion--default .ds-accordion__item{border-bottom:var(--accordion-border-width) solid var(--accordion-border-color, var(--border-color))}.ds-accordion--default .ds-accordion__item:last-child{border-bottom:none}.ds-accordion--bordered{border:var(--accordion-border-width) solid var(--accordion-border-color, var(--border-color));border-radius:var(--accordion-radius, var(--radius-2));overflow:hidden}.ds-accordion--bordered .ds-accordion__item{border-bottom:var(--accordion-border-width) solid var(--accordion-border-color, var(--border-color))}.ds-accordion--bordered .ds-accordion__item:last-child{border-bottom:none}.ds-accordion--separated .ds-accordion__item{margin-bottom:var(--accordion-item-gap, var(--space-2));border:var(--accordion-border-width) solid var(--accordion-border-color, var(--border-color));border-radius:var(--accordion-radius, var(--radius-2));overflow:hidden}.ds-accordion--separated .ds-accordion__item:last-child{margin-bottom:0}.ds-accordion--separated .ds-accordion__item--expanded{border-color:var(--accordion-expanded-border-color, var(--color-primary))}.ds-accordion--sm .ds-accordion__header{padding:var(--accordion-header-padding-sm, var(--space-2) var(--space-3));font-size:var(--accordion-header-font-size-sm, var(--font-size-2))}.ds-accordion--sm .ds-accordion__body{padding:var(--accordion-body-padding-sm, var(--space-2) var(--space-3));font-size:var(--accordion-body-font-size-sm, var(--font-size-1))}.ds-accordion--lg .ds-accordion__header{padding:var(--accordion-header-padding-lg, var(--space-5) var(--space-6));font-size:var(--accordion-header-font-size-lg, var(--font-size-4))}.ds-accordion--lg .ds-accordion__body{padding:var(--accordion-body-padding-lg, var(--space-5) var(--space-6));font-size:var(--accordion-body-font-size-lg, var(--font-size-3))}.ds-accordion--disabled{opacity:.5;pointer-events:none}\n"] }]
|
|
5603
|
+
}], ctorParameters: () => [], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], expandedIds: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandedIds", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], itemChange: [{ type: i0.Output, args: ["itemChange"] }], accordionItems: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => DsAccordionItem), { isSignal: true }] }] } });
|
|
5423
5604
|
|
|
5424
5605
|
/**
|
|
5425
5606
|
* # DsPagination
|
|
@@ -15929,6 +16110,611 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
|
|
|
15929
16110
|
args: [{ selector: 'ds-list-group', standalone: true, imports: [CommonModule, FontAwesomeModule, DsBadge], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div [class]=\"groupClasses()\">\n <!-- Header du groupe -->\n <div\n class=\"ds-list-group__header\"\n [attr.role]=\"isCollapsible() ? 'button' : null\"\n [attr.tabindex]=\"isCollapsible() ? 0 : null\"\n [attr.aria-expanded]=\"isCollapsible() ? isExpanded() : null\"\n (click)=\"toggle()\"\n (keydown)=\"handleKeyDown($event)\"\n >\n <!-- Chevron (collapsible uniquement) -->\n @if (isCollapsible()) {\n <fa-icon\n [icon]=\"chevronIcon()\"\n class=\"ds-list-group__chevron\"\n [class.ds-list-group__chevron--expanded]=\"isExpanded()\"\n />\n }\n\n <!-- Ic\u00F4ne personnalis\u00E9e -->\n @if (icon()) {\n <fa-icon [icon]=\"icon()!\" class=\"ds-list-group__icon\" />\n }\n\n <!-- Titre -->\n <span class=\"ds-list-group__title\">{{ title() }}</span>\n\n <!-- Sous-titre -->\n @if (subtitle()) {\n <span class=\"ds-list-group__subtitle\">{{ subtitle() }}</span>\n }\n\n <!-- Compteur (badge) -->\n @if (showCount()) {\n <ds-badge type=\"neutral\" size=\"sm\" class=\"ds-list-group__count\">\n {{ count() }}\n </ds-badge>\n }\n </div>\n\n <!-- Contenu du groupe -->\n @if (isExpanded()) {\n <div\n class=\"ds-list-group__content\"\n role=\"group\"\n [attr.aria-label]=\"title()\"\n >\n <ng-content />\n </div>\n }\n</div>\n", styles: [":host{display:block}.ds-list-group__header{display:flex;align-items:center;gap:var(--space-2, 8px);padding:var(--space-2, 8px) var(--space-3, 12px);font-size:var(--font-size-1, 12px);font-weight:var(--font-weight-semibold, 600);color:var(--text-muted, #9ca3af);text-transform:uppercase;letter-spacing:.05em;-webkit-user-select:none;user-select:none}.ds-list-group--collapsible .ds-list-group__header{cursor:pointer;border-radius:var(--radius-1, 4px);transition:background-color .15s ease}.ds-list-group--collapsible .ds-list-group__header:hover{background-color:var(--background-hover, rgba(255, 255, 255, .05))}.ds-list-group--collapsible .ds-list-group__header:focus-visible{outline:2px solid var(--color-primary, #3b82f6);outline-offset:-2px}.ds-list-group--sticky .ds-list-group__header{position:sticky;top:0;background:var(--background-main, #111827);z-index:10;border-bottom:1px solid var(--border-default, #374151)}.ds-list-group__chevron{font-size:10px;color:var(--text-muted, #9ca3af);transition:transform .2s ease;flex-shrink:0}.ds-list-group__chevron--expanded,.ds-list-group--collapsed .ds-list-group__chevron{transform:rotate(0)}.ds-list-group__icon{font-size:var(--font-size-2, 14px);color:var(--text-muted, #9ca3af);flex-shrink:0}.ds-list-group__title{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.ds-list-group__subtitle{font-weight:var(--font-weight-normal, 400);color:var(--text-muted, #6b7280);text-transform:none;letter-spacing:normal}.ds-list-group__count{flex-shrink:0}.ds-list-group--collapsed .ds-list-group__content{display:none}\n"] }]
|
|
15930
16111
|
}], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: true }] }], subtitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "subtitle", required: false }] }], count: [{ type: i0.Input, args: [{ isSignal: true, alias: "count", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], expanded: [{ type: i0.Input, args: [{ isSignal: true, alias: "expanded", required: false }] }], expandedChange: [{ type: i0.Output, args: ["expandedChange"] }], sticky: [{ type: i0.Input, args: [{ isSignal: true, alias: "sticky", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }] } });
|
|
15931
16112
|
|
|
16113
|
+
/**
|
|
16114
|
+
* Chip coloré pour afficher une entité sélectionnée dans ds-entity-picker
|
|
16115
|
+
*
|
|
16116
|
+
* @example
|
|
16117
|
+
* ```html
|
|
16118
|
+
* <ds-entity-chip
|
|
16119
|
+
* [option]="{ value: '1', label: 'Important', color: '#ef4444', emoji: '🏷️' }"
|
|
16120
|
+
* [removable]="true"
|
|
16121
|
+
* (removed)="onRemove()"
|
|
16122
|
+
* />
|
|
16123
|
+
* ```
|
|
16124
|
+
*/
|
|
16125
|
+
class DsEntityChip {
|
|
16126
|
+
/** Option à afficher */
|
|
16127
|
+
option = input.required(...(ngDevMode ? [{ debugName: "option" }] : []));
|
|
16128
|
+
/** Taille du chip */
|
|
16129
|
+
size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : []));
|
|
16130
|
+
/** Afficher le bouton de suppression */
|
|
16131
|
+
removable = input(true, ...(ngDevMode ? [{ debugName: "removable" }] : []));
|
|
16132
|
+
/** Chip désactivé */
|
|
16133
|
+
disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
|
|
16134
|
+
/** Événement de suppression */
|
|
16135
|
+
removed = output();
|
|
16136
|
+
/** Icône de fermeture */
|
|
16137
|
+
closeIcon = faXmark;
|
|
16138
|
+
/** Couleur du chip (depuis l'option ou fallback) */
|
|
16139
|
+
chipColor = computed(() => {
|
|
16140
|
+
return this.option().color || 'var(--gray-400)';
|
|
16141
|
+
}, ...(ngDevMode ? [{ debugName: "chipColor" }] : []));
|
|
16142
|
+
/** Couleur de fond (10% opacity) */
|
|
16143
|
+
backgroundColor = computed(() => {
|
|
16144
|
+
const color = this.option().color;
|
|
16145
|
+
if (!color) {
|
|
16146
|
+
return 'var(--gray-100)';
|
|
16147
|
+
}
|
|
16148
|
+
// Utilise color-mix pour créer une version transparente
|
|
16149
|
+
return `color-mix(in srgb, ${color} 12%, transparent)`;
|
|
16150
|
+
}, ...(ngDevMode ? [{ debugName: "backgroundColor" }] : []));
|
|
16151
|
+
/** Gestion du clic sur le bouton supprimer */
|
|
16152
|
+
handleRemove(event) {
|
|
16153
|
+
event.stopPropagation();
|
|
16154
|
+
event.preventDefault();
|
|
16155
|
+
if (this.disabled()) {
|
|
16156
|
+
return;
|
|
16157
|
+
}
|
|
16158
|
+
this.removed.emit(this.option());
|
|
16159
|
+
}
|
|
16160
|
+
/** Gestion du clavier */
|
|
16161
|
+
handleKeyDown(event) {
|
|
16162
|
+
if (this.disabled()) {
|
|
16163
|
+
return;
|
|
16164
|
+
}
|
|
16165
|
+
if (this.removable() && (event.key === 'Delete' || event.key === 'Backspace')) {
|
|
16166
|
+
event.preventDefault();
|
|
16167
|
+
this.removed.emit(this.option());
|
|
16168
|
+
}
|
|
16169
|
+
}
|
|
16170
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DsEntityChip, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
16171
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: DsEntityChip, isStandalone: true, selector: "ds-entity-chip", inputs: { option: { classPropertyName: "option", publicName: "option", isSignal: true, isRequired: true, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, removable: { classPropertyName: "removable", publicName: "removable", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { removed: "removed" }, ngImport: i0, template: `
|
|
16172
|
+
<div
|
|
16173
|
+
class="ds-entity-chip"
|
|
16174
|
+
[class.ds-entity-chip--sm]="size() === 'sm'"
|
|
16175
|
+
[class.ds-entity-chip--md]="size() === 'md'"
|
|
16176
|
+
[class.ds-entity-chip--lg]="size() === 'lg'"
|
|
16177
|
+
[class.ds-entity-chip--disabled]="disabled()"
|
|
16178
|
+
[style.--chip-color]="chipColor()"
|
|
16179
|
+
[style.background-color]="backgroundColor()"
|
|
16180
|
+
[style.border-color]="chipColor()"
|
|
16181
|
+
[attr.tabindex]="disabled() ? -1 : 0"
|
|
16182
|
+
(keydown)="handleKeyDown($event)"
|
|
16183
|
+
>
|
|
16184
|
+
@if (option().emoji) {
|
|
16185
|
+
<span class="ds-entity-chip__emoji">{{ option().emoji }}</span>
|
|
16186
|
+
} @else if (option().icon) {
|
|
16187
|
+
<fa-icon
|
|
16188
|
+
class="ds-entity-chip__icon"
|
|
16189
|
+
[icon]="option().icon!"
|
|
16190
|
+
[fixedWidth]="true"
|
|
16191
|
+
[style.color]="chipColor()"
|
|
16192
|
+
/>
|
|
16193
|
+
}
|
|
16194
|
+
|
|
16195
|
+
<span class="ds-entity-chip__label">{{ option().label }}</span>
|
|
16196
|
+
|
|
16197
|
+
@if (removable() && !disabled()) {
|
|
16198
|
+
<button
|
|
16199
|
+
type="button"
|
|
16200
|
+
class="ds-entity-chip__remove"
|
|
16201
|
+
[attr.aria-label]="'Supprimer ' + option().label"
|
|
16202
|
+
(click)="handleRemove($event)"
|
|
16203
|
+
>
|
|
16204
|
+
<fa-icon [icon]="closeIcon" [fixedWidth]="true" />
|
|
16205
|
+
</button>
|
|
16206
|
+
}
|
|
16207
|
+
</div>
|
|
16208
|
+
`, isInline: true, styles: [".ds-entity-chip{display:inline-flex;align-items:center;gap:var(--space-1, .25rem);padding:var(--space-1, .25rem) var(--space-2, .5rem);border-radius:var(--radius-md, 6px);font-family:var(--font-family-base, sans-serif);font-size:var(--font-size-sm, .875rem);font-weight:500;line-height:1.4;border:1px solid var(--chip-color, var(--gray-300));background-color:color-mix(in srgb,var(--chip-color, var(--gray-300)) 10%,transparent);color:var(--text-default, #1a1a1a);transition:background-color var(--duration-fast, .15s) var(--easing-default, ease),transform var(--duration-fast, .15s) var(--easing-default, ease);-webkit-user-select:none;user-select:none;outline:none;max-width:200px}.ds-entity-chip:focus-visible{box-shadow:0 0 0 2px var(--background-main, #fff),0 0 0 4px var(--chip-color, var(--color-primary))}.ds-entity-chip__emoji{flex-shrink:0;font-size:1em}.ds-entity-chip__icon{flex-shrink:0;font-size:.875em}.ds-entity-chip__label{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0}.ds-entity-chip__remove{display:flex;align-items:center;justify-content:center;padding:var(--space-0-5, .125rem);margin:0;margin-left:var(--space-1, .25rem);background:none;border:none;border-radius:var(--radius-sm, 4px);cursor:pointer;color:var(--chip-color, var(--gray-600));opacity:.7;transition:opacity var(--duration-fast, .15s) var(--easing-default, ease),background-color var(--duration-fast, .15s) var(--easing-default, ease),transform var(--duration-fast, .15s) var(--easing-default, ease);flex-shrink:0}.ds-entity-chip__remove:hover{opacity:1;background-color:color-mix(in srgb,var(--chip-color, var(--gray-300)) 20%,transparent)}.ds-entity-chip__remove:active{transform:scale(.9)}.ds-entity-chip__remove:focus-visible{outline:none;opacity:1;box-shadow:0 0 0 2px var(--chip-color, var(--color-primary))}.ds-entity-chip__remove fa-icon{font-size:.75rem}.ds-entity-chip--sm{padding:var(--space-0-5, .125rem) var(--space-1-5, .375rem);font-size:var(--font-size-xs, .75rem);gap:var(--space-0-5, .125rem);max-width:150px}.ds-entity-chip--sm .ds-entity-chip__remove{padding:.0625rem}.ds-entity-chip--sm .ds-entity-chip__remove fa-icon{font-size:.625rem}.ds-entity-chip--lg{padding:var(--space-1-5, .375rem) var(--space-3, .75rem);font-size:var(--font-size-base, 1rem);gap:var(--space-2, .5rem);max-width:250px}.ds-entity-chip--lg .ds-entity-chip__remove fa-icon{font-size:.875rem}.ds-entity-chip--disabled{opacity:.5;cursor:not-allowed;pointer-events:none}\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 });
|
|
16209
|
+
}
|
|
16210
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DsEntityChip, decorators: [{
|
|
16211
|
+
type: Component,
|
|
16212
|
+
args: [{ selector: 'ds-entity-chip', standalone: true, imports: [CommonModule, FontAwesomeModule], template: `
|
|
16213
|
+
<div
|
|
16214
|
+
class="ds-entity-chip"
|
|
16215
|
+
[class.ds-entity-chip--sm]="size() === 'sm'"
|
|
16216
|
+
[class.ds-entity-chip--md]="size() === 'md'"
|
|
16217
|
+
[class.ds-entity-chip--lg]="size() === 'lg'"
|
|
16218
|
+
[class.ds-entity-chip--disabled]="disabled()"
|
|
16219
|
+
[style.--chip-color]="chipColor()"
|
|
16220
|
+
[style.background-color]="backgroundColor()"
|
|
16221
|
+
[style.border-color]="chipColor()"
|
|
16222
|
+
[attr.tabindex]="disabled() ? -1 : 0"
|
|
16223
|
+
(keydown)="handleKeyDown($event)"
|
|
16224
|
+
>
|
|
16225
|
+
@if (option().emoji) {
|
|
16226
|
+
<span class="ds-entity-chip__emoji">{{ option().emoji }}</span>
|
|
16227
|
+
} @else if (option().icon) {
|
|
16228
|
+
<fa-icon
|
|
16229
|
+
class="ds-entity-chip__icon"
|
|
16230
|
+
[icon]="option().icon!"
|
|
16231
|
+
[fixedWidth]="true"
|
|
16232
|
+
[style.color]="chipColor()"
|
|
16233
|
+
/>
|
|
16234
|
+
}
|
|
16235
|
+
|
|
16236
|
+
<span class="ds-entity-chip__label">{{ option().label }}</span>
|
|
16237
|
+
|
|
16238
|
+
@if (removable() && !disabled()) {
|
|
16239
|
+
<button
|
|
16240
|
+
type="button"
|
|
16241
|
+
class="ds-entity-chip__remove"
|
|
16242
|
+
[attr.aria-label]="'Supprimer ' + option().label"
|
|
16243
|
+
(click)="handleRemove($event)"
|
|
16244
|
+
>
|
|
16245
|
+
<fa-icon [icon]="closeIcon" [fixedWidth]="true" />
|
|
16246
|
+
</button>
|
|
16247
|
+
}
|
|
16248
|
+
</div>
|
|
16249
|
+
`, changeDetection: ChangeDetectionStrategy.OnPush, styles: [".ds-entity-chip{display:inline-flex;align-items:center;gap:var(--space-1, .25rem);padding:var(--space-1, .25rem) var(--space-2, .5rem);border-radius:var(--radius-md, 6px);font-family:var(--font-family-base, sans-serif);font-size:var(--font-size-sm, .875rem);font-weight:500;line-height:1.4;border:1px solid var(--chip-color, var(--gray-300));background-color:color-mix(in srgb,var(--chip-color, var(--gray-300)) 10%,transparent);color:var(--text-default, #1a1a1a);transition:background-color var(--duration-fast, .15s) var(--easing-default, ease),transform var(--duration-fast, .15s) var(--easing-default, ease);-webkit-user-select:none;user-select:none;outline:none;max-width:200px}.ds-entity-chip:focus-visible{box-shadow:0 0 0 2px var(--background-main, #fff),0 0 0 4px var(--chip-color, var(--color-primary))}.ds-entity-chip__emoji{flex-shrink:0;font-size:1em}.ds-entity-chip__icon{flex-shrink:0;font-size:.875em}.ds-entity-chip__label{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0}.ds-entity-chip__remove{display:flex;align-items:center;justify-content:center;padding:var(--space-0-5, .125rem);margin:0;margin-left:var(--space-1, .25rem);background:none;border:none;border-radius:var(--radius-sm, 4px);cursor:pointer;color:var(--chip-color, var(--gray-600));opacity:.7;transition:opacity var(--duration-fast, .15s) var(--easing-default, ease),background-color var(--duration-fast, .15s) var(--easing-default, ease),transform var(--duration-fast, .15s) var(--easing-default, ease);flex-shrink:0}.ds-entity-chip__remove:hover{opacity:1;background-color:color-mix(in srgb,var(--chip-color, var(--gray-300)) 20%,transparent)}.ds-entity-chip__remove:active{transform:scale(.9)}.ds-entity-chip__remove:focus-visible{outline:none;opacity:1;box-shadow:0 0 0 2px var(--chip-color, var(--color-primary))}.ds-entity-chip__remove fa-icon{font-size:.75rem}.ds-entity-chip--sm{padding:var(--space-0-5, .125rem) var(--space-1-5, .375rem);font-size:var(--font-size-xs, .75rem);gap:var(--space-0-5, .125rem);max-width:150px}.ds-entity-chip--sm .ds-entity-chip__remove{padding:.0625rem}.ds-entity-chip--sm .ds-entity-chip__remove fa-icon{font-size:.625rem}.ds-entity-chip--lg{padding:var(--space-1-5, .375rem) var(--space-3, .75rem);font-size:var(--font-size-base, 1rem);gap:var(--space-2, .5rem);max-width:250px}.ds-entity-chip--lg .ds-entity-chip__remove fa-icon{font-size:.875rem}.ds-entity-chip--disabled{opacity:.5;cursor:not-allowed;pointer-events:none}\n"] }]
|
|
16250
|
+
}], propDecorators: { option: [{ type: i0.Input, args: [{ isSignal: true, alias: "option", required: true }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], removable: [{ type: i0.Input, args: [{ isSignal: true, alias: "removable", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], removed: [{ type: i0.Output, args: ["removed"] }] } });
|
|
16251
|
+
|
|
16252
|
+
/**
|
|
16253
|
+
* Entity Picker - Sélecteur d'entités riches
|
|
16254
|
+
*
|
|
16255
|
+
* Permet la sélection d'entités avec icônes, couleurs, emojis.
|
|
16256
|
+
* Supporte la sélection simple et multiple avec affichage en chips colorés.
|
|
16257
|
+
*
|
|
16258
|
+
* @example
|
|
16259
|
+
* ```html
|
|
16260
|
+
* <!-- Sélection simple -->
|
|
16261
|
+
* <ds-entity-picker
|
|
16262
|
+
* [options]="tags"
|
|
16263
|
+
* [(ngModel)]="selectedTag"
|
|
16264
|
+
* placeholder="Choisir un tag"
|
|
16265
|
+
* />
|
|
16266
|
+
*
|
|
16267
|
+
* <!-- Sélection multiple -->
|
|
16268
|
+
* <ds-entity-picker
|
|
16269
|
+
* [options]="categories"
|
|
16270
|
+
* [multiple]="true"
|
|
16271
|
+
* [(ngModel)]="selectedCategories"
|
|
16272
|
+
* [allowCreate]="true"
|
|
16273
|
+
* (createRequested)="onCreateCategory($event)"
|
|
16274
|
+
* />
|
|
16275
|
+
* ```
|
|
16276
|
+
*/
|
|
16277
|
+
class DsEntityPicker {
|
|
16278
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
16279
|
+
// Inputs
|
|
16280
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
16281
|
+
/** Liste des options disponibles */
|
|
16282
|
+
options = input([], ...(ngDevMode ? [{ debugName: "options" }] : []));
|
|
16283
|
+
/** Active la sélection multiple */
|
|
16284
|
+
multiple = input(false, ...(ngDevMode ? [{ debugName: "multiple" }] : []));
|
|
16285
|
+
/** Permet la création d'options à la volée */
|
|
16286
|
+
allowCreate = input(false, ...(ngDevMode ? [{ debugName: "allowCreate" }] : []));
|
|
16287
|
+
/** Placeholder du champ de recherche */
|
|
16288
|
+
placeholder = input('Rechercher...', ...(ngDevMode ? [{ debugName: "placeholder" }] : []));
|
|
16289
|
+
/** Taille du composant */
|
|
16290
|
+
size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : []));
|
|
16291
|
+
/** Mode d'affichage des sélections multiples */
|
|
16292
|
+
displayMode = input('chip', ...(ngDevMode ? [{ debugName: "displayMode" }] : []));
|
|
16293
|
+
/** Afficher le bouton clear */
|
|
16294
|
+
clearable = input(true, ...(ngDevMode ? [{ debugName: "clearable" }] : []));
|
|
16295
|
+
/** Nombre maximum de sélections (multi-select) */
|
|
16296
|
+
maxSelections = input(undefined, ...(ngDevMode ? [{ debugName: "maxSelections" }] : []));
|
|
16297
|
+
/** Label du champ */
|
|
16298
|
+
label = input('', ...(ngDevMode ? [{ debugName: "label" }] : []));
|
|
16299
|
+
/** Message d'erreur */
|
|
16300
|
+
error = input('', ...(ngDevMode ? [{ debugName: "error" }] : []));
|
|
16301
|
+
/** Texte d'aide */
|
|
16302
|
+
helper = input('', ...(ngDevMode ? [{ debugName: "helper" }] : []));
|
|
16303
|
+
/** Champ désactivé */
|
|
16304
|
+
disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
|
|
16305
|
+
/** Champ obligatoire */
|
|
16306
|
+
required = input(false, ...(ngDevMode ? [{ debugName: "required" }] : []));
|
|
16307
|
+
/** Caractères minimum avant filtrage */
|
|
16308
|
+
minChars = input(0, ...(ngDevMode ? [{ debugName: "minChars" }] : []));
|
|
16309
|
+
/** Texte si aucun résultat */
|
|
16310
|
+
noResultsText = input('Aucun résultat', ...(ngDevMode ? [{ debugName: "noResultsText" }] : []));
|
|
16311
|
+
/** Template du texte de création (utiliser {query} comme placeholder) */
|
|
16312
|
+
createText = input('Créer "{query}"', ...(ngDevMode ? [{ debugName: "createText" }] : []));
|
|
16313
|
+
/** Nom du champ (pour formulaires) */
|
|
16314
|
+
name = input('', ...(ngDevMode ? [{ debugName: "name" }] : []));
|
|
16315
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
16316
|
+
// Outputs
|
|
16317
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
16318
|
+
/** Émis lors d'un changement de sélection */
|
|
16319
|
+
selectionChange = output();
|
|
16320
|
+
/** Émis lors d'une demande de création */
|
|
16321
|
+
createRequested = output();
|
|
16322
|
+
/** Émis lors d'un changement de recherche */
|
|
16323
|
+
searchChange = output();
|
|
16324
|
+
/** Émis à l'ouverture du panel */
|
|
16325
|
+
opened = output();
|
|
16326
|
+
/** Émis à la fermeture du panel */
|
|
16327
|
+
closed = output();
|
|
16328
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
16329
|
+
// Internal state
|
|
16330
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
16331
|
+
isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : []));
|
|
16332
|
+
searchQuery = signal('', ...(ngDevMode ? [{ debugName: "searchQuery" }] : []));
|
|
16333
|
+
focusedIndex = signal(-1, ...(ngDevMode ? [{ debugName: "focusedIndex" }] : []));
|
|
16334
|
+
internalValue = signal(null, ...(ngDevMode ? [{ debugName: "internalValue" }] : []));
|
|
16335
|
+
cvaDisabled = signal(false, ...(ngDevMode ? [{ debugName: "cvaDisabled" }] : []));
|
|
16336
|
+
inputElement;
|
|
16337
|
+
listbox;
|
|
16338
|
+
onChange = () => { };
|
|
16339
|
+
onTouched = () => { };
|
|
16340
|
+
// Icons
|
|
16341
|
+
iconPlus = faPlus;
|
|
16342
|
+
iconChevron = faChevronDown;
|
|
16343
|
+
iconClear = faXmark;
|
|
16344
|
+
iconSearch = faSearch;
|
|
16345
|
+
// CDK Overlay positions
|
|
16346
|
+
overlayPositions = AUTOCOMPLETE_POSITIONS;
|
|
16347
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
16348
|
+
// Computed
|
|
16349
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
16350
|
+
isDisabled = computed(() => this.disabled() || this.cvaDisabled(), ...(ngDevMode ? [{ debugName: "isDisabled" }] : []));
|
|
16351
|
+
/** Options sélectionnées (objets complets) */
|
|
16352
|
+
selectedOptions = computed(() => {
|
|
16353
|
+
const value = this.internalValue();
|
|
16354
|
+
const opts = this.options();
|
|
16355
|
+
if (value === null)
|
|
16356
|
+
return [];
|
|
16357
|
+
if (this.multiple()) {
|
|
16358
|
+
const values = Array.isArray(value) ? value : [value];
|
|
16359
|
+
return opts.filter(opt => values.includes(opt.value));
|
|
16360
|
+
}
|
|
16361
|
+
else {
|
|
16362
|
+
const found = opts.find(opt => opt.value === value);
|
|
16363
|
+
return found ? [found] : [];
|
|
16364
|
+
}
|
|
16365
|
+
}, ...(ngDevMode ? [{ debugName: "selectedOptions" }] : []));
|
|
16366
|
+
/** Texte affiché dans l'input (mode single) */
|
|
16367
|
+
displayValue = computed(() => {
|
|
16368
|
+
if (this.multiple())
|
|
16369
|
+
return '';
|
|
16370
|
+
const selected = this.selectedOptions();
|
|
16371
|
+
return selected.length > 0 ? selected[0].label : '';
|
|
16372
|
+
}, ...(ngDevMode ? [{ debugName: "displayValue" }] : []));
|
|
16373
|
+
/** Options filtrées selon la recherche */
|
|
16374
|
+
filteredOptions = computed(() => {
|
|
16375
|
+
const query = this.searchQuery().toLowerCase().trim();
|
|
16376
|
+
const minLen = this.minChars();
|
|
16377
|
+
const selected = this.selectedOptions().map(o => o.value);
|
|
16378
|
+
if (query.length < minLen) {
|
|
16379
|
+
// En multi-select, exclure les options déjà sélectionnées
|
|
16380
|
+
if (this.multiple()) {
|
|
16381
|
+
return this.options().filter(opt => !selected.includes(opt.value));
|
|
16382
|
+
}
|
|
16383
|
+
return this.options();
|
|
16384
|
+
}
|
|
16385
|
+
let results = this.options().filter(opt => {
|
|
16386
|
+
const matchLabel = opt.label.toLowerCase().includes(query);
|
|
16387
|
+
const matchDesc = opt.description?.toLowerCase().includes(query);
|
|
16388
|
+
return matchLabel || matchDesc;
|
|
16389
|
+
});
|
|
16390
|
+
// En multi-select, exclure les options déjà sélectionnées
|
|
16391
|
+
if (this.multiple()) {
|
|
16392
|
+
results = results.filter(opt => !selected.includes(opt.value));
|
|
16393
|
+
}
|
|
16394
|
+
return results;
|
|
16395
|
+
}, ...(ngDevMode ? [{ debugName: "filteredOptions" }] : []));
|
|
16396
|
+
/** Peut créer une nouvelle option */
|
|
16397
|
+
canCreate = computed(() => {
|
|
16398
|
+
if (!this.allowCreate())
|
|
16399
|
+
return false;
|
|
16400
|
+
const query = this.searchQuery().trim();
|
|
16401
|
+
if (!query)
|
|
16402
|
+
return false;
|
|
16403
|
+
// Vérifie si l'option n'existe pas déjà
|
|
16404
|
+
const exists = this.options().some(opt => opt.label.toLowerCase() === query.toLowerCase());
|
|
16405
|
+
return !exists;
|
|
16406
|
+
}, ...(ngDevMode ? [{ debugName: "canCreate" }] : []));
|
|
16407
|
+
/** Afficher le dropdown */
|
|
16408
|
+
shouldShowDropdown = computed(() => {
|
|
16409
|
+
return this.isOpen();
|
|
16410
|
+
}, ...(ngDevMode ? [{ debugName: "shouldShowDropdown" }] : []));
|
|
16411
|
+
/** Classes du container */
|
|
16412
|
+
containerClasses = computed(() => ({
|
|
16413
|
+
'ds-entity-picker': true,
|
|
16414
|
+
'ds-entity-picker--open': this.isOpen(),
|
|
16415
|
+
'ds-entity-picker--disabled': this.isDisabled(),
|
|
16416
|
+
'ds-entity-picker--error': !!this.error(),
|
|
16417
|
+
'ds-entity-picker--multiple': this.multiple(),
|
|
16418
|
+
[`ds-entity-picker--${this.size()}`]: true,
|
|
16419
|
+
}), ...(ngDevMode ? [{ debugName: "containerClasses" }] : []));
|
|
16420
|
+
/** Classes de l'input */
|
|
16421
|
+
inputClasses = computed(() => ({
|
|
16422
|
+
'ds-entity-picker__input': true,
|
|
16423
|
+
'ds-entity-picker__input--has-value': this.multiple()
|
|
16424
|
+
? this.selectedOptions().length > 0
|
|
16425
|
+
: !!this.internalValue(),
|
|
16426
|
+
}), ...(ngDevMode ? [{ debugName: "inputClasses" }] : []));
|
|
16427
|
+
/** ID unique pour le listbox */
|
|
16428
|
+
listboxId = computed(() => `${this.name() || 'entity-picker'}-listbox`, ...(ngDevMode ? [{ debugName: "listboxId" }] : []));
|
|
16429
|
+
/** ID unique pour l'input */
|
|
16430
|
+
inputId = computed(() => `${this.name() || 'entity-picker'}-input`, ...(ngDevMode ? [{ debugName: "inputId" }] : []));
|
|
16431
|
+
/** Texte du compteur (mode count) */
|
|
16432
|
+
countText = computed(() => {
|
|
16433
|
+
const count = this.selectedOptions().length;
|
|
16434
|
+
if (count === 0)
|
|
16435
|
+
return '';
|
|
16436
|
+
return `${count} sélectionné${count > 1 ? 's' : ''}`;
|
|
16437
|
+
}, ...(ngDevMode ? [{ debugName: "countText" }] : []));
|
|
16438
|
+
/** Limite de sélection atteinte */
|
|
16439
|
+
maxReached = computed(() => {
|
|
16440
|
+
const max = this.maxSelections();
|
|
16441
|
+
if (max === undefined)
|
|
16442
|
+
return false;
|
|
16443
|
+
return this.selectedOptions().length >= max;
|
|
16444
|
+
}, ...(ngDevMode ? [{ debugName: "maxReached" }] : []));
|
|
16445
|
+
/** Texte formaté pour l'option de création */
|
|
16446
|
+
formattedCreateText = computed(() => {
|
|
16447
|
+
return this.createText().replace('{query}', this.searchQuery());
|
|
16448
|
+
}, ...(ngDevMode ? [{ debugName: "formattedCreateText" }] : []));
|
|
16449
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
16450
|
+
// ControlValueAccessor
|
|
16451
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
16452
|
+
writeValue(value) {
|
|
16453
|
+
this.internalValue.set(value);
|
|
16454
|
+
}
|
|
16455
|
+
registerOnChange(fn) {
|
|
16456
|
+
this.onChange = fn;
|
|
16457
|
+
}
|
|
16458
|
+
registerOnTouched(fn) {
|
|
16459
|
+
this.onTouched = fn;
|
|
16460
|
+
}
|
|
16461
|
+
setDisabledState(isDisabled) {
|
|
16462
|
+
this.cvaDisabled.set(isDisabled);
|
|
16463
|
+
}
|
|
16464
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
16465
|
+
// Public methods
|
|
16466
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
16467
|
+
onInputFocus() {
|
|
16468
|
+
if (this.isDisabled())
|
|
16469
|
+
return;
|
|
16470
|
+
this.open();
|
|
16471
|
+
}
|
|
16472
|
+
onInputBlur() {
|
|
16473
|
+
this.onTouched();
|
|
16474
|
+
// Fermeture retardée pour permettre le clic sur une option
|
|
16475
|
+
setTimeout(() => {
|
|
16476
|
+
if (!this.isOpen())
|
|
16477
|
+
return;
|
|
16478
|
+
this.close();
|
|
16479
|
+
}, 200);
|
|
16480
|
+
}
|
|
16481
|
+
onSearchInput(event) {
|
|
16482
|
+
const input = event.target;
|
|
16483
|
+
this.searchQuery.set(input.value);
|
|
16484
|
+
this.searchChange.emit(input.value);
|
|
16485
|
+
this.focusedIndex.set(0);
|
|
16486
|
+
if (!this.isOpen() && input.value.length >= this.minChars()) {
|
|
16487
|
+
this.open();
|
|
16488
|
+
}
|
|
16489
|
+
}
|
|
16490
|
+
open() {
|
|
16491
|
+
if (this.isDisabled() || this.isOpen())
|
|
16492
|
+
return;
|
|
16493
|
+
this.isOpen.set(true);
|
|
16494
|
+
this.focusedIndex.set(0);
|
|
16495
|
+
this.opened.emit();
|
|
16496
|
+
}
|
|
16497
|
+
close() {
|
|
16498
|
+
if (!this.isOpen())
|
|
16499
|
+
return;
|
|
16500
|
+
this.isOpen.set(false);
|
|
16501
|
+
this.searchQuery.set('');
|
|
16502
|
+
this.focusedIndex.set(-1);
|
|
16503
|
+
this.closed.emit();
|
|
16504
|
+
}
|
|
16505
|
+
selectOption(option) {
|
|
16506
|
+
if (option.disabled || this.isDisabled())
|
|
16507
|
+
return;
|
|
16508
|
+
if (this.multiple()) {
|
|
16509
|
+
// Mode multi-sélection
|
|
16510
|
+
const current = this.internalValue() || [];
|
|
16511
|
+
const newValues = [...current, option.value];
|
|
16512
|
+
this.internalValue.set(newValues);
|
|
16513
|
+
this.onChange(newValues);
|
|
16514
|
+
// Émettre les options complètes
|
|
16515
|
+
const selectedOpts = this.options().filter(o => newValues.includes(o.value));
|
|
16516
|
+
this.selectionChange.emit(selectedOpts);
|
|
16517
|
+
// Reset recherche mais garde le panel ouvert
|
|
16518
|
+
this.searchQuery.set('');
|
|
16519
|
+
this.inputElement?.nativeElement?.focus();
|
|
16520
|
+
}
|
|
16521
|
+
else {
|
|
16522
|
+
// Mode sélection simple
|
|
16523
|
+
this.internalValue.set(option.value);
|
|
16524
|
+
this.onChange(option.value);
|
|
16525
|
+
this.selectionChange.emit(option);
|
|
16526
|
+
this.close();
|
|
16527
|
+
}
|
|
16528
|
+
}
|
|
16529
|
+
removeOption(option) {
|
|
16530
|
+
if (!this.multiple() || this.isDisabled())
|
|
16531
|
+
return;
|
|
16532
|
+
const current = this.internalValue() || [];
|
|
16533
|
+
const newValues = current.filter(v => v !== option.value);
|
|
16534
|
+
this.internalValue.set(newValues.length > 0 ? newValues : null);
|
|
16535
|
+
this.onChange(newValues.length > 0 ? newValues : null);
|
|
16536
|
+
const selectedOpts = this.options().filter(o => newValues.includes(o.value));
|
|
16537
|
+
this.selectionChange.emit(selectedOpts.length > 0 ? selectedOpts : null);
|
|
16538
|
+
}
|
|
16539
|
+
clear(event) {
|
|
16540
|
+
event?.stopPropagation();
|
|
16541
|
+
event?.preventDefault();
|
|
16542
|
+
if (this.isDisabled())
|
|
16543
|
+
return;
|
|
16544
|
+
this.internalValue.set(this.multiple() ? [] : null);
|
|
16545
|
+
this.onChange(this.multiple() ? [] : null);
|
|
16546
|
+
this.selectionChange.emit(null);
|
|
16547
|
+
this.searchQuery.set('');
|
|
16548
|
+
this.inputElement?.nativeElement?.focus();
|
|
16549
|
+
}
|
|
16550
|
+
requestCreate() {
|
|
16551
|
+
if (!this.canCreate())
|
|
16552
|
+
return;
|
|
16553
|
+
const value = this.searchQuery().trim();
|
|
16554
|
+
this.createRequested.emit(value);
|
|
16555
|
+
this.searchQuery.set('');
|
|
16556
|
+
this.close();
|
|
16557
|
+
}
|
|
16558
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
16559
|
+
// Keyboard navigation
|
|
16560
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
16561
|
+
onKeyDown(event) {
|
|
16562
|
+
if (this.isDisabled())
|
|
16563
|
+
return;
|
|
16564
|
+
switch (event.key) {
|
|
16565
|
+
case 'ArrowDown':
|
|
16566
|
+
event.preventDefault();
|
|
16567
|
+
if (!this.isOpen()) {
|
|
16568
|
+
this.open();
|
|
16569
|
+
}
|
|
16570
|
+
else {
|
|
16571
|
+
this.moveFocus(1);
|
|
16572
|
+
}
|
|
16573
|
+
break;
|
|
16574
|
+
case 'ArrowUp':
|
|
16575
|
+
event.preventDefault();
|
|
16576
|
+
if (this.isOpen()) {
|
|
16577
|
+
this.moveFocus(-1);
|
|
16578
|
+
}
|
|
16579
|
+
break;
|
|
16580
|
+
case 'Enter':
|
|
16581
|
+
if (this.isOpen()) {
|
|
16582
|
+
event.preventDefault();
|
|
16583
|
+
const idx = this.focusedIndex();
|
|
16584
|
+
const options = this.filteredOptions();
|
|
16585
|
+
if (idx >= 0 && options[idx] && !options[idx].disabled) {
|
|
16586
|
+
this.selectOption(options[idx]);
|
|
16587
|
+
}
|
|
16588
|
+
else if (this.canCreate()) {
|
|
16589
|
+
this.requestCreate();
|
|
16590
|
+
}
|
|
16591
|
+
}
|
|
16592
|
+
break;
|
|
16593
|
+
case 'Escape':
|
|
16594
|
+
if (this.isOpen()) {
|
|
16595
|
+
event.preventDefault();
|
|
16596
|
+
this.close();
|
|
16597
|
+
}
|
|
16598
|
+
break;
|
|
16599
|
+
case 'Backspace':
|
|
16600
|
+
// Supprimer le dernier chip si l'input est vide en mode multi
|
|
16601
|
+
if (this.multiple() && !this.searchQuery()) {
|
|
16602
|
+
const selected = this.selectedOptions();
|
|
16603
|
+
if (selected.length > 0) {
|
|
16604
|
+
this.removeOption(selected[selected.length - 1]);
|
|
16605
|
+
}
|
|
16606
|
+
}
|
|
16607
|
+
break;
|
|
16608
|
+
case 'Tab':
|
|
16609
|
+
if (this.isOpen()) {
|
|
16610
|
+
this.close();
|
|
16611
|
+
}
|
|
16612
|
+
break;
|
|
16613
|
+
}
|
|
16614
|
+
}
|
|
16615
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
16616
|
+
// Click outside
|
|
16617
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
16618
|
+
onDocumentClick(event) {
|
|
16619
|
+
const target = event.target;
|
|
16620
|
+
if (!target.closest('.ds-entity-picker')) {
|
|
16621
|
+
this.close();
|
|
16622
|
+
}
|
|
16623
|
+
}
|
|
16624
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
16625
|
+
// Helpers
|
|
16626
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
16627
|
+
moveFocus(delta) {
|
|
16628
|
+
const options = this.filteredOptions();
|
|
16629
|
+
const canCreateOpt = this.canCreate() ? 1 : 0;
|
|
16630
|
+
const total = options.length + canCreateOpt;
|
|
16631
|
+
if (total === 0)
|
|
16632
|
+
return;
|
|
16633
|
+
let newIndex = this.focusedIndex() + delta;
|
|
16634
|
+
// Wrap around
|
|
16635
|
+
if (newIndex < 0)
|
|
16636
|
+
newIndex = total - 1;
|
|
16637
|
+
if (newIndex >= total)
|
|
16638
|
+
newIndex = 0;
|
|
16639
|
+
// Skip disabled options
|
|
16640
|
+
let attempts = 0;
|
|
16641
|
+
while (newIndex < options.length && options[newIndex]?.disabled && attempts < total) {
|
|
16642
|
+
newIndex += delta;
|
|
16643
|
+
if (newIndex < 0)
|
|
16644
|
+
newIndex = total - 1;
|
|
16645
|
+
if (newIndex >= total)
|
|
16646
|
+
newIndex = 0;
|
|
16647
|
+
attempts++;
|
|
16648
|
+
}
|
|
16649
|
+
this.focusedIndex.set(newIndex);
|
|
16650
|
+
this.scrollFocusedOptionIntoView();
|
|
16651
|
+
}
|
|
16652
|
+
scrollFocusedOptionIntoView() {
|
|
16653
|
+
const index = this.focusedIndex();
|
|
16654
|
+
if (index < 0)
|
|
16655
|
+
return;
|
|
16656
|
+
const optionId = this.getOptionId(index);
|
|
16657
|
+
const optionElement = document.getElementById(optionId);
|
|
16658
|
+
if (optionElement) {
|
|
16659
|
+
optionElement.scrollIntoView({
|
|
16660
|
+
block: 'nearest',
|
|
16661
|
+
behavior: 'smooth',
|
|
16662
|
+
});
|
|
16663
|
+
}
|
|
16664
|
+
}
|
|
16665
|
+
isOptionFocused(index) {
|
|
16666
|
+
return this.focusedIndex() === index;
|
|
16667
|
+
}
|
|
16668
|
+
isOptionSelected(option) {
|
|
16669
|
+
const value = this.internalValue();
|
|
16670
|
+
if (value === null)
|
|
16671
|
+
return false;
|
|
16672
|
+
if (this.multiple()) {
|
|
16673
|
+
return value.includes(option.value);
|
|
16674
|
+
}
|
|
16675
|
+
return value === option.value;
|
|
16676
|
+
}
|
|
16677
|
+
getOptionId(index) {
|
|
16678
|
+
return `${this.name() || 'entity-picker'}-option-${index}`;
|
|
16679
|
+
}
|
|
16680
|
+
isCreateFocused() {
|
|
16681
|
+
return this.canCreate() && this.focusedIndex() === this.filteredOptions().length;
|
|
16682
|
+
}
|
|
16683
|
+
trackOption(_, option) {
|
|
16684
|
+
return option.value;
|
|
16685
|
+
}
|
|
16686
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DsEntityPicker, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
16687
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: DsEntityPicker, isStandalone: true, selector: "ds-entity-picker", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, allowCreate: { classPropertyName: "allowCreate", publicName: "allowCreate", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, displayMode: { classPropertyName: "displayMode", publicName: "displayMode", isSignal: true, isRequired: false, transformFunction: null }, clearable: { classPropertyName: "clearable", publicName: "clearable", isSignal: true, isRequired: false, transformFunction: null }, maxSelections: { classPropertyName: "maxSelections", publicName: "maxSelections", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, error: { classPropertyName: "error", publicName: "error", isSignal: true, isRequired: false, transformFunction: null }, helper: { classPropertyName: "helper", publicName: "helper", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, minChars: { classPropertyName: "minChars", publicName: "minChars", isSignal: true, isRequired: false, transformFunction: null }, noResultsText: { classPropertyName: "noResultsText", publicName: "noResultsText", isSignal: true, isRequired: false, transformFunction: null }, createText: { classPropertyName: "createText", publicName: "createText", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectionChange: "selectionChange", createRequested: "createRequested", searchChange: "searchChange", opened: "opened", closed: "closed" }, host: { listeners: { "keydown": "onKeyDown($event)", "document:click": "onDocumentClick($event)" } }, providers: [
|
|
16688
|
+
{
|
|
16689
|
+
provide: NG_VALUE_ACCESSOR,
|
|
16690
|
+
useExisting: forwardRef(() => DsEntityPicker),
|
|
16691
|
+
multi: true,
|
|
16692
|
+
},
|
|
16693
|
+
], viewQueries: [{ propertyName: "inputElement", first: true, predicate: ["inputElement"], descendants: true }, { propertyName: "listbox", first: true, predicate: ["listbox"], descendants: true }], ngImport: i0, template: "<div [ngClass]=\"containerClasses()\">\n <!-- Label -->\n @if (label()) {\n <label class=\"ds-entity-picker__label\" [attr.for]=\"inputId()\">\n {{ label() }}\n @if (required()) {\n <span class=\"ds-entity-picker__required\">*</span>\n }\n </label>\n }\n\n <!-- Input wrapper -->\n <div class=\"ds-entity-picker__wrapper\"\n #triggerOrigin=\"cdkOverlayOrigin\"\n cdkOverlayOrigin>\n <!-- Chips (mode multiple) -->\n @if (multiple() && displayMode() === 'chip') {\n <div class=\"ds-entity-picker__chips\">\n @for (option of selectedOptions(); track option.value) {\n <ds-entity-chip\n [option]=\"option\"\n [size]=\"size()\"\n [removable]=\"!isDisabled()\"\n [disabled]=\"isDisabled()\"\n (removed)=\"removeOption($event)\"\n />\n }\n </div>\n }\n\n <!-- Count badge (mode count) -->\n @if (multiple() && displayMode() === 'count' && selectedOptions().length > 0) {\n <span class=\"ds-entity-picker__count\">\n {{ countText() }}\n </span>\n }\n\n <!-- Input -->\n <div class=\"ds-entity-picker__input-container\">\n <input\n #inputElement\n type=\"text\"\n [id]=\"inputId()\"\n [ngClass]=\"inputClasses()\"\n [placeholder]=\"multiple() ? placeholder() : (displayValue() || placeholder())\"\n [disabled]=\"isDisabled()\"\n [value]=\"multiple() ? searchQuery() : (searchQuery() || displayValue())\"\n [attr.aria-expanded]=\"isOpen()\"\n [attr.aria-autocomplete]=\"'list'\"\n [attr.aria-controls]=\"listboxId()\"\n [attr.aria-activedescendant]=\"focusedIndex() >= 0 ? getOptionId(focusedIndex()) : null\"\n role=\"combobox\"\n autocomplete=\"off\"\n (focus)=\"onInputFocus()\"\n (blur)=\"onInputBlur()\"\n (input)=\"onSearchInput($event)\"\n />\n\n <!-- Icons -->\n <span class=\"ds-entity-picker__icons\">\n @if (clearable() && (selectedOptions().length > 0 || searchQuery())) {\n <button\n type=\"button\"\n class=\"ds-entity-picker__clear\"\n aria-label=\"Effacer\"\n tabindex=\"-1\"\n (mousedown)=\"clear($event)\"\n >\n <fa-icon [icon]=\"iconClear\" />\n </button>\n }\n <span class=\"ds-entity-picker__arrow\" [class.ds-entity-picker__arrow--open]=\"isOpen()\">\n <fa-icon [icon]=\"iconChevron\" />\n </span>\n </span>\n </div>\n </div>\n\n <!-- Dropdown (CDK Overlay) -->\n <ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"triggerOrigin\"\n [cdkConnectedOverlayOpen]=\"shouldShowDropdown()\"\n [cdkConnectedOverlayPositions]=\"overlayPositions\"\n [cdkConnectedOverlayWidth]=\"triggerOrigin.elementRef.nativeElement.offsetWidth\"\n [cdkConnectedOverlayHasBackdrop]=\"false\"\n [cdkConnectedOverlayPanelClass]=\"'ds-entity-picker-overlay'\">\n <div class=\"ds-entity-picker__dropdown\" role=\"presentation\">\n <ul\n #listbox\n [id]=\"listboxId()\"\n class=\"ds-entity-picker__listbox\"\n role=\"listbox\"\n [attr.aria-label]=\"label() || 'Options'\"\n [attr.aria-multiselectable]=\"multiple()\"\n >\n @for (option of filteredOptions(); track trackOption($index, option); let i = $index) {\n <li\n [id]=\"getOptionId(i)\"\n class=\"ds-entity-picker__option\"\n [class.ds-entity-picker__option--focused]=\"isOptionFocused(i)\"\n [class.ds-entity-picker__option--selected]=\"isOptionSelected(option)\"\n [class.ds-entity-picker__option--disabled]=\"option.disabled || maxReached()\"\n [style.--option-color]=\"option.color || 'var(--gray-400)'\"\n role=\"option\"\n [attr.aria-selected]=\"isOptionSelected(option)\"\n [attr.aria-disabled]=\"option.disabled || maxReached()\"\n (mousedown)=\"selectOption(option)\"\n >\n <!-- Indicateur de couleur -->\n @if (option.color) {\n <span\n class=\"ds-entity-picker__option-indicator\"\n [style.background-color]=\"option.color\"\n ></span>\n }\n\n <!-- Emoji ou ic\u00F4ne -->\n @if (option.emoji) {\n <span class=\"ds-entity-picker__option-emoji\">{{ option.emoji }}</span>\n } @else if (option.icon) {\n <fa-icon\n class=\"ds-entity-picker__option-icon\"\n [icon]=\"option.icon\"\n [style.color]=\"option.color\"\n />\n }\n\n <!-- Contenu texte -->\n <span class=\"ds-entity-picker__option-content\">\n <span class=\"ds-entity-picker__option-label\">{{ option.label }}</span>\n @if (option.description) {\n <span class=\"ds-entity-picker__option-description\">{{ option.description }}</span>\n }\n </span>\n\n <!-- Check si s\u00E9lectionn\u00E9 -->\n @if (isOptionSelected(option)) {\n <svg\n class=\"ds-entity-picker__check\"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n >\n <polyline points=\"20 6 9 17 4 12\"></polyline>\n </svg>\n }\n </li>\n } @empty {\n @if (!canCreate()) {\n <li class=\"ds-entity-picker__empty\" role=\"option\" aria-disabled=\"true\">\n {{ noResultsText() }}\n </li>\n }\n }\n\n <!-- Option de cr\u00E9ation -->\n @if (canCreate()) {\n <li\n class=\"ds-entity-picker__option ds-entity-picker__option--create\"\n [class.ds-entity-picker__option--focused]=\"isCreateFocused()\"\n role=\"option\"\n (mousedown)=\"requestCreate()\"\n >\n <fa-icon class=\"ds-entity-picker__option-icon\" [icon]=\"iconPlus\" />\n <span class=\"ds-entity-picker__option-content\">\n <span class=\"ds-entity-picker__option-label\">\n {{ formattedCreateText() }}\n </span>\n </span>\n </li>\n }\n </ul>\n </div>\n </ng-template>\n\n <!-- Helper / Error -->\n @if (error()) {\n <span class=\"ds-entity-picker__error\" role=\"alert\">{{ error() }}</span>\n } @else if (helper()) {\n <span class=\"ds-entity-picker__helper\">{{ helper() }}</span>\n }\n</div>\n", styles: ["@charset \"UTF-8\";.ds-entity-picker{display:flex;flex-direction:column;gap:var(--space-1, .25rem);position:relative;width:100%;font-family:var(--font-family-base, sans-serif)}.ds-entity-picker__label{display:block;font-size:var(--font-size-sm, .875rem);font-weight:500;color:var(--text-default, #1a1a1a);margin-bottom:var(--space-1, .25rem)}.ds-entity-picker__required{color:var(--error, #ef4444);margin-left:var(--space-0-5, .125rem)}.ds-entity-picker__wrapper{display:flex;flex-wrap:wrap;align-items:center;gap:var(--space-1, .25rem);padding:var(--space-1-5, .375rem) var(--space-2, .5rem);min-height:var(--input-height-md, 40px);background-color:var(--input-bg, #fff);border:1px solid var(--input-border, #d1d5db);border-radius:var(--radius-md, 6px);transition:border-color var(--duration-fast, .15s) var(--easing-default, ease),box-shadow var(--duration-fast, .15s) var(--easing-default, ease);cursor:text}.ds-entity-picker__wrapper:hover:not(.ds-entity-picker--disabled .ds-entity-picker__wrapper){border-color:var(--input-border-hover, #9ca3af)}.ds-entity-picker--open .ds-entity-picker__wrapper,.ds-entity-picker__wrapper:focus-within{border-color:var(--color-primary, #6366f1);box-shadow:0 0 0 3px var(--primary-100, rgba(99, 102, 241, .1))}.ds-entity-picker--error .ds-entity-picker__wrapper{border-color:var(--error, #ef4444)}.ds-entity-picker--error .ds-entity-picker__wrapper:focus-within{box-shadow:0 0 0 3px var(--error-100, rgba(239, 68, 68, .1))}.ds-entity-picker--disabled .ds-entity-picker__wrapper{background-color:var(--input-bg-disabled, #f3f4f6);border-color:var(--input-border-disabled, #e5e7eb);cursor:not-allowed;opacity:.6}.ds-entity-picker__chips{display:flex;flex-wrap:wrap;gap:var(--space-1, .25rem);max-width:100%}.ds-entity-picker__count{display:inline-flex;align-items:center;padding:var(--space-0-5, .125rem) var(--space-2, .5rem);background-color:var(--primary-100, #eef2ff);color:var(--color-primary, #6366f1);font-size:var(--font-size-sm, .875rem);font-weight:500;border-radius:var(--radius-pill, 9999px)}.ds-entity-picker__input-container{display:flex;align-items:center;flex:1;min-width:120px;position:relative}.ds-entity-picker__input{flex:1;min-width:0;padding:var(--space-1, .25rem) 0;border:none;background:transparent;font-family:inherit;font-size:var(--font-size-base, 1rem);color:var(--text-default, #1a1a1a);outline:none}.ds-entity-picker__input::placeholder{color:var(--text-muted, #9ca3af)}.ds-entity-picker__input:disabled{cursor:not-allowed}.ds-entity-picker__icons{display:flex;align-items:center;gap:var(--space-1, .25rem);margin-left:var(--space-1, .25rem);flex-shrink:0}.ds-entity-picker__clear{display:flex;align-items:center;justify-content:center;padding:var(--space-1, .25rem);border:none;background:none;color:var(--text-muted, #9ca3af);cursor:pointer;border-radius:var(--radius-sm, 4px);transition:color var(--duration-fast, .15s) var(--easing-default, ease),background-color var(--duration-fast, .15s) var(--easing-default, ease)}.ds-entity-picker__clear:hover{color:var(--text-default, #1a1a1a);background-color:var(--gray-100, #f3f4f6)}.ds-entity-picker__arrow{display:flex;align-items:center;color:var(--text-muted, #9ca3af);transition:transform var(--duration-fast, .15s) var(--easing-default, ease)}.ds-entity-picker__arrow--open{transform:rotate(180deg)}.ds-entity-picker__dropdown{background-color:var(--dropdown-bg, #fff);border:1px solid var(--dropdown-border, #e5e7eb);border-radius:var(--radius-md, 6px);box-shadow:var(--shadow-lg, 0 10px 15px -3px rgba(0, 0, 0, .1));max-height:280px;overflow-y:auto;animation:slideDown .15s ease-out}@keyframes slideDown{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}.ds-entity-picker__listbox{list-style:none;margin:0;padding:var(--space-1, .25rem)}.ds-entity-picker__option{display:flex;align-items:center;gap:var(--space-2, .5rem);padding:var(--space-2, .5rem) var(--space-3, .75rem);border-radius:var(--radius-sm, 4px);cursor:pointer;transition:background-color var(--duration-fast, .15s) var(--easing-default, ease)}.ds-entity-picker__option:hover:not(.ds-entity-picker__option--disabled){background-color:var(--gray-50, #f9fafb)}.ds-entity-picker__option--focused:not(.ds-entity-picker__option--disabled){background-color:var(--gray-100, #f3f4f6)}.ds-entity-picker__option--selected{background-color:var(--primary-50, #eef2ff)}.ds-entity-picker__option--selected:hover{background-color:var(--primary-100, #e0e7ff)}.ds-entity-picker__option--disabled{opacity:.5;cursor:not-allowed}.ds-entity-picker__option--create{border-top:1px solid var(--gray-200, #e5e7eb);margin-top:var(--space-1, .25rem);padding-top:var(--space-3, .75rem);color:var(--color-primary, #6366f1)}.ds-entity-picker__option--create .ds-entity-picker__option-icon{color:var(--color-primary, #6366f1)}.ds-entity-picker__option-indicator{width:4px;height:100%;min-height:24px;border-radius:var(--radius-pill, 9999px);flex-shrink:0;margin-right:var(--space-1, .25rem)}.ds-entity-picker__option-emoji{font-size:1.125rem;flex-shrink:0}.ds-entity-picker__option-icon{font-size:1rem;flex-shrink:0;color:var(--option-color, var(--gray-600))}.ds-entity-picker__option-content{flex:1;min-width:0;display:flex;flex-direction:column;gap:var(--space-0-5, .125rem)}.ds-entity-picker__option-label{font-size:var(--font-size-base, 1rem);color:var(--text-default, #1a1a1a);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.ds-entity-picker__option-description{font-size:var(--font-size-sm, .875rem);color:var(--text-muted, #6b7280);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.ds-entity-picker__check{flex-shrink:0;color:var(--color-primary, #6366f1)}.ds-entity-picker__empty{padding:var(--space-3, .75rem);text-align:center;color:var(--text-muted, #9ca3af);font-size:var(--font-size-sm, .875rem)}.ds-entity-picker__helper,.ds-entity-picker__error{font-size:var(--font-size-sm, .875rem);margin-top:var(--space-1, .25rem)}.ds-entity-picker__helper{color:var(--text-muted, #6b7280)}.ds-entity-picker__error{color:var(--error, #ef4444)}.ds-entity-picker--sm .ds-entity-picker__wrapper{min-height:var(--input-height-sm, 32px);padding:var(--space-1, .25rem) var(--space-1-5, .375rem)}.ds-entity-picker--sm .ds-entity-picker__input{font-size:var(--font-size-sm, .875rem)}.ds-entity-picker--sm .ds-entity-picker__option{padding:var(--space-1-5, .375rem) var(--space-2, .5rem)}.ds-entity-picker--sm .ds-entity-picker__option-label{font-size:var(--font-size-sm, .875rem)}.ds-entity-picker--sm .ds-entity-picker__option-description{font-size:var(--font-size-xs, .75rem)}.ds-entity-picker--lg .ds-entity-picker__wrapper{min-height:var(--input-height-lg, 48px);padding:var(--space-2, .5rem) var(--space-3, .75rem)}.ds-entity-picker--lg .ds-entity-picker__input{font-size:var(--font-size-lg, 1.125rem)}.ds-entity-picker--lg .ds-entity-picker__option{padding:var(--space-3, .75rem) var(--space-4, 1rem)}.ds-entity-picker--lg .ds-entity-picker__option-label{font-size:var(--font-size-lg, 1.125rem)}\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"] }, { kind: "component", type: DsEntityChip, selector: "ds-entity-chip", inputs: ["option", "size", "removable", "disabled"], outputs: ["removed"] }, { kind: "directive", type: CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
16694
|
+
}
|
|
16695
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DsEntityPicker, decorators: [{
|
|
16696
|
+
type: Component,
|
|
16697
|
+
args: [{ selector: 'ds-entity-picker', standalone: true, imports: [CommonModule, FontAwesomeModule, DsEntityChip, CdkConnectedOverlay, CdkOverlayOrigin], changeDetection: ChangeDetectionStrategy.OnPush, providers: [
|
|
16698
|
+
{
|
|
16699
|
+
provide: NG_VALUE_ACCESSOR,
|
|
16700
|
+
useExisting: forwardRef(() => DsEntityPicker),
|
|
16701
|
+
multi: true,
|
|
16702
|
+
},
|
|
16703
|
+
], template: "<div [ngClass]=\"containerClasses()\">\n <!-- Label -->\n @if (label()) {\n <label class=\"ds-entity-picker__label\" [attr.for]=\"inputId()\">\n {{ label() }}\n @if (required()) {\n <span class=\"ds-entity-picker__required\">*</span>\n }\n </label>\n }\n\n <!-- Input wrapper -->\n <div class=\"ds-entity-picker__wrapper\"\n #triggerOrigin=\"cdkOverlayOrigin\"\n cdkOverlayOrigin>\n <!-- Chips (mode multiple) -->\n @if (multiple() && displayMode() === 'chip') {\n <div class=\"ds-entity-picker__chips\">\n @for (option of selectedOptions(); track option.value) {\n <ds-entity-chip\n [option]=\"option\"\n [size]=\"size()\"\n [removable]=\"!isDisabled()\"\n [disabled]=\"isDisabled()\"\n (removed)=\"removeOption($event)\"\n />\n }\n </div>\n }\n\n <!-- Count badge (mode count) -->\n @if (multiple() && displayMode() === 'count' && selectedOptions().length > 0) {\n <span class=\"ds-entity-picker__count\">\n {{ countText() }}\n </span>\n }\n\n <!-- Input -->\n <div class=\"ds-entity-picker__input-container\">\n <input\n #inputElement\n type=\"text\"\n [id]=\"inputId()\"\n [ngClass]=\"inputClasses()\"\n [placeholder]=\"multiple() ? placeholder() : (displayValue() || placeholder())\"\n [disabled]=\"isDisabled()\"\n [value]=\"multiple() ? searchQuery() : (searchQuery() || displayValue())\"\n [attr.aria-expanded]=\"isOpen()\"\n [attr.aria-autocomplete]=\"'list'\"\n [attr.aria-controls]=\"listboxId()\"\n [attr.aria-activedescendant]=\"focusedIndex() >= 0 ? getOptionId(focusedIndex()) : null\"\n role=\"combobox\"\n autocomplete=\"off\"\n (focus)=\"onInputFocus()\"\n (blur)=\"onInputBlur()\"\n (input)=\"onSearchInput($event)\"\n />\n\n <!-- Icons -->\n <span class=\"ds-entity-picker__icons\">\n @if (clearable() && (selectedOptions().length > 0 || searchQuery())) {\n <button\n type=\"button\"\n class=\"ds-entity-picker__clear\"\n aria-label=\"Effacer\"\n tabindex=\"-1\"\n (mousedown)=\"clear($event)\"\n >\n <fa-icon [icon]=\"iconClear\" />\n </button>\n }\n <span class=\"ds-entity-picker__arrow\" [class.ds-entity-picker__arrow--open]=\"isOpen()\">\n <fa-icon [icon]=\"iconChevron\" />\n </span>\n </span>\n </div>\n </div>\n\n <!-- Dropdown (CDK Overlay) -->\n <ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"triggerOrigin\"\n [cdkConnectedOverlayOpen]=\"shouldShowDropdown()\"\n [cdkConnectedOverlayPositions]=\"overlayPositions\"\n [cdkConnectedOverlayWidth]=\"triggerOrigin.elementRef.nativeElement.offsetWidth\"\n [cdkConnectedOverlayHasBackdrop]=\"false\"\n [cdkConnectedOverlayPanelClass]=\"'ds-entity-picker-overlay'\">\n <div class=\"ds-entity-picker__dropdown\" role=\"presentation\">\n <ul\n #listbox\n [id]=\"listboxId()\"\n class=\"ds-entity-picker__listbox\"\n role=\"listbox\"\n [attr.aria-label]=\"label() || 'Options'\"\n [attr.aria-multiselectable]=\"multiple()\"\n >\n @for (option of filteredOptions(); track trackOption($index, option); let i = $index) {\n <li\n [id]=\"getOptionId(i)\"\n class=\"ds-entity-picker__option\"\n [class.ds-entity-picker__option--focused]=\"isOptionFocused(i)\"\n [class.ds-entity-picker__option--selected]=\"isOptionSelected(option)\"\n [class.ds-entity-picker__option--disabled]=\"option.disabled || maxReached()\"\n [style.--option-color]=\"option.color || 'var(--gray-400)'\"\n role=\"option\"\n [attr.aria-selected]=\"isOptionSelected(option)\"\n [attr.aria-disabled]=\"option.disabled || maxReached()\"\n (mousedown)=\"selectOption(option)\"\n >\n <!-- Indicateur de couleur -->\n @if (option.color) {\n <span\n class=\"ds-entity-picker__option-indicator\"\n [style.background-color]=\"option.color\"\n ></span>\n }\n\n <!-- Emoji ou ic\u00F4ne -->\n @if (option.emoji) {\n <span class=\"ds-entity-picker__option-emoji\">{{ option.emoji }}</span>\n } @else if (option.icon) {\n <fa-icon\n class=\"ds-entity-picker__option-icon\"\n [icon]=\"option.icon\"\n [style.color]=\"option.color\"\n />\n }\n\n <!-- Contenu texte -->\n <span class=\"ds-entity-picker__option-content\">\n <span class=\"ds-entity-picker__option-label\">{{ option.label }}</span>\n @if (option.description) {\n <span class=\"ds-entity-picker__option-description\">{{ option.description }}</span>\n }\n </span>\n\n <!-- Check si s\u00E9lectionn\u00E9 -->\n @if (isOptionSelected(option)) {\n <svg\n class=\"ds-entity-picker__check\"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n >\n <polyline points=\"20 6 9 17 4 12\"></polyline>\n </svg>\n }\n </li>\n } @empty {\n @if (!canCreate()) {\n <li class=\"ds-entity-picker__empty\" role=\"option\" aria-disabled=\"true\">\n {{ noResultsText() }}\n </li>\n }\n }\n\n <!-- Option de cr\u00E9ation -->\n @if (canCreate()) {\n <li\n class=\"ds-entity-picker__option ds-entity-picker__option--create\"\n [class.ds-entity-picker__option--focused]=\"isCreateFocused()\"\n role=\"option\"\n (mousedown)=\"requestCreate()\"\n >\n <fa-icon class=\"ds-entity-picker__option-icon\" [icon]=\"iconPlus\" />\n <span class=\"ds-entity-picker__option-content\">\n <span class=\"ds-entity-picker__option-label\">\n {{ formattedCreateText() }}\n </span>\n </span>\n </li>\n }\n </ul>\n </div>\n </ng-template>\n\n <!-- Helper / Error -->\n @if (error()) {\n <span class=\"ds-entity-picker__error\" role=\"alert\">{{ error() }}</span>\n } @else if (helper()) {\n <span class=\"ds-entity-picker__helper\">{{ helper() }}</span>\n }\n</div>\n", styles: ["@charset \"UTF-8\";.ds-entity-picker{display:flex;flex-direction:column;gap:var(--space-1, .25rem);position:relative;width:100%;font-family:var(--font-family-base, sans-serif)}.ds-entity-picker__label{display:block;font-size:var(--font-size-sm, .875rem);font-weight:500;color:var(--text-default, #1a1a1a);margin-bottom:var(--space-1, .25rem)}.ds-entity-picker__required{color:var(--error, #ef4444);margin-left:var(--space-0-5, .125rem)}.ds-entity-picker__wrapper{display:flex;flex-wrap:wrap;align-items:center;gap:var(--space-1, .25rem);padding:var(--space-1-5, .375rem) var(--space-2, .5rem);min-height:var(--input-height-md, 40px);background-color:var(--input-bg, #fff);border:1px solid var(--input-border, #d1d5db);border-radius:var(--radius-md, 6px);transition:border-color var(--duration-fast, .15s) var(--easing-default, ease),box-shadow var(--duration-fast, .15s) var(--easing-default, ease);cursor:text}.ds-entity-picker__wrapper:hover:not(.ds-entity-picker--disabled .ds-entity-picker__wrapper){border-color:var(--input-border-hover, #9ca3af)}.ds-entity-picker--open .ds-entity-picker__wrapper,.ds-entity-picker__wrapper:focus-within{border-color:var(--color-primary, #6366f1);box-shadow:0 0 0 3px var(--primary-100, rgba(99, 102, 241, .1))}.ds-entity-picker--error .ds-entity-picker__wrapper{border-color:var(--error, #ef4444)}.ds-entity-picker--error .ds-entity-picker__wrapper:focus-within{box-shadow:0 0 0 3px var(--error-100, rgba(239, 68, 68, .1))}.ds-entity-picker--disabled .ds-entity-picker__wrapper{background-color:var(--input-bg-disabled, #f3f4f6);border-color:var(--input-border-disabled, #e5e7eb);cursor:not-allowed;opacity:.6}.ds-entity-picker__chips{display:flex;flex-wrap:wrap;gap:var(--space-1, .25rem);max-width:100%}.ds-entity-picker__count{display:inline-flex;align-items:center;padding:var(--space-0-5, .125rem) var(--space-2, .5rem);background-color:var(--primary-100, #eef2ff);color:var(--color-primary, #6366f1);font-size:var(--font-size-sm, .875rem);font-weight:500;border-radius:var(--radius-pill, 9999px)}.ds-entity-picker__input-container{display:flex;align-items:center;flex:1;min-width:120px;position:relative}.ds-entity-picker__input{flex:1;min-width:0;padding:var(--space-1, .25rem) 0;border:none;background:transparent;font-family:inherit;font-size:var(--font-size-base, 1rem);color:var(--text-default, #1a1a1a);outline:none}.ds-entity-picker__input::placeholder{color:var(--text-muted, #9ca3af)}.ds-entity-picker__input:disabled{cursor:not-allowed}.ds-entity-picker__icons{display:flex;align-items:center;gap:var(--space-1, .25rem);margin-left:var(--space-1, .25rem);flex-shrink:0}.ds-entity-picker__clear{display:flex;align-items:center;justify-content:center;padding:var(--space-1, .25rem);border:none;background:none;color:var(--text-muted, #9ca3af);cursor:pointer;border-radius:var(--radius-sm, 4px);transition:color var(--duration-fast, .15s) var(--easing-default, ease),background-color var(--duration-fast, .15s) var(--easing-default, ease)}.ds-entity-picker__clear:hover{color:var(--text-default, #1a1a1a);background-color:var(--gray-100, #f3f4f6)}.ds-entity-picker__arrow{display:flex;align-items:center;color:var(--text-muted, #9ca3af);transition:transform var(--duration-fast, .15s) var(--easing-default, ease)}.ds-entity-picker__arrow--open{transform:rotate(180deg)}.ds-entity-picker__dropdown{background-color:var(--dropdown-bg, #fff);border:1px solid var(--dropdown-border, #e5e7eb);border-radius:var(--radius-md, 6px);box-shadow:var(--shadow-lg, 0 10px 15px -3px rgba(0, 0, 0, .1));max-height:280px;overflow-y:auto;animation:slideDown .15s ease-out}@keyframes slideDown{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}.ds-entity-picker__listbox{list-style:none;margin:0;padding:var(--space-1, .25rem)}.ds-entity-picker__option{display:flex;align-items:center;gap:var(--space-2, .5rem);padding:var(--space-2, .5rem) var(--space-3, .75rem);border-radius:var(--radius-sm, 4px);cursor:pointer;transition:background-color var(--duration-fast, .15s) var(--easing-default, ease)}.ds-entity-picker__option:hover:not(.ds-entity-picker__option--disabled){background-color:var(--gray-50, #f9fafb)}.ds-entity-picker__option--focused:not(.ds-entity-picker__option--disabled){background-color:var(--gray-100, #f3f4f6)}.ds-entity-picker__option--selected{background-color:var(--primary-50, #eef2ff)}.ds-entity-picker__option--selected:hover{background-color:var(--primary-100, #e0e7ff)}.ds-entity-picker__option--disabled{opacity:.5;cursor:not-allowed}.ds-entity-picker__option--create{border-top:1px solid var(--gray-200, #e5e7eb);margin-top:var(--space-1, .25rem);padding-top:var(--space-3, .75rem);color:var(--color-primary, #6366f1)}.ds-entity-picker__option--create .ds-entity-picker__option-icon{color:var(--color-primary, #6366f1)}.ds-entity-picker__option-indicator{width:4px;height:100%;min-height:24px;border-radius:var(--radius-pill, 9999px);flex-shrink:0;margin-right:var(--space-1, .25rem)}.ds-entity-picker__option-emoji{font-size:1.125rem;flex-shrink:0}.ds-entity-picker__option-icon{font-size:1rem;flex-shrink:0;color:var(--option-color, var(--gray-600))}.ds-entity-picker__option-content{flex:1;min-width:0;display:flex;flex-direction:column;gap:var(--space-0-5, .125rem)}.ds-entity-picker__option-label{font-size:var(--font-size-base, 1rem);color:var(--text-default, #1a1a1a);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.ds-entity-picker__option-description{font-size:var(--font-size-sm, .875rem);color:var(--text-muted, #6b7280);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.ds-entity-picker__check{flex-shrink:0;color:var(--color-primary, #6366f1)}.ds-entity-picker__empty{padding:var(--space-3, .75rem);text-align:center;color:var(--text-muted, #9ca3af);font-size:var(--font-size-sm, .875rem)}.ds-entity-picker__helper,.ds-entity-picker__error{font-size:var(--font-size-sm, .875rem);margin-top:var(--space-1, .25rem)}.ds-entity-picker__helper{color:var(--text-muted, #6b7280)}.ds-entity-picker__error{color:var(--error, #ef4444)}.ds-entity-picker--sm .ds-entity-picker__wrapper{min-height:var(--input-height-sm, 32px);padding:var(--space-1, .25rem) var(--space-1-5, .375rem)}.ds-entity-picker--sm .ds-entity-picker__input{font-size:var(--font-size-sm, .875rem)}.ds-entity-picker--sm .ds-entity-picker__option{padding:var(--space-1-5, .375rem) var(--space-2, .5rem)}.ds-entity-picker--sm .ds-entity-picker__option-label{font-size:var(--font-size-sm, .875rem)}.ds-entity-picker--sm .ds-entity-picker__option-description{font-size:var(--font-size-xs, .75rem)}.ds-entity-picker--lg .ds-entity-picker__wrapper{min-height:var(--input-height-lg, 48px);padding:var(--space-2, .5rem) var(--space-3, .75rem)}.ds-entity-picker--lg .ds-entity-picker__input{font-size:var(--font-size-lg, 1.125rem)}.ds-entity-picker--lg .ds-entity-picker__option{padding:var(--space-3, .75rem) var(--space-4, 1rem)}.ds-entity-picker--lg .ds-entity-picker__option-label{font-size:var(--font-size-lg, 1.125rem)}\n"] }]
|
|
16704
|
+
}], propDecorators: { options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], allowCreate: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowCreate", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], displayMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "displayMode", required: false }] }], clearable: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearable", required: false }] }], maxSelections: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxSelections", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], helper: [{ type: i0.Input, args: [{ isSignal: true, alias: "helper", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], minChars: [{ type: i0.Input, args: [{ isSignal: true, alias: "minChars", required: false }] }], noResultsText: [{ type: i0.Input, args: [{ isSignal: true, alias: "noResultsText", required: false }] }], createText: [{ type: i0.Input, args: [{ isSignal: true, alias: "createText", required: false }] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], selectionChange: [{ type: i0.Output, args: ["selectionChange"] }], createRequested: [{ type: i0.Output, args: ["createRequested"] }], searchChange: [{ type: i0.Output, args: ["searchChange"] }], opened: [{ type: i0.Output, args: ["opened"] }], closed: [{ type: i0.Output, args: ["closed"] }], inputElement: [{
|
|
16705
|
+
type: ViewChild,
|
|
16706
|
+
args: ['inputElement']
|
|
16707
|
+
}], listbox: [{
|
|
16708
|
+
type: ViewChild,
|
|
16709
|
+
args: ['listbox']
|
|
16710
|
+
}], onKeyDown: [{
|
|
16711
|
+
type: HostListener,
|
|
16712
|
+
args: ['keydown', ['$event']]
|
|
16713
|
+
}], onDocumentClick: [{
|
|
16714
|
+
type: HostListener,
|
|
16715
|
+
args: ['document:click', ['$event']]
|
|
16716
|
+
}] } });
|
|
16717
|
+
|
|
15932
16718
|
/*
|
|
15933
16719
|
* Components barrel export
|
|
15934
16720
|
*/
|
|
@@ -16415,5 +17201,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
|
|
|
16415
17201
|
* Generated bundle index. Do not edit.
|
|
16416
17202
|
*/
|
|
16417
17203
|
|
|
16418
|
-
export { AUTOCOMPLETE_POSITIONS, DROPDOWN_POSITIONS, DROPDOWN_POSITIONS_RIGHT, DROPDOWN_POSITIONS_TOP, DsAccordion, DsAlert, DsAvatar, DsBadge, DsBreadcrumb, DsButton, DsCalendar, DsCard, DsCarousel, DsCheckbox, DsCheckboxList, DsChip, DsColorPicker, DsCombobox, DsContainer, DsDatePicker, DsDivider, DsDrawer, DsDropdown, DsEmpty, DsFileUpload, DsI18nService, DsInputField, DsInputNumber, DsInputTextarea, DsList, DsListGroup, DsListItem, DsMenu, DsModalComponent, DsNavList, DsNotificationContainerComponent, DsNotificationItemComponent, DsNotificationService, DsPagination, DsPasswordStrength, DsPopover, DsPopoverComponent, DsProgressBar, DsRadioGroup, DsRating, DsSearchInput, DsSegmentedControl, DsSelect, DsSidebar, DsSidebarFooterItemComponent, DsSidebarItemComponent, 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, SIDEBAR_POPOVER_POSITIONS_LEFT, SIDEBAR_POPOVER_POSITIONS_RIGHT, TOOLTIP_POSITIONS, generateId, generateShortId };
|
|
17204
|
+
export { AUTOCOMPLETE_POSITIONS, DROPDOWN_POSITIONS, DROPDOWN_POSITIONS_RIGHT, DROPDOWN_POSITIONS_TOP, DsAccordion, DsAccordionItem, DsAlert, DsAvatar, DsBadge, DsBreadcrumb, DsButton, DsCalendar, DsCard, DsCarousel, DsCheckbox, DsCheckboxList, DsChip, DsColorPicker, DsCombobox, DsContainer, DsDatePicker, DsDivider, DsDrawer, DsDropdown, DsEmpty, DsEntityChip, DsEntityPicker, DsFileUpload, DsI18nService, DsInputField, DsInputNumber, DsInputTextarea, DsList, DsListGroup, DsListItem, DsMenu, DsModalComponent, DsNavList, DsNotificationContainerComponent, DsNotificationItemComponent, DsNotificationService, DsPagination, DsPasswordStrength, DsPopover, DsPopoverComponent, DsProgressBar, DsRadioGroup, DsRating, DsSearchInput, DsSegmentedControl, DsSelect, DsSidebar, DsSidebarFooterItemComponent, DsSidebarItemComponent, 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, SIDEBAR_POPOVER_POSITIONS_LEFT, SIDEBAR_POPOVER_POSITIONS_RIGHT, TOOLTIP_POSITIONS, generateId, generateShortId };
|
|
16419
17205
|
//# sourceMappingURL=kksdev-ds-angular.mjs.map
|