@cityway/bo-ui 1.1.0-beta011 → 1.1.0-beta014

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.
Binary file
@@ -29,11 +29,11 @@ Liste hiérarchique réordonnable par glisser-déposer (CDK drag-drop), pilotée
29
29
  | Input | Type | Défaut | Description |
30
30
  |-------|------|--------|-------------|
31
31
  | `items` | `DragItem[]` | `[]` | Arbre des items à afficher. Le composant en fait une **copie interne mutable** sur laquelle le CDK opère. Voir §3. |
32
- | `itemTemplate` | `TemplateRef<any> \| undefined` | `undefined` | Template du **corps** de carte (slot). Reçoit `$implicit = item` et `depth`. Si absent, fallback interne (label + code). |
32
+ | `itemTemplate` | `TemplateRef<any> \| undefined` | `undefined` | Template du **corps** de carte (slot). Reçoit `$implicit = item` et `depth`. Si absent, **aucun corps n'est rendu** — sauf `item.code`, affiché seul (le titre de l'en-tête porte déjà `title ?? label`). |
33
33
  | `column` | `DragListColumn \| undefined` | `undefined` | Configuration de la colonne : titre, défauts de visibilité des actions, libellés, plafonds. Voir §3. |
34
34
  | `reorderOnDrop` | `boolean` | `true` | Renumérote `order` (1..n par niveau) récursivement à chaque drop. `false` = déplacement visuel seul, `order` intact. |
35
35
  | `maxDepth` | `number \| undefined` | `undefined` | Profondeur max (0-based, racine = 0). Une carte à `depth < maxDepth` peut recevoir des enfants ; `>= maxDepth` est terminale. `undefined` = imbrication infinie. Ex. `maxDepth = 1` → 2 niveaux. |
36
- | `selectedId` | `number \| string \| undefined` | `undefined` | Sélection **exclusive** gérée par la lib : la carte dont `id === selectedId` reçoit la classe `ddn-list-card-selected`. Une seule carte à la fois, tout niveau confondu. Le flag `DragItem.selected` reste supporté en parallèle. |
36
+ | `selectedId` | `number \| string \| undefined` | `undefined` | Sélection **exclusive** gérée par la lib : la carte dont `id === selectedId` reçoit la classe `ddn-list-card-selected` — **elle seule**, jamais ses parents (voir §5, « Rendu de la sélection en profondeur »). Le flag `DragItem.selected` reste supporté en parallèle. ⚠️ Les `id` doivent être uniques **sur tout l'arbre**, pas seulement par niveau. |
37
37
 
38
38
  ### Outputs
39
39
 
@@ -60,6 +60,8 @@ Le **corps** de chaque carte est fourni par un `TemplateRef` passé à `[itemTem
60
60
 
61
61
  > L'en-tête (titre, sous-titre, badge, compteur, actions, poignée) reste **toujours** data-driven ; seul le corps est personnalisable.
62
62
 
63
+ Sans `[itemTemplate]`, la carte se réduit à son en-tête : le composant ne réaffiche pas le label, qui est déjà le titre. Seul `item.code`, s'il est renseigné, est rendu dans le corps. C'est le mode à privilégier quand l'en-tête suffit — chaque corps redondant coûte une hauteur de carte à tous les niveaux de l'arbre.
64
+
63
65
  ---
64
66
 
65
67
  ## 3. Modèles & types
@@ -67,8 +69,8 @@ Le **corps** de chaque carte est fourni par un `TemplateRef` passé à `[itemTem
67
69
  ```ts
68
70
  interface DragItem {
69
71
  id: number | string; // clé de tri (trackBy) — unique
70
- label: string; // libellé (fallback de title, corps par défaut)
71
- code?: string; // affiché dans le corps par défaut
72
+ label: string; // libellé (fallback de title dans l'en-tête)
73
+ code?: string; // affiché seul dans le corps quand il n'y a pas d'itemTemplate
72
74
  order?: number; // position 1..n (renumérotée si reorderOnDrop)
73
75
  disabled?: boolean; // verrouille le drag de CETTE carte (poignée inactive)
74
76
  children?: DragItem[]; // sous-arbre
@@ -101,8 +103,8 @@ interface DragItemActions { // chaque champ = visibilité (booléen). unde
101
103
 
102
104
  interface DragListColumn {
103
105
  title: string; // titre de colonne (clé i18n) — affiché « Titre (count) » / « (count/max) »
104
- description?: string;
105
- descriptionRwd?: string;
106
+ description?: string; // IGNORÉ par ce composant (n'existe que pour cw-drag-n-drop-list)
107
+ descriptionRwd?: string; // idem
106
108
  cssClass?: string; // classe sur chaque <ul> de niveau
107
109
 
108
110
  collapsible?: boolean; // cartes pliables (défaut true) ; false désactive globalement
@@ -256,6 +258,10 @@ restore(t: DragItem) {
256
258
  onReorder(items: DragItem[]) { this.items = items; }
257
259
  ```
258
260
 
261
+ **Rendu en profondeur.** Une seule carte est peinte à l'écran, jamais toute une branche. La carte sélectionnée porte `ddn-list-card-selected` ; un parent qui la contient ne porte `ddn-list-card-has-selection` que **s'il est replié** — la carte sélectionnée n'étant alors pas rendue (`destroyOnHide` de `cw-card`), le parent en reprend le rendu et signale « un élément actif est là-dedans ». Déplié, il redevient neutre. La lib suit le pliage réel de chaque carte via `(collapseClicked)`, pas seulement l'état initial.
262
+
263
+ ⚠️ **Unicité des `id`.** La correspondance se fait sur `id === selectedId` à tous les niveaux. Si un item de niveau 1 et un item de niveau 2 partagent le même `id` (typique quand chaque niveau vient d'une table différente : thème `1`, fichier `1`), **les deux cartes s'allument**. Préfixer côté hôte (`` `theme-${t.id}` ``, `` `file-${f.id}` ``) ou utiliser une clé composite.
264
+
259
265
  ### Corps de carte custom (`itemTemplate`)
260
266
 
261
267
  ```html
@@ -272,12 +278,12 @@ onReorder(items: DragItem[]) { this.items = items; }
272
278
 
273
279
  ## 5. Notes d'intégration
274
280
 
275
- - **CDK drag-drop** : repose sur `@angular/cdk/drag-drop` (`DragDropModule`). Chaque niveau est un `cdkDropList` **isolé** (pas de `cdkDropListConnectedTo`) → le tri est **intra-liste à chaque niveau**, jamais entre niveaux ni entre listes. Le drag ne démarre que depuis la **poignée** (`cdkDragHandle`).
281
+ - **CDK drag-drop** : repose sur `@angular/cdk/drag-drop` (`DragDropModule`). Chaque niveau est un `cdkDropList` **isolé** (pas de `cdkDropListConnectedTo`) → le tri est **intra-liste à chaque niveau**, jamais entre niveaux ni entre listes. Le drag ne démarre que depuis la **poignée** (`cdkDragHandle`). Poignée inactive (carte `disabled` ou `pendingDelete`) : elle garde son rendu normal, seule l'interaction disparaît — le rendu `disabled` du `.btn` (aplat plein `base-disabled`) est neutralisé sur `.ddn-list-handle`, sinon une poignée morte est plus voyante qu'une poignée active.
276
282
  - **Source de vérité** : le composant clone `items` dans une copie interne mutable (`_items`) à chaque changement (effect). C'est cette copie que le CDK déplace ; l'arbre réordonné est émis via `itemsChange`. **Persister** ce payload côté hôte (sinon un re-rendu ultérieur repart de l'ordre périmé).
277
283
  - **Imbrication & `maxDepth`** : `maxDepth` est 0-based (racine = 0). `maxDepth = 1` ⇒ 2 niveaux. `undefined` ⇒ imbrication infinie (ajout possible partout).
278
284
  - **Type de carte alterné** : la lib alterne `CardTypeEnum.default` (profondeur paire) / `light` (impaire).
279
285
  - **i18n** : tous les libellés (`column.title`, `addLabel`, `maxReachedLabel`, `restoreBlockedLabel`, libellés de badge…) passent par `translate` → fournir des **clés**, pas du texte en dur.
280
- - **États & styles** : la lib **lit** `selected` / `selectedId` / `pendingDelete` et pose les classes DS (`ddn-list-card-selected`, `ddn-list-card-deleting`) ; elle ne mute pas les flags. C'est l'hôte qui les flippe et re-passe `items`. Préférer `selectedId` (exclusif, sans parcours d'arbre) au flag `selected` (multi-sélection non garantie).
286
+ - **États & styles** : la lib **lit** `selected` / `selectedId` / `pendingDelete` et pose les classes DS (`ddn-list-card-selected`, `ddn-list-card-has-selection`, `ddn-list-card-deleting`) ; elle ne mute pas les flags. C'est l'hôte qui les flippe et re-passe `items`. Préférer `selectedId` (exclusif, sans parcours d'arbre) au flag `selected` (multi-sélection non garantie).
281
287
  - **Soft-delete** : sur une carte `pendingDelete`, le corps est masqué (carte compacte, non pliable, non déplaçable) et la corbeille devient « Restaurer » (émet `restore`, pas `delete`). En mode `excludePendingDeleteFromMax`, restaurer peut être **bloqué** si le niveau est entre-temps redevenu plein.
282
288
 
283
289
  ---
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { input, ChangeDetectionStrategy, Component, output, effect, computed, inject, contentChild, signal, isSignal, DestroyRef, viewChildren, viewChild, afterRenderEffect, afterNextRender, contentChildren } from '@angular/core';
2
+ import { input, ChangeDetectionStrategy, Component, output, effect, signal, computed, isDevMode, inject, contentChild, isSignal, DestroyRef, viewChildren, viewChild, afterRenderEffect, afterNextRender, contentChildren } from '@angular/core';
3
3
  import * as i1 from '@ngx-translate/core';
4
4
  import { TranslateModule, TranslateService } from '@ngx-translate/core';
5
5
  import * as i1$3 from '@angular/common';
@@ -175,9 +175,14 @@ class DragNDropNestedListComponent {
175
175
  this.maxDepth = input(undefined, ...(ngDevMode ? [{ debugName: "maxDepth" }] : []));
176
176
  /**
177
177
  * Sélection EXCLUSIVE gérée par la lib : la carte dont l'`id` vaut `selectedId` reçoit
178
- * la classe `ddn-list-card-selected`. Une seule carte à la fois, à n'importe quel niveau,
179
- * sans avoir à manipuler `DragItem.selected` (qui reste supporté en parallèle).
178
+ * la classe `ddn-list-card-selected` — elle seule ; un parent n'est jamais repeint, il est
179
+ * seulement marqué d'un liseré quand il est replié (cf. `cardCssClass`).
180
+ * Sans avoir à manipuler `DragItem.selected` (qui reste supporté en parallèle).
180
181
  * Piloté par le consommateur (ex. l'id de la carte en cours d'édition ; `undefined` = aucune).
182
+ *
183
+ * ⚠️ La correspondance est un `===` sur l'`id` à TOUS les niveaux : les `id` doivent être
184
+ * uniques sur l'arbre entier, pas seulement au sein d'un niveau. Deux items de niveaux
185
+ * différents qui partagent un `id` (thème `1` / fichier `1`) s'allument tous les deux.
181
186
  */
182
187
  this.selectedId = input(undefined, ...(ngDevMode ? [{ debugName: "selectedId" }] : []));
183
188
  this.itemsChange = output();
@@ -195,9 +200,57 @@ class DragNDropNestedListComponent {
195
200
  this.alertType = AlertTypeEnum;
196
201
  // Copie interne mutable sur laquelle le CDK opère (pas un signal — cf. DragNDropListComponent)
197
202
  this._items = [];
203
+ /**
204
+ * État de pliage par carte, alimenté par `(collapseClicked)` de `cw-card`.
205
+ * Une carte absente de la map n'a jamais été manipulée : son état est celui posé à l'init
206
+ * (`isCollapsible`, cf. `isCollapsedCard`). Sert au marquage « sélection repliée » des ancêtres.
207
+ */
208
+ this.collapsedById = signal(new Map(), ...(ngDevMode ? [{ debugName: "collapsedById" }] : []));
209
+ /**
210
+ * Ids des ancêtres de la carte sélectionnée (parent, grand-parent, …).
211
+ * Calculé sur `items()` : l'imbrication ne change jamais au drag (chaque niveau est une
212
+ * `cdkDropList` isolée), seul l'ordre intra-niveau bouge.
213
+ */
214
+ this.selectedAncestorIds = computed(() => {
215
+ const selectedId = this.selectedId();
216
+ const ancestors = new Set();
217
+ const walk = (nodes, trail) => {
218
+ for (const node of nodes) {
219
+ if (node.selected || (selectedId !== undefined && node.id === selectedId)) {
220
+ trail.forEach(id => ancestors.add(id));
221
+ }
222
+ if (node.children?.length)
223
+ walk(node.children, [...trail, node.id]);
224
+ }
225
+ };
226
+ walk(this.items(), []);
227
+ return ancestors;
228
+ }, ...(ngDevMode ? [{ debugName: "selectedAncestorIds" }] : []));
198
229
  effect(() => {
199
230
  this._items = this.cloneTree(this.items());
200
231
  });
232
+ // Diagnostic dev : `selectedId` doit désigner UNE carte. Des `id` qui se répètent d'un
233
+ // niveau à l'autre (thème `1` / fichier `1`, typique quand chaque niveau vient d'une table
234
+ // différente) en allument plusieurs — symptôme : « toute la branche est en surbrillance ».
235
+ effect(() => {
236
+ const selectedId = this.selectedId();
237
+ if (!isDevMode() || selectedId === undefined)
238
+ return;
239
+ let matches = 0;
240
+ const count = (nodes) => {
241
+ for (const node of nodes) {
242
+ if (node.id === selectedId)
243
+ matches++;
244
+ if (node.children?.length)
245
+ count(node.children);
246
+ }
247
+ };
248
+ count(this.items());
249
+ if (matches > 1) {
250
+ console.warn(`[cw-drag-n-drop-nested-list] selectedId="${selectedId}" correspond à ${matches} cartes : `
251
+ + `les \`id\` doivent être uniques sur tout l'arbre, pas seulement au sein d'un niveau.`);
252
+ }
253
+ });
201
254
  }
