@sinequa/atomic-angular 2.4.1 → 2.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,7 +2,7 @@ import * as i0 from "@angular/core";
2
2
  import { ChangeDetectionStrategy, ChangeDetectorRef, Component, DOCUMENT, DestroyRef, Directive, ElementRef, EnvironmentInjector, HostBinding, HostListener, Inject, Injectable, InjectionToken, Injector, LOCALE_ID, Optional, Pipe, Service, TemplateRef, ViewEncapsulation, afterNextRender, afterRenderEffect, assertInInjectionContext, booleanAttribute, computed, contentChild, contentChildren, effect, inject, input, isDevMode, linkedSignal, makeEnvironmentProviders, model, numberAttribute, output, provideEnvironmentInitializer, resource, runInInjectionContext, signal, untracked, viewChild, viewChildren } from "@angular/core";
3
3
  import { BehaviorSubject, EMPTY, Subject, Subscription, catchError, debounceTime, filter, firstValueFrom, from, fromEvent, map, of, scan, shareReplay, switchMap, tap, throwError } from "rxjs";
4
4
  import { TranslocoPipe, TranslocoService, provideTranslocoScope } from "@jsverse/transloco";
5
- import { ArrowDownZaIcon, ArrowLeftIcon, ArrowRightFromBracketIcon, ArrowRightIcon, ArrowUpAzIcon, ArrowUpRightFromSquareIcon, ArrowsMaximizeIcon, AutocompleteComponent, AvatarComponent, AvatarFallbackComponent, AvatarImageComponent, BadgeComponent, BarsIcon, BellIcon, BookmarkIcon, BreakpointObserverService, ButtonComponent, CalendarDayIcon, CheckIcon, CheckboxComponent, ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon, ChevronsLeftIcon, ChevronsRightIcon, CircleCheckIcon, CommentIcon, CommentsIcon, DIALOG_REF, DesktopIcon, DialogBodyComponent, DialogComponent, DialogContentComponent, DialogDescriptionComponent, DialogFooterComponent, DialogHeaderComponent, DialogTitleComponent, DropdownDirective, EditIcon, EllipsisIcon, EllipsisVerticalIcon, EyeIcon, EyeSlashIcon, FileHTMLIcon, FileIcon, FileOutputIcon, FileSpreadsheetIcon, FileTextIcon, FilterIcon, FilterXIcon, FlagEnglishIcon, FlagFrenchIcon, FlagGermanIcon, FlashlightIcon, FolderIcon, FolderOpenIcon, FrownIcon, GearIcon, GitForkIcon, GlobeIcon, HighlighterIcon, HistoryIcon, HomeIcon, ImageIcon, InboxIcon, InfoCircleIcon, InputComponent, InputControlDirective, InputIconRightDirective, KbdComponent, KbdGroupComponent, KeyIcon, KeyboardIcon, LanguageIcon, LightbulbIcon, LightbulbSlashIcon, LinkComponent, ListComponent, ListFilterIcon, ListItemActionComponent, ListItemAvatarDirective, ListItemComponent, ListItemLeftDirective, ListItemTextComponent, LoadingCircleIcon, MagnifyingGlassIcon, MagnifyingGlassMinusIcon, MagnifyingGlassPlusIcon, MenuComponent, MenuContentComponent, MenuItemComponent, MenuTriggerDirective, MoonIcon, PaletteIcon, PaperclipIcon, PenToSquareIcon, PlusIcon, PopoverDirective, PresentationIcon, QuestionCircleIcon, RadioComponent, RobotIcon, SaveIcon, SearchBarComponent, SearchInputComponent, SelectComponent, SelectTriggerDirective, SendIcon, SheetBodyComponent, SheetComponent, SheetHeaderComponent, SlashIcon, SlidersIcon, SparklesIcon, SpinnerIcon, SquareCheckIcon, SquareIcon, SquareMinusIcon, StarIcon, SunBrightIcon, SwitchComponent, SyncIcon, TabComponent, TabListComponent, TabPanelComponent, TabsComponent, TagComponent, TagIcon, TagsIcon, TextareaComponent, TextareaControlDirective, ThumbsDownIcon, ThumbsUpIcon, ToggleComponent, ToggleGroupComponent, ToggleItemComponent, ToggleLeftIcon, ToggleRightIcon, TooltipDirective, TrashCanIcon, TrashIcon, TreeComponent, TreeItemComponent, TreeItemExpanderComponent, TreeItemGroupComponent, TriangleAlertIcon, UndoIcon, UserIcon, UserSecretIcon, VideoIcon, XMarkIcon, createCallable, injectCallRef } from "@sinequa/galactik";
5
+ import { ArrowDownIcon, ArrowDownZaIcon, ArrowLeftIcon, ArrowRightFromBracketIcon, ArrowRightIcon, ArrowUpAzIcon, ArrowUpIcon, ArrowUpRightFromSquareIcon, ArrowsMaximizeIcon, AutocompleteComponent, AvatarComponent, AvatarFallbackComponent, AvatarImageComponent, BadgeComponent, BarsIcon, BellIcon, BookmarkIcon, BreakpointObserverService, ButtonComponent, CalendarDayIcon, CheckIcon, CheckboxComponent, ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon, ChevronsLeftIcon, ChevronsRightIcon, CircleCheckIcon, CommentIcon, CommentsIcon, DIALOG_REF, DesktopIcon, DialogBodyComponent, DialogComponent, DialogContentComponent, DialogDescriptionComponent, DialogFooterComponent, DialogHeaderComponent, DialogTitleComponent, DropdownDirective, EditIcon, EllipsisIcon, EllipsisVerticalIcon, EyeIcon, EyeSlashIcon, FileHTMLIcon, FileIcon, FileOutputIcon, FileSpreadsheetIcon, FileTextIcon, FilterIcon, FilterXIcon, FlagEnglishIcon, FlagFrenchIcon, FlagGermanIcon, FlashlightIcon, FolderIcon, FolderOpenIcon, FrownIcon, GearIcon, GitForkIcon, GlobeIcon, HighlighterIcon, HistoryIcon, HomeIcon, ImageIcon, InboxIcon, InfoCircleIcon, InputComponent, InputControlDirective, InputIconRightDirective, KbdComponent, KbdGroupComponent, KeyIcon, KeyboardIcon, LanguageIcon, LightbulbIcon, LightbulbSlashIcon, LinkComponent, ListComponent, ListFilterIcon, ListItemActionComponent, ListItemAvatarDirective, ListItemComponent, ListItemLeftDirective, ListItemTextComponent, LoadingCircleIcon, MagnifyingGlassIcon, MagnifyingGlassMinusIcon, MagnifyingGlassPlusIcon, MenuComponent, MenuContentComponent, MenuItemComponent, MenuTriggerDirective, MoonIcon, PaletteIcon, PaperclipIcon, PenToSquareIcon, PlusIcon, PopoverDirective, PresentationIcon, QuestionCircleIcon, RadioComponent, RobotIcon, SaveIcon, SearchBarComponent, SearchInputComponent, SelectComponent, SelectTriggerDirective, SendIcon, SheetBodyComponent, SheetComponent, SheetHeaderComponent, SlashIcon, SlidersIcon, SparklesIcon, SpinnerIcon, SquareCheckIcon, SquareIcon, SquareMinusIcon, StarIcon, SunBrightIcon, SwitchComponent, SyncIcon, TabComponent, TabListComponent, TabPanelComponent, TabsComponent, TagComponent, TagIcon, TagsIcon, TextareaComponent, TextareaControlDirective, ThumbsDownIcon, ThumbsUpIcon, ToggleComponent, ToggleGroupComponent, ToggleItemComponent, ToggleLeftIcon, ToggleRightIcon, TooltipDirective, TrashCanIcon, TrashIcon, TreeComponent, TreeItemComponent, TreeItemExpanderComponent, TreeItemGroupComponent, TriangleAlertIcon, UndoIcon, UserIcon, UserSecretIcon, VideoIcon, XMarkIcon, createCallable, injectCallRef, isApplePlatform } from "@sinequa/galactik";
6
6
  import { withDevtools } from "@angular-architects/ngrx-toolkit";
7
7
  import { getState, patchState, signalStore, signalStoreFeature, withComputed, withMethods, withState } from "@ngrx/signals";
8
8
  import { ActivatedRoute, NavigationEnd, Router, RouterLink, RouterModule } from "@angular/router";
@@ -6619,7 +6619,7 @@ i0.ɵɵngDeclareClassMetadata({
6619
6619
  }] }
6620
6620
  });
6621
6621
  const Export = createCallable(ExportDialog);
6622
- const multiSelectionToolbarVariants = cva("flex divide-x rounded-xl bg-linear-to-b px-3 py-2 shadow [&_ul]:flex [&_ul]:flex-col [&_ul]:p-1 [&>li]:px-2", {
6622
+ const multiSelectionToolbarVariants = cva("flex divide-x rounded-xl bg-linear-to-b px-3 py-2 shadow [&_ul]:flex [&_ul]:flex-col [&_ul]:p-1 [&>div]:px-2", {
6623
6623
  variants: { variant: {
6624
6624
  dark: "divide-gray-800 bg-gray-900 from-gray-500 to-gray-900 text-white",
6625
6625
  light: "divide-gray-400 bg-white from-white to-purple-50 text-gray-800",
@@ -6635,7 +6635,9 @@ var MultiSelectionToolbarComponent = class MultiSelectionToolbarComponent {
6635
6635
  appFeatures = this.appStore.general();
6636
6636
  class = input("", ...ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []);
6637
6637
  variant = input("dark", ...ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []);
6638
+ hint = input(...ngDevMode ? [void 0, { debugName: "hint" }] : /* istanbul ignore next */ []);
6638
6639
  updatedCollections = output();
6640
+ cleared = output();
6639
6641
  count = this.selection.multiSelectCount;
6640
6642
  variants = computed(() => cn(multiSelectionToolbarVariants({
6641
6643
  variant: this.variant(),
@@ -6651,7 +6653,27 @@ var MultiSelectionToolbarComponent = class MultiSelectionToolbarComponent {
6651
6653
  return `search-results-assistant`;
6652
6654
  }, ...ngDevMode ? [{ debugName: "instanceId" }] : /* istanbul ignore next */ []);
6653
6655
  enabledUserInput = computed(() => this.appStore.assistants()[this.instanceId()]?.modeSettings.enabledUserInput === true, ...ngDevMode ? [{ debugName: "enabledUserInput" }] : /* istanbul ignore next */ []);
6654
- clearSelection = () => this.selection.clearMultiSelection();
6656
+ showHint = signal(false, ...ngDevMode ? [{ debugName: "showHint" }] : /* istanbul ignore next */ []);
6657
+ armed = true;
6658
+ constructor() {
6659
+ effect(() => {
6660
+ const count = this.count();
6661
+ untracked(() => {
6662
+ if (count === 0) {
6663
+ this.armed = true;
6664
+ this.showHint.set(false);
6665
+ } else if (this.armed) {
6666
+ this.armed = false;
6667
+ this.showHint.set(true);
6668
+ } else this.showHint.set(false);
6669
+ });
6670
+ });
6671
+ }
6672
+ clearSelection = () => {
6673
+ if (this.count() === 0) return;
6674
+ this.selection.clearMultiSelection();
6675
+ this.cleared.emit();
6676
+ };
6655
6677
  openCollectionDialog = () => AddToCollection.call(getState(this.selection).multiSelection, { injector: this.injector }).then((event) => {
6656
6678
  if (event === "dialog-no" || event === "dialog-yes") {
6657
6679
  this.updatedCollections.emit();
@@ -6688,9 +6710,19 @@ var MultiSelectionToolbarComponent = class MultiSelectionToolbarComponent {
6688
6710
  isSignal: true,
6689
6711
  isRequired: false,
6690
6712
  transformFunction: null
6713
+ },
6714
+ hint: {
6715
+ classPropertyName: "hint",
6716
+ publicName: "hint",
6717
+ isSignal: true,
6718
+ isRequired: false,
6719
+ transformFunction: null
6691
6720
  }
6692
6721
  },
6693
- outputs: { updatedCollections: "updatedCollections" },
6722
+ outputs: {
6723
+ updatedCollections: "updatedCollections",
6724
+ cleared: "cleared"
6725
+ },
6694
6726
  host: {
6695
6727
  properties: {
6696
6728
  "class.opacity-100": "count() > 0",
@@ -6701,37 +6733,57 @@ var MultiSelectionToolbarComponent = class MultiSelectionToolbarComponent {
6701
6733
  providers: [provideTranslocoScope("multi-selection-toolbar", "article", "collections", "export")],
6702
6734
  ngImport: i0,
6703
6735
  template: `
6704
- <menu id="multi-select-toolbar" [class]="cn(variants(), class())">
6705
- <li class="ps-0!">
6736
+ <!-- Région de statut hors de la barre : celle-ci est inerte sans sélection, et une région
6737
+ inerte n'est pas annoncée. Le texte n'existe que tant que la sélection est non vide. -->
6738
+ <span role="status" class="sr-only">
6739
+ @if (count() > 0) {
6740
+ {{ 'multiSelectionToolbar.itemsSelected' | transloco: { count: count() } }}
6741
+ @if (showHint() && hint()) {
6742
+ . {{ hint() }}
6743
+ }
6744
+ }
6745
+ </span>
6746
+
6747
+ <!-- inert sans sélection : la barre n'est que transparente et hors écran, ses boutons resteraient
6748
+ sinon dans l'ordre de tabulation et activables (Entrée ouvrait « Ajouter à une collection » sur
6749
+ un panier vide, ES-31356). -->
6750
+ <div
6751
+ id="multi-select-toolbar"
6752
+ role="toolbar"
6753
+ [attr.aria-label]="'multiSelectionToolbar.label' | transloco"
6754
+ [attr.inert]="count() === 0 ? '' : null"
6755
+ (keydown.escape)="clearSelection()"
6756
+ [class]="cn(variants(), class())">
6757
+ <div class="ps-0!">
6706
6758
  <button class="cursor-pointer inline-flex items-center gap-1" (click)="clearSelection()">
6707
6759
  {{ 'multiSelectionToolbar.itemsSelected' | transloco: { count: count() } }}
6708
- <x-mark-icon />
6760
+ <x-mark-icon aria-hidden="true" />
6709
6761
  </button>
6710
- </li>
6762
+ </div>
6711
6763
 
6712
- <li>
6713
- <button class="cursor-pointer inline-flex items-center gap-1" title="menu" [attr.aria-label]="'menu'" (click)="openCollectionDialog()">
6714
- <inbox-icon />
6764
+ <div>
6765
+ <button class="cursor-pointer inline-flex items-center gap-1" (click)="openCollectionDialog()">
6766
+ <inbox-icon aria-hidden="true" />
6715
6767
  {{ 'collections.label' | transloco }}
6716
6768
  </button>
6717
- </li>
6769
+ </div>
6718
6770
 
6719
- <li>
6771
+ <div>
6720
6772
  <button class="cursor-pointer inline-flex items-center gap-1" (click)="openExportDialog()">
6721
- <file-output-icon />
6773
+ <file-output-icon aria-hidden="true" />
6722
6774
  {{ 'export.title' | transloco }}
6723
6775
  </button>
6724
- </li>
6776
+ </div>
6725
6777
 
6726
6778
  @if (enabledUserInput()) {
6727
- <li class="pe-0!">
6779
+ <div class="pe-0!">
6728
6780
  <button class="cursor-pointer inline-flex items-center gap-1" (click)="attachToAssistant()">
6729
- <sparkles-icon />
6781
+ <sparkles-icon aria-hidden="true" />
6730
6782
  {{ 'article.addToAIOverview' | transloco }}
6731
6783
  </button>
6732
- </li>
6784
+ </div>
6733
6785
  }
6734
- </menu>
6786
+ </div>
6735
6787
  `,
6736
6788
  isInline: true,
6737
6789
  dependencies: [
@@ -6785,37 +6837,57 @@ i0.ɵɵngDeclareClassMetadata({
6785
6837
  ],
6786
6838
  providers: [provideTranslocoScope("multi-selection-toolbar", "article", "collections", "export")],
6787
6839
  template: `
6788
- <menu id="multi-select-toolbar" [class]="cn(variants(), class())">
6789
- <li class="ps-0!">
6840
+ <!-- Région de statut hors de la barre : celle-ci est inerte sans sélection, et une région
6841
+ inerte n'est pas annoncée. Le texte n'existe que tant que la sélection est non vide. -->
6842
+ <span role="status" class="sr-only">
6843
+ @if (count() > 0) {
6844
+ {{ 'multiSelectionToolbar.itemsSelected' | transloco: { count: count() } }}
6845
+ @if (showHint() && hint()) {
6846
+ . {{ hint() }}
6847
+ }
6848
+ }
6849
+ </span>
6850
+
6851
+ <!-- inert sans sélection : la barre n'est que transparente et hors écran, ses boutons resteraient
6852
+ sinon dans l'ordre de tabulation et activables (Entrée ouvrait « Ajouter à une collection » sur
6853
+ un panier vide, ES-31356). -->
6854
+ <div
6855
+ id="multi-select-toolbar"
6856
+ role="toolbar"
6857
+ [attr.aria-label]="'multiSelectionToolbar.label' | transloco"
6858
+ [attr.inert]="count() === 0 ? '' : null"
6859
+ (keydown.escape)="clearSelection()"
6860
+ [class]="cn(variants(), class())">
6861
+ <div class="ps-0!">
6790
6862
  <button class="cursor-pointer inline-flex items-center gap-1" (click)="clearSelection()">
6791
6863
  {{ 'multiSelectionToolbar.itemsSelected' | transloco: { count: count() } }}
6792
- <x-mark-icon />
6864
+ <x-mark-icon aria-hidden="true" />
6793
6865
  </button>
6794
- </li>
6866
+ </div>
6795
6867
 
6796
- <li>
6797
- <button class="cursor-pointer inline-flex items-center gap-1" title="menu" [attr.aria-label]="'menu'" (click)="openCollectionDialog()">
6798
- <inbox-icon />
6868
+ <div>
6869
+ <button class="cursor-pointer inline-flex items-center gap-1" (click)="openCollectionDialog()">
6870
+ <inbox-icon aria-hidden="true" />
6799
6871
  {{ 'collections.label' | transloco }}
6800
6872
  </button>
6801
- </li>
6873
+ </div>
6802
6874
 
6803
- <li>
6875
+ <div>
6804
6876
  <button class="cursor-pointer inline-flex items-center gap-1" (click)="openExportDialog()">
6805
- <file-output-icon />
6877
+ <file-output-icon aria-hidden="true" />
6806
6878
  {{ 'export.title' | transloco }}
6807
6879
  </button>
6808
- </li>
6880
+ </div>
6809
6881
 
6810
6882
  @if (enabledUserInput()) {
6811
- <li class="pe-0!">
6883
+ <div class="pe-0!">
6812
6884
  <button class="cursor-pointer inline-flex items-center gap-1" (click)="attachToAssistant()">
6813
- <sparkles-icon />
6885
+ <sparkles-icon aria-hidden="true" />
6814
6886
  {{ 'article.addToAIOverview' | transloco }}
6815
6887
  </button>
6816
- </li>
6888
+ </div>
6817
6889
  }
6818
- </menu>
6890
+ </div>
6819
6891
  `,
6820
6892
  host: {
6821
6893
  class: "fixed -bottom-20 left-[50%] translate-x-[-50%] z-50 transition-[translate,opacity,discrete] duration-300 opacity-0",
@@ -6824,6 +6896,7 @@ i0.ɵɵngDeclareClassMetadata({
6824
6896
  }
6825
6897
  }]
6826
6898
  }],
6899
+ ctorParameters: () => [],
6827
6900
  propDecorators: {
6828
6901
  class: [{
6829
6902
  type: i0.Input,
@@ -6841,9 +6914,21 @@ i0.ɵɵngDeclareClassMetadata({
6841
6914
  required: false
6842
6915
  }]
6843
6916
  }],
6917
+ hint: [{
6918
+ type: i0.Input,
6919
+ args: [{
6920
+ isSignal: true,
6921
+ alias: "hint",
6922
+ required: false
6923
+ }]
6924
+ }],
6844
6925
  updatedCollections: [{
6845
6926
  type: i0.Output,
6846
6927
  args: ["updatedCollections"]
6928
+ }],
6929
+ cleared: [{
6930
+ type: i0.Output,
6931
+ args: ["cleared"]
6847
6932
  }]
6848
6933
  }
6849
6934
  });
@@ -18727,11 +18812,18 @@ var ListPanelComponent = class ListPanelComponent {
18727
18812
  getValue = input.required(...ngDevMode ? [{ debugName: "getValue" }] : /* istanbul ignore next */ []);
18728
18813
  getLabel = input(...ngDevMode ? [void 0, { debugName: "getLabel" }] : /* istanbul ignore next */ []);
18729
18814
  deleteButtonTitle = input("remove", ...ngDevMode ? [{ debugName: "deleteButtonTitle" }] : /* istanbul ignore next */ []);
18815
+ deletable = input(true, {
18816
+ ...ngDevMode ? { debugName: "deletable" } : /* istanbul ignore next */ {},
18817
+ transform: booleanAttribute
18818
+ });
18730
18819
  ariaLabel = input(...ngDevMode ? [void 0, { debugName: "ariaLabel" }] : /* istanbul ignore next */ []);
18731
18820
  itemClass = input("", ...ngDevMode ? [{ debugName: "itemClass" }] : /* istanbul ignore next */ []);
18732
18821
  itemClick = output();
18733
18822
  delete = output();
18734
18823
  itemTemplate = contentChild(ListPanelItemDirective, ...ngDevMode ? [{ debugName: "itemTemplate" }] : /* istanbul ignore next */ []);
18824
+ deleteKeys = isApplePlatform() ? ["Delete", "Backspace"] : ["Delete"];
18825
+ list = viewChild(ListComponent, ...ngDevMode ? [{ debugName: "list" }] : /* istanbul ignore next */ []);
18826
+ keyboardFocused = computed(() => this.list()?.keyboardFocused() ?? false, ...ngDevMode ? [{ debugName: "keyboardFocused" }] : /* istanbul ignore next */ []);
18735
18827
  host = inject(ElementRef);
18736
18828
  injector = inject(Injector);
18737
18829
  pendingFocusIndex = signal(null, ...ngDevMode ? [{ debugName: "pendingFocusIndex" }] : /* istanbul ignore next */ []);
@@ -18807,6 +18899,13 @@ var ListPanelComponent = class ListPanelComponent {
18807
18899
  isRequired: false,
18808
18900
  transformFunction: null
18809
18901
  },
18902
+ deletable: {
18903
+ classPropertyName: "deletable",
18904
+ publicName: "deletable",
18905
+ isSignal: true,
18906
+ isRequired: false,
18907
+ transformFunction: null
18908
+ },
18810
18909
  ariaLabel: {
18811
18910
  classPropertyName: "ariaLabel",
18812
18911
  publicName: "ariaLabel",
@@ -18827,6 +18926,7 @@ var ListPanelComponent = class ListPanelComponent {
18827
18926
  delete: "delete"
18828
18927
  },
18829
18928
  host: { classAttribute: "block max-h-115 overflow-auto" },
18929
+ providers: [provideTranslocoScope("list-panel")],
18830
18930
  queries: [{
18831
18931
  propertyName: "itemTemplate",
18832
18932
  first: true,
@@ -18834,6 +18934,13 @@ var ListPanelComponent = class ListPanelComponent {
18834
18934
  descendants: true,
18835
18935
  isSignal: true
18836
18936
  }],
18937
+ viewQueries: [{
18938
+ propertyName: "list",
18939
+ first: true,
18940
+ predicate: ListComponent,
18941
+ descendants: true,
18942
+ isSignal: true
18943
+ }],
18837
18944
  ngImport: i0,
18838
18945
  template: `
18839
18946
  <List variant="list-navigation" size="medium" class="gap-1" selectionMode="explicit" [attr.aria-label]="ariaLabel()">
@@ -18846,9 +18953,13 @@ var ListPanelComponent = class ListPanelComponent {
18846
18953
  (keydown.enter)="activate(item, $event)"
18847
18954
  (keydown.space)="activate(item, $event)">
18848
18955
  <ng-container *ngTemplateOutlet="itemTemplate()?.template; context: { $implicit: item }" />
18849
- <ListItemAction [ariaLabel]="deleteButtonTitle() | transloco" (click)="onDelete(item, i, $event)">
18850
- <TrashIcon />
18851
- </ListItemAction>
18956
+ @if (deletable()) {
18957
+ <ListItemAction [ariaLabel]="deleteButtonTitle() | transloco" [keys]="deleteKeys" [shortcut]="'listPanel.deleteShortcut' | transloco"
18958
+ [description]="'listPanel.deleteDescription' | transloco: { key: 'listPanel.deleteShortcut' | transloco }"
18959
+ (click)="onDelete(item, i, $event)">
18960
+ <TrashIcon />
18961
+ </ListItemAction>
18962
+ }
18852
18963
  </ListItem>
18853
18964
  } @empty {
18854
18965
  <span class="py-4 text-center text-neutral-500">
@@ -18903,7 +19014,13 @@ var ListPanelComponent = class ListPanelComponent {
18903
19014
  kind: "component",
18904
19015
  type: ListItemActionComponent,
18905
19016
  selector: "ListItemAction,list-item-action,listitemaction",
18906
- inputs: ["ariaLabel", "disabled"],
19017
+ inputs: [
19018
+ "ariaLabel",
19019
+ "disabled",
19020
+ "keys",
19021
+ "shortcut",
19022
+ "description"
19023
+ ],
18907
19024
  exportAs: ["listItemAction"]
18908
19025
  },
18909
19026
  {
@@ -18923,6 +19040,7 @@ i0.ɵɵngDeclareClassMetadata({
18923
19040
  type: Component,
18924
19041
  args: [{
18925
19042
  selector: "list-panel, ListPanel",
19043
+ providers: [provideTranslocoScope("list-panel")],
18926
19044
  imports: [
18927
19045
  NgTemplateOutlet,
18928
19046
  TrashIcon,
@@ -18942,9 +19060,13 @@ i0.ɵɵngDeclareClassMetadata({
18942
19060
  (keydown.enter)="activate(item, $event)"
18943
19061
  (keydown.space)="activate(item, $event)">
18944
19062
  <ng-container *ngTemplateOutlet="itemTemplate()?.template; context: { $implicit: item }" />
18945
- <ListItemAction [ariaLabel]="deleteButtonTitle() | transloco" (click)="onDelete(item, i, $event)">
18946
- <TrashIcon />
18947
- </ListItemAction>
19063
+ @if (deletable()) {
19064
+ <ListItemAction [ariaLabel]="deleteButtonTitle() | transloco" [keys]="deleteKeys" [shortcut]="'listPanel.deleteShortcut' | transloco"
19065
+ [description]="'listPanel.deleteDescription' | transloco: { key: 'listPanel.deleteShortcut' | transloco }"
19066
+ (click)="onDelete(item, i, $event)">
19067
+ <TrashIcon />
19068
+ </ListItemAction>
19069
+ }
18948
19070
  </ListItem>
18949
19071
  } @empty {
18950
19072
  <span class="py-4 text-center text-neutral-500">
@@ -18991,6 +19113,14 @@ i0.ɵɵngDeclareClassMetadata({
18991
19113
  required: false
18992
19114
  }]
18993
19115
  }],
19116
+ deletable: [{
19117
+ type: i0.Input,
19118
+ args: [{
19119
+ isSignal: true,
19120
+ alias: "deletable",
19121
+ required: false
19122
+ }]
19123
+ }],
18994
19124
  ariaLabel: [{
18995
19125
  type: i0.Input,
18996
19126
  args: [{
@@ -19018,6 +19148,10 @@ i0.ɵɵngDeclareClassMetadata({
19018
19148
  itemTemplate: [{
19019
19149
  type: i0.ContentChild,
19020
19150
  args: [i0.forwardRef(() => ListPanelItemDirective), { isSignal: true }]
19151
+ }],
19152
+ list: [{
19153
+ type: i0.ViewChild,
19154
+ args: [i0.forwardRef(() => ListComponent), { isSignal: true }]
19021
19155
  }]
19022
19156
  }
19023
19157
  });
@@ -19027,6 +19161,10 @@ var ListPanelFooterComponent = class ListPanelFooterComponent {
19027
19161
  hasMore = input.required(...ngDevMode ? [{ debugName: "hasMore" }] : /* istanbul ignore next */ []);
19028
19162
  config = input.required(...ngDevMode ? [{ debugName: "config" }] : /* istanbul ignore next */ []);
19029
19163
  loadMore = output();
19164
+ navigationHint = input(false, {
19165
+ ...ngDevMode ? { debugName: "navigationHint" } : /* istanbul ignore next */ {},
19166
+ transform: booleanAttribute
19167
+ });
19030
19168
  onLoadMore(event) {
19031
19169
  event.stopPropagation();
19032
19170
  this.loadMore.emit();
@@ -19066,10 +19204,17 @@ var ListPanelFooterComponent = class ListPanelFooterComponent {
19066
19204
  isSignal: true,
19067
19205
  isRequired: true,
19068
19206
  transformFunction: null
19207
+ },
19208
+ navigationHint: {
19209
+ classPropertyName: "navigationHint",
19210
+ publicName: "navigationHint",
19211
+ isSignal: true,
19212
+ isRequired: false,
19213
+ transformFunction: null
19069
19214
  }
19070
19215
  },
19071
19216
  outputs: { loadMore: "loadMore" },
19072
- host: { properties: { "class": "cn('flex flex-col px-2 mt-2', class())" } },
19217
+ host: { properties: { "class": "cn('flex flex-col px-2 mt-2 py-(--spacing-xs)', class())" } },
19073
19218
  providers: [provideTranslocoScope("list-panel")],
19074
19219
  ngImport: i0,
19075
19220
  template: `
@@ -19080,9 +19225,33 @@ var ListPanelFooterComponent = class ListPanelFooterComponent {
19080
19225
  </button>
19081
19226
  }
19082
19227
  @let seeMore = 'listPanel.seeMore' | transloco;
19083
- <button variant="secondary" size="sm" class="ml-auto" [attr.title]="seeMore" [routerLink]="[config().routerLink]">
19084
- {{ seeMore }}
19085
- </button>
19228
+ <div class="flex items-center gap-(--spacing-xs)">
19229
+ <!-- Aide de navigation de la liste, tant que navigationHint est vrai (focus clavier dans la liste) : le
19230
+ focus est un arrêt unique de tabulation, les flèches font le reste, et rien ne le dit.
19231
+ aria-hidden : le listbox annonce déjà sa navigation aux lecteurs d'écran, et l'ouverture
19232
+ d'une ligne est ce que tout le monde attend d'Entrée. La touche Suppr est, elle, écrite dans la
19233
+ ligne. -->
19234
+ @if (navigationHint()) {
19235
+ <p aria-hidden="true" class="flex min-w-0 flex-wrap items-center gap-x-(--spacing-xs) gap-y-(--spacing-4xs) text-(length:--size-sm) leading-(--line-height-2) text-(--font-neutral-base)">
19236
+ <span class="inline-flex items-center gap-(--spacing-2xs)">
19237
+ <!-- Des icônes et non les caractères ↑ ↓ : le centre visuel d'une flèche typographique ne tombe pas au
19238
+ milieu de la ligne de texte, et elle sortait décentrée de sa touche. -->
19239
+ <span class="inline-flex gap-(--spacing-4xs)">
19240
+ <kbd><arrow-up-icon /></kbd>
19241
+ <kbd><arrow-down-icon /></kbd>
19242
+ </span>
19243
+ {{ 'listPanel.hintNavigate' | transloco }}
19244
+ </span>
19245
+ <span class="inline-flex items-center gap-(--spacing-2xs)">
19246
+ <kbd>{{ 'listPanel.keyEnter' | transloco }}</kbd>
19247
+ {{ 'listPanel.hintOpen' | transloco }}
19248
+ </span>
19249
+ </p>
19250
+ }
19251
+ <button variant="secondary" size="sm" class="ml-auto shrink-0" [attr.title]="seeMore" [routerLink]="[config().routerLink]">
19252
+ {{ seeMore }}
19253
+ </button>
19254
+ </div>
19086
19255
  `,
19087
19256
  isInline: true,
19088
19257
  dependencies: [
@@ -19117,6 +19286,24 @@ var ListPanelFooterComponent = class ListPanelFooterComponent {
19117
19286
  "size"
19118
19287
  ]
19119
19288
  },
19289
+ {
19290
+ kind: "directive",
19291
+ type: KbdComponent,
19292
+ selector: "kbd, Kbd",
19293
+ inputs: ["class", "size"]
19294
+ },
19295
+ {
19296
+ kind: "component",
19297
+ type: ArrowUpIcon,
19298
+ selector: "arrow-up, arrow-up-icon, ArrowUp, ArrowUpIcon",
19299
+ inputs: ["class"]
19300
+ },
19301
+ {
19302
+ kind: "component",
19303
+ type: ArrowDownIcon,
19304
+ selector: "arrow-down, arrow-down-icon, ArrowDown, ArrowDownIcon",
19305
+ inputs: ["class"]
19306
+ },
19120
19307
  {
19121
19308
  kind: "pipe",
19122
19309
  type: TranslocoPipe,
@@ -19137,7 +19324,10 @@ i0.ɵɵngDeclareClassMetadata({
19137
19324
  imports: [
19138
19325
  TranslocoPipe,
19139
19326
  RouterLink,
19140
- ButtonComponent
19327
+ ButtonComponent,
19328
+ KbdComponent,
19329
+ ArrowUpIcon,
19330
+ ArrowDownIcon
19141
19331
  ],
19142
19332
  providers: [provideTranslocoScope("list-panel")],
19143
19333
  template: `
@@ -19148,11 +19338,35 @@ i0.ɵɵngDeclareClassMetadata({
19148
19338
  </button>
19149
19339
  }
19150
19340
  @let seeMore = 'listPanel.seeMore' | transloco;
19151
- <button variant="secondary" size="sm" class="ml-auto" [attr.title]="seeMore" [routerLink]="[config().routerLink]">
19152
- {{ seeMore }}
19153
- </button>
19341
+ <div class="flex items-center gap-(--spacing-xs)">
19342
+ <!-- Aide de navigation de la liste, tant que navigationHint est vrai (focus clavier dans la liste) : le
19343
+ focus est un arrêt unique de tabulation, les flèches font le reste, et rien ne le dit.
19344
+ aria-hidden : le listbox annonce déjà sa navigation aux lecteurs d'écran, et l'ouverture
19345
+ d'une ligne est ce que tout le monde attend d'Entrée. La touche Suppr est, elle, écrite dans la
19346
+ ligne. -->
19347
+ @if (navigationHint()) {
19348
+ <p aria-hidden="true" class="flex min-w-0 flex-wrap items-center gap-x-(--spacing-xs) gap-y-(--spacing-4xs) text-(length:--size-sm) leading-(--line-height-2) text-(--font-neutral-base)">
19349
+ <span class="inline-flex items-center gap-(--spacing-2xs)">
19350
+ <!-- Des icônes et non les caractères ↑ ↓ : le centre visuel d'une flèche typographique ne tombe pas au
19351
+ milieu de la ligne de texte, et elle sortait décentrée de sa touche. -->
19352
+ <span class="inline-flex gap-(--spacing-4xs)">
19353
+ <kbd><arrow-up-icon /></kbd>
19354
+ <kbd><arrow-down-icon /></kbd>
19355
+ </span>
19356
+ {{ 'listPanel.hintNavigate' | transloco }}
19357
+ </span>
19358
+ <span class="inline-flex items-center gap-(--spacing-2xs)">
19359
+ <kbd>{{ 'listPanel.keyEnter' | transloco }}</kbd>
19360
+ {{ 'listPanel.hintOpen' | transloco }}
19361
+ </span>
19362
+ </p>
19363
+ }
19364
+ <button variant="secondary" size="sm" class="ml-auto shrink-0" [attr.title]="seeMore" [routerLink]="[config().routerLink]">
19365
+ {{ seeMore }}
19366
+ </button>
19367
+ </div>
19154
19368
  `,
19155
- host: { "[class]": "cn('flex flex-col px-2 mt-2', class())" }
19369
+ host: { "[class]": "cn('flex flex-col px-2 mt-2 py-(--spacing-xs)', class())" }
19156
19370
  }]
19157
19371
  }],
19158
19372
  propDecorators: {
@@ -19183,6 +19397,14 @@ i0.ɵɵngDeclareClassMetadata({
19183
19397
  loadMore: [{
19184
19398
  type: i0.Output,
19185
19399
  args: ["loadMore"]
19400
+ }],
19401
+ navigationHint: [{
19402
+ type: i0.Input,
19403
+ args: [{
19404
+ isSignal: true,
19405
+ alias: "navigationHint",
19406
+ required: false
19407
+ }]
19186
19408
  }]
19187
19409
  }
19188
19410
  });
@@ -19368,7 +19590,7 @@ var BookmarksComponent = class BookmarksComponent {
19368
19590
  } },
19369
19591
  providers: [provideTranslocoScope("bookmarks")],
19370
19592
  ngImport: i0,
19371
- template: "<ListPanelHeader\n [label]=\"'bookmarks.label' | transloco\"\n [floating]=\"!!floating\" />\n\n<ListPanel\n [items]=\"paginatedBookmarks()\"\n [getValue]=\"idOf\"\n [getLabel]=\"labelOf\"\n deleteButtonTitle=\"bookmarks.removeBookmark\"\n [ariaLabel]=\"'bookmarks.label' | transloco\"\n (itemClick)=\"onClick($event)\"\n (delete)=\"onDelete($event)\">\n <ng-template listPanelItem let-bookmark>\n <ListItemLeft>\n <BookmarkIcon solid class=\"shrink-0\" />\n <ListItemText>{{ bookmark.label }}</ListItemText>\n </ListItemLeft>\n\n @if (bookmark.author) {\n <Tag variant=\"primary\" scheme=\"sage\" size=\"xs\" class=\"gap-1\">\n <UserIcon class=\"size-3\" />\n <span class=\"min-w-0 truncate\">{{ bookmark.author }}</span>\n </Tag>\n }\n @if (bookmark.parentFolder) {\n <Tag variant=\"primary\" scheme=\"sage\" size=\"xs\" class=\"gap-1\">\n <FolderIcon class=\"size-3\" />\n <span class=\"min-w-0 truncate\">{{ bookmark.parentFolder }}</span>\n </Tag>\n }\n </ng-template>\n\n {{ \"bookmarks.noBookmarks\" | transloco }}\n</ListPanel>\n\n@if (paginatedBookmarks().length > 0) {\n <ListPanelFooter\n [hasMore]=\"hasMore()\"\n [config]=\"config\"\n (loadMore)=\"loadMore()\" />\n}\n",
19593
+ template: "<ListPanelHeader\n [label]=\"'bookmarks.label' | transloco\"\n [floating]=\"!!floating\" />\n\n<ListPanel\n #panel\n [items]=\"paginatedBookmarks()\"\n [getValue]=\"idOf\"\n [getLabel]=\"labelOf\"\n deleteButtonTitle=\"bookmarks.removeBookmark\"\n [ariaLabel]=\"'bookmarks.label' | transloco\"\n (itemClick)=\"onClick($event)\"\n (delete)=\"onDelete($event)\">\n <ng-template listPanelItem let-bookmark>\n <ListItemLeft>\n <BookmarkIcon solid class=\"shrink-0\" />\n <ListItemText>{{ bookmark.label }}</ListItemText>\n </ListItemLeft>\n\n @if (bookmark.author) {\n <Tag variant=\"primary\" scheme=\"sage\" size=\"xs\" class=\"gap-1\">\n <UserIcon class=\"size-3\" />\n <span class=\"min-w-0 truncate\">{{ bookmark.author }}</span>\n </Tag>\n }\n @if (bookmark.parentFolder) {\n <Tag variant=\"primary\" scheme=\"sage\" size=\"xs\" class=\"gap-1\">\n <FolderIcon class=\"size-3\" />\n <span class=\"min-w-0 truncate\">{{ bookmark.parentFolder }}</span>\n </Tag>\n }\n </ng-template>\n\n {{ \"bookmarks.noBookmarks\" | transloco }}\n</ListPanel>\n\n@if (paginatedBookmarks().length > 0) {\n <ListPanelFooter\n [navigationHint]=\"panel.keyboardFocused()\"\n [hasMore]=\"hasMore()\"\n [config]=\"config\"\n (loadMore)=\"loadMore()\" />\n}\n",
19372
19594
  dependencies: [
19373
19595
  {
19374
19596
  kind: "component",
@@ -19385,6 +19607,7 @@ var BookmarksComponent = class BookmarksComponent {
19385
19607
  "getValue",
19386
19608
  "getLabel",
19387
19609
  "deleteButtonTitle",
19610
+ "deletable",
19388
19611
  "ariaLabel",
19389
19612
  "itemClass"
19390
19613
  ],
@@ -19397,7 +19620,8 @@ var BookmarksComponent = class BookmarksComponent {
19397
19620
  inputs: [
19398
19621
  "class",
19399
19622
  "hasMore",
19400
- "config"
19623
+ "config",
19624
+ "navigationHint"
19401
19625
  ],
19402
19626
  outputs: ["loadMore"]
19403
19627
  },
@@ -19479,7 +19703,7 @@ i0.ɵɵngDeclareClassMetadata({
19479
19703
  TagComponent
19480
19704
  ],
19481
19705
  providers: [provideTranslocoScope("bookmarks")],
19482
- template: "<ListPanelHeader\n [label]=\"'bookmarks.label' | transloco\"\n [floating]=\"!!floating\" />\n\n<ListPanel\n [items]=\"paginatedBookmarks()\"\n [getValue]=\"idOf\"\n [getLabel]=\"labelOf\"\n deleteButtonTitle=\"bookmarks.removeBookmark\"\n [ariaLabel]=\"'bookmarks.label' | transloco\"\n (itemClick)=\"onClick($event)\"\n (delete)=\"onDelete($event)\">\n <ng-template listPanelItem let-bookmark>\n <ListItemLeft>\n <BookmarkIcon solid class=\"shrink-0\" />\n <ListItemText>{{ bookmark.label }}</ListItemText>\n </ListItemLeft>\n\n @if (bookmark.author) {\n <Tag variant=\"primary\" scheme=\"sage\" size=\"xs\" class=\"gap-1\">\n <UserIcon class=\"size-3\" />\n <span class=\"min-w-0 truncate\">{{ bookmark.author }}</span>\n </Tag>\n }\n @if (bookmark.parentFolder) {\n <Tag variant=\"primary\" scheme=\"sage\" size=\"xs\" class=\"gap-1\">\n <FolderIcon class=\"size-3\" />\n <span class=\"min-w-0 truncate\">{{ bookmark.parentFolder }}</span>\n </Tag>\n }\n </ng-template>\n\n {{ \"bookmarks.noBookmarks\" | transloco }}\n</ListPanel>\n\n@if (paginatedBookmarks().length > 0) {\n <ListPanelFooter\n [hasMore]=\"hasMore()\"\n [config]=\"config\"\n (loadMore)=\"loadMore()\" />\n}\n"
19706
+ template: "<ListPanelHeader\n [label]=\"'bookmarks.label' | transloco\"\n [floating]=\"!!floating\" />\n\n<ListPanel\n #panel\n [items]=\"paginatedBookmarks()\"\n [getValue]=\"idOf\"\n [getLabel]=\"labelOf\"\n deleteButtonTitle=\"bookmarks.removeBookmark\"\n [ariaLabel]=\"'bookmarks.label' | transloco\"\n (itemClick)=\"onClick($event)\"\n (delete)=\"onDelete($event)\">\n <ng-template listPanelItem let-bookmark>\n <ListItemLeft>\n <BookmarkIcon solid class=\"shrink-0\" />\n <ListItemText>{{ bookmark.label }}</ListItemText>\n </ListItemLeft>\n\n @if (bookmark.author) {\n <Tag variant=\"primary\" scheme=\"sage\" size=\"xs\" class=\"gap-1\">\n <UserIcon class=\"size-3\" />\n <span class=\"min-w-0 truncate\">{{ bookmark.author }}</span>\n </Tag>\n }\n @if (bookmark.parentFolder) {\n <Tag variant=\"primary\" scheme=\"sage\" size=\"xs\" class=\"gap-1\">\n <FolderIcon class=\"size-3\" />\n <span class=\"min-w-0 truncate\">{{ bookmark.parentFolder }}</span>\n </Tag>\n }\n </ng-template>\n\n {{ \"bookmarks.noBookmarks\" | transloco }}\n</ListPanel>\n\n@if (paginatedBookmarks().length > 0) {\n <ListPanelFooter\n [navigationHint]=\"panel.keyboardFocused()\"\n [hasMore]=\"hasMore()\"\n [config]=\"config\"\n (loadMore)=\"loadMore()\" />\n}\n"
19483
19707
  }]
19484
19708
  }],
19485
19709
  ctorParameters: () => [],
@@ -19735,7 +19959,7 @@ var CollectionsComponent = class CollectionsComponent {
19735
19959
  } },
19736
19960
  providers: [provideTranslocoScope("collections")],
19737
19961
  ngImport: i0,
19738
- template: "<ListPanelHeader\n [label]=\"'collections.label' | transloco\"\n [floating]=\"!!floating\" />\n\n<ListPanel\n [items]=\"paginatedCollections()\"\n [getValue]=\"nameOf\"\n [getLabel]=\"nameOf\"\n deleteButtonTitle=\"collections.deleteCollection\"\n [ariaLabel]=\"'collections.label' | transloco\"\n (itemClick)=\"onClick($event)\"\n (delete)=\"onDelete($event)\">\n <ng-template listPanelItem let-collection>\n <ListItemLeft>\n <inbox-icon />\n <ListItemText>{{ collection.name }}</ListItemText>\n </ListItemLeft>\n </ng-template>\n\n {{ \"collections.noCollections\" | transloco }}\n</ListPanel>\n\n@if (paginatedCollections().length > 0) {\n <ListPanelFooter\n [hasMore]=\"hasMore()\"\n [config]=\"config\"\n (loadMore)=\"loadMore()\" />\n}\n",
19962
+ template: "<ListPanelHeader\n [label]=\"'collections.label' | transloco\"\n [floating]=\"!!floating\" />\n\n<ListPanel\n #panel\n [items]=\"paginatedCollections()\"\n [getValue]=\"nameOf\"\n [getLabel]=\"nameOf\"\n deleteButtonTitle=\"collections.deleteCollection\"\n [ariaLabel]=\"'collections.label' | transloco\"\n (itemClick)=\"onClick($event)\"\n (delete)=\"onDelete($event)\">\n <ng-template listPanelItem let-collection>\n <ListItemLeft>\n <inbox-icon />\n <ListItemText>{{ collection.name }}</ListItemText>\n </ListItemLeft>\n </ng-template>\n\n {{ \"collections.noCollections\" | transloco }}\n</ListPanel>\n\n@if (paginatedCollections().length > 0) {\n <ListPanelFooter\n [navigationHint]=\"panel.keyboardFocused()\"\n [hasMore]=\"hasMore()\"\n [config]=\"config\"\n (loadMore)=\"loadMore()\" />\n}\n",
19739
19963
  dependencies: [
19740
19964
  {
19741
19965
  kind: "component",
@@ -19752,6 +19976,7 @@ var CollectionsComponent = class CollectionsComponent {
19752
19976
  "getValue",
19753
19977
  "getLabel",
19754
19978
  "deleteButtonTitle",
19979
+ "deletable",
19755
19980
  "ariaLabel",
19756
19981
  "itemClass"
19757
19982
  ],
@@ -19764,7 +19989,8 @@ var CollectionsComponent = class CollectionsComponent {
19764
19989
  inputs: [
19765
19990
  "class",
19766
19991
  "hasMore",
19767
- "config"
19992
+ "config",
19993
+ "navigationHint"
19768
19994
  ],
19769
19995
  outputs: ["loadMore"]
19770
19996
  },
@@ -19820,7 +20046,7 @@ i0.ɵɵngDeclareClassMetadata({
19820
20046
  ListItemTextComponent
19821
20047
  ],
19822
20048
  providers: [provideTranslocoScope("collections")],
19823
- template: "<ListPanelHeader\n [label]=\"'collections.label' | transloco\"\n [floating]=\"!!floating\" />\n\n<ListPanel\n [items]=\"paginatedCollections()\"\n [getValue]=\"nameOf\"\n [getLabel]=\"nameOf\"\n deleteButtonTitle=\"collections.deleteCollection\"\n [ariaLabel]=\"'collections.label' | transloco\"\n (itemClick)=\"onClick($event)\"\n (delete)=\"onDelete($event)\">\n <ng-template listPanelItem let-collection>\n <ListItemLeft>\n <inbox-icon />\n <ListItemText>{{ collection.name }}</ListItemText>\n </ListItemLeft>\n </ng-template>\n\n {{ \"collections.noCollections\" | transloco }}\n</ListPanel>\n\n@if (paginatedCollections().length > 0) {\n <ListPanelFooter\n [hasMore]=\"hasMore()\"\n [config]=\"config\"\n (loadMore)=\"loadMore()\" />\n}\n"
20049
+ template: "<ListPanelHeader\n [label]=\"'collections.label' | transloco\"\n [floating]=\"!!floating\" />\n\n<ListPanel\n #panel\n [items]=\"paginatedCollections()\"\n [getValue]=\"nameOf\"\n [getLabel]=\"nameOf\"\n deleteButtonTitle=\"collections.deleteCollection\"\n [ariaLabel]=\"'collections.label' | transloco\"\n (itemClick)=\"onClick($event)\"\n (delete)=\"onDelete($event)\">\n <ng-template listPanelItem let-collection>\n <ListItemLeft>\n <inbox-icon />\n <ListItemText>{{ collection.name }}</ListItemText>\n </ListItemLeft>\n </ng-template>\n\n {{ \"collections.noCollections\" | transloco }}\n</ListPanel>\n\n@if (paginatedCollections().length > 0) {\n <ListPanelFooter\n [navigationHint]=\"panel.keyboardFocused()\"\n [hasMore]=\"hasMore()\"\n [config]=\"config\"\n (loadMore)=\"loadMore()\" />\n}\n"
19824
20050
  }]
19825
20051
  }],
19826
20052
  ctorParameters: () => [],
@@ -30211,7 +30437,7 @@ var RecentSearchesComponent = class RecentSearchesComponent {
30211
30437
  template: `
30212
30438
  <ListPanelHeader [label]="'searches.recent.label' | transloco" [floating]="!!floating" />
30213
30439
 
30214
- <ListPanel
30440
+ <ListPanel #panel
30215
30441
  [items]="paginatedRecentSearches()"
30216
30442
  [getValue]="urlOf"
30217
30443
  [getLabel]="labelOf"
@@ -30243,7 +30469,7 @@ var RecentSearchesComponent = class RecentSearchesComponent {
30243
30469
  </ListPanel>
30244
30470
 
30245
30471
  @if (paginatedRecentSearches().length > 0) {
30246
- <ListPanelFooter
30472
+ <ListPanelFooter [navigationHint]="panel.keyboardFocused()"
30247
30473
  [hasMore]="hasMore()"
30248
30474
  [config]="config"
30249
30475
  (loadMore)="loadMore()" />
@@ -30320,6 +30546,7 @@ var RecentSearchesComponent = class RecentSearchesComponent {
30320
30546
  "getValue",
30321
30547
  "getLabel",
30322
30548
  "deleteButtonTitle",
30549
+ "deletable",
30323
30550
  "ariaLabel",
30324
30551
  "itemClass"
30325
30552
  ],
@@ -30332,7 +30559,8 @@ var RecentSearchesComponent = class RecentSearchesComponent {
30332
30559
  inputs: [
30333
30560
  "class",
30334
30561
  "hasMore",
30335
- "config"
30562
+ "config",
30563
+ "navigationHint"
30336
30564
  ],
30337
30565
  outputs: ["loadMore"]
30338
30566
  },
@@ -30370,7 +30598,7 @@ i0.ɵɵngDeclareClassMetadata({
30370
30598
  template: `
30371
30599
  <ListPanelHeader [label]="'searches.recent.label' | transloco" [floating]="!!floating" />
30372
30600
 
30373
- <ListPanel
30601
+ <ListPanel #panel
30374
30602
  [items]="paginatedRecentSearches()"
30375
30603
  [getValue]="urlOf"
30376
30604
  [getLabel]="labelOf"
@@ -30402,7 +30630,7 @@ i0.ɵɵngDeclareClassMetadata({
30402
30630
  </ListPanel>
30403
30631
 
30404
30632
  @if (paginatedRecentSearches().length > 0) {
30405
- <ListPanelFooter
30633
+ <ListPanelFooter [navigationHint]="panel.keyboardFocused()"
30406
30634
  [hasMore]="hasMore()"
30407
30635
  [config]="config"
30408
30636
  (loadMore)="loadMore()" />
@@ -30487,7 +30715,7 @@ var SavedSearchDialog = class SavedSearchDialog {
30487
30715
  [formField]="nameField"
30488
30716
  [attr.aria-label]="'searches.saved.saveName' | transloco"
30489
30717
  [attr.placeholder]="'searches.saved.saveName' | transloco"
30490
- (keydown.enter)="saveName().trim() && confirm()" />
30718
+ (keydown.enter)="$event.preventDefault(); saveName().trim() && confirm()" />
30491
30719
  </input-group>
30492
30720
  </DialogBody>
30493
30721
 
@@ -30634,7 +30862,7 @@ i0.ɵɵngDeclareClassMetadata({
30634
30862
  [formField]="nameField"
30635
30863
  [attr.aria-label]="'searches.saved.saveName' | transloco"
30636
30864
  [attr.placeholder]="'searches.saved.saveName' | transloco"
30637
- (keydown.enter)="saveName().trim() && confirm()" />
30865
+ (keydown.enter)="$event.preventDefault(); saveName().trim() && confirm()" />
30638
30866
  </input-group>
30639
30867
  </DialogBody>
30640
30868
 
@@ -30932,7 +31160,7 @@ var SavedSearchesComponent = class SavedSearchesComponent {
30932
31160
  template: `
30933
31161
  <ListPanelHeader [label]="'searches.saved.label' | transloco" [floating]="!!floating" />
30934
31162
 
30935
- <ListPanel
31163
+ <ListPanel #panel
30936
31164
  [items]="paginatedSearches()"
30937
31165
  [getValue]="urlOf"
30938
31166
  [getLabel]="labelOf"
@@ -30964,7 +31192,7 @@ var SavedSearchesComponent = class SavedSearchesComponent {
30964
31192
  </ListPanel>
30965
31193
 
30966
31194
  @if(paginatedSearches().length > 0) {
30967
- <ListPanelFooter [hasMore]="hasMore()" [config]="config" (loadMore)="loadMore()" />
31195
+ <ListPanelFooter [navigationHint]="panel.keyboardFocused()" [hasMore]="hasMore()" [config]="config" (loadMore)="loadMore()" />
30968
31196
  }
30969
31197
  `,
30970
31198
  isInline: true,
@@ -31038,6 +31266,7 @@ var SavedSearchesComponent = class SavedSearchesComponent {
31038
31266
  "getValue",
31039
31267
  "getLabel",
31040
31268
  "deleteButtonTitle",
31269
+ "deletable",
31041
31270
  "ariaLabel",
31042
31271
  "itemClass"
31043
31272
  ],
@@ -31050,7 +31279,8 @@ var SavedSearchesComponent = class SavedSearchesComponent {
31050
31279
  inputs: [
31051
31280
  "class",
31052
31281
  "hasMore",
31053
- "config"
31282
+ "config",
31283
+ "navigationHint"
31054
31284
  ],
31055
31285
  outputs: ["loadMore"]
31056
31286
  },
@@ -31088,7 +31318,7 @@ i0.ɵɵngDeclareClassMetadata({
31088
31318
  template: `
31089
31319
  <ListPanelHeader [label]="'searches.saved.label' | transloco" [floating]="!!floating" />
31090
31320
 
31091
- <ListPanel
31321
+ <ListPanel #panel
31092
31322
  [items]="paginatedSearches()"
31093
31323
  [getValue]="urlOf"
31094
31324
  [getLabel]="labelOf"
@@ -31120,7 +31350,7 @@ i0.ɵɵngDeclareClassMetadata({
31120
31350
  </ListPanel>
31121
31351
 
31122
31352
  @if(paginatedSearches().length > 0) {
31123
- <ListPanelFooter [hasMore]="hasMore()" [config]="config" (loadMore)="loadMore()" />
31353
+ <ListPanelFooter [navigationHint]="panel.keyboardFocused()" [hasMore]="hasMore()" [config]="config" (loadMore)="loadMore()" />
31124
31354
  }
31125
31355
  `
31126
31356
  }]
@@ -31555,7 +31785,11 @@ function splitPropertyId(id) {
31555
31785
  key: id.slice(separator + 1)
31556
31786
  };
31557
31787
  }
31788
+ const FIRST_CONTROL = "button:not(:disabled), textarea, input:not([type='file']), a[href]";
31558
31789
  var SettingsAccountPanelComponent = class SettingsAccountPanelComponent {
31790
+ focusOnOpen = input(false, ...ngDevMode ? [{ debugName: "focusOnOpen" }] : /* istanbul ignore next */ []);
31791
+ host = inject(ElementRef);
31792
+ destroyRef = inject(DestroyRef);
31559
31793
  principalStore = inject(PrincipalStore);
31560
31794
  appStore = inject(AppStore);
31561
31795
  client = inject(ATOMIC_CLIENT);
@@ -31568,6 +31802,13 @@ var SettingsAccountPanelComponent = class SettingsAccountPanelComponent {
31568
31802
  const { allowChangePassword = false } = this.appStore.general()?.features || {};
31569
31803
  return allowChangePassword && useCredentials && (this.principalStore.editablePartition?.() || false);
31570
31804
  }, ...ngDevMode ? [{ debugName: "allowChangePassword" }] : /* istanbul ignore next */ []);
31805
+ constructor() {
31806
+ afterNextRender(() => {
31807
+ if (!this.focusOnOpen()) return;
31808
+ const frame = requestAnimationFrame(() => focusWhenReady(() => this.host.nativeElement.querySelector(FIRST_CONTROL), "settings-account-panel", { destroyRef: this.destroyRef }));
31809
+ this.destroyRef.onDestroy(() => cancelAnimationFrame(frame));
31810
+ });
31811
+ }
31571
31812
  resetSettings() {
31572
31813
  ResetUserSettings.call(void 0, { injector: this.injector });
31573
31814
  }
@@ -31591,6 +31832,13 @@ var SettingsAccountPanelComponent = class SettingsAccountPanelComponent {
31591
31832
  type: SettingsAccountPanelComponent,
31592
31833
  isStandalone: true,
31593
31834
  selector: "settings-account-panel",
31835
+ inputs: { focusOnOpen: {
31836
+ classPropertyName: "focusOnOpen",
31837
+ publicName: "focusOnOpen",
31838
+ isSignal: true,
31839
+ isRequired: false,
31840
+ transformFunction: null
31841
+ } },
31594
31842
  providers: [provideTranslocoScope("settings")],
31595
31843
  ngImport: i0,
31596
31844
  template: `
@@ -31773,7 +32021,16 @@ i0.ɵɵngDeclareClassMetadata({
31773
32021
  </div>
31774
32022
  `
31775
32023
  }]
31776
- }]
32024
+ }],
32025
+ ctorParameters: () => [],
32026
+ propDecorators: { focusOnOpen: [{
32027
+ type: i0.Input,
32028
+ args: [{
32029
+ isSignal: true,
32030
+ alias: "focusOnOpen",
32031
+ required: false
32032
+ }]
32033
+ }] }
31777
32034
  });
31778
32035
  const THEMES$1 = [
31779
32036
  "light",
@@ -32117,6 +32374,11 @@ var SettingsDialogComponent = class SettingsDialogComponent {
32117
32374
  }
32118
32375
  ];
32119
32376
  panel = signal(this.call.props()?.panel ?? "account", ...ngDevMode ? [{ debugName: "panel" }] : /* istanbul ignore next */ []);
32377
+ navigated = signal(false, ...ngDevMode ? [{ debugName: "navigated" }] : /* istanbul ignore next */ []);
32378
+ navigate(id) {
32379
+ this.navigated.set(true);
32380
+ this.panel.set(id);
32381
+ }
32120
32382
  duplicate = active !== void 0;
32121
32383
  constructor() {
32122
32384
  if (active) {
@@ -32176,7 +32438,7 @@ var SettingsDialogComponent = class SettingsDialogComponent {
32176
32438
  variant="none"
32177
32439
  class="flex h-(--row-height-md) w-full cursor-pointer items-center justify-start gap-(--spacing-xs) rounded-(--radius-sm) border-0 bg-transparent px-(--spacing-xs) text-left text-(--layer-page-font) transition-colors hover:bg-(--bg-primary-light) focus-visible:outline-2 focus-visible:outline-offset-0 focus-visible:outline-(--stroke-focus) aria-[current=page]:bg-(--bg-primary-base) aria-[current=page]:text-(--font-neutral-white) aria-[current=page]:hover:bg-(--bg-primary-base)"
32178
32440
  [attr.aria-current]="panel() === item.id ? 'page' : null"
32179
- (click)="panel.set(item.id)">
32441
+ (click)="navigate(item.id)">
32180
32442
  @switch (item.id) {
32181
32443
  @case ("account") {
32182
32444
  <user-icon aria-hidden="true" />
@@ -32197,7 +32459,7 @@ var SettingsDialogComponent = class SettingsDialogComponent {
32197
32459
  <div class="m-(--spacing-xs) flex min-w-0 flex-1 flex-col overflow-y-auto rounded-(--radius-lg) bg-(--layer-page-layer) p-(--spacing-xl)">
32198
32460
  @switch (panel()) {
32199
32461
  @case ("account") {
32200
- <settings-account-panel class="flex min-h-0 flex-1 flex-col" />
32462
+ <settings-account-panel class="flex min-h-0 flex-1 flex-col" [focusOnOpen]="!navigated()" />
32201
32463
  }
32202
32464
  @case ("appearance") {
32203
32465
  <settings-appearance-panel />
@@ -32270,7 +32532,8 @@ var SettingsDialogComponent = class SettingsDialogComponent {
32270
32532
  {
32271
32533
  kind: "component",
32272
32534
  type: SettingsAccountPanelComponent,
32273
- selector: "settings-account-panel"
32535
+ selector: "settings-account-panel",
32536
+ inputs: ["focusOnOpen"]
32274
32537
  },
32275
32538
  {
32276
32539
  kind: "component",
@@ -32336,7 +32599,7 @@ i0.ɵɵngDeclareClassMetadata({
32336
32599
  variant="none"
32337
32600
  class="flex h-(--row-height-md) w-full cursor-pointer items-center justify-start gap-(--spacing-xs) rounded-(--radius-sm) border-0 bg-transparent px-(--spacing-xs) text-left text-(--layer-page-font) transition-colors hover:bg-(--bg-primary-light) focus-visible:outline-2 focus-visible:outline-offset-0 focus-visible:outline-(--stroke-focus) aria-[current=page]:bg-(--bg-primary-base) aria-[current=page]:text-(--font-neutral-white) aria-[current=page]:hover:bg-(--bg-primary-base)"
32338
32601
  [attr.aria-current]="panel() === item.id ? 'page' : null"
32339
- (click)="panel.set(item.id)">
32602
+ (click)="navigate(item.id)">
32340
32603
  @switch (item.id) {
32341
32604
  @case ("account") {
32342
32605
  <user-icon aria-hidden="true" />
@@ -32357,7 +32620,7 @@ i0.ɵɵngDeclareClassMetadata({
32357
32620
  <div class="m-(--spacing-xs) flex min-w-0 flex-1 flex-col overflow-y-auto rounded-(--radius-lg) bg-(--layer-page-layer) p-(--spacing-xl)">
32358
32621
  @switch (panel()) {
32359
32622
  @case ("account") {
32360
- <settings-account-panel class="flex min-h-0 flex-1 flex-col" />
32623
+ <settings-account-panel class="flex min-h-0 flex-1 flex-col" [focusOnOpen]="!navigated()" />
32361
32624
  }
32362
32625
  @case ("appearance") {
32363
32626
  <settings-appearance-panel />