202
255
  drop(event) {
203
256
  // Pas de transferArrayItem : chaque cdkDropList est isolée (pas de connectedTo),
@@ -289,18 +342,41 @@ class DragNDropNestedListComponent {
289
342
  }
290
343
  /**
291
344
  * Classe(s) de la carte selon son état (posées par la lib, stylées dans le SCSS DS).
292
- * Sélection → `ddn-list-card-selected` si `item.id === selectedId` (exclusif, géré par la lib)
293
- * OU `item.selected === true` (flag legacy). `pendingDelete` → `ddn-list-card-deleting`.
345
+ * - `ddn-list-card-selected` : la carte sélectionnée elle-même (`item.id === selectedId`,
346
+ * ou flag legacy `item.selected`). **Elle seule** — le fond de sélection ne remonte pas
347
+ * sur les ancêtres, sinon toute la branche prend la même couleur et plus rien ne se lit.
348
+ * - `ddn-list-card-has-selection` : ancêtre **replié** de la carte sélectionnée, qui reprend
349
+ * le rendu de sélection — la carte sélectionnée n'étant pas rendue tant que le parent est
350
+ * replié (`destroyOnHide` de `cw-card`), une seule carte est peinte à l'écran. Dépliée,
351
+ * la classe n'est plus posée : la sélection se voit d'elle-même sur la bonne carte.
352
+ * - `ddn-list-card-deleting` : carte `pendingDelete`.
294
353
  */
295
- cardCssClass(item) {
354
+ cardCssClass(item, depth) {
296
355
  const selectedId = this.selectedId();
297
356
  const selected = item.selected || (selectedId !== undefined && item.id === selectedId);
357
+ const hidesSelection = !selected
358
+ && this.selectedAncestorIds().has(item.id)
359
+ && this.isCollapsedCard(item, depth);
298
360
  return [
299
361
  'ddn-list-card',
300
362
  selected ? 'ddn-list-card-selected' : '',
363
+ hidesSelection ? 'ddn-list-card-has-selection' : '',
301
364
  item.pendingDelete ? 'ddn-list-card-deleting' : '',
302
365
  ].filter(Boolean).join(' ');
303
366
  }
367
+ /**
368
+ * Carte repliée ? Réponse de la map alimentée par `(collapseClicked)`, sinon état initial
369
+ * (une carte pliable démarre repliée). Sert aussi de `[collapsed]` : l'état survit ainsi
370
+ * à un re-rendu de la liste (drop, mise à jour de `items`).
371
+ */
372
+ isCollapsedCard(item, depth) {
373
+ return this.collapsedById().get(item.id) ?? this.isCollapsible(item, depth);
374
+ }
375
+ onCollapseChange(item, collapsed) {
376
+ const next = new Map(this.collapsedById());
377
+ next.set(item.id, collapsed);
378
+ this.collapsedById.set(next);
379
+ }
304
380
  /**
305
381
  * Libellé du compteur d'enfants, en gérant singulier/pluriel.
306
382
  * Affiché aussi à `0` quand la carte est vide mais peut recevoir des enfants
@@ -341,11 +417,11 @@ class DragNDropNestedListComponent {
341
417
  }));
342
418
  }
343
419
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.20", ngImport: i0, type: DragNDropNestedListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
344
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.20", type: DragNDropNestedListComponent, isStandalone: true, selector: "cw-drag-n-drop-nested-list", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, itemTemplate: { classPropertyName: "itemTemplate", publicName: "itemTemplate", isSignal: true, isRequired: false, transformFunction: null }, column: { classPropertyName: "column", publicName: "column", isSignal: true, isRequired: false, transformFunction: null }, reorderOnDrop: { classPropertyName: "reorderOnDrop", publicName: "reorderOnDrop", isSignal: true, isRequired: false, transformFunction: null }, maxDepth: { classPropertyName: "maxDepth", publicName: "maxDepth", isSignal: true, isRequired: false, transformFunction: null }, selectedId: { classPropertyName: "selectedId", publicName: "selectedId", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { itemsChange: "itemsChange", view: "view", edit: "edit", delete: "delete", restore: "restore", add: "add" }, ngImport: i0, template: "<div class=\"ddn-list d-flex-v gap-md\">\n <div class=\"d-flex-h justify-between\">\n @if (column()?.title) {\n <h2>{{ column()!.title | translate }} ({{ columnCountLabel() }})</h2>\n }\n\n @if (column()?.showAddRoot) {\n <cw-button cssClass=\"ddn-list-add\" [type]=\"buttonType.link\" [withIcon]=\"spriteIcon.add\"\n [iconPosition]=\"buttonPosition.left\" [label]=\"column()?.addRootLabel ?? column()?.addLabel ?? '_COMMON._ACTION.ADD'\"\n [isDisabled]=\"isLevelFull(_items, 0)\" (btnAction)=\"onAdd(undefined, 0)\" />\n }\n </div>\n\n <ng-container *ngTemplateOutlet=\"nodeTpl; context: { $implicit: _items, depth: 0, parent: undefined }\" />\n</div>\n\n<!--\n Template r\u00E9cursif : \u00E0 chaque niveau, on rend un cdkDropList isol\u00E9\n (pas de cdkDropListConnectedTo => transfert inter-listes impossible),\n puis on r\u00E9-instancie le m\u00EAme template pour la sous-liste de chaque enfant.\n-->\n<ng-template #nodeTpl let-nodes let-depth=\"depth\" let-parent=\"parent\">\n @if (isLevelFull(nodes, depth)) {\n <cw-alert [type]=\"alertType.warning\" cssClass=\"ddn-list-max-alert\">\n {{ (column()?.maxReachedLabel ?? '_COMMON.MAX_ITEMS_REACHED') | translate:{ max: levelMax(depth) } }}\n </cw-alert>\n }\n\n <ul class=\"list-unstyled d-flex-v gap-md ms-none\" [ngClass]=\"column()?.cssClass\" [attr.data-depth]=\"depth\"\n cdkDropList [cdkDropListData]=\"nodes\" (cdkDropListDropped)=\"drop($event)\">\n\n @for (item of nodes; track item.id) {\n <li cdkDrag [cdkDragDisabled]=\"(item.disabled ?? false) || (item.pendingDelete ?? false)\" cdkDragPreviewClass=\"ddn-list-card-preview\">\n <cw-card [cssClass]=\"cardCssClass(item)\" [title]=\"(item.title ?? item.label) || ''\"\n [subtitle]=\"item.subtitle ?? ''\" [type]=\"cardType(depth)\" [collapsible]=\"isCollapsible(item, depth)\"\n [collapsed]=\"isCollapsible(item, depth)\" [collapseStretched]=\"false\">\n\n <!-- Poign\u00E9e de drag (\u00E0 gauche du titre) : le glisser ne d\u00E9marre que d'ici -->\n <button header-start type=\"button\" class=\"ddn-list-handle\" cdkDragHandle\n [disabled]=\"(item.disabled ?? false) || (item.pendingDelete ?? false)\" [attr.aria-label]=\"'_COMMON._ACTION.MOVE' | translate\">\n <cw-icon [icon]=\"spriteIcon.grip\" [iconSize]=\"iconSize['md']\" />\n </button>\n\n <!-- En-t\u00EAte : compteur d'enfants + badge + actions -->\n <div header-custom-area class=\"d-flex-h gap-2xs justify-end align-start\">\n @if (childrenCountLabel(item, depth); as count) {\n <span class=\"ddn-list-count fs fs-xs\">{{ count }}</span>\n }\n\n @if (item.badge) {\n <cw-badge [type]=\"item.badge.type\" [label]=\"item.badge.label\" [withIcon]=\"item.badge.icon\" />\n }\n\n <!-- Sur une carte pendingDelete, seul \u00AB Restaurer \u00BB est propos\u00E9 (view/edit masqu\u00E9s). -->\n @if (!item.pendingDelete && showAction(item, 'view')) {\n <cw-button label=\"_COMMON._ACTION.VIEW\" [withIcon]=\"spriteIcon.search\" [withOnlyIcon]=\"true\"\n [type]=\"buttonType.secondary\" [iconSize]=\"buttonIconSize.xsmall\" (btnAction)=\"view.emit(item)\" />\n }\n @if (!item.pendingDelete && showAction(item, 'edit')) {\n <cw-button label=\"_COMMON._ACTION.EDIT\" [withIcon]=\"spriteIcon.edit\" [withOnlyIcon]=\"true\"\n [type]=\"buttonType.secondary\" [iconSize]=\"buttonIconSize.xsmall\" (btnAction)=\"edit.emit(item)\" />\n }\n @if (showAction(item, 'delete')) {\n @if (item.pendingDelete) {\n <!-- Soft-delete : la corbeille bascule en \u00AB Restaurer \u00BB (d\u00E9sactiv\u00E9 si le niveau est plein). -->\n <cw-button label=\"_COMMON._ACTION.RESTORE\" [withIcon]=\"spriteIcon.toolbarRefresh\" [withOnlyIcon]=\"true\"\n [type]=\"buttonType.secondary\" cssClass=\"ddn-list-action-restore\"\n [isDisabled]=\"isRestoreBlocked(nodes, depth)\"\n [iconSize]=\"buttonIconSize.xsmall\" (btnAction)=\"restore.emit(item)\" />\n } @else {\n <cw-button label=\"_COMMON._ACTION.DELETE\" [withIcon]=\"spriteIcon.trash\" [withOnlyIcon]=\"true\"\n [type]=\"buttonType.secondary\" cssClass=\"ddn-list-action-delete\"\n [iconSize]=\"buttonIconSize.xsmall\" (btnAction)=\"delete.emit(item)\" />\n }\n }\n </div>\n\n <!-- Restauration impossible : niveau plein (mode excludePendingDeleteFromMax). -->\n @if (item.pendingDelete && isRestoreBlocked(nodes, depth)) {\n <cw-alert [type]=\"alertType.warning\" cssClass=\"ddn-list-restore-blocked-alert\">\n {{ (column()?.restoreBlockedLabel ?? '_COMMON.MAX_RESTORE_BLOCKED') | translate:{ max: levelMax(depth) } }}\n </cw-alert>\n }\n\n <!-- Corps masqu\u00E9 sur une carte pendingDelete : on n'affiche que l'en-t\u00EAte (carte compacte,\n non pliable, non d\u00E9pla\u00E7able). L'encart \u00AB restauration impossible \u00BB ci-dessus reste, lui, visible. -->\n @if (!item.pendingDelete) {\n <!-- Corps : template custom (slot) ou fallback -->\n <ng-container\n *ngTemplateOutlet=\"itemTemplate() || defaultTemplate; context: { $implicit: item, depth: depth }\" />\n\n @if (item.children?.length) {\n <ng-container\n *ngTemplateOutlet=\"nodeTpl; context: { $implicit: item.children, depth: depth + 1, parent: item }\" />\n }\n\n @if (canAdd(item, depth)) {\n <div class=\"d-flex-h justify-end\">\n <cw-button class=\"ddn-list-add\" [type]=\"buttonType.link\" [withIcon]=\"spriteIcon.add\"\n [iconPosition]=\"buttonPosition.left\" [label]=\"column()?.addLabel ?? '_COMMON._ACTION.ADD'\"\n [isDisabled]=\"isLevelFull(item.children ?? [], depth + 1)\" (btnAction)=\"onAdd(item, depth + 1)\" />\n </div>\n }\n }\n </cw-card>\n </li>\n }\n\n </ul>\n</ng-template>\n\n<ng-template #defaultTemplate let-item>\n <div class=\"default-item d-flex justify-content-between\">\n <span>\n {{ item.label }}\n @if (item.code) { <span class=\"text-muted\">({{ item.code }})</span> }\n </span>\n </div>\n</ng-template>\n", dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "ngmodule", type: DragDropModule }, { kind: "directive", type: i1$1.CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer", "cdkDropListHasAnchor"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: i1$1.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: i1$1.CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "component", type: CardComponent, selector: "cw-card", inputs: ["title", "subtitle", "type", "titleRank", "cssClass", "collapsible", "collapsed", "disabled", "collapseLocked", "collapseStretched", "collapseId", "destroyOnHide"], outputs: ["collapsibleChange", "destroyOnHideChange", "collapseClicked"] }, { kind: "component", type: BadgeComponent, selector: "cw-badge", inputs: ["type", "label", "withIcon", "iconPosition", "cssClass", "skeletonMode", "dataTest"] }, { kind: "component", type: IconComponent, selector: "cw-icon", inputs: ["icon", "label", "type", "iconSize", "iconCssClass", "iconUiType", "iconColorCustom", "spritePath"] }, { kind: "component", type: ButtonComponent, selector: "cw-button", inputs: ["type", "label", "id", "link", "isDropdown", "hideCaret", "withIcon", "withOnlyIcon", "iconSize", "iconPosition", "dropdownPosition", "isMinWidth", "isDisabled", "isLoading", "loadingAnnounce", "cssClass", "dataTest", "skeletonMode", "withTooltip", "tooltipText", "tooltipTitle", "tooltipTrigger", "tooltipPosition", "tooltipType"], outputs: ["btnAction", "dropDownClicked"] }, { kind: "component", type: AlertComponent, selector: "cw-alert", inputs: ["type", "title", "isDismissible", "cssClass", "dataTest"], outputs: ["close"] }, { kind: "pipe", type: i1.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
420
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.20", type: DragNDropNestedListComponent, isStandalone: true, selector: "cw-drag-n-drop-nested-list", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, itemTemplate: { classPropertyName: "itemTemplate", publicName: "itemTemplate", isSignal: true, isRequired: false, transformFunction: null }, column: { classPropertyName: "column", publicName: "column", isSignal: true, isRequired: false, transformFunction: null }, reorderOnDrop: { classPropertyName: "reorderOnDrop", publicName: "reorderOnDrop", isSignal: true, isRequired: false, transformFunction: null }, maxDepth: { classPropertyName: "maxDepth", publicName: "maxDepth", isSignal: true, isRequired: false, transformFunction: null }, selectedId: { classPropertyName: "selectedId", publicName: "selectedId", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { itemsChange: "itemsChange", view: "view", edit: "edit", delete: "delete", restore: "restore", add: "add" }, ngImport: i0, template: "<div class=\"ddn-list d-flex-v gap-md\">\n <div class=\"d-flex-h justify-between\">\n @if (column()?.title) {\n <h2>{{ column()!.title | translate }} ({{ columnCountLabel() }})</h2>\n }\n\n @if (column()?.showAddRoot) {\n <cw-button cssClass=\"ddn-list-add\" [type]=\"buttonType.link\" [withIcon]=\"spriteIcon.add\"\n [iconPosition]=\"buttonPosition.left\" [label]=\"column()?.addRootLabel ?? column()?.addLabel ?? '_COMMON._ACTION.ADD'\"\n [isDisabled]=\"isLevelFull(_items, 0)\" (btnAction)=\"onAdd(undefined, 0)\" />\n }\n </div>\n\n <ng-container *ngTemplateOutlet=\"nodeTpl; context: { $implicit: _items, depth: 0, parent: undefined }\" />\n</div>\n\n<!--\n Template r\u00E9cursif : \u00E0 chaque niveau, on rend un cdkDropList isol\u00E9\n (pas de cdkDropListConnectedTo => transfert inter-listes impossible),\n puis on r\u00E9-instancie le m\u00EAme template pour la sous-liste de chaque enfant.\n-->\n<ng-template #nodeTpl let-nodes let-depth=\"depth\" let-parent=\"parent\">\n @if (isLevelFull(nodes, depth)) {\n <cw-alert [type]=\"alertType.warning\" cssClass=\"ddn-list-max-alert\">\n {{ (column()?.maxReachedLabel ?? '_COMMON.MAX_ITEMS_REACHED') | translate:{ max: levelMax(depth) } }}\n </cw-alert>\n }\n\n <ul class=\"list-unstyled d-flex-v gap-md ms-none\" [ngClass]=\"column()?.cssClass\" [attr.data-depth]=\"depth\"\n cdkDropList [cdkDropListData]=\"nodes\" (cdkDropListDropped)=\"drop($event)\">\n\n @for (item of nodes; track item.id) {\n <li cdkDrag [cdkDragDisabled]=\"(item.disabled ?? false) || (item.pendingDelete ?? false)\" cdkDragPreviewClass=\"ddn-list-card-preview\">\n <cw-card [cssClass]=\"cardCssClass(item, depth)\" [title]=\"(item.title ?? item.label) || ''\"\n [subtitle]=\"item.subtitle ?? ''\" [type]=\"cardType(depth)\" [collapsible]=\"isCollapsible(item, depth)\"\n [collapsed]=\"isCollapsedCard(item, depth)\" [collapseStretched]=\"false\"\n (collapseClicked)=\"onCollapseChange(item, $event)\">\n\n <!-- Poign\u00E9e de drag (\u00E0 gauche du titre) : le glisser ne d\u00E9marre que d'ici -->\n <button header-start type=\"button\" class=\"ddn-list-handle btn btn-ghost\" cdkDragHandle\n [disabled]=\"(item.disabled ?? false) || (item.pendingDelete ?? false)\" [attr.aria-label]=\"'_COMMON._ACTION.MOVE' | translate\">\n <cw-icon [icon]=\"spriteIcon.grip\" [iconSize]=\"iconSize['md']\" />\n </button>\n\n <!-- En-t\u00EAte : compteur d'enfants + badge + actions -->\n <div header-custom-area class=\"d-flex-h gap-2xs justify-end align-start\">\n @if (childrenCountLabel(item, depth); as count) {\n <span class=\"ddn-list-count fs fs-xs\">{{ count }}</span>\n }\n\n @if (item.badge) {\n <cw-badge [type]=\"item.badge.type\" [label]=\"item.badge.label\" [withIcon]=\"item.badge.icon\" />\n }\n\n <!-- Sur une carte pendingDelete, seul \u00AB Restaurer \u00BB est propos\u00E9 (view/edit masqu\u00E9s). -->\n @if (!item.pendingDelete && showAction(item, 'view')) {\n <cw-button label=\"_COMMON._ACTION.VIEW\" [withIcon]=\"spriteIcon.search\" [withOnlyIcon]=\"true\"\n [type]=\"buttonType.secondary\" [iconSize]=\"buttonIconSize.xsmall\" (btnAction)=\"view.emit(item)\" />\n }\n @if (!item.pendingDelete && showAction(item, 'edit')) {\n <cw-button label=\"_COMMON._ACTION.EDIT\" [withIcon]=\"spriteIcon.edit\" [withOnlyIcon]=\"true\"\n [type]=\"buttonType.secondary\" [iconSize]=\"buttonIconSize.xsmall\" (btnAction)=\"edit.emit(item)\" />\n }\n @if (showAction(item, 'delete')) {\n @if (item.pendingDelete) {\n <!-- Soft-delete : la corbeille bascule en \u00AB Restaurer \u00BB (d\u00E9sactiv\u00E9 si le niveau est plein). -->\n <cw-button label=\"_COMMON._ACTION.RESTORE\" [withIcon]=\"spriteIcon.toolbarRefresh\" [withOnlyIcon]=\"true\"\n [type]=\"buttonType.secondary\" cssClass=\"ddn-list-action-restore\"\n [isDisabled]=\"isRestoreBlocked(nodes, depth)\"\n [iconSize]=\"buttonIconSize.xsmall\" (btnAction)=\"restore.emit(item)\" />\n } @else {\n <cw-button label=\"_COMMON._ACTION.DELETE\" [withIcon]=\"spriteIcon.trash\" [withOnlyIcon]=\"true\"\n [type]=\"buttonType.secondary\" cssClass=\"ddn-list-action-delete\"\n [iconSize]=\"buttonIconSize.xsmall\" (btnAction)=\"delete.emit(item)\" />\n }\n }\n </div>\n\n <!-- Restauration impossible : niveau plein (mode excludePendingDeleteFromMax). -->\n @if (item.pendingDelete && isRestoreBlocked(nodes, depth)) {\n <cw-alert [type]=\"alertType.warning\" cssClass=\"ddn-list-restore-blocked-alert\">\n {{ (column()?.restoreBlockedLabel ?? '_COMMON.MAX_RESTORE_BLOCKED') | translate:{ max: levelMax(depth) } }}\n </cw-alert>\n }\n\n <!-- Corps masqu\u00E9 sur une carte pendingDelete : on n'affiche que l'en-t\u00EAte (carte compacte,\n non pliable, non d\u00E9pla\u00E7able). L'encart \u00AB restauration impossible \u00BB ci-dessus reste, lui, visible. -->\n @if (!item.pendingDelete) {\n <!-- Corps : template custom (slot). Sans slot, on ne rend que ce que l'en-t\u00EAte ne porte\n pas d\u00E9j\u00E0 (le titre vaut `title ?? label`) : le code seul, s'il existe. -->\n @if (itemTemplate(); as tpl) {\n <ng-container *ngTemplateOutlet=\"tpl; context: { $implicit: item, depth: depth }\" />\n } @else if (item.code) {\n <div class=\"default-item\"><span class=\"text-muted\">({{ item.code }})</span></div>\n }\n\n @if (item.children?.length) {\n <ng-container\n *ngTemplateOutlet=\"nodeTpl; context: { $implicit: item.children, depth: depth + 1, parent: item }\" />\n }\n\n @if (canAdd(item, depth)) {\n <div class=\"d-flex-h justify-end\">\n <cw-button class=\"ddn-list-add\" [type]=\"buttonType.link\" [withIcon]=\"spriteIcon.add\"\n [iconPosition]=\"buttonPosition.left\" [label]=\"column()?.addLabel ?? '_COMMON._ACTION.ADD'\"\n [isDisabled]=\"isLevelFull(item.children ?? [], depth + 1)\" (btnAction)=\"onAdd(item, depth + 1)\" />\n </div>\n }\n }\n </cw-card>\n </li>\n }\n\n </ul>\n</ng-template>\n", dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "ngmodule", type: DragDropModule }, { kind: "directive", type: i1$1.CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer", "cdkDropListHasAnchor"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: i1$1.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: i1$1.CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "component", type: CardComponent, selector: "cw-card", inputs: ["title", "subtitle", "type", "titleRank", "cssClass", "collapsible", "collapsed", "disabled", "collapseLocked", "collapseStretched", "collapseId", "destroyOnHide"], outputs: ["collapsibleChange", "destroyOnHideChange", "collapseClicked"] }, { kind: "component", type: BadgeComponent, selector: "cw-badge", inputs: ["type", "label", "withIcon", "iconPosition", "cssClass", "skeletonMode", "dataTest"] }, { kind: "component", type: IconComponent, selector: "cw-icon", inputs: ["icon", "label", "type", "iconSize", "iconCssClass", "iconUiType", "iconColorCustom", "spritePath"] }, { kind: "component", type: ButtonComponent, selector: "cw-button", inputs: ["type", "label", "id", "link", "isDropdown", "hideCaret", "withIcon", "withOnlyIcon", "iconSize", "iconPosition", "dropdownPosition", "isMinWidth", "isDisabled", "isLoading", "loadingAnnounce", "cssClass", "dataTest", "skeletonMode", "withTooltip", "tooltipText", "tooltipTitle", "tooltipTrigger", "tooltipPosition", "tooltipType"], outputs: ["btnAction", "dropDownClicked"] }, { kind: "component", type: AlertComponent, selector: "cw-alert", inputs: ["type", "title", "isDismissible", "cssClass", "dataTest"], outputs: ["close"] }, { kind: "pipe", type: i1.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
345
421
  }
346
422
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.20", ngImport: i0, type: DragNDropNestedListComponent, decorators: [{
347
423
  type: Component,
348
- args: [{ selector: 'cw-drag-n-drop-nested-list', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgClass, NgTemplateOutlet, TranslateModule, DragDropModule, CardComponent, BadgeComponent, IconComponent, ButtonComponent, AlertComponent], template: "<div class=\"ddn-list d-flex-v gap-md\">\n <div class=\"d-flex-h justify-between\">\n @if (column()?.title) {\n <h2>{{ column()!.title | translate }} ({{ columnCountLabel() }})</h2>\n }\n\n @if (column()?.showAddRoot) {\n <cw-button cssClass=\"ddn-list-add\" [type]=\"buttonType.link\" [withIcon]=\"spriteIcon.add\"\n [iconPosition]=\"buttonPosition.left\" [label]=\"column()?.addRootLabel ?? column()?.addLabel ?? '_COMMON._ACTION.ADD'\"\n [isDisabled]=\"isLevelFull(_items, 0)\" (btnAction)=\"onAdd(undefined, 0)\" />\n }\n </div>\n\n <ng-container *ngTemplateOutlet=\"nodeTpl; context: { $implicit: _items, depth: 0, parent: undefined }\" />\n</div>\n\n<!--\n Template r\u00E9cursif : \u00E0 chaque niveau, on rend un cdkDropList isol\u00E9\n (pas de cdkDropListConnectedTo => transfert inter-listes impossible),\n puis on r\u00E9-instancie le m\u00EAme template pour la sous-liste de chaque enfant.\n-->\n<ng-template #nodeTpl let-nodes let-depth=\"depth\" let-parent=\"parent\">\n @if (isLevelFull(nodes, depth)) {\n <cw-alert [type]=\"alertType.warning\" cssClass=\"ddn-list-max-alert\">\n {{ (column()?.maxReachedLabel ?? '_COMMON.MAX_ITEMS_REACHED') | translate:{ max: levelMax(depth) } }}\n </cw-alert>\n }\n\n <ul class=\"list-unstyled d-flex-v gap-md ms-none\" [ngClass]=\"column()?.cssClass\" [attr.data-depth]=\"depth\"\n cdkDropList [cdkDropListData]=\"nodes\" (cdkDropListDropped)=\"drop($event)\">\n\n @for (item of nodes; track item.id) {\n <li cdkDrag [cdkDragDisabled]=\"(item.disabled ?? false) || (item.pendingDelete ?? false)\" cdkDragPreviewClass=\"ddn-list-card-preview\">\n <cw-card [cssClass]=\"cardCssClass(item)\" [title]=\"(item.title ?? item.label) || ''\"\n [subtitle]=\"item.subtitle ?? ''\" [type]=\"cardType(depth)\" [collapsible]=\"isCollapsible(item, depth)\"\n [collapsed]=\"isCollapsible(item, depth)\" [collapseStretched]=\"false\">\n\n <!-- Poign\u00E9e de drag (\u00E0 gauche du titre) : le glisser ne d\u00E9marre que d'ici -->\n <button header-start type=\"button\" class=\"ddn-list-handle\" cdkDragHandle\n [disabled]=\"(item.disabled ?? false) || (item.pendingDelete ?? false)\" [attr.aria-label]=\"'_COMMON._ACTION.MOVE' | translate\">\n <cw-icon [icon]=\"spriteIcon.grip\" [iconSize]=\"iconSize['md']\" />\n </button>\n\n <!-- En-t\u00EAte : compteur d'enfants + badge + actions -->\n <div header-custom-area class=\"d-flex-h gap-2xs justify-end align-start\">\n @if (childrenCountLabel(item, depth); as count) {\n <span class=\"ddn-list-count fs fs-xs\">{{ count }}</span>\n }\n\n @if (item.badge) {\n <cw-badge [type]=\"item.badge.type\" [label]=\"item.badge.label\" [withIcon]=\"item.badge.icon\" />\n }\n\n <!-- Sur une carte pendingDelete, seul \u00AB Restaurer \u00BB est propos\u00E9 (view/edit masqu\u00E9s). -->\n @if (!item.pendingDelete && showAction(item, 'view')) {\n <cw-button label=\"_COMMON._ACTION.VIEW\" [withIcon]=\"spriteIcon.search\" [withOnlyIcon]=\"true\"\n [type]=\"buttonType.secondary\" [iconSize]=\"buttonIconSize.xsmall\" (btnAction)=\"view.emit(item)\" />\n }\n @if (!item.pendingDelete && showAction(item, 'edit')) {\n <cw-button label=\"_COMMON._ACTION.EDIT\" [withIcon]=\"spriteIcon.edit\" [withOnlyIcon]=\"true\"\n [type]=\"buttonType.secondary\" [iconSize]=\"buttonIconSize.xsmall\" (btnAction)=\"edit.emit(item)\" />\n }\n @if (showAction(item, 'delete')) {\n @if (item.pendingDelete) {\n <!-- Soft-delete : la corbeille bascule en \u00AB Restaurer \u00BB (d\u00E9sactiv\u00E9 si le niveau est plein). -->\n <cw-button label=\"_COMMON._ACTION.RESTORE\" [withIcon]=\"spriteIcon.toolbarRefresh\" [withOnlyIcon]=\"true\"\n [type]=\"buttonType.secondary\" cssClass=\"ddn-list-action-restore\"\n [isDisabled]=\"isRestoreBlocked(nodes, depth)\"\n [iconSize]=\"buttonIconSize.xsmall\" (btnAction)=\"restore.emit(item)\" />\n } @else {\n <cw-button label=\"_COMMON._ACTION.DELETE\" [withIcon]=\"spriteIcon.trash\" [withOnlyIcon]=\"true\"\n [type]=\"buttonType.secondary\" cssClass=\"ddn-list-action-delete\"\n [iconSize]=\"buttonIconSize.xsmall\" (btnAction)=\"delete.emit(item)\" />\n }\n }\n </div>\n\n <!-- Restauration impossible : niveau plein (mode excludePendingDeleteFromMax). -->\n @if (item.pendingDelete && isRestoreBlocked(nodes, depth)) {\n <cw-alert [type]=\"alertType.warning\" cssClass=\"ddn-list-restore-blocked-alert\">\n {{ (column()?.restoreBlockedLabel ?? '_COMMON.MAX_RESTORE_BLOCKED') | translate:{ max: levelMax(depth) } }}\n </cw-alert>\n }\n\n <!-- Corps masqu\u00E9 sur une carte pendingDelete : on n'affiche que l'en-t\u00EAte (carte compacte,\n non pliable, non d\u00E9pla\u00E7able). L'encart \u00AB restauration impossible \u00BB ci-dessus reste, lui, visible. -->\n @if (!item.pendingDelete) {\n <!-- Corps : template custom (slot) ou fallback -->\n <ng-container\n *ngTemplateOutlet=\"itemTemplate() || defaultTemplate; context: { $implicit: item, depth: depth }\" />\n\n @if (item.children?.length) {\n <ng-container\n *ngTemplateOutlet=\"nodeTpl; context: { $implicit: item.children, depth: depth + 1, parent: item }\" />\n }\n\n @if (canAdd(item, depth)) {\n <div class=\"d-flex-h justify-end\">\n <cw-button class=\"ddn-list-add\" [type]=\"buttonType.link\" [withIcon]=\"spriteIcon.add\"\n [iconPosition]=\"buttonPosition.left\" [label]=\"column()?.addLabel ?? '_COMMON._ACTION.ADD'\"\n [isDisabled]=\"isLevelFull(item.children ?? [], depth + 1)\" (btnAction)=\"onAdd(item, depth + 1)\" />\n </div>\n }\n }\n </cw-card>\n </li>\n }\n\n </ul>\n</ng-template>\n\n<ng-template #defaultTemplate let-item>\n <div class=\"default-item d-flex justify-content-between\">\n <span>\n {{ item.label }}\n @if (item.code) { <span class=\"text-muted\">({{ item.code }})</span> }\n </span>\n </div>\n</ng-template>\n" }]
424
+ args: [{ selector: 'cw-drag-n-drop-nested-list', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgClass, NgTemplateOutlet, TranslateModule, DragDropModule, CardComponent, BadgeComponent, IconComponent, ButtonComponent, AlertComponent], template: "<div class=\"ddn-list d-flex-v gap-md\">\n <div class=\"d-flex-h justify-between\">\n @if (column()?.title) {\n <h2>{{ column()!.title | translate }} ({{ columnCountLabel() }})</h2>\n }\n\n @if (column()?.showAddRoot) {\n <cw-button cssClass=\"ddn-list-add\" [type]=\"buttonType.link\" [withIcon]=\"spriteIcon.add\"\n [iconPosition]=\"buttonPosition.left\" [label]=\"column()?.addRootLabel ?? column()?.addLabel ?? '_COMMON._ACTION.ADD'\"\n [isDisabled]=\"isLevelFull(_items, 0)\" (btnAction)=\"onAdd(undefined, 0)\" />\n }\n </div>\n\n <ng-container *ngTemplateOutlet=\"nodeTpl; context: { $implicit: _items, depth: 0, parent: undefined }\" />\n</div>\n\n<!--\n Template r\u00E9cursif : \u00E0 chaque niveau, on rend un cdkDropList isol\u00E9\n (pas de cdkDropListConnectedTo => transfert inter-listes impossible),\n puis on r\u00E9-instancie le m\u00EAme template pour la sous-liste de chaque enfant.\n-->\n<ng-template #nodeTpl let-nodes let-depth=\"depth\" let-parent=\"parent\">\n @if (isLevelFull(nodes, depth)) {\n <cw-alert [type]=\"alertType.warning\" cssClass=\"ddn-list-max-alert\">\n {{ (column()?.maxReachedLabel ?? '_COMMON.MAX_ITEMS_REACHED') | translate:{ max: levelMax(depth) } }}\n </cw-alert>\n }\n\n <ul class=\"list-unstyled d-flex-v gap-md ms-none\" [ngClass]=\"column()?.cssClass\" [attr.data-depth]=\"depth\"\n cdkDropList [cdkDropListData]=\"nodes\" (cdkDropListDropped)=\"drop($event)\">\n\n @for (item of nodes; track item.id) {\n <li cdkDrag [cdkDragDisabled]=\"(item.disabled ?? false) || (item.pendingDelete ?? false)\" cdkDragPreviewClass=\"ddn-list-card-preview\">\n <cw-card [cssClass]=\"cardCssClass(item, depth)\" [title]=\"(item.title ?? item.label) || ''\"\n [subtitle]=\"item.subtitle ?? ''\" [type]=\"cardType(depth)\" [collapsible]=\"isCollapsible(item, depth)\"\n [collapsed]=\"isCollapsedCard(item, depth)\" [collapseStretched]=\"false\"\n (collapseClicked)=\"onCollapseChange(item, $event)\">\n\n <!-- Poign\u00E9e de drag (\u00E0 gauche du titre) : le glisser ne d\u00E9marre que d'ici -->\n <button header-start type=\"button\" class=\"ddn-list-handle btn btn-ghost\" cdkDragHandle\n [disabled]=\"(item.disabled ?? false) || (item.pendingDelete ?? false)\" [attr.aria-label]=\"'_COMMON._ACTION.MOVE' | translate\">\n <cw-icon [icon]=\"spriteIcon.grip\" [iconSize]=\"iconSize['md']\" />\n </button>\n\n <!-- En-t\u00EAte : compteur d'enfants + badge + actions -->\n <div header-custom-area class=\"d-flex-h gap-2xs justify-end align-start\">\n @if (childrenCountLabel(item, depth); as count) {\n <span class=\"ddn-list-count fs fs-xs\">{{ count }}</span>\n }\n\n @if (item.badge) {\n <cw-badge [type]=\"item.badge.type\" [label]=\"item.badge.label\" [withIcon]=\"item.badge.icon\" />\n }\n\n <!-- Sur une carte pendingDelete, seul \u00AB Restaurer \u00BB est propos\u00E9 (view/edit masqu\u00E9s). -->\n @if (!item.pendingDelete && showAction(item, 'view')) {\n <cw-button label=\"_COMMON._ACTION.VIEW\" [withIcon]=\"spriteIcon.search\" [withOnlyIcon]=\"true\"\n [type]=\"buttonType.secondary\" [iconSize]=\"buttonIconSize.xsmall\" (btnAction)=\"view.emit(item)\" />\n }\n @if (!item.pendingDelete && showAction(item, 'edit')) {\n <cw-button label=\"_COMMON._ACTION.EDIT\" [withIcon]=\"spriteIcon.edit\" [withOnlyIcon]=\"true\"\n [type]=\"buttonType.secondary\" [iconSize]=\"buttonIconSize.xsmall\" (btnAction)=\"edit.emit(item)\" />\n }\n @if (showAction(item, 'delete')) {\n @if (item.pendingDelete) {\n <!-- Soft-delete : la corbeille bascule en \u00AB Restaurer \u00BB (d\u00E9sactiv\u00E9 si le niveau est plein). -->\n <cw-button label=\"_COMMON._ACTION.RESTORE\" [withIcon]=\"spriteIcon.toolbarRefresh\" [withOnlyIcon]=\"true\"\n [type]=\"buttonType.secondary\" cssClass=\"ddn-list-action-restore\"\n [isDisabled]=\"isRestoreBlocked(nodes, depth)\"\n [iconSize]=\"buttonIconSize.xsmall\" (btnAction)=\"restore.emit(item)\" />\n } @else {\n <cw-button label=\"_COMMON._ACTION.DELETE\" [withIcon]=\"spriteIcon.trash\" [withOnlyIcon]=\"true\"\n [type]=\"buttonType.secondary\" cssClass=\"ddn-list-action-delete\"\n [iconSize]=\"buttonIconSize.xsmall\" (btnAction)=\"delete.emit(item)\" />\n }\n }\n </div>\n\n <!-- Restauration impossible : niveau plein (mode excludePendingDeleteFromMax). -->\n @if (item.pendingDelete && isRestoreBlocked(nodes, depth)) {\n <cw-alert [type]=\"alertType.warning\" cssClass=\"ddn-list-restore-blocked-alert\">\n {{ (column()?.restoreBlockedLabel ?? '_COMMON.MAX_RESTORE_BLOCKED') | translate:{ max: levelMax(depth) } }}\n </cw-alert>\n }\n\n <!-- Corps masqu\u00E9 sur une carte pendingDelete : on n'affiche que l'en-t\u00EAte (carte compacte,\n non pliable, non d\u00E9pla\u00E7able). L'encart \u00AB restauration impossible \u00BB ci-dessus reste, lui, visible. -->\n @if (!item.pendingDelete) {\n <!-- Corps : template custom (slot). Sans slot, on ne rend que ce que l'en-t\u00EAte ne porte\n pas d\u00E9j\u00E0 (le titre vaut `title ?? label`) : le code seul, s'il existe. -->\n @if (itemTemplate(); as tpl) {\n <ng-container *ngTemplateOutlet=\"tpl; context: { $implicit: item, depth: depth }\" />\n } @else if (item.code) {\n <div class=\"default-item\"><span class=\"text-muted\">({{ item.code }})</span></div>\n }\n\n @if (item.children?.length) {\n <ng-container\n *ngTemplateOutlet=\"nodeTpl; context: { $implicit: item.children, depth: depth + 1, parent: item }\" />\n }\n\n @if (canAdd(item, depth)) {\n <div class=\"d-flex-h justify-end\">\n <cw-button class=\"ddn-list-add\" [type]=\"buttonType.link\" [withIcon]=\"spriteIcon.add\"\n [iconPosition]=\"buttonPosition.left\" [label]=\"column()?.addLabel ?? '_COMMON._ACTION.ADD'\"\n [isDisabled]=\"isLevelFull(item.children ?? [], depth + 1)\" (btnAction)=\"onAdd(item, depth + 1)\" />\n </div>\n }\n }\n </cw-card>\n </li>\n }\n\n </ul>\n</ng-template>\n" }]
349
425
  }], ctorParameters: () => [], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], itemTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemTemplate", required: false }] }], column: [{ type: i0.Input, args: [{ isSignal: true, alias: "column", required: false }] }], reorderOnDrop: [{ type: i0.Input, args: [{ isSignal: true, alias: "reorderOnDrop", required: false }] }], maxDepth: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxDepth", required: false }] }], selectedId: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedId", required: false }] }], itemsChange: [{ type: i0.Output, args: ["itemsChange"] }], view: [{ type: i0.Output, args: ["view"] }], edit: [{ type: i0.Output, args: ["edit"] }], delete: [{ type: i0.Output, args: ["delete"] }], restore: [{ type: i0.Output, args: ["restore"] }], add: [{ type: i0.Output, args: ["add"] }] } });
350
426
 
351
427
  class PaginationComponent {
@@ -771,7 +847,7 @@ class TableComponent {
771
847
  return typeof descriptor.link === 'function' ? descriptor.link(row) : descriptor.link;
772
848
  }
773
849
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.20", ngImport: i0, type: TableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
774
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.20", type: TableComponent, isStandalone: true, selector: "cw-table", inputs: { checkbox: { classPropertyName: "checkbox", publicName: "checkbox", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, rowClassFn: { classPropertyName: "rowClassFn", publicName: "rowClassFn", isSignal: true, isRequired: false, transformFunction: null }, pagination: { classPropertyName: "pagination", publicName: "pagination", isSignal: true, isRequired: false, transformFunction: null }, bulkActions: { classPropertyName: "bulkActions", publicName: "bulkActions", isSignal: true, isRequired: false, transformFunction: null }, rowActions: { classPropertyName: "rowActions", publicName: "rowActions", isSignal: true, isRequired: false, transformFunction: null }, emptyStateNoData: { classPropertyName: "emptyStateNoData", publicName: "emptyStateNoData", isSignal: true, isRequired: false, transformFunction: null }, emptyStateNoResult: { classPropertyName: "emptyStateNoResult", publicName: "emptyStateNoResult", isSignal: true, isRequired: false, transformFunction: null }, isFiltered: { classPropertyName: "isFiltered", publicName: "isFiltered", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { cellClick: "cellClick", sortChange: "sortChange", selectionChange: "selectionChange", paginationChange: "paginationChange", bulkDelete: "bulkDelete", bulkAction: "bulkAction" }, host: { classAttribute: "cw-table" }, queries: [{ propertyName: "actionsTemplate", first: true, predicate: ["actionsTemplate"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (checkbox() && selectedRows().size > 0) {\n <div class=\"table-selection-info mb-2 d-flex align-items-center gap-2 flex-wrap\">\n <span>\n {{ selectedRows().size }} {{ '_COMMON._TABLE._BULK_ACTION.SELECTED_ITEMS_CURRENT_PAGE' | translate }}\n </span>\n @for (action of bulkActions(); track $index) {\n <cw-button\n [type]=\"resolveVariant(action)\"\n [label]=\"action.label\"\n [withIcon]=\"action.icon\"\n [isDisabled]=\"resolveDisabled(action)\"\n (btnAction)=\"onBulkActionClick(action)\">\n </cw-button>\n }\n </div>\n}\n\n<div class=\"table-responsive\">\n <table class=\"table\">\n <caption class=\"visually-hidden\" [innerHTML]=\"'_COMMON._TABLE.CAPTION' | translate: { label: title() } \"></caption>\n <thead>\n <tr>\n @if(checkbox()) {\n <th scope=\"col\" width=\"10\">\n <div class=\"field-check\">\n <input class=\"field-check-input\" type=\"checkbox\" [id]=\"uid + '-all'\" [checked]=\"allSelected()\"\n [indeterminate]=\"someSelected()\" (change)=\"toggleAll()\">\n <label class=\"field-check-label\" [for]=\"uid + '-all'\">\n <span class=\"visually-hidden\">{{ '_COMMON._TABLE._THEAD.CHECK_LINE' | translate }}</span>\n </label>\n </div>\n </th>\n }\n\n @for (column of columns(); track column.key) {\n @if (!column.hidden) {\n <th scope=\"col\" [class.p-0]=\"column.sort\" [attr.aria-sort]=\"column.sort ? getAriaSort(column.key) : null\">\n @if (column.sort) {\n <button class=\"d-flex-h gap-2xs\" [class]=\"getSortClass(column.key)\" (click)=\"setSortProperty(column.key)\">\n {{ column.label | translate}}\n <cw-icon\n [icon]=\"getSortIcon(column.key)\"\n [label]=\"'_COMMON._TABLE._SORT.LABEL' | translate\"\n [type]=\"iconType.default\"\n [iconSize]=\"iconSize['xs']\"></cw-icon>\n </button>\n }\n @else {\n {{ column.label | translate }}\n }\n </th>\n }\n }\n </tr>\n </thead>\n <tbody>\n @if (loading()) {\n <tr>\n <td [attr.colspan]=\"visibleColumnCount()\">\n <cw-loader></cw-loader>\n </td>\n </tr>\n }\n @else if (!data() || data().length === 0) {\n <tr>\n <td class=\"table-info no-result\" [attr.colspan]=\"visibleColumnCount()\">\n @if (currentEmptyState(); as empty) {\n <cw-empty-state\n [illustration]=\"empty.illustration ?? (isFiltered() ? illustrationEnum.noResult : illustrationEnum.noData)\"\n [imageSource]=\"empty.imageSource\"\n [title]=\"empty.title\"\n [description]=\"empty.description\"\n [primaryButton]=\"empty.primaryButton\"\n [secondaryButton]=\"empty.secondaryButton\"\n (primaryClick)=\"empty.primaryButton?.click?.()\"\n (secondaryClick)=\"empty.secondaryButton?.click?.()\">\n </cw-empty-state>\n } @else {\n {{ '_COMMON._TABLE.NO_RESULT' | translate }}\n }\n </td>\n </tr>\n }\n @else {\n @for (row of data(); track row) {\n <tr [class.tr-selected]=\"isSelected(row)\" [class]=\"getRowClass(row)\">\n @if (checkbox()) {\n <td>\n <input class=\"field-check-input\" type=\"checkbox\" [checked]=\"isSelected(row)\" (change)=\"toggleRow(row)\" [id]=\"uid + '-check-' + row.id\"\n [attr.aria-label]=\"('_COMMON._TABLE._THEAD.CHECK_LINE' | translate) + ' ' + row.id\">\n <label class=\"visually-hidden\" [for]=\"uid + '-check-' + row.id\">{{ '_COMMON._TABLE._THEAD.CHECK_LINE' | translate }} {{ row.id }}</label>\n </td>\n }\n @for (column of columns(); track column.key) {\n @if (!column.hidden) {\n <td [class.text-end]=\"column.align === 'right'\" [class.text-center]=\"column.align === 'center'\"\n [class.td-actions]=\"column.type === 'actions'\">\n @switch (column.type) {\n @case ('link') {\n <a href=\"javascript:void(0)\" (click)=\"onCellClick(row, column)\">\n {{ column.translate ? (row[column.key] | translate) : row[column.key] }}\n </a>\n }\n @case ('badge') {\n <cw-badge\n [type]=\"getBadge(column, row[column.key]).type\"\n [label]=\"getBadge(column, row[column.key]).label ?? row[column.key]\"\n [withIcon]=\"getBadge(column, row[column.key]).withIcon\"\n [iconPosition]=\"getBadge(column, row[column.key]).iconPosition\"></cw-badge>\n }\n @case ('icon') {\n @if (isClickable(column)) {\n <a href=\"javascript:void(0)\" (click)=\"onCellClick(row, column)\" [attr.aria-label]=\"row[column.key].label\">\n <cw-icon\n [icon]=\"row[column.key].icon\"\n [label]=\"row[column.key].label\"\n [type]=\"iconType.default\"\n [iconSize]=\"iconSize['md']\"\n [iconCssClass]=\"row[column.key].iconCssClass\"\n ></cw-icon>\n </a>\n } @else {\n <cw-icon\n [icon]=\"row[column.key].icon\"\n [label]=\"row[column.key].label\"\n [type]=\"iconType.default\"\n [iconSize]=\"iconSize['md']\"\n [iconCssClass]=\"row[column.key].iconCssClass\"\n ></cw-icon>\n }\n }\n @case ('image') {\n @if (isClickable(column)) {\n <a href=\"javascript:void(0)\" (click)=\"onCellClick(row, column)\" [attr.aria-label]=\"row[column.key].label\">\n <cw-image\n [source]=\"row[column.key].source\"\n [alt]=\"row[column.key].label\"\n [isAriaHidden]=\"true\"\n [cssClass]=\"row[column.key].iconCssClass\"\n width=\"32\"\n height=\"32\"\n ></cw-image>\n </a>\n } @else {\n <cw-image\n [source]=\"row[column.key].source\"\n [alt]=\"row[column.key].label\"\n [isAriaHidden]=\"true\"\n [cssClass]=\"row[column.key].iconCssClass\"\n width=\"32\"\n height=\"32\"\n ></cw-image>\n }\n }\n @case ('check') {\n @if (isTruthy(row[column.key])) {\n <cw-icon\n [icon]=\"spriteIcon.checkCircle\"\n [label]=\"'_COMMON._PRO_SENTENCE.YES' | translate\"\n [type]=\"iconType.default\"\n iconCssClass=\"text-success\"\n [iconSize]=\"iconSize['md']\"></cw-icon>\n } @else {\n <cw-icon\n [icon]=\"spriteIcon.closeCircle\"\n [label]=\"'_COMMON._PRO_SENTENCE.NO' | translate\"\n [type]=\"iconType.default\"\n iconCssClass=\"text-danger\"\n [iconSize]=\"iconSize['md']\"></cw-icon>\n }\n }\n @case ('progressbar') {\n <div class=\"td-progressbar\">\n <cw-progress-bar\n [value]=\"row[column.key]\"\n [size]=\"progressBarSize.sm\"\n [type]=\"progressBarType.information\"></cw-progress-bar>\n <span class=\"td-progressbar-value\">{{ row[column.key] }}%</span>\n </div>\n }\n @case ('actions') {\n @if (usingRowActions) {\n @let actions = getResolvedActions(row);\n @if (actions.length > 0) {\n @if (!useDropdownActions()) {\n @for (action of actions; track $index) {\n <cw-button\n [type]=\"buttonType.ghost\"\n [label]=\"action.label\"\n [withIcon]=\"action.icon\"\n [link]=\"action.link\"\n [isDisabled]=\"action.disabled\"\n [cssClass]=\"actionCssClass(action)\"\n (btnAction)=\"onRowActionClick(action, row)\">\n </cw-button>\n }\n } @else {\n <cw-button\n [label]=\"'_COMMON._TABLE.ACTIONS_MENU'\"\n [withIcon]=\"spriteIcon.menuVertical\"\n [withOnlyIcon]=\"true\"\n [type]=\"buttonType.ghost\"\n [isDropdown]=\"true\"\n [hideCaret]=\"true\">\n <ul class=\"p-0 m-0\">\n @for (action of actions; track $index) {\n <li>\n @if (action.link) {\n <cw-button\n [type]=\"buttonType.ghost\"\n [label]=\"action.label\"\n [withIcon]=\"action.icon\"\n [link]=\"action.link\"\n [isDisabled]=\"action.disabled\"\n [cssClass]=\"'dropdown-item ' + actionCssClass(action)\">\n </cw-button>\n } @else {\n <cw-button\n [type]=\"buttonType.ghost\"\n [label]=\"action.label\"\n [withIcon]=\"action.icon\"\n [isDisabled]=\"action.disabled\"\n [cssClass]=\"'dropdown-item ' + actionCssClass(action)\"\n (btnAction)=\"onRowActionClick(action, row)\">\n </cw-button>\n }\n </li>\n }\n </ul>\n </cw-button>\n }\n }\n } @else {\n <ng-container\n *ngTemplateOutlet=\"actionsTemplate(); context: { $implicit: row }\">\n </ng-container>\n }\n }\n @default {\n {{ column.translate ? (row[column.key] | translate) : row[column.key] }}\n }\n }\n </td>\n }\n }\n </tr>\n }\n }\n </tbody>\n </table>\n</div>\n\n@if (pagination()) {\n <cw-pagination\n [pagination]=\"pagination()!\"\n (paginationChange)=\"paginationChange.emit($event)\">\n </cw-pagination>\n}\n", dependencies: [{ kind: "ngmodule", type: TranslateModule }, { kind: "component", type: LoaderComponent, selector: "cw-loader", inputs: ["size", "displayText"] }, { kind: "component", type: BadgeComponent, selector: "cw-badge", inputs: ["type", "label", "withIcon", "iconPosition", "cssClass", "skeletonMode", "dataTest"] }, { kind: "component", type: ButtonComponent, selector: "cw-button", inputs: ["type", "label", "id", "link", "isDropdown", "hideCaret", "withIcon", "withOnlyIcon", "iconSize", "iconPosition", "dropdownPosition", "isMinWidth", "isDisabled", "isLoading", "loadingAnnounce", "cssClass", "dataTest", "skeletonMode", "withTooltip", "tooltipText", "tooltipTitle", "tooltipTrigger", "tooltipPosition", "tooltipType"], outputs: ["btnAction", "dropDownClicked"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: PaginationComponent, selector: "cw-pagination", inputs: ["pagination"], outputs: ["paginationChange"] }, { kind: "component", type: IconComponent, selector: "cw-icon", inputs: ["icon", "label", "type", "iconSize", "iconCssClass", "iconUiType", "iconColorCustom", "spritePath"] }, { kind: "component", type: ImageComponent, selector: "cw-image", inputs: ["source", "alt", "isAriaHidden", "cssClass", "width", "height"] }, { kind: "component", type: EmptyStateComponent, selector: "cw-empty-state", inputs: ["illustration", "illustrationBasePath", "imageSource", "imageAlt", "title", "description", "primaryButton", "secondaryButton", "dataTest"], outputs: ["primaryClick", "secondaryClick"] }, { kind: "component", type: ProgressBarComponent, selector: "cw-progress-bar", inputs: ["value", "max", "size", "type", "showValue", "label", "dataTest"] }, { kind: "pipe", type: i1.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
850
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.20", type: TableComponent, isStandalone: true, selector: "cw-table", inputs: { checkbox: { classPropertyName: "checkbox", publicName: "checkbox", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, rowClassFn: { classPropertyName: "rowClassFn", publicName: "rowClassFn", isSignal: true, isRequired: false, transformFunction: null }, pagination: { classPropertyName: "pagination", publicName: "pagination", isSignal: true, isRequired: false, transformFunction: null }, bulkActions: { classPropertyName: "bulkActions", publicName: "bulkActions", isSignal: true, isRequired: false, transformFunction: null }, rowActions: { classPropertyName: "rowActions", publicName: "rowActions", isSignal: true, isRequired: false, transformFunction: null }, emptyStateNoData: { classPropertyName: "emptyStateNoData", publicName: "emptyStateNoData", isSignal: true, isRequired: false, transformFunction: null }, emptyStateNoResult: { classPropertyName: "emptyStateNoResult", publicName: "emptyStateNoResult", isSignal: true, isRequired: false, transformFunction: null }, isFiltered: { classPropertyName: "isFiltered", publicName: "isFiltered", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { cellClick: "cellClick", sortChange: "sortChange", selectionChange: "selectionChange", paginationChange: "paginationChange", bulkDelete: "bulkDelete", bulkAction: "bulkAction" }, host: { classAttribute: "cw-table" }, queries: [{ propertyName: "actionsTemplate", first: true, predicate: ["actionsTemplate"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (checkbox() && selectedRows().size > 0) {\n <!-- Espacement DS : gap-md = 16px = component/button/set/gap (espacement entre\n boutons d'un set). Utilitaires basic-ui (adosses a l'echelle $sizing des\n tokens) et non ceux de Bootstrap : gap-2 valait 8px. d-flex-h centre deja\n verticalement, align-items-center est donc inutile. -->\n <div class=\"table-selection-info mb-md d-flex-h gap-md flex-wrap\">\n <span class=\"flex-grow-1\">\n {{ selectedRows().size }} {{ '_COMMON._TABLE._BULK_ACTION.SELECTED_ITEMS_CURRENT_PAGE' | translate }}\n </span>\n @for (action of bulkActions(); track $index) {\n <cw-button\n [type]=\"resolveVariant(action)\"\n [label]=\"action.label\"\n [withIcon]=\"action.icon\"\n [isDisabled]=\"resolveDisabled(action)\"\n (btnAction)=\"onBulkActionClick(action)\">\n </cw-button>\n }\n </div>\n}\n\n<div class=\"table-responsive\">\n <table class=\"table\">\n <caption class=\"visually-hidden\" [innerHTML]=\"'_COMMON._TABLE.CAPTION' | translate: { label: title() } \"></caption>\n <thead>\n <tr>\n @if(checkbox()) {\n <th scope=\"col\" width=\"10\">\n <div class=\"field-check\">\n <input class=\"field-check-input\" type=\"checkbox\" [id]=\"uid + '-all'\" [checked]=\"allSelected()\"\n [indeterminate]=\"someSelected()\" (change)=\"toggleAll()\">\n <label class=\"field-check-label\" [for]=\"uid + '-all'\">\n <span class=\"visually-hidden\">{{ '_COMMON._TABLE._THEAD.CHECK_LINE' | translate }}</span>\n </label>\n </div>\n </th>\n }\n\n @for (column of columns(); track column.key) {\n @if (!column.hidden) {\n <th scope=\"col\" [class.p-0]=\"column.sort\" [attr.aria-sort]=\"column.sort ? getAriaSort(column.key) : null\">\n @if (column.sort) {\n <button class=\"d-flex-h gap-2xs\" [class]=\"getSortClass(column.key)\" (click)=\"setSortProperty(column.key)\">\n {{ column.label | translate}}\n <cw-icon\n [icon]=\"getSortIcon(column.key)\"\n [label]=\"'_COMMON._TABLE._SORT.LABEL' | translate\"\n [type]=\"iconType.default\"\n [iconSize]=\"iconSize['xs']\"></cw-icon>\n </button>\n }\n @else {\n {{ column.label | translate }}\n }\n </th>\n }\n }\n </tr>\n </thead>\n <tbody>\n @if (loading()) {\n <tr>\n <td [attr.colspan]=\"visibleColumnCount()\">\n <cw-loader></cw-loader>\n </td>\n </tr>\n }\n @else if (!data() || data().length === 0) {\n <tr>\n <td class=\"table-info no-result\" [attr.colspan]=\"visibleColumnCount()\">\n @if (currentEmptyState(); as empty) {\n <cw-empty-state\n [illustration]=\"empty.illustration ?? (isFiltered() ? illustrationEnum.noResult : illustrationEnum.noData)\"\n [imageSource]=\"empty.imageSource\"\n [title]=\"empty.title\"\n [description]=\"empty.description\"\n [primaryButton]=\"empty.primaryButton\"\n [secondaryButton]=\"empty.secondaryButton\"\n (primaryClick)=\"empty.primaryButton?.click?.()\"\n (secondaryClick)=\"empty.secondaryButton?.click?.()\">\n </cw-empty-state>\n } @else {\n {{ '_COMMON._TABLE.NO_RESULT' | translate }}\n }\n </td>\n </tr>\n }\n @else {\n @for (row of data(); track row) {\n <tr [class.tr-selected]=\"isSelected(row)\" [class]=\"getRowClass(row)\">\n @if (checkbox()) {\n <td>\n <input class=\"field-check-input\" type=\"checkbox\" [checked]=\"isSelected(row)\" (change)=\"toggleRow(row)\" [id]=\"uid + '-check-' + row.id\"\n [attr.aria-label]=\"('_COMMON._TABLE._THEAD.CHECK_LINE' | translate) + ' ' + row.id\">\n <label class=\"visually-hidden\" [for]=\"uid + '-check-' + row.id\">{{ '_COMMON._TABLE._THEAD.CHECK_LINE' | translate }} {{ row.id }}</label>\n </td>\n }\n @for (column of columns(); track column.key) {\n @if (!column.hidden) {\n <td [class.text-end]=\"column.align === 'right'\" [class.text-center]=\"column.align === 'center'\"\n [class.td-actions]=\"column.type === 'actions'\">\n @switch (column.type) {\n @case ('link') {\n <a href=\"javascript:void(0)\" (click)=\"onCellClick(row, column)\">\n {{ column.translate ? (row[column.key] | translate) : row[column.key] }}\n </a>\n }\n @case ('badge') {\n <cw-badge\n [type]=\"getBadge(column, row[column.key]).type\"\n [label]=\"getBadge(column, row[column.key]).label ?? row[column.key]\"\n [withIcon]=\"getBadge(column, row[column.key]).withIcon\"\n [iconPosition]=\"getBadge(column, row[column.key]).iconPosition\"></cw-badge>\n }\n @case ('icon') {\n @if (isClickable(column)) {\n <a href=\"javascript:void(0)\" (click)=\"onCellClick(row, column)\" [attr.aria-label]=\"row[column.key].label\">\n <cw-icon\n [icon]=\"row[column.key].icon\"\n [label]=\"row[column.key].label\"\n [type]=\"iconType.default\"\n [iconSize]=\"iconSize['md']\"\n [iconCssClass]=\"row[column.key].iconCssClass\"\n ></cw-icon>\n </a>\n } @else {\n <cw-icon\n [icon]=\"row[column.key].icon\"\n [label]=\"row[column.key].label\"\n [type]=\"iconType.default\"\n [iconSize]=\"iconSize['md']\"\n [iconCssClass]=\"row[column.key].iconCssClass\"\n ></cw-icon>\n }\n }\n @case ('image') {\n @if (isClickable(column)) {\n <a href=\"javascript:void(0)\" (click)=\"onCellClick(row, column)\" [attr.aria-label]=\"row[column.key].label\">\n <cw-image\n [source]=\"row[column.key].source\"\n [alt]=\"row[column.key].label\"\n [isAriaHidden]=\"true\"\n [cssClass]=\"row[column.key].iconCssClass\"\n width=\"32\"\n height=\"32\"\n ></cw-image>\n </a>\n } @else {\n <cw-image\n [source]=\"row[column.key].source\"\n [alt]=\"row[column.key].label\"\n [isAriaHidden]=\"true\"\n [cssClass]=\"row[column.key].iconCssClass\"\n width=\"32\"\n height=\"32\"\n ></cw-image>\n }\n }\n @case ('check') {\n @if (isTruthy(row[column.key])) {\n <cw-icon\n [icon]=\"spriteIcon.checkCircle\"\n [label]=\"'_COMMON._PRO_SENTENCE.YES' | translate\"\n [type]=\"iconType.default\"\n iconCssClass=\"text-success\"\n [iconSize]=\"iconSize['md']\"></cw-icon>\n } @else {\n <cw-icon\n [icon]=\"spriteIcon.closeCircle\"\n [label]=\"'_COMMON._PRO_SENTENCE.NO' | translate\"\n [type]=\"iconType.default\"\n iconCssClass=\"text-danger\"\n [iconSize]=\"iconSize['md']\"></cw-icon>\n }\n }\n @case ('progressbar') {\n <div class=\"td-progressbar\">\n <cw-progress-bar\n [value]=\"row[column.key]\"\n [size]=\"progressBarSize.sm\"\n [type]=\"progressBarType.information\"></cw-progress-bar>\n <span class=\"td-progressbar-value\">{{ row[column.key] }}%</span>\n </div>\n }\n @case ('actions') {\n @if (usingRowActions) {\n @let actions = getResolvedActions(row);\n @if (actions.length > 0) {\n @if (!useDropdownActions()) {\n @for (action of actions; track $index) {\n <cw-button\n [type]=\"buttonType.ghost\"\n [label]=\"action.label\"\n [withIcon]=\"action.icon\"\n [link]=\"action.link\"\n [isDisabled]=\"action.disabled\"\n [cssClass]=\"actionCssClass(action)\"\n (btnAction)=\"onRowActionClick(action, row)\">\n </cw-button>\n }\n } @else {\n <cw-button\n [label]=\"'_COMMON._TABLE.ACTIONS_MENU'\"\n [withIcon]=\"spriteIcon.menuVertical\"\n [withOnlyIcon]=\"true\"\n [type]=\"buttonType.ghost\"\n [isDropdown]=\"true\"\n [hideCaret]=\"true\">\n <ul class=\"p-0 m-0\">\n @for (action of actions; track $index) {\n <li>\n @if (action.link) {\n <cw-button\n [type]=\"buttonType.ghost\"\n [label]=\"action.label\"\n [withIcon]=\"action.icon\"\n [link]=\"action.link\"\n [isDisabled]=\"action.disabled\"\n [cssClass]=\"'dropdown-item ' + actionCssClass(action)\">\n </cw-button>\n } @else {\n <cw-button\n [type]=\"buttonType.ghost\"\n [label]=\"action.label\"\n [withIcon]=\"action.icon\"\n [isDisabled]=\"action.disabled\"\n [cssClass]=\"'dropdown-item ' + actionCssClass(action)\"\n (btnAction)=\"onRowActionClick(action, row)\">\n </cw-button>\n }\n </li>\n }\n </ul>\n </cw-button>\n }\n }\n } @else {\n <ng-container\n *ngTemplateOutlet=\"actionsTemplate(); context: { $implicit: row }\">\n </ng-container>\n }\n }\n @default {\n {{ column.translate ? (row[column.key] | translate) : row[column.key] }}\n }\n }\n </td>\n }\n }\n </tr>\n }\n }\n </tbody>\n </table>\n</div>\n\n@if (pagination()) {\n <cw-pagination\n [pagination]=\"pagination()!\"\n (paginationChange)=\"paginationChange.emit($event)\">\n </cw-pagination>\n}\n", dependencies: [{ kind: "ngmodule", type: TranslateModule }, { kind: "component", type: LoaderComponent, selector: "cw-loader", inputs: ["size", "displayText"] }, { kind: "component", type: BadgeComponent, selector: "cw-badge", inputs: ["type", "label", "withIcon", "iconPosition", "cssClass", "skeletonMode", "dataTest"] }, { kind: "component", type: ButtonComponent, selector: "cw-button", inputs: ["type", "label", "id", "link", "isDropdown", "hideCaret", "withIcon", "withOnlyIcon", "iconSize", "iconPosition", "dropdownPosition", "isMinWidth", "isDisabled", "isLoading", "loadingAnnounce", "cssClass", "dataTest", "skeletonMode", "withTooltip", "tooltipText", "tooltipTitle", "tooltipTrigger", "tooltipPosition", "tooltipType"], outputs: ["btnAction", "dropDownClicked"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: PaginationComponent, selector: "cw-pagination", inputs: ["pagination"], outputs: ["paginationChange"] }, { kind: "component", type: IconComponent, selector: "cw-icon", inputs: ["icon", "label", "type", "iconSize", "iconCssClass", "iconUiType", "iconColorCustom", "spritePath"] }, { kind: "component", type: ImageComponent, selector: "cw-image", inputs: ["source", "alt", "isAriaHidden", "cssClass", "width", "height"] }, { kind: "component", type: EmptyStateComponent, selector: "cw-empty-state", inputs: ["illustration", "illustrationBasePath", "imageSource", "imageAlt", "title", "description", "primaryButton", "secondaryButton", "dataTest"], outputs: ["primaryClick", "secondaryClick"] }, { kind: "component", type: ProgressBarComponent, selector: "cw-progress-bar", inputs: ["value", "max", "size", "type", "showValue", "label", "dataTest"] }, { kind: "pipe", type: i1.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
775
851
  }
776
852
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.20", ngImport: i0, type: TableComponent, decorators: [{
777
853
  type: Component,
@@ -786,7 +862,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.20", ngImpo
786
862
  ImageComponent,
787
863
  EmptyStateComponent,
788
864
  ProgressBarComponent
789
- ], template: "@if (checkbox() && selectedRows().size > 0) {\n <div class=\"table-selection-info mb-2 d-flex align-items-center gap-2 flex-wrap\">\n <span>\n {{ selectedRows().size }} {{ '_COMMON._TABLE._BULK_ACTION.SELECTED_ITEMS_CURRENT_PAGE' | translate }}\n </span>\n @for (action of bulkActions(); track $index) {\n <cw-button\n [type]=\"resolveVariant(action)\"\n [label]=\"action.label\"\n [withIcon]=\"action.icon\"\n [isDisabled]=\"resolveDisabled(action)\"\n (btnAction)=\"onBulkActionClick(action)\">\n </cw-button>\n }\n </div>\n}\n\n<div class=\"table-responsive\">\n <table class=\"table\">\n <caption class=\"visually-hidden\" [innerHTML]=\"'_COMMON._TABLE.CAPTION' | translate: { label: title() } \"></caption>\n <thead>\n <tr>\n @if(checkbox()) {\n <th scope=\"col\" width=\"10\">\n <div class=\"field-check\">\n <input class=\"field-check-input\" type=\"checkbox\" [id]=\"uid + '-all'\" [checked]=\"allSelected()\"\n [indeterminate]=\"someSelected()\" (change)=\"toggleAll()\">\n <label class=\"field-check-label\" [for]=\"uid + '-all'\">\n <span class=\"visually-hidden\">{{ '_COMMON._TABLE._THEAD.CHECK_LINE' | translate }}</span>\n </label>\n </div>\n </th>\n }\n\n @for (column of columns(); track column.key) {\n @if (!column.hidden) {\n <th scope=\"col\" [class.p-0]=\"column.sort\" [attr.aria-sort]=\"column.sort ? getAriaSort(column.key) : null\">\n @if (column.sort) {\n <button class=\"d-flex-h gap-2xs\" [class]=\"getSortClass(column.key)\" (click)=\"setSortProperty(column.key)\">\n {{ column.label | translate}}\n <cw-icon\n [icon]=\"getSortIcon(column.key)\"\n [label]=\"'_COMMON._TABLE._SORT.LABEL' | translate\"\n [type]=\"iconType.default\"\n [iconSize]=\"iconSize['xs']\"></cw-icon>\n </button>\n }\n @else {\n {{ column.label | translate }}\n }\n </th>\n }\n }\n </tr>\n </thead>\n <tbody>\n @if (loading()) {\n <tr>\n <td [attr.colspan]=\"visibleColumnCount()\">\n <cw-loader></cw-loader>\n </td>\n </tr>\n }\n @else if (!data() || data().length === 0) {\n <tr>\n <td class=\"table-info no-result\" [attr.colspan]=\"visibleColumnCount()\">\n @if (currentEmptyState(); as empty) {\n <cw-empty-state\n [illustration]=\"empty.illustration ?? (isFiltered() ? illustrationEnum.noResult : illustrationEnum.noData)\"\n [imageSource]=\"empty.imageSource\"\n [title]=\"empty.title\"\n [description]=\"empty.description\"\n [primaryButton]=\"empty.primaryButton\"\n [secondaryButton]=\"empty.secondaryButton\"\n (primaryClick)=\"empty.primaryButton?.click?.()\"\n (secondaryClick)=\"empty.secondaryButton?.click?.()\">\n </cw-empty-state>\n } @else {\n {{ '_COMMON._TABLE.NO_RESULT' | translate }}\n }\n </td>\n </tr>\n }\n @else {\n @for (row of data(); track row) {\n <tr [class.tr-selected]=\"isSelected(row)\" [class]=\"getRowClass(row)\">\n @if (checkbox()) {\n <td>\n <input class=\"field-check-input\" type=\"checkbox\" [checked]=\"isSelected(row)\" (change)=\"toggleRow(row)\" [id]=\"uid + '-check-' + row.id\"\n [attr.aria-label]=\"('_COMMON._TABLE._THEAD.CHECK_LINE' | translate) + ' ' + row.id\">\n <label class=\"visually-hidden\" [for]=\"uid + '-check-' + row.id\">{{ '_COMMON._TABLE._THEAD.CHECK_LINE' | translate }} {{ row.id }}</label>\n </td>\n }\n @for (column of columns(); track column.key) {\n @if (!column.hidden) {\n <td [class.text-end]=\"column.align === 'right'\" [class.text-center]=\"column.align === 'center'\"\n [class.td-actions]=\"column.type === 'actions'\">\n @switch (column.type) {\n @case ('link') {\n <a href=\"javascript:void(0)\" (click)=\"onCellClick(row, column)\">\n {{ column.translate ? (row[column.key] | translate) : row[column.key] }}\n </a>\n }\n @case ('badge') {\n <cw-badge\n [type]=\"getBadge(column, row[column.key]).type\"\n [label]=\"getBadge(column, row[column.key]).label ?? row[column.key]\"\n [withIcon]=\"getBadge(column, row[column.key]).withIcon\"\n [iconPosition]=\"getBadge(column, row[column.key]).iconPosition\"></cw-badge>\n }\n @case ('icon') {\n @if (isClickable(column)) {\n <a href=\"javascript:void(0)\" (click)=\"onCellClick(row, column)\" [attr.aria-label]=\"row[column.key].label\">\n <cw-icon\n [icon]=\"row[column.key].icon\"\n [label]=\"row[column.key].label\"\n [type]=\"iconType.default\"\n [iconSize]=\"iconSize['md']\"\n [iconCssClass]=\"row[column.key].iconCssClass\"\n ></cw-icon>\n </a>\n } @else {\n <cw-icon\n [icon]=\"row[column.key].icon\"\n [label]=\"row[column.key].label\"\n [type]=\"iconType.default\"\n [iconSize]=\"iconSize['md']\"\n [iconCssClass]=\"row[column.key].iconCssClass\"\n ></cw-icon>\n }\n }\n @case ('image') {\n @if (isClickable(column)) {\n <a href=\"javascript:void(0)\" (click)=\"onCellClick(row, column)\" [attr.aria-label]=\"row[column.key].label\">\n <cw-image\n [source]=\"row[column.key].source\"\n [alt]=\"row[column.key].label\"\n [isAriaHidden]=\"true\"\n [cssClass]=\"row[column.key].iconCssClass\"\n width=\"32\"\n height=\"32\"\n ></cw-image>\n </a>\n } @else {\n <cw-image\n [source]=\"row[column.key].source\"\n [alt]=\"row[column.key].label\"\n [isAriaHidden]=\"true\"\n [cssClass]=\"row[column.key].iconCssClass\"\n width=\"32\"\n height=\"32\"\n ></cw-image>\n }\n }\n @case ('check') {\n @if (isTruthy(row[column.key])) {\n <cw-icon\n [icon]=\"spriteIcon.checkCircle\"\n [label]=\"'_COMMON._PRO_SENTENCE.YES' | translate\"\n [type]=\"iconType.default\"\n iconCssClass=\"text-success\"\n [iconSize]=\"iconSize['md']\"></cw-icon>\n } @else {\n <cw-icon\n [icon]=\"spriteIcon.closeCircle\"\n [label]=\"'_COMMON._PRO_SENTENCE.NO' | translate\"\n [type]=\"iconType.default\"\n iconCssClass=\"text-danger\"\n [iconSize]=\"iconSize['md']\"></cw-icon>\n }\n }\n @case ('progressbar') {\n <div class=\"td-progressbar\">\n <cw-progress-bar\n [value]=\"row[column.key]\"\n [size]=\"progressBarSize.sm\"\n [type]=\"progressBarType.information\"></cw-progress-bar>\n <span class=\"td-progressbar-value\">{{ row[column.key] }}%</span>\n </div>\n }\n @case ('actions') {\n @if (usingRowActions) {\n @let actions = getResolvedActions(row);\n @if (actions.length > 0) {\n @if (!useDropdownActions()) {\n @for (action of actions; track $index) {\n <cw-button\n [type]=\"buttonType.ghost\"\n [label]=\"action.label\"\n [withIcon]=\"action.icon\"\n [link]=\"action.link\"\n [isDisabled]=\"action.disabled\"\n [cssClass]=\"actionCssClass(action)\"\n (btnAction)=\"onRowActionClick(action, row)\">\n </cw-button>\n }\n } @else {\n <cw-button\n [label]=\"'_COMMON._TABLE.ACTIONS_MENU'\"\n [withIcon]=\"spriteIcon.menuVertical\"\n [withOnlyIcon]=\"true\"\n [type]=\"buttonType.ghost\"\n [isDropdown]=\"true\"\n [hideCaret]=\"true\">\n <ul class=\"p-0 m-0\">\n @for (action of actions; track $index) {\n <li>\n @if (action.link) {\n <cw-button\n [type]=\"buttonType.ghost\"\n [label]=\"action.label\"\n [withIcon]=\"action.icon\"\n [link]=\"action.link\"\n [isDisabled]=\"action.disabled\"\n [cssClass]=\"'dropdown-item ' + actionCssClass(action)\">\n </cw-button>\n } @else {\n <cw-button\n [type]=\"buttonType.ghost\"\n [label]=\"action.label\"\n [withIcon]=\"action.icon\"\n [isDisabled]=\"action.disabled\"\n [cssClass]=\"'dropdown-item ' + actionCssClass(action)\"\n (btnAction)=\"onRowActionClick(action, row)\">\n </cw-button>\n }\n </li>\n }\n </ul>\n </cw-button>\n }\n }\n } @else {\n <ng-container\n *ngTemplateOutlet=\"actionsTemplate(); context: { $implicit: row }\">\n </ng-container>\n }\n }\n @default {\n {{ column.translate ? (row[column.key] | translate) : row[column.key] }}\n }\n }\n </td>\n }\n }\n </tr>\n }\n }\n </tbody>\n </table>\n</div>\n\n@if (pagination()) {\n <cw-pagination\n [pagination]=\"pagination()!\"\n (paginationChange)=\"paginationChange.emit($event)\">\n </cw-pagination>\n}\n" }]
865
+ ], template: "@if (checkbox() && selectedRows().size > 0) {\n <!-- Espacement DS : gap-md = 16px = component/button/set/gap (espacement entre\n boutons d'un set). Utilitaires basic-ui (adosses a l'echelle $sizing des\n tokens) et non ceux de Bootstrap : gap-2 valait 8px. d-flex-h centre deja\n verticalement, align-items-center est donc inutile. -->\n <div class=\"table-selection-info mb-md d-flex-h gap-md flex-wrap\">\n <span class=\"flex-grow-1\">\n {{ selectedRows().size }} {{ '_COMMON._TABLE._BULK_ACTION.SELECTED_ITEMS_CURRENT_PAGE' | translate }}\n </span>\n @for (action of bulkActions(); track $index) {\n <cw-button\n [type]=\"resolveVariant(action)\"\n [label]=\"action.label\"\n [withIcon]=\"action.icon\"\n [isDisabled]=\"resolveDisabled(action)\"\n (btnAction)=\"onBulkActionClick(action)\">\n </cw-button>\n }\n </div>\n}\n\n<div class=\"table-responsive\">\n <table class=\"table\">\n <caption class=\"visually-hidden\" [innerHTML]=\"'_COMMON._TABLE.CAPTION' | translate: { label: title() } \"></caption>\n <thead>\n <tr>\n @if(checkbox()) {\n <th scope=\"col\" width=\"10\">\n <div class=\"field-check\">\n <input class=\"field-check-input\" type=\"checkbox\" [id]=\"uid + '-all'\" [checked]=\"allSelected()\"\n [indeterminate]=\"someSelected()\" (change)=\"toggleAll()\">\n <label class=\"field-check-label\" [for]=\"uid + '-all'\">\n <span class=\"visually-hidden\">{{ '_COMMON._TABLE._THEAD.CHECK_LINE' | translate }}</span>\n </label>\n </div>\n </th>\n }\n\n @for (column of columns(); track column.key) {\n @if (!column.hidden) {\n <th scope=\"col\" [class.p-0]=\"column.sort\" [attr.aria-sort]=\"column.sort ? getAriaSort(column.key) : null\">\n @if (column.sort) {\n <button class=\"d-flex-h gap-2xs\" [class]=\"getSortClass(column.key)\" (click)=\"setSortProperty(column.key)\">\n {{ column.label | translate}}\n <cw-icon\n [icon]=\"getSortIcon(column.key)\"\n [label]=\"'_COMMON._TABLE._SORT.LABEL' | translate\"\n [type]=\"iconType.default\"\n [iconSize]=\"iconSize['xs']\"></cw-icon>\n </button>\n }\n @else {\n {{ column.label | translate }}\n }\n </th>\n }\n }\n </tr>\n </thead>\n <tbody>\n @if (loading()) {\n <tr>\n <td [attr.colspan]=\"visibleColumnCount()\">\n <cw-loader></cw-loader>\n </td>\n </tr>\n }\n @else if (!data() || data().length === 0) {\n <tr>\n <td class=\"table-info no-result\" [attr.colspan]=\"visibleColumnCount()\">\n @if (currentEmptyState(); as empty) {\n <cw-empty-state\n [illustration]=\"empty.illustration ?? (isFiltered() ? illustrationEnum.noResult : illustrationEnum.noData)\"\n [imageSource]=\"empty.imageSource\"\n [title]=\"empty.title\"\n [description]=\"empty.description\"\n [primaryButton]=\"empty.primaryButton\"\n [secondaryButton]=\"empty.secondaryButton\"\n (primaryClick)=\"empty.primaryButton?.click?.()\"\n (secondaryClick)=\"empty.secondaryButton?.click?.()\">\n </cw-empty-state>\n } @else {\n {{ '_COMMON._TABLE.NO_RESULT' | translate }}\n }\n </td>\n </tr>\n }\n @else {\n @for (row of data(); track row) {\n <tr [class.tr-selected]=\"isSelected(row)\" [class]=\"getRowClass(row)\">\n @if (checkbox()) {\n <td>\n <input class=\"field-check-input\" type=\"checkbox\" [checked]=\"isSelected(row)\" (change)=\"toggleRow(row)\" [id]=\"uid + '-check-' + row.id\"\n [attr.aria-label]=\"('_COMMON._TABLE._THEAD.CHECK_LINE' | translate) + ' ' + row.id\">\n <label class=\"visually-hidden\" [for]=\"uid + '-check-' + row.id\">{{ '_COMMON._TABLE._THEAD.CHECK_LINE' | translate }} {{ row.id }}</label>\n </td>\n }\n @for (column of columns(); track column.key) {\n @if (!column.hidden) {\n <td [class.text-end]=\"column.align === 'right'\" [class.text-center]=\"column.align === 'center'\"\n [class.td-actions]=\"column.type === 'actions'\">\n @switch (column.type) {\n @case ('link') {\n <a href=\"javascript:void(0)\" (click)=\"onCellClick(row, column)\">\n {{ column.translate ? (row[column.key] | translate) : row[column.key] }}\n </a>\n }\n @case ('badge') {\n <cw-badge\n [type]=\"getBadge(column, row[column.key]).type\"\n [label]=\"getBadge(column, row[column.key]).label ?? row[column.key]\"\n [withIcon]=\"getBadge(column, row[column.key]).withIcon\"\n [iconPosition]=\"getBadge(column, row[column.key]).iconPosition\"></cw-badge>\n }\n @case ('icon') {\n @if (isClickable(column)) {\n <a href=\"javascript:void(0)\" (click)=\"onCellClick(row, column)\" [attr.aria-label]=\"row[column.key].label\">\n <cw-icon\n [icon]=\"row[column.key].icon\"\n [label]=\"row[column.key].label\"\n [type]=\"iconType.default\"\n [iconSize]=\"iconSize['md']\"\n [iconCssClass]=\"row[column.key].iconCssClass\"\n ></cw-icon>\n </a>\n } @else {\n <cw-icon\n [icon]=\"row[column.key].icon\"\n [label]=\"row[column.key].label\"\n [type]=\"iconType.default\"\n [iconSize]=\"iconSize['md']\"\n [iconCssClass]=\"row[column.key].iconCssClass\"\n ></cw-icon>\n }\n }\n @case ('image') {\n @if (isClickable(column)) {\n <a href=\"javascript:void(0)\" (click)=\"onCellClick(row, column)\" [attr.aria-label]=\"row[column.key].label\">\n <cw-image\n [source]=\"row[column.key].source\"\n [alt]=\"row[column.key].label\"\n [isAriaHidden]=\"true\"\n [cssClass]=\"row[column.key].iconCssClass\"\n width=\"32\"\n height=\"32\"\n ></cw-image>\n </a>\n } @else {\n <cw-image\n [source]=\"row[column.key].source\"\n [alt]=\"row[column.key].label\"\n [isAriaHidden]=\"true\"\n [cssClass]=\"row[column.key].iconCssClass\"\n width=\"32\"\n height=\"32\"\n ></cw-image>\n }\n }\n @case ('check') {\n @if (isTruthy(row[column.key])) {\n <cw-icon\n [icon]=\"spriteIcon.checkCircle\"\n [label]=\"'_COMMON._PRO_SENTENCE.YES' | translate\"\n [type]=\"iconType.default\"\n iconCssClass=\"text-success\"\n [iconSize]=\"iconSize['md']\"></cw-icon>\n } @else {\n <cw-icon\n [icon]=\"spriteIcon.closeCircle\"\n [label]=\"'_COMMON._PRO_SENTENCE.NO' | translate\"\n [type]=\"iconType.default\"\n iconCssClass=\"text-danger\"\n [iconSize]=\"iconSize['md']\"></cw-icon>\n }\n }\n @case ('progressbar') {\n <div class=\"td-progressbar\">\n <cw-progress-bar\n [value]=\"row[column.key]\"\n [size]=\"progressBarSize.sm\"\n [type]=\"progressBarType.information\"></cw-progress-bar>\n <span class=\"td-progressbar-value\">{{ row[column.key] }}%</span>\n </div>\n }\n @case ('actions') {\n @if (usingRowActions) {\n @let actions = getResolvedActions(row);\n @if (actions.length > 0) {\n @if (!useDropdownActions()) {\n @for (action of actions; track $index) {\n <cw-button\n [type]=\"buttonType.ghost\"\n [label]=\"action.label\"\n [withIcon]=\"action.icon\"\n [link]=\"action.link\"\n [isDisabled]=\"action.disabled\"\n [cssClass]=\"actionCssClass(action)\"\n (btnAction)=\"onRowActionClick(action, row)\">\n </cw-button>\n }\n } @else {\n <cw-button\n [label]=\"'_COMMON._TABLE.ACTIONS_MENU'\"\n [withIcon]=\"spriteIcon.menuVertical\"\n [withOnlyIcon]=\"true\"\n [type]=\"buttonType.ghost\"\n [isDropdown]=\"true\"\n [hideCaret]=\"true\">\n <ul class=\"p-0 m-0\">\n @for (action of actions; track $index) {\n <li>\n @if (action.link) {\n <cw-button\n [type]=\"buttonType.ghost\"\n [label]=\"action.label\"\n [withIcon]=\"action.icon\"\n [link]=\"action.link\"\n [isDisabled]=\"action.disabled\"\n [cssClass]=\"'dropdown-item ' + actionCssClass(action)\">\n </cw-button>\n } @else {\n <cw-button\n [type]=\"buttonType.ghost\"\n [label]=\"action.label\"\n [withIcon]=\"action.icon\"\n [isDisabled]=\"action.disabled\"\n [cssClass]=\"'dropdown-item ' + actionCssClass(action)\"\n (btnAction)=\"onRowActionClick(action, row)\">\n </cw-button>\n }\n </li>\n }\n </ul>\n </cw-button>\n }\n }\n } @else {\n <ng-container\n *ngTemplateOutlet=\"actionsTemplate(); context: { $implicit: row }\">\n </ng-container>\n }\n }\n @default {\n {{ column.translate ? (row[column.key] | translate) : row[column.key] }}\n }\n }\n </td>\n }\n }\n </tr>\n }\n }\n </tbody>\n </table>\n</div>\n\n@if (pagination()) {\n <cw-pagination\n [pagination]=\"pagination()!\"\n (paginationChange)=\"paginationChange.emit($event)\">\n </cw-pagination>\n}\n" }]
790
866
  }], ctorParameters: () => [], propDecorators: { checkbox: [{ type: i0.Input, args: [{ isSignal: true, alias: "checkbox", required: false }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: false }] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], rowClassFn: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowClassFn", required: false }] }], pagination: [{ type: i0.Input, args: [{ isSignal: true, alias: "pagination", required: false }] }], bulkActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "bulkActions", required: false }] }], rowActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowActions", required: false }] }], emptyStateNoData: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyStateNoData", required: false }] }], emptyStateNoResult: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyStateNoResult", required: false }] }], isFiltered: [{ type: i0.Input, args: [{ isSignal: true, alias: "isFiltered", required: false }] }], cellClick: [{ type: i0.Output, args: ["cellClick"] }], sortChange: [{ type: i0.Output, args: ["sortChange"] }], selectionChange: [{ type: i0.Output, args: ["selectionChange"] }], paginationChange: [{ type: i0.Output, args: ["paginationChange"] }], bulkDelete: [{ type: i0.Output, args: ["bulkDelete"] }], bulkAction: [{ type: i0.Output, args: ["bulkAction"] }], actionsTemplate: [{ type: i0.ContentChild, args: ['actionsTemplate', { isSignal: true }] }] } });
791
867
 
792
868
  const RANGE_TYPES = new Set([