@sinequa/atomic-angular 2.14.0 → 2.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components/multi-selection-toolbar/i18n/de.json +2 -1
- package/components/multi-selection-toolbar/i18n/en.json +2 -1
- package/components/multi-selection-toolbar/i18n/fr.json +2 -1
- package/features/collections/i18n/de.json +15 -1
- package/features/collections/i18n/en.json +15 -1
- package/features/collections/i18n/fr.json +15 -1
- package/fesm2022/sinequa-atomic-angular.mjs +1210 -84
- package/fesm2022/sinequa-atomic-angular.mjs.map +1 -1
- package/package.json +1 -1
- package/types/sinequa-atomic-angular-document-workspaces.d.ts +14 -14
- package/types/sinequa-atomic-angular.d.ts +241 -59
|
@@ -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, ViewContainerRef, 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, finalize, firstValueFrom, from, fromEvent, map, of, scan, shareReplay, switchMap, tap, throwError } from "rxjs";
|
|
4
4
|
import { TranslocoPipe, TranslocoService, provideTranslocoScope } from "@jsverse/transloco";
|
|
5
|
-
import { ArrowDownIcon, ArrowDownZaIcon, ArrowLeftIcon, ArrowRightFromBracketIcon, ArrowRightIcon, ArrowUpAzIcon, ArrowUpIcon, ArrowUpRightFromSquareIcon, ArrowsMaximizeIcon, AutocompleteComponent, AvatarComponent, AvatarFallbackComponent, AvatarImageComponent, BadgeComponent, BarsIcon, BellIcon, BellSlashIcon, BookmarkIcon, BreakpointObserverService, BuildingIcon, ButtonComponent, CalendarDayIcon, CheckIcon, CheckboxComponent, ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon, ChevronUpIcon, CircleCheckIcon, ClockIcon, CollapseIcon, CommentIcon, CommentsIcon, DIALOG_REF, DesktopIcon, DialogBodyComponent, DialogComponent, DialogContentComponent, DialogDescriptionComponent, DialogFooterComponent, DialogHeaderComponent, DialogTitleComponent, DropdownDirective, EditIcon, EllipsisIcon, EllipsisVerticalIcon, ExpandIcon, EyeIcon, EyeSlashIcon, FileHTMLIcon, FileIcon, FileMagnifyingGlassIcon, FileOutputIcon, FileSpreadsheetIcon, FileTextIcon, FilesIcon, FilterIcon, FlagEnglishIcon, FlagFrenchIcon, FlagGermanIcon, FlashlightIcon, FolderIcon, FolderOpenIcon, FrownIcon, GearIcon, GitForkIcon, GlobeIcon, GripVerticalIcon, HighlighterIcon, HistoryIcon, HomeIcon, ImageIcon, InboxIcon, InfoCircleIcon, InputComponent, InputControlDirective, InputIconRightDirective, KbdComponent, KbdGroupComponent, KeyIcon, KeyboardIcon, LanguageIcon, LightbulbIcon, LightbulbSlashIcon, LinkComponent, LinkIcon, ListComponent, ListItemActionComponent, ListItemAvatarDirective, ListItemComponent, ListItemIconDirective, ListItemLeftDirective, ListItemTextComponent, LoadingCircleIcon, LockIcon, MagnifyingGlassIcon, MagnifyingGlassMinusIcon, MagnifyingGlassPlusIcon, MapPinIcon, MenuComponent, MenuContentComponent, MenuItemComponent, MenuTriggerDirective, MoonIcon, PaletteIcon, PanelRightIcon, PaperclipIcon, PenToSquareIcon, PlusIcon, PopoverDirective, PopoverResizeHandleComponent, PresentationIcon, QuestionCircleIcon, QuickFilterIcon, RadioComponent, RobotIcon, SaveIcon, SearchBarComponent, SearchBarSuggestionsComponent, SearchIcon, SearchInputComponent, SelectComponent, SelectTriggerDirective, SendIcon, SheetBodyComponent, SheetComponent, SheetHeaderComponent, SidebarInsetDirective, SlashIcon, SlidersIcon, SortableDirective, SortableItemDirective, SparklesIcon, SpinnerIcon, SquareCheckIcon, SquareIcon, SquareMinusIcon, StarIcon, SunBrightIcon, SwipeActionComponent, SwitchComponent, SyncIcon, TabComponent, TabListComponent, TabPanelComponent, TabsComponent, TagComponent, TagIcon, TagInputComponent, TagsIcon, TextareaComponent, TextareaControlDirective, ThumbsDownIcon, ThumbsUpIcon, ToggleGroupComponent, ToggleItemComponent, ToggleLeftIcon, ToggleRightIcon, TooltipDirective, TrashCanIcon, TrashIcon, TreeComponent, TreeItemComponent, TreeItemExpanderComponent, TreeItemGroupComponent, TriangleAlertIcon, TruncatedDirective, UndoIcon, UserIcon, UserSecretIcon, VideoIcon, XMarkIcon, createCallable, injectCallRef, injectFloatingPanel, injectKeyboardAvailable, isApplePlatform } from "@sinequa/galactik";
|
|
5
|
+
import { ArrowDownIcon, ArrowDownZaIcon, ArrowLeftIcon, ArrowRightFromBracketIcon, ArrowRightIcon, ArrowUpAzIcon, ArrowUpIcon, ArrowUpRightFromSquareIcon, ArrowsMaximizeIcon, AutocompleteComponent, AvatarComponent, AvatarFallbackComponent, AvatarImageComponent, BadgeComponent, BarsIcon, BellIcon, BellSlashIcon, BookmarkIcon, BreakpointObserverService, BuildingIcon, ButtonComponent, CalendarDayIcon, CheckIcon, CheckboxComponent, ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon, ChevronUpIcon, CircleCheckIcon, ClockIcon, CollapseIcon, CommentIcon, CommentsIcon, DIALOG_REF, DesktopIcon, DialogBodyComponent, DialogComponent, DialogContentComponent, DialogDescriptionComponent, DialogFooterComponent, DialogHeaderComponent, DialogTitleComponent, DropdownDirective, EditIcon, EllipsisIcon, EllipsisVerticalIcon, ExpandIcon, EyeIcon, EyeSlashIcon, FileHTMLIcon, FileIcon, FileMagnifyingGlassIcon, FileOutputIcon, FileSpreadsheetIcon, FileTextIcon, FilesIcon, FilterIcon, FlagEnglishIcon, FlagFrenchIcon, FlagGermanIcon, FlashlightIcon, FolderIcon, FolderOpenIcon, FrownIcon, GearIcon, GitForkIcon, GlobeIcon, GripVerticalIcon, HighlighterIcon, HistoryIcon, HomeIcon, ImageIcon, InboxIcon, InfoCircleIcon, InputComponent, InputControlDirective, InputIconLeftDirective, InputIconRightDirective, KbdComponent, KbdGroupComponent, KeyIcon, KeyboardIcon, LanguageIcon, LightbulbIcon, LightbulbSlashIcon, LinkComponent, LinkIcon, ListComponent, ListItemActionComponent, ListItemAvatarDirective, ListItemComponent, ListItemIconDirective, ListItemLeftDirective, ListItemTextComponent, LoadingCircleIcon, LockIcon, MagnifyingGlassIcon, MagnifyingGlassMinusIcon, MagnifyingGlassPlusIcon, MapPinIcon, MenuComponent, MenuContentComponent, MenuItemComponent, MenuTriggerDirective, MoonIcon, PaletteIcon, PanelRightIcon, PaperclipIcon, PenToSquareIcon, PlusIcon, PopoverDirective, PopoverResizeHandleComponent, PresentationIcon, QuestionCircleIcon, QuickFilterIcon, RadioComponent, RobotIcon, SaveIcon, SearchBarComponent, SearchBarSuggestionsComponent, SearchIcon, SearchInputComponent, SelectComponent, SelectTriggerDirective, SendIcon, SheetBodyComponent, SheetComponent, SheetHeaderComponent, SidebarInsetDirective, SlashIcon, SlidersIcon, SortableDirective, SortableItemDirective, SparklesIcon, SpinnerIcon, SquareCheckIcon, SquareIcon, SquareMinusIcon, StarIcon, SunBrightIcon, SwipeActionComponent, SwitchComponent, SyncIcon, TabComponent, TabListComponent, TabPanelComponent, TabsComponent, TagComponent, TagIcon, TagInputComponent, TagsIcon, TextareaComponent, TextareaControlDirective, ThumbsDownIcon, ThumbsUpIcon, ToggleGroupComponent, ToggleItemComponent, ToggleLeftIcon, ToggleRightIcon, TooltipDirective, TrashCanIcon, TrashIcon, TreeComponent, TreeItemComponent, TreeItemExpanderComponent, TreeItemGroupComponent, TriangleAlertIcon, TruncatedDirective, UndoIcon, UserIcon, UserSecretIcon, VideoIcon, XMarkIcon, createCallable, injectCallRef, injectFloatingPanel, injectKeyboardAvailable, isApplePlatform } from "@sinequa/galactik";
|
|
6
6
|
import { withDevtools } from "@ngrx-toolkit/core";
|
|
7
7
|
import { getState, patchState, signalStore, signalStoreFeature, type, withComputed, withMethods, withState } from "@ngrx/signals";
|
|
8
8
|
import { ActivatedRoute, NavigationEnd, Router, RouterLink, RouterModule } from "@angular/router";
|
|
@@ -14,7 +14,7 @@ import { cn } from "cn";
|
|
|
14
14
|
import highlightWords from "highlight-words";
|
|
15
15
|
import { rxResource, takeUntilDestroyed, toSignal } from "@angular/core/rxjs-interop";
|
|
16
16
|
import { cva } from "class-variance-authority";
|
|
17
|
-
import { FormField, FormRoot, applyEach, debounce, form, readonly, required, schema, submit, validate } from "@angular/forms/signals";
|
|
17
|
+
import { FormField, FormRoot, applyEach, debounce, form, maxLength, readonly, required, schema, submit, validate } from "@angular/forms/signals";
|
|
18
18
|
import { injectVirtualizer } from "@tanstack/angular-virtual";
|
|
19
19
|
import { catchError as catchError$1, filter as filter$2, map as map$1, switchMap as switchMap$1 } from "rxjs/operators";
|
|
20
20
|
import { Tab } from "@angular/aria/tabs";
|
|
@@ -6686,6 +6686,799 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
6686
6686
|
}
|
|
6687
6687
|
});
|
|
6688
6688
|
const AddToCollection = createCallable(CollectionsDialog);
|
|
6689
|
+
let nextId = 0;
|
|
6690
|
+
var AddToCollectionPanelComponent = class AddToCollectionPanelComponent {
|
|
6691
|
+
articles = input.required(...ngDevMode ? [{ debugName: "articles" }] : /* istanbul ignore next */ []);
|
|
6692
|
+
done = output();
|
|
6693
|
+
changed = output();
|
|
6694
|
+
closeRequested = output();
|
|
6695
|
+
userSettingsStore = inject(UserSettingsStore);
|
|
6696
|
+
injector = inject(Injector);
|
|
6697
|
+
titleId = `add-to-collection-title-${nextId}`;
|
|
6698
|
+
nameId = `add-to-collection-name-${nextId}`;
|
|
6699
|
+
errorId = `add-to-collection-error-${nextId++}`;
|
|
6700
|
+
scrollElement = viewChild("scrollElement", ...ngDevMode ? [{ debugName: "scrollElement" }] : /* istanbul ignore next */ []);
|
|
6701
|
+
searchInput = viewChild("searchInput", ...ngDevMode ? [{ debugName: "searchInput" }] : /* istanbul ignore next */ []);
|
|
6702
|
+
nameInput = viewChild("nameInput", ...ngDevMode ? [{ debugName: "nameInput" }] : /* istanbul ignore next */ []);
|
|
6703
|
+
collections = computed(() => this.userSettingsStore.baskets(), ...ngDevMode ? [{ debugName: "collections" }] : /* istanbul ignore next */ []);
|
|
6704
|
+
showSearch = computed(() => this.collections().length > 6, ...ngDevMode ? [{ debugName: "showSearch" }] : /* istanbul ignore next */ []);
|
|
6705
|
+
count = computed(() => this.ids().length, ...ngDevMode ? [{ debugName: "count" }] : /* istanbul ignore next */ []);
|
|
6706
|
+
ids = computed(() => Array.from(new Set(this.articles().map((a) => a.id).filter((id) => !!id))), ...ngDevMode ? [{ debugName: "ids" }] : /* istanbul ignore next */ []);
|
|
6707
|
+
searchText = signal("", ...ngDevMode ? [{ debugName: "searchText" }] : /* istanbul ignore next */ []);
|
|
6708
|
+
searchField = form(this.searchText);
|
|
6709
|
+
createdHere = signal([], ...ngDevMode ? [{ debugName: "createdHere" }] : /* istanbul ignore next */ []);
|
|
6710
|
+
filteredCollections = computed(() => {
|
|
6711
|
+
const query = this.searchText().trim().toLowerCase();
|
|
6712
|
+
const created = this.createdHere();
|
|
6713
|
+
const all = this.collections();
|
|
6714
|
+
const matching = query ? all.filter((c) => c.name.toLowerCase().includes(query)) : all;
|
|
6715
|
+
const rank = (c) => {
|
|
6716
|
+
const i = created.indexOf(c.name);
|
|
6717
|
+
return i < 0 ? created.length : i;
|
|
6718
|
+
};
|
|
6719
|
+
return created.length ? [...matching].sort((a, b) => rank(a) - rank(b)) : matching;
|
|
6720
|
+
}, ...ngDevMode ? [{ debugName: "filteredCollections" }] : /* istanbul ignore next */ []);
|
|
6721
|
+
status = signal(null, ...ngDevMode ? [{ debugName: "status" }] : /* istanbul ignore next */ []);
|
|
6722
|
+
creating = signal(false, ...ngDevMode ? [{ debugName: "creating" }] : /* istanbul ignore next */ []);
|
|
6723
|
+
createModel = signal({ name: "" }, ...ngDevMode ? [{ debugName: "createModel" }] : /* istanbul ignore next */ []);
|
|
6724
|
+
createForm = form(this.createModel, (path) => {
|
|
6725
|
+
maxLength(path.name, 50);
|
|
6726
|
+
validate(path.name, ({ value }) => {
|
|
6727
|
+
const name = value().trim();
|
|
6728
|
+
if (!name) return { kind: "nameRequired" };
|
|
6729
|
+
if (this.nameTaken(name)) return { kind: "nameExists" };
|
|
6730
|
+
});
|
|
6731
|
+
}, { submission: { action: async () => this.create() } });
|
|
6732
|
+
nameError = computed(() => {
|
|
6733
|
+
const field = this.createForm.name();
|
|
6734
|
+
const kinds = field.errors().map((e) => e.kind);
|
|
6735
|
+
if (kinds.includes("nameExists")) return "nameExists";
|
|
6736
|
+
if (kinds.includes("nameRequired") && field.touched()) return "nameRequired";
|
|
6737
|
+
return null;
|
|
6738
|
+
}, ...ngDevMode ? [{ debugName: "nameError" }] : /* istanbul ignore next */ []);
|
|
6739
|
+
virtualizer = injectVirtualizer(() => {
|
|
6740
|
+
const list = this.filteredCollections();
|
|
6741
|
+
return {
|
|
6742
|
+
count: list.length,
|
|
6743
|
+
estimateSize: (index) => this.coverageOf(list[index]) === "some" ? 52 : 40,
|
|
6744
|
+
getItemKey: (index) => list[index]?.name ?? index,
|
|
6745
|
+
scrollElement: this.scrollElement()
|
|
6746
|
+
};
|
|
6747
|
+
});
|
|
6748
|
+
doneTimer;
|
|
6749
|
+
constructor() {
|
|
6750
|
+
afterNextRender(() => this.focusFirst());
|
|
6751
|
+
inject(DestroyRef).onDestroy(() => clearTimeout(this.doneTimer));
|
|
6752
|
+
}
|
|
6753
|
+
coverageOf(collection) {
|
|
6754
|
+
if (!collection) return "none";
|
|
6755
|
+
const held = this.heldIn(collection);
|
|
6756
|
+
if (held === 0) return "none";
|
|
6757
|
+
return held === this.count() ? "all" : "some";
|
|
6758
|
+
}
|
|
6759
|
+
heldIn(collection) {
|
|
6760
|
+
const inCollection = new Set(collection.ids ?? []);
|
|
6761
|
+
return this.ids().filter((id) => inCollection.has(id)).length;
|
|
6762
|
+
}
|
|
6763
|
+
async toggle(collection) {
|
|
6764
|
+
const ids = this.ids();
|
|
6765
|
+
if (ids.length === 0) return;
|
|
6766
|
+
const removing = this.coverageOf(collection) === "all";
|
|
6767
|
+
const updated = {
|
|
6768
|
+
...collection,
|
|
6769
|
+
ids: removing ? (collection.ids ?? []).filter((id) => !ids.includes(id)) : Array.from(/* @__PURE__ */ new Set([...collection.ids ?? [], ...ids]))
|
|
6770
|
+
};
|
|
6771
|
+
const index = this.userSettingsStore.baskets().findIndex((b) => b.name === collection.name);
|
|
6772
|
+
if (index < 0) return;
|
|
6773
|
+
try {
|
|
6774
|
+
await this.userSettingsStore.updateBasket(updated, index);
|
|
6775
|
+
} catch (e) {
|
|
6776
|
+
error("Error updating collection:", e);
|
|
6777
|
+
return;
|
|
6778
|
+
}
|
|
6779
|
+
this.changed.emit();
|
|
6780
|
+
if (removing) this.status.set({
|
|
6781
|
+
kind: "removed",
|
|
6782
|
+
name: collection.name
|
|
6783
|
+
});
|
|
6784
|
+
else this.confirmAdded(collection.name);
|
|
6785
|
+
}
|
|
6786
|
+
startCreation() {
|
|
6787
|
+
this.creating.set(true);
|
|
6788
|
+
afterNextRender(() => this.nameInput()?.nativeElement.focus(), { injector: this.injector });
|
|
6789
|
+
}
|
|
6790
|
+
cancelCreation(event) {
|
|
6791
|
+
if (this.collections().length === 0) return;
|
|
6792
|
+
event?.preventDefault();
|
|
6793
|
+
event?.stopPropagation();
|
|
6794
|
+
this.createModel.set({ name: "" });
|
|
6795
|
+
this.createForm().reset();
|
|
6796
|
+
this.creating.set(false);
|
|
6797
|
+
afterNextRender(() => this.focusFirst(), { injector: this.injector });
|
|
6798
|
+
}
|
|
6799
|
+
async create() {
|
|
6800
|
+
const name = this.createModel().name.trim();
|
|
6801
|
+
try {
|
|
6802
|
+
await this.userSettingsStore.createBasket({
|
|
6803
|
+
name,
|
|
6804
|
+
ids: []
|
|
6805
|
+
});
|
|
6806
|
+
} catch (e) {
|
|
6807
|
+
error("Error creating collection:", e);
|
|
6808
|
+
return;
|
|
6809
|
+
}
|
|
6810
|
+
this.createModel.set({ name: "" });
|
|
6811
|
+
this.createForm().reset();
|
|
6812
|
+
this.searchText.set("");
|
|
6813
|
+
this.createdHere.update((names) => [name, ...names.filter((n) => n !== name)]);
|
|
6814
|
+
this.creating.set(false);
|
|
6815
|
+
this.status.set({
|
|
6816
|
+
kind: "created",
|
|
6817
|
+
name
|
|
6818
|
+
});
|
|
6819
|
+
this.changed.emit();
|
|
6820
|
+
afterNextRender(() => {
|
|
6821
|
+
const list = this.scrollElement()?.nativeElement;
|
|
6822
|
+
if (!list) return;
|
|
6823
|
+
list.scrollTop = 0;
|
|
6824
|
+
list.querySelector("button")?.focus();
|
|
6825
|
+
}, { injector: this.injector });
|
|
6826
|
+
}
|
|
6827
|
+
confirmAdded(name) {
|
|
6828
|
+
this.status.set({
|
|
6829
|
+
kind: "added",
|
|
6830
|
+
name
|
|
6831
|
+
});
|
|
6832
|
+
clearTimeout(this.doneTimer);
|
|
6833
|
+
this.doneTimer = setTimeout(() => this.done.emit(name), 900);
|
|
6834
|
+
}
|
|
6835
|
+
nameTaken(name) {
|
|
6836
|
+
const lower = name.toLowerCase();
|
|
6837
|
+
return this.collections().some((c) => c.name.toLowerCase() === lower);
|
|
6838
|
+
}
|
|
6839
|
+
onHostToggle(event) {
|
|
6840
|
+
if (event.newState === "open") this.focusFirst();
|
|
6841
|
+
}
|
|
6842
|
+
focusFirst() {
|
|
6843
|
+
(this.nameInput()?.nativeElement ?? this.searchInput()?.nativeElement ?? this.scrollElement()?.nativeElement.querySelector("button"))?.focus();
|
|
6844
|
+
}
|
|
6845
|
+
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
6846
|
+
minVersion: "12.0.0",
|
|
6847
|
+
version: "22.2.1",
|
|
6848
|
+
ngImport: i0,
|
|
6849
|
+
type: AddToCollectionPanelComponent,
|
|
6850
|
+
deps: [],
|
|
6851
|
+
target: i0.ɵɵFactoryTarget.Component
|
|
6852
|
+
});
|
|
6853
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({
|
|
6854
|
+
minVersion: "17.0.0",
|
|
6855
|
+
version: "22.2.1",
|
|
6856
|
+
type: AddToCollectionPanelComponent,
|
|
6857
|
+
isStandalone: true,
|
|
6858
|
+
selector: "AddToCollectionPanel, add-to-collection-panel",
|
|
6859
|
+
inputs: { articles: {
|
|
6860
|
+
classPropertyName: "articles",
|
|
6861
|
+
publicName: "articles",
|
|
6862
|
+
isSignal: true,
|
|
6863
|
+
isRequired: true,
|
|
6864
|
+
transformFunction: null
|
|
6865
|
+
} },
|
|
6866
|
+
outputs: {
|
|
6867
|
+
done: "done",
|
|
6868
|
+
changed: "changed",
|
|
6869
|
+
closeRequested: "closeRequested"
|
|
6870
|
+
},
|
|
6871
|
+
host: {
|
|
6872
|
+
attributes: { "role": "dialog" },
|
|
6873
|
+
listeners: { "toggle": "onHostToggle($event)" },
|
|
6874
|
+
properties: { "attr.aria-labelledby": "titleId" },
|
|
6875
|
+
classAttribute: "flex w-80 max-w-[calc(100vw-2*var(--spacing-md))] flex-col overflow-hidden rounded-(--radius-xl) border border-(--stroke-neutral-white) bg-(--bg-neutral-white) text-(--font-neutral-black) shadow-(--shadow-3)"
|
|
6876
|
+
},
|
|
6877
|
+
providers: [provideTranslocoScope("collections")],
|
|
6878
|
+
viewQueries: [
|
|
6879
|
+
{
|
|
6880
|
+
propertyName: "scrollElement",
|
|
6881
|
+
first: true,
|
|
6882
|
+
predicate: ["scrollElement"],
|
|
6883
|
+
descendants: true,
|
|
6884
|
+
isSignal: true
|
|
6885
|
+
},
|
|
6886
|
+
{
|
|
6887
|
+
propertyName: "searchInput",
|
|
6888
|
+
first: true,
|
|
6889
|
+
predicate: ["searchInput"],
|
|
6890
|
+
descendants: true,
|
|
6891
|
+
isSignal: true
|
|
6892
|
+
},
|
|
6893
|
+
{
|
|
6894
|
+
propertyName: "nameInput",
|
|
6895
|
+
first: true,
|
|
6896
|
+
predicate: ["nameInput"],
|
|
6897
|
+
descendants: true,
|
|
6898
|
+
isSignal: true
|
|
6899
|
+
}
|
|
6900
|
+
],
|
|
6901
|
+
ngImport: i0,
|
|
6902
|
+
template: `
|
|
6903
|
+
<div class="flex items-center gap-(--spacing-2xs) py-(--spacing-xs) ps-(--spacing-md) pe-(--spacing-xs)">
|
|
6904
|
+
@if (status()?.kind === 'added') {
|
|
6905
|
+
<circle-check-icon class="shrink-0 text-(--font-success-muted)" aria-hidden="true" />
|
|
6906
|
+
}
|
|
6907
|
+
<!-- The title is also the live region: the confirmation replaces it, and a change of an
|
|
6908
|
+
existing status node is what a screen reader announces. -->
|
|
6909
|
+
<p [id]="titleId" role="status" class="m-0 min-w-0 flex-1 text-(length:--size-base) leading-(--line-height-3)">
|
|
6910
|
+
@switch (status()?.kind) {
|
|
6911
|
+
@case ('added') {
|
|
6912
|
+
{{ 'collections.addedTo' | transloco: { name: status()!.name } }}
|
|
6913
|
+
}
|
|
6914
|
+
@case ('removed') {
|
|
6915
|
+
{{ 'collections.removedFrom' | transloco: { name: status()!.name } }}
|
|
6916
|
+
}
|
|
6917
|
+
@case ('created') {
|
|
6918
|
+
{{ 'collections.createdNamed' | transloco: { name: status()!.name } }}
|
|
6919
|
+
}
|
|
6920
|
+
@default {
|
|
6921
|
+
{{ 'collections.addDocuments' | transloco: { count: count() } }}
|
|
6922
|
+
}
|
|
6923
|
+
}
|
|
6924
|
+
</p>
|
|
6925
|
+
<button
|
|
6926
|
+
type="button"
|
|
6927
|
+
variant="none"
|
|
6928
|
+
class="inline-flex size-6 shrink-0 cursor-pointer items-center justify-center rounded-(--radius-xs) text-(--font-primary-muted) hover:bg-(--bg-primary-lighter) hover:text-(--font-primary-base) focus-visible:outline-2 focus-visible:outline-offset-0 focus-visible:outline-(--stroke-focus) focus-visible:outline-solid pointer-coarse:size-11"
|
|
6929
|
+
[attr.aria-label]="'collections.close' | transloco"
|
|
6930
|
+
[tooltip]="'collections.close' | transloco"
|
|
6931
|
+
(click)="closeRequested.emit()">
|
|
6932
|
+
<x-mark-icon aria-hidden="true" />
|
|
6933
|
+
</button>
|
|
6934
|
+
</div>
|
|
6935
|
+
|
|
6936
|
+
<div class="flex min-h-0 flex-col gap-(--spacing-2xs) border-t border-(--stroke-neutral-white) pt-(--spacing-xs) pb-(--spacing-2xs)">
|
|
6937
|
+
@if (collections().length === 0) {
|
|
6938
|
+
<div class="flex flex-col items-center gap-(--spacing-3xs) px-(--spacing-md) pt-(--spacing-2xs) text-center">
|
|
6939
|
+
<span class="mb-(--spacing-3xs) inline-flex size-10 items-center justify-center rounded-(--radius-md) bg-(--bg-indigo-base-alt) text-(--font-indigo-base)" aria-hidden="true">
|
|
6940
|
+
<inbox-icon />
|
|
6941
|
+
</span>
|
|
6942
|
+
<p class="m-0 text-(length:--size-base) font-semibold">{{ 'collections.noCollections' | transloco }}</p>
|
|
6943
|
+
<p class="m-0 text-(length:--size-sm) text-(--font-neutral-muted)">{{ 'collections.noCollectionsPanelHint' | transloco }}</p>
|
|
6944
|
+
</div>
|
|
6945
|
+
}
|
|
6946
|
+
|
|
6947
|
+
<!-- As in lexiQ, the name field opens at the top of the list, which stays on screen, dimmed and
|
|
6948
|
+
inert, until the collection is created or the creation cancelled: the user does not leave
|
|
6949
|
+
the list for another screen. -->
|
|
6950
|
+
@if (creating() || collections().length === 0) {
|
|
6951
|
+
<form [formRoot]="createForm" class="flex flex-col gap-(--spacing-3xs) px-(--spacing-xs)">
|
|
6952
|
+
<label [for]="nameId" class="px-(--spacing-3xs) text-(length:--size-sm) font-medium text-(--font-neutral-base)">
|
|
6953
|
+
{{ 'collections.collectionName' | transloco }}
|
|
6954
|
+
</label>
|
|
6955
|
+
<div class="flex items-center gap-(--spacing-3xs)">
|
|
6956
|
+
<input-group class="min-w-0 flex-1">
|
|
6957
|
+
<input
|
|
6958
|
+
#nameInput
|
|
6959
|
+
input-control
|
|
6960
|
+
type="text"
|
|
6961
|
+
autocomplete="off"
|
|
6962
|
+
spellcheck="false"
|
|
6963
|
+
[id]="nameId"
|
|
6964
|
+
[attr.placeholder]="'collections.collectionNamePlaceholder' | transloco"
|
|
6965
|
+
[formField]="createForm.name"
|
|
6966
|
+
[attr.aria-invalid]="nameError() ? 'true' : null"
|
|
6967
|
+
[attr.aria-describedby]="nameError() ? errorId : null"
|
|
6968
|
+
(keydown.escape)="cancelCreation($event)" />
|
|
6969
|
+
</input-group>
|
|
6970
|
+
@if (collections().length > 0) {
|
|
6971
|
+
<button
|
|
6972
|
+
type="button"
|
|
6973
|
+
variant="secondary"
|
|
6974
|
+
size="md"
|
|
6975
|
+
[iconOnly]="true"
|
|
6976
|
+
class="shrink-0 pointer-coarse:size-11"
|
|
6977
|
+
[attr.aria-label]="'collections.cancelCreation' | transloco"
|
|
6978
|
+
[tooltip]="'collections.cancelCreation' | transloco"
|
|
6979
|
+
(click)="cancelCreation()">
|
|
6980
|
+
<x-mark-icon aria-hidden="true" />
|
|
6981
|
+
</button>
|
|
6982
|
+
<button
|
|
6983
|
+
type="submit"
|
|
6984
|
+
size="md"
|
|
6985
|
+
[iconOnly]="true"
|
|
6986
|
+
class="shrink-0 pointer-coarse:size-11"
|
|
6987
|
+
[attr.aria-label]="'collections.createCollection' | transloco"
|
|
6988
|
+
[tooltip]="'collections.createCollection' | transloco">
|
|
6989
|
+
<check-icon aria-hidden="true" />
|
|
6990
|
+
</button>
|
|
6991
|
+
} @else {
|
|
6992
|
+
<button type="submit" size="md" class="shrink-0 pointer-coarse:h-11">{{ 'collections.create' | transloco }}</button>
|
|
6993
|
+
}
|
|
6994
|
+
</div>
|
|
6995
|
+
<!-- No line kept in reserve for the message: it would leave an empty gap above the list. -->
|
|
6996
|
+
@if (nameError(); as kind) {
|
|
6997
|
+
<p [id]="errorId" class="m-0 px-(--spacing-3xs) text-(length:--size-sm) text-(--font-error-base)">
|
|
6998
|
+
{{ 'collections.' + kind | transloco }}
|
|
6999
|
+
</p>
|
|
7000
|
+
}
|
|
7001
|
+
</form>
|
|
7002
|
+
} @else {
|
|
7003
|
+
@if (showSearch()) {
|
|
7004
|
+
<input-group class="mx-(--spacing-xs) min-w-0">
|
|
7005
|
+
<search-icon input-icon-left aria-hidden="true" />
|
|
7006
|
+
<input
|
|
7007
|
+
#searchInput
|
|
7008
|
+
input-control
|
|
7009
|
+
type="search"
|
|
7010
|
+
autocomplete="off"
|
|
7011
|
+
spellcheck="false"
|
|
7012
|
+
[attr.aria-label]="'collections.searchCollections' | transloco"
|
|
7013
|
+
[attr.placeholder]="'collections.searchCollections' | transloco"
|
|
7014
|
+
[formField]="searchField" />
|
|
7015
|
+
</input-group>
|
|
7016
|
+
}
|
|
7017
|
+
|
|
7018
|
+
<div class="flex items-center ps-(--spacing-md) pe-(--spacing-xs)">
|
|
7019
|
+
<span class="flex-1 text-(length:--size-base) font-medium">{{ 'collections.label' | transloco }}</span>
|
|
7020
|
+
<button type="button" variant="tertiary" size="sm" (click)="startCreation()">
|
|
7021
|
+
<plus-icon aria-hidden="true" />
|
|
7022
|
+
{{ 'collections.newCollection' | transloco }}
|
|
7023
|
+
</button>
|
|
7024
|
+
</div>
|
|
7025
|
+
}
|
|
7026
|
+
|
|
7027
|
+
@if (collections().length > 0) {
|
|
7028
|
+
<div
|
|
7029
|
+
#scrollElement
|
|
7030
|
+
role="group"
|
|
7031
|
+
[attr.aria-label]="'collections.label' | transloco"
|
|
7032
|
+
[attr.inert]="creating() ? '' : null"
|
|
7033
|
+
class="max-h-[min(15rem,var(--panel-max-h,15rem))] overflow-y-auto px-(--spacing-2xs) transition-opacity duration-150 [scrollbar-color:color-mix(in_srgb,currentColor_40%,transparent)_transparent] [scrollbar-width:thin] motion-reduce:transition-none"
|
|
7034
|
+
[class.opacity-40]="creating()">
|
|
7035
|
+
@if (filteredCollections().length) {
|
|
7036
|
+
<div class="relative w-full" [style.height.px]="virtualizer.getTotalSize()">
|
|
7037
|
+
@for (vItem of virtualizer.getVirtualItems(); track vItem.key) {
|
|
7038
|
+
@let collection = filteredCollections()[vItem.index];
|
|
7039
|
+
@let coverage = coverageOf(collection);
|
|
7040
|
+
<div
|
|
7041
|
+
class="absolute inset-x-0 flex items-center gap-(--spacing-2xs) rounded-(--radius-md) px-(--spacing-2xs) hover:bg-(--bg-primary-lightest) data-[fresh=true]:bg-(--bg-primary-lightest)"
|
|
7042
|
+
[attr.data-fresh]="status()?.name === collection.name && status()?.kind !== 'removed'"
|
|
7043
|
+
[style.height.px]="vItem.size"
|
|
7044
|
+
[style.transform]="'translateY(' + vItem.start + 'px)'">
|
|
7045
|
+
<span class="inline-flex size-6 shrink-0 items-center justify-center rounded-(--radius-xs) bg-(--bg-primary-lighter) text-(--font-primary-base)" aria-hidden="true">
|
|
7046
|
+
<folder-icon />
|
|
7047
|
+
</span>
|
|
7048
|
+
<span class="min-w-0 flex-1">
|
|
7049
|
+
<span class="block truncate text-(length:--size-base)">{{ collection.name }}</span>
|
|
7050
|
+
@if (coverage === 'some') {
|
|
7051
|
+
<span class="block truncate text-(length:--size-sm) text-(--font-neutral-muted)">
|
|
7052
|
+
{{ 'collections.alreadyHasSome' | transloco: { count: heldIn(collection), total: count() } }}
|
|
7053
|
+
</span>
|
|
7054
|
+
}
|
|
7055
|
+
</span>
|
|
7056
|
+
@if (coverage === 'all') {
|
|
7057
|
+
<button
|
|
7058
|
+
type="button"
|
|
7059
|
+
size="sm"
|
|
7060
|
+
[iconOnly]="true"
|
|
7061
|
+
class="shrink-0 focus-visible:-outline-offset-2 pointer-coarse:size-11"
|
|
7062
|
+
aria-pressed="true"
|
|
7063
|
+
[attr.aria-label]="'collections.removeFrom' | transloco: { name: collection.name }"
|
|
7064
|
+
(click)="toggle(collection)">
|
|
7065
|
+
<check-icon aria-hidden="true" />
|
|
7066
|
+
</button>
|
|
7067
|
+
} @else {
|
|
7068
|
+
<button
|
|
7069
|
+
type="button"
|
|
7070
|
+
variant="secondary"
|
|
7071
|
+
size="sm"
|
|
7072
|
+
[iconOnly]="true"
|
|
7073
|
+
class="shrink-0 bg-(--bg-neutral-white) focus-visible:-outline-offset-2 pointer-coarse:size-11"
|
|
7074
|
+
[attr.aria-pressed]="coverage === 'some' ? 'mixed' : 'false'"
|
|
7075
|
+
[attr.aria-label]="(coverage === 'some' ? 'collections.addMissingTo' : 'collections.addDocumentsTo') | transloco: { count: count(), name: collection.name }"
|
|
7076
|
+
(click)="toggle(collection)">
|
|
7077
|
+
<plus-icon aria-hidden="true" />
|
|
7078
|
+
</button>
|
|
7079
|
+
}
|
|
7080
|
+
</div>
|
|
7081
|
+
}
|
|
7082
|
+
</div>
|
|
7083
|
+
} @else {
|
|
7084
|
+
<p class="m-0 px-(--spacing-2xs) py-(--spacing-xs) text-(length:--size-sm) text-(--font-neutral-muted)">
|
|
7085
|
+
{{ 'collections.noMatch' | transloco }}
|
|
7086
|
+
</p>
|
|
7087
|
+
}
|
|
7088
|
+
</div>
|
|
7089
|
+
}
|
|
7090
|
+
</div>
|
|
7091
|
+
`,
|
|
7092
|
+
isInline: true,
|
|
7093
|
+
dependencies: [
|
|
7094
|
+
{
|
|
7095
|
+
kind: "directive",
|
|
7096
|
+
type: FormRoot,
|
|
7097
|
+
selector: "form[formRoot]",
|
|
7098
|
+
inputs: ["formRoot"]
|
|
7099
|
+
},
|
|
7100
|
+
{
|
|
7101
|
+
kind: "directive",
|
|
7102
|
+
type: FormField,
|
|
7103
|
+
selector: "[formField]",
|
|
7104
|
+
inputs: ["formField"],
|
|
7105
|
+
exportAs: ["formField"]
|
|
7106
|
+
},
|
|
7107
|
+
{
|
|
7108
|
+
kind: "directive",
|
|
7109
|
+
type: ButtonComponent,
|
|
7110
|
+
selector: "button",
|
|
7111
|
+
inputs: [
|
|
7112
|
+
"class",
|
|
7113
|
+
"variant",
|
|
7114
|
+
"scheme",
|
|
7115
|
+
"iconOnly",
|
|
7116
|
+
"size"
|
|
7117
|
+
]
|
|
7118
|
+
},
|
|
7119
|
+
{
|
|
7120
|
+
kind: "directive",
|
|
7121
|
+
type: InputComponent,
|
|
7122
|
+
selector: "input-group, inputgroup, InputGroup",
|
|
7123
|
+
inputs: [
|
|
7124
|
+
"class",
|
|
7125
|
+
"size",
|
|
7126
|
+
"scheme",
|
|
7127
|
+
"filled",
|
|
7128
|
+
"numbers",
|
|
7129
|
+
"autoHeight",
|
|
7130
|
+
"textSize"
|
|
7131
|
+
]
|
|
7132
|
+
},
|
|
7133
|
+
{
|
|
7134
|
+
kind: "directive",
|
|
7135
|
+
type: InputControlDirective,
|
|
7136
|
+
selector: "input[input-control], input[inputControl]",
|
|
7137
|
+
inputs: ["class"]
|
|
7138
|
+
},
|
|
7139
|
+
{
|
|
7140
|
+
kind: "directive",
|
|
7141
|
+
type: InputIconLeftDirective,
|
|
7142
|
+
selector: "[input-icon-left], [inputIconLeft]",
|
|
7143
|
+
inputs: ["class"]
|
|
7144
|
+
},
|
|
7145
|
+
{
|
|
7146
|
+
kind: "directive",
|
|
7147
|
+
type: TooltipDirective,
|
|
7148
|
+
selector: "[tooltip]",
|
|
7149
|
+
inputs: [
|
|
7150
|
+
"tooltip",
|
|
7151
|
+
"tooltipPosition",
|
|
7152
|
+
"tooltipEvent",
|
|
7153
|
+
"showDelay",
|
|
7154
|
+
"hideDelay",
|
|
7155
|
+
"life",
|
|
7156
|
+
"tooltipOffset",
|
|
7157
|
+
"autoHide",
|
|
7158
|
+
"hideOnEscape",
|
|
7159
|
+
"escape",
|
|
7160
|
+
"tooltipDisabled",
|
|
7161
|
+
"tooltipArrow",
|
|
7162
|
+
"tooltipStyleClass",
|
|
7163
|
+
"tooltipOptions",
|
|
7164
|
+
"tooltip-position",
|
|
7165
|
+
"tooltip-delay",
|
|
7166
|
+
"tooltip-duration",
|
|
7167
|
+
"tooltip-offset"
|
|
7168
|
+
],
|
|
7169
|
+
exportAs: ["tooltip"]
|
|
7170
|
+
},
|
|
7171
|
+
{
|
|
7172
|
+
kind: "component",
|
|
7173
|
+
type: CheckIcon,
|
|
7174
|
+
selector: "check, check-icon, Check, CheckIcon",
|
|
7175
|
+
inputs: ["class"]
|
|
7176
|
+
},
|
|
7177
|
+
{
|
|
7178
|
+
kind: "component",
|
|
7179
|
+
type: CircleCheckIcon,
|
|
7180
|
+
selector: "circle-check, circle-check-icon, CircleCheck, CircleCheckIcon",
|
|
7181
|
+
inputs: ["class"]
|
|
7182
|
+
},
|
|
7183
|
+
{
|
|
7184
|
+
kind: "component",
|
|
7185
|
+
type: FolderIcon,
|
|
7186
|
+
selector: "folder, folder-icon, Folder, FolderIcon",
|
|
7187
|
+
inputs: ["class"]
|
|
7188
|
+
},
|
|
7189
|
+
{
|
|
7190
|
+
kind: "component",
|
|
7191
|
+
type: InboxIcon,
|
|
7192
|
+
selector: "inbox, inbox-icon, Inbox, InboxIcon",
|
|
7193
|
+
inputs: ["class"]
|
|
7194
|
+
},
|
|
7195
|
+
{
|
|
7196
|
+
kind: "component",
|
|
7197
|
+
type: PlusIcon,
|
|
7198
|
+
selector: "plus, plus-icon, Plus, PlusIcon",
|
|
7199
|
+
inputs: ["class"]
|
|
7200
|
+
},
|
|
7201
|
+
{
|
|
7202
|
+
kind: "component",
|
|
7203
|
+
type: SearchIcon,
|
|
7204
|
+
selector: "search, search-icon, Search, SearchIcon",
|
|
7205
|
+
inputs: ["class"]
|
|
7206
|
+
},
|
|
7207
|
+
{
|
|
7208
|
+
kind: "component",
|
|
7209
|
+
type: XMarkIcon,
|
|
7210
|
+
selector: "x-mark, x-mark-icon, XMark, XMarkIcon",
|
|
7211
|
+
inputs: ["class"]
|
|
7212
|
+
},
|
|
7213
|
+
{
|
|
7214
|
+
kind: "pipe",
|
|
7215
|
+
type: TranslocoPipe,
|
|
7216
|
+
name: "transloco"
|
|
7217
|
+
}
|
|
7218
|
+
]
|
|
7219
|
+
});
|
|
7220
|
+
};
|
|
7221
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
7222
|
+
minVersion: "12.0.0",
|
|
7223
|
+
version: "22.2.1",
|
|
7224
|
+
ngImport: i0,
|
|
7225
|
+
type: AddToCollectionPanelComponent,
|
|
7226
|
+
decorators: [{
|
|
7227
|
+
type: Component,
|
|
7228
|
+
args: [{
|
|
7229
|
+
selector: "AddToCollectionPanel, add-to-collection-panel",
|
|
7230
|
+
imports: [
|
|
7231
|
+
FormRoot,
|
|
7232
|
+
FormField,
|
|
7233
|
+
TranslocoPipe,
|
|
7234
|
+
ButtonComponent,
|
|
7235
|
+
InputComponent,
|
|
7236
|
+
InputControlDirective,
|
|
7237
|
+
InputIconLeftDirective,
|
|
7238
|
+
TooltipDirective,
|
|
7239
|
+
CheckIcon,
|
|
7240
|
+
CircleCheckIcon,
|
|
7241
|
+
FolderIcon,
|
|
7242
|
+
InboxIcon,
|
|
7243
|
+
PlusIcon,
|
|
7244
|
+
SearchIcon,
|
|
7245
|
+
XMarkIcon
|
|
7246
|
+
],
|
|
7247
|
+
providers: [provideTranslocoScope("collections")],
|
|
7248
|
+
host: {
|
|
7249
|
+
role: "dialog",
|
|
7250
|
+
"[attr.aria-labelledby]": "titleId",
|
|
7251
|
+
"(toggle)": "onHostToggle($event)",
|
|
7252
|
+
class: "flex w-80 max-w-[calc(100vw-2*var(--spacing-md))] flex-col overflow-hidden rounded-(--radius-xl) border border-(--stroke-neutral-white) bg-(--bg-neutral-white) text-(--font-neutral-black) shadow-(--shadow-3)"
|
|
7253
|
+
},
|
|
7254
|
+
template: `
|
|
7255
|
+
<div class="flex items-center gap-(--spacing-2xs) py-(--spacing-xs) ps-(--spacing-md) pe-(--spacing-xs)">
|
|
7256
|
+
@if (status()?.kind === 'added') {
|
|
7257
|
+
<circle-check-icon class="shrink-0 text-(--font-success-muted)" aria-hidden="true" />
|
|
7258
|
+
}
|
|
7259
|
+
<!-- The title is also the live region: the confirmation replaces it, and a change of an
|
|
7260
|
+
existing status node is what a screen reader announces. -->
|
|
7261
|
+
<p [id]="titleId" role="status" class="m-0 min-w-0 flex-1 text-(length:--size-base) leading-(--line-height-3)">
|
|
7262
|
+
@switch (status()?.kind) {
|
|
7263
|
+
@case ('added') {
|
|
7264
|
+
{{ 'collections.addedTo' | transloco: { name: status()!.name } }}
|
|
7265
|
+
}
|
|
7266
|
+
@case ('removed') {
|
|
7267
|
+
{{ 'collections.removedFrom' | transloco: { name: status()!.name } }}
|
|
7268
|
+
}
|
|
7269
|
+
@case ('created') {
|
|
7270
|
+
{{ 'collections.createdNamed' | transloco: { name: status()!.name } }}
|
|
7271
|
+
}
|
|
7272
|
+
@default {
|
|
7273
|
+
{{ 'collections.addDocuments' | transloco: { count: count() } }}
|
|
7274
|
+
}
|
|
7275
|
+
}
|
|
7276
|
+
</p>
|
|
7277
|
+
<button
|
|
7278
|
+
type="button"
|
|
7279
|
+
variant="none"
|
|
7280
|
+
class="inline-flex size-6 shrink-0 cursor-pointer items-center justify-center rounded-(--radius-xs) text-(--font-primary-muted) hover:bg-(--bg-primary-lighter) hover:text-(--font-primary-base) focus-visible:outline-2 focus-visible:outline-offset-0 focus-visible:outline-(--stroke-focus) focus-visible:outline-solid pointer-coarse:size-11"
|
|
7281
|
+
[attr.aria-label]="'collections.close' | transloco"
|
|
7282
|
+
[tooltip]="'collections.close' | transloco"
|
|
7283
|
+
(click)="closeRequested.emit()">
|
|
7284
|
+
<x-mark-icon aria-hidden="true" />
|
|
7285
|
+
</button>
|
|
7286
|
+
</div>
|
|
7287
|
+
|
|
7288
|
+
<div class="flex min-h-0 flex-col gap-(--spacing-2xs) border-t border-(--stroke-neutral-white) pt-(--spacing-xs) pb-(--spacing-2xs)">
|
|
7289
|
+
@if (collections().length === 0) {
|
|
7290
|
+
<div class="flex flex-col items-center gap-(--spacing-3xs) px-(--spacing-md) pt-(--spacing-2xs) text-center">
|
|
7291
|
+
<span class="mb-(--spacing-3xs) inline-flex size-10 items-center justify-center rounded-(--radius-md) bg-(--bg-indigo-base-alt) text-(--font-indigo-base)" aria-hidden="true">
|
|
7292
|
+
<inbox-icon />
|
|
7293
|
+
</span>
|
|
7294
|
+
<p class="m-0 text-(length:--size-base) font-semibold">{{ 'collections.noCollections' | transloco }}</p>
|
|
7295
|
+
<p class="m-0 text-(length:--size-sm) text-(--font-neutral-muted)">{{ 'collections.noCollectionsPanelHint' | transloco }}</p>
|
|
7296
|
+
</div>
|
|
7297
|
+
}
|
|
7298
|
+
|
|
7299
|
+
<!-- As in lexiQ, the name field opens at the top of the list, which stays on screen, dimmed and
|
|
7300
|
+
inert, until the collection is created or the creation cancelled: the user does not leave
|
|
7301
|
+
the list for another screen. -->
|
|
7302
|
+
@if (creating() || collections().length === 0) {
|
|
7303
|
+
<form [formRoot]="createForm" class="flex flex-col gap-(--spacing-3xs) px-(--spacing-xs)">
|
|
7304
|
+
<label [for]="nameId" class="px-(--spacing-3xs) text-(length:--size-sm) font-medium text-(--font-neutral-base)">
|
|
7305
|
+
{{ 'collections.collectionName' | transloco }}
|
|
7306
|
+
</label>
|
|
7307
|
+
<div class="flex items-center gap-(--spacing-3xs)">
|
|
7308
|
+
<input-group class="min-w-0 flex-1">
|
|
7309
|
+
<input
|
|
7310
|
+
#nameInput
|
|
7311
|
+
input-control
|
|
7312
|
+
type="text"
|
|
7313
|
+
autocomplete="off"
|
|
7314
|
+
spellcheck="false"
|
|
7315
|
+
[id]="nameId"
|
|
7316
|
+
[attr.placeholder]="'collections.collectionNamePlaceholder' | transloco"
|
|
7317
|
+
[formField]="createForm.name"
|
|
7318
|
+
[attr.aria-invalid]="nameError() ? 'true' : null"
|
|
7319
|
+
[attr.aria-describedby]="nameError() ? errorId : null"
|
|
7320
|
+
(keydown.escape)="cancelCreation($event)" />
|
|
7321
|
+
</input-group>
|
|
7322
|
+
@if (collections().length > 0) {
|
|
7323
|
+
<button
|
|
7324
|
+
type="button"
|
|
7325
|
+
variant="secondary"
|
|
7326
|
+
size="md"
|
|
7327
|
+
[iconOnly]="true"
|
|
7328
|
+
class="shrink-0 pointer-coarse:size-11"
|
|
7329
|
+
[attr.aria-label]="'collections.cancelCreation' | transloco"
|
|
7330
|
+
[tooltip]="'collections.cancelCreation' | transloco"
|
|
7331
|
+
(click)="cancelCreation()">
|
|
7332
|
+
<x-mark-icon aria-hidden="true" />
|
|
7333
|
+
</button>
|
|
7334
|
+
<button
|
|
7335
|
+
type="submit"
|
|
7336
|
+
size="md"
|
|
7337
|
+
[iconOnly]="true"
|
|
7338
|
+
class="shrink-0 pointer-coarse:size-11"
|
|
7339
|
+
[attr.aria-label]="'collections.createCollection' | transloco"
|
|
7340
|
+
[tooltip]="'collections.createCollection' | transloco">
|
|
7341
|
+
<check-icon aria-hidden="true" />
|
|
7342
|
+
</button>
|
|
7343
|
+
} @else {
|
|
7344
|
+
<button type="submit" size="md" class="shrink-0 pointer-coarse:h-11">{{ 'collections.create' | transloco }}</button>
|
|
7345
|
+
}
|
|
7346
|
+
</div>
|
|
7347
|
+
<!-- No line kept in reserve for the message: it would leave an empty gap above the list. -->
|
|
7348
|
+
@if (nameError(); as kind) {
|
|
7349
|
+
<p [id]="errorId" class="m-0 px-(--spacing-3xs) text-(length:--size-sm) text-(--font-error-base)">
|
|
7350
|
+
{{ 'collections.' + kind | transloco }}
|
|
7351
|
+
</p>
|
|
7352
|
+
}
|
|
7353
|
+
</form>
|
|
7354
|
+
} @else {
|
|
7355
|
+
@if (showSearch()) {
|
|
7356
|
+
<input-group class="mx-(--spacing-xs) min-w-0">
|
|
7357
|
+
<search-icon input-icon-left aria-hidden="true" />
|
|
7358
|
+
<input
|
|
7359
|
+
#searchInput
|
|
7360
|
+
input-control
|
|
7361
|
+
type="search"
|
|
7362
|
+
autocomplete="off"
|
|
7363
|
+
spellcheck="false"
|
|
7364
|
+
[attr.aria-label]="'collections.searchCollections' | transloco"
|
|
7365
|
+
[attr.placeholder]="'collections.searchCollections' | transloco"
|
|
7366
|
+
[formField]="searchField" />
|
|
7367
|
+
</input-group>
|
|
7368
|
+
}
|
|
7369
|
+
|
|
7370
|
+
<div class="flex items-center ps-(--spacing-md) pe-(--spacing-xs)">
|
|
7371
|
+
<span class="flex-1 text-(length:--size-base) font-medium">{{ 'collections.label' | transloco }}</span>
|
|
7372
|
+
<button type="button" variant="tertiary" size="sm" (click)="startCreation()">
|
|
7373
|
+
<plus-icon aria-hidden="true" />
|
|
7374
|
+
{{ 'collections.newCollection' | transloco }}
|
|
7375
|
+
</button>
|
|
7376
|
+
</div>
|
|
7377
|
+
}
|
|
7378
|
+
|
|
7379
|
+
@if (collections().length > 0) {
|
|
7380
|
+
<div
|
|
7381
|
+
#scrollElement
|
|
7382
|
+
role="group"
|
|
7383
|
+
[attr.aria-label]="'collections.label' | transloco"
|
|
7384
|
+
[attr.inert]="creating() ? '' : null"
|
|
7385
|
+
class="max-h-[min(15rem,var(--panel-max-h,15rem))] overflow-y-auto px-(--spacing-2xs) transition-opacity duration-150 [scrollbar-color:color-mix(in_srgb,currentColor_40%,transparent)_transparent] [scrollbar-width:thin] motion-reduce:transition-none"
|
|
7386
|
+
[class.opacity-40]="creating()">
|
|
7387
|
+
@if (filteredCollections().length) {
|
|
7388
|
+
<div class="relative w-full" [style.height.px]="virtualizer.getTotalSize()">
|
|
7389
|
+
@for (vItem of virtualizer.getVirtualItems(); track vItem.key) {
|
|
7390
|
+
@let collection = filteredCollections()[vItem.index];
|
|
7391
|
+
@let coverage = coverageOf(collection);
|
|
7392
|
+
<div
|
|
7393
|
+
class="absolute inset-x-0 flex items-center gap-(--spacing-2xs) rounded-(--radius-md) px-(--spacing-2xs) hover:bg-(--bg-primary-lightest) data-[fresh=true]:bg-(--bg-primary-lightest)"
|
|
7394
|
+
[attr.data-fresh]="status()?.name === collection.name && status()?.kind !== 'removed'"
|
|
7395
|
+
[style.height.px]="vItem.size"
|
|
7396
|
+
[style.transform]="'translateY(' + vItem.start + 'px)'">
|
|
7397
|
+
<span class="inline-flex size-6 shrink-0 items-center justify-center rounded-(--radius-xs) bg-(--bg-primary-lighter) text-(--font-primary-base)" aria-hidden="true">
|
|
7398
|
+
<folder-icon />
|
|
7399
|
+
</span>
|
|
7400
|
+
<span class="min-w-0 flex-1">
|
|
7401
|
+
<span class="block truncate text-(length:--size-base)">{{ collection.name }}</span>
|
|
7402
|
+
@if (coverage === 'some') {
|
|
7403
|
+
<span class="block truncate text-(length:--size-sm) text-(--font-neutral-muted)">
|
|
7404
|
+
{{ 'collections.alreadyHasSome' | transloco: { count: heldIn(collection), total: count() } }}
|
|
7405
|
+
</span>
|
|
7406
|
+
}
|
|
7407
|
+
</span>
|
|
7408
|
+
@if (coverage === 'all') {
|
|
7409
|
+
<button
|
|
7410
|
+
type="button"
|
|
7411
|
+
size="sm"
|
|
7412
|
+
[iconOnly]="true"
|
|
7413
|
+
class="shrink-0 focus-visible:-outline-offset-2 pointer-coarse:size-11"
|
|
7414
|
+
aria-pressed="true"
|
|
7415
|
+
[attr.aria-label]="'collections.removeFrom' | transloco: { name: collection.name }"
|
|
7416
|
+
(click)="toggle(collection)">
|
|
7417
|
+
<check-icon aria-hidden="true" />
|
|
7418
|
+
</button>
|
|
7419
|
+
} @else {
|
|
7420
|
+
<button
|
|
7421
|
+
type="button"
|
|
7422
|
+
variant="secondary"
|
|
7423
|
+
size="sm"
|
|
7424
|
+
[iconOnly]="true"
|
|
7425
|
+
class="shrink-0 bg-(--bg-neutral-white) focus-visible:-outline-offset-2 pointer-coarse:size-11"
|
|
7426
|
+
[attr.aria-pressed]="coverage === 'some' ? 'mixed' : 'false'"
|
|
7427
|
+
[attr.aria-label]="(coverage === 'some' ? 'collections.addMissingTo' : 'collections.addDocumentsTo') | transloco: { count: count(), name: collection.name }"
|
|
7428
|
+
(click)="toggle(collection)">
|
|
7429
|
+
<plus-icon aria-hidden="true" />
|
|
7430
|
+
</button>
|
|
7431
|
+
}
|
|
7432
|
+
</div>
|
|
7433
|
+
}
|
|
7434
|
+
</div>
|
|
7435
|
+
} @else {
|
|
7436
|
+
<p class="m-0 px-(--spacing-2xs) py-(--spacing-xs) text-(length:--size-sm) text-(--font-neutral-muted)">
|
|
7437
|
+
{{ 'collections.noMatch' | transloco }}
|
|
7438
|
+
</p>
|
|
7439
|
+
}
|
|
7440
|
+
</div>
|
|
7441
|
+
}
|
|
7442
|
+
</div>
|
|
7443
|
+
`
|
|
7444
|
+
}]
|
|
7445
|
+
}],
|
|
7446
|
+
ctorParameters: () => [],
|
|
7447
|
+
propDecorators: {
|
|
7448
|
+
articles: [{
|
|
7449
|
+
type: i0.Input,
|
|
7450
|
+
args: [{
|
|
7451
|
+
isSignal: true,
|
|
7452
|
+
alias: "articles",
|
|
7453
|
+
required: true
|
|
7454
|
+
}]
|
|
7455
|
+
}],
|
|
7456
|
+
done: [{
|
|
7457
|
+
type: i0.Output,
|
|
7458
|
+
args: ["done"]
|
|
7459
|
+
}],
|
|
7460
|
+
changed: [{
|
|
7461
|
+
type: i0.Output,
|
|
7462
|
+
args: ["changed"]
|
|
7463
|
+
}],
|
|
7464
|
+
closeRequested: [{
|
|
7465
|
+
type: i0.Output,
|
|
7466
|
+
args: ["closeRequested"]
|
|
7467
|
+
}],
|
|
7468
|
+
scrollElement: [{
|
|
7469
|
+
type: i0.ViewChild,
|
|
7470
|
+
args: ["scrollElement", { isSignal: true }]
|
|
7471
|
+
}],
|
|
7472
|
+
searchInput: [{
|
|
7473
|
+
type: i0.ViewChild,
|
|
7474
|
+
args: ["searchInput", { isSignal: true }]
|
|
7475
|
+
}],
|
|
7476
|
+
nameInput: [{
|
|
7477
|
+
type: i0.ViewChild,
|
|
7478
|
+
args: ["nameInput", { isSignal: true }]
|
|
7479
|
+
}]
|
|
7480
|
+
}
|
|
7481
|
+
});
|
|
6689
7482
|
var ExportService = class ExportService {
|
|
6690
7483
|
client = inject(ATOMIC_CLIENT);
|
|
6691
7484
|
download(options) {
|
|
@@ -7227,14 +8020,16 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
7227
8020
|
}] }
|
|
7228
8021
|
});
|
|
7229
8022
|
const Export = createCallable(ExportDialog);
|
|
7230
|
-
const multiSelectionToolbarVariants = cva("
|
|
8023
|
+
const multiSelectionToolbarVariants = cva("", {
|
|
7231
8024
|
variants: { variant: {
|
|
7232
|
-
dark: "divide-gray-800 bg-gray-900 from-gray-500 to-gray-900 text-white",
|
|
7233
|
-
light: "divide-gray-400 bg-white from-white to-purple-50 text-gray-800",
|
|
7234
|
-
glassy: "divide-gray-300 bg-white/70 from-transparent to-white text-gray-800 backdrop-blur-[15px]"
|
|
8025
|
+
dark: "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 divide-gray-800 bg-gray-900 from-gray-500 to-gray-900 text-white",
|
|
8026
|
+
light: "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 divide-gray-400 bg-white from-white to-purple-50 text-gray-800",
|
|
8027
|
+
glassy: "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 divide-gray-300 bg-white/70 from-transparent to-white text-gray-800 backdrop-blur-[15px]",
|
|
8028
|
+
floating: "flex flex-wrap items-center justify-end gap-(--spacing-2xs)"
|
|
7235
8029
|
} },
|
|
7236
8030
|
defaultVariants: { variant: "dark" }
|
|
7237
8031
|
});
|
|
8032
|
+
const FLOATING_BUTTON = "shadow-(--shadow-2) pointer-coarse:h-11";
|
|
7238
8033
|
var MultiSelectionToolbarComponent = class MultiSelectionToolbarComponent {
|
|
7239
8034
|
cn = cn;
|
|
7240
8035
|
appStore = inject(AppStore);
|
|
@@ -7246,6 +8041,7 @@ var MultiSelectionToolbarComponent = class MultiSelectionToolbarComponent {
|
|
|
7246
8041
|
hint = input(...ngDevMode ? [void 0, { debugName: "hint" }] : /* istanbul ignore next */ []);
|
|
7247
8042
|
updatedCollections = output();
|
|
7248
8043
|
cleared = output();
|
|
8044
|
+
addedToCollection = output();
|
|
7249
8045
|
count = this.selection.multiSelectCount;
|
|
7250
8046
|
variants = computed(() => cn(multiSelectionToolbarVariants({
|
|
7251
8047
|
variant: this.variant(),
|
|
@@ -7265,6 +8061,25 @@ var MultiSelectionToolbarComponent = class MultiSelectionToolbarComponent {
|
|
|
7265
8061
|
showAssistantAction = computed(() => this.allowAI() && this.appStore.isAssistantAllowed(this.instanceId()) && this.enabledUserInput(), ...ngDevMode ? [{ debugName: "showAssistantAction" }] : /* istanbul ignore next */ []);
|
|
7266
8062
|
showHint = signal(false, ...ngDevMode ? [{ debugName: "showHint" }] : /* istanbul ignore next */ []);
|
|
7267
8063
|
armed = true;
|
|
8064
|
+
floatingButton = FLOATING_BUTTON;
|
|
8065
|
+
hostClass = computed(() => {
|
|
8066
|
+
const active = this.count() > 0;
|
|
8067
|
+
if (this.variant() === "floating") return cn("fixed end-(--spacing-xl) bottom-(--spacing-xl) z-50 transition-[translate,opacity] duration-300 motion-reduce:transition-none", active ? "translate-y-0 opacity-100" : "pointer-events-none translate-y-2 opacity-0");
|
|
8068
|
+
return cn("fixed -bottom-20 left-[50%] z-50 translate-x-[-50%] transition-[translate,opacity,discrete] duration-300", active ? "-translate-y-24 opacity-100" : "opacity-0");
|
|
8069
|
+
}, ...ngDevMode ? [{ debugName: "hostClass" }] : /* istanbul ignore next */ []);
|
|
8070
|
+
toolbarClass = computed(() => this.variants(), ...ngDevMode ? [{ debugName: "toolbarClass" }] : /* istanbul ignore next */ []);
|
|
8071
|
+
static nextId = 0;
|
|
8072
|
+
panelId = `multi-selection-collections-${MultiSelectionToolbarComponent.nextId++}`;
|
|
8073
|
+
panelOpen = signal(false, ...ngDevMode ? [{ debugName: "panelOpen" }] : /* istanbul ignore next */ []);
|
|
8074
|
+
panelArticles = signal([], ...ngDevMode ? [{ debugName: "panelArticles" }] : /* istanbul ignore next */ []);
|
|
8075
|
+
lastFiled = signal(null, ...ngDevMode ? [{ debugName: "lastFiled" }] : /* istanbul ignore next */ []);
|
|
8076
|
+
collectionsChanged = false;
|
|
8077
|
+
collectionTrigger = viewChild("collectionTrigger", ...ngDevMode ? [{ debugName: "collectionTrigger" }] : /* istanbul ignore next */ []);
|
|
8078
|
+
panel = viewChild("panel", {
|
|
8079
|
+
...ngDevMode ? { debugName: "panel" } : /* istanbul ignore next */ {},
|
|
8080
|
+
read: ElementRef
|
|
8081
|
+
});
|
|
8082
|
+
lastFiledTimer;
|
|
7268
8083
|
constructor() {
|
|
7269
8084
|
effect(() => {
|
|
7270
8085
|
const count = this.count();
|
|
@@ -7275,9 +8090,21 @@ var MultiSelectionToolbarComponent = class MultiSelectionToolbarComponent {
|
|
|
7275
8090
|
} else if (this.armed) {
|
|
7276
8091
|
this.armed = false;
|
|
7277
8092
|
this.showHint.set(true);
|
|
8093
|
+
this.lastFiled.set(null);
|
|
7278
8094
|
} else this.showHint.set(false);
|
|
7279
8095
|
});
|
|
7280
8096
|
});
|
|
8097
|
+
effect(() => {
|
|
8098
|
+
if (this.count() === 0) untracked(() => this.panelOpen() && this.closePanel());
|
|
8099
|
+
});
|
|
8100
|
+
injectFloatingPanel({
|
|
8101
|
+
panel: () => this.panel()?.nativeElement,
|
|
8102
|
+
anchor: () => this.collectionTrigger()?.nativeElement,
|
|
8103
|
+
placement: "top-end",
|
|
8104
|
+
offset: 8,
|
|
8105
|
+
topLayer: true,
|
|
8106
|
+
maxHeightVariable: "--panel-max-h"
|
|
8107
|
+
});
|
|
7281
8108
|
}
|
|
7282
8109
|
clearSelection = () => {
|
|
7283
8110
|
if (this.count() === 0) return;
|
|
@@ -7292,6 +8119,43 @@ var MultiSelectionToolbarComponent = class MultiSelectionToolbarComponent {
|
|
|
7292
8119
|
});
|
|
7293
8120
|
openExportDialog = () => void Export.call(this.ids(), { injector: this.injector });
|
|
7294
8121
|
attachToAssistant = () => this.selection.update({ assistantIdsToAttach: this.ids() });
|
|
8122
|
+
togglePanel() {
|
|
8123
|
+
if (this.panelOpen()) {
|
|
8124
|
+
this.closePanel();
|
|
8125
|
+
return;
|
|
8126
|
+
}
|
|
8127
|
+
this.panelArticles.set([...getState(this.selection).multiSelection]);
|
|
8128
|
+
this.collectionsChanged = false;
|
|
8129
|
+
this.panelOpen.set(true);
|
|
8130
|
+
}
|
|
8131
|
+
closePanel() {
|
|
8132
|
+
const el = this.panel()?.nativeElement;
|
|
8133
|
+
if (el?.matches(":popover-open")) el.hidePopover();
|
|
8134
|
+
else this.panelClosed();
|
|
8135
|
+
}
|
|
8136
|
+
onPanelToggle(event) {
|
|
8137
|
+
if (event.newState === "closed") this.panelClosed();
|
|
8138
|
+
}
|
|
8139
|
+
onFiled(name) {
|
|
8140
|
+
const count = this.panelArticles().length;
|
|
8141
|
+
this.closePanel();
|
|
8142
|
+
this.clearSelection();
|
|
8143
|
+
this.lastFiled.set({
|
|
8144
|
+
count,
|
|
8145
|
+
name
|
|
8146
|
+
});
|
|
8147
|
+
clearTimeout(this.lastFiledTimer);
|
|
8148
|
+
this.lastFiledTimer = setTimeout(() => this.lastFiled.set(null), 5e3);
|
|
8149
|
+
this.addedToCollection.emit(name);
|
|
8150
|
+
}
|
|
8151
|
+
panelClosed() {
|
|
8152
|
+
if (!this.panelOpen()) return;
|
|
8153
|
+
this.panelOpen.set(false);
|
|
8154
|
+
if (this.collectionsChanged) {
|
|
8155
|
+
this.collectionsChanged = false;
|
|
8156
|
+
this.updatedCollections.emit();
|
|
8157
|
+
}
|
|
8158
|
+
}
|
|
7295
8159
|
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
7296
8160
|
minVersion: "12.0.0",
|
|
7297
8161
|
version: "22.2.1",
|
|
@@ -7338,26 +8202,38 @@ var MultiSelectionToolbarComponent = class MultiSelectionToolbarComponent {
|
|
|
7338
8202
|
},
|
|
7339
8203
|
outputs: {
|
|
7340
8204
|
updatedCollections: "updatedCollections",
|
|
7341
|
-
cleared: "cleared"
|
|
7342
|
-
|
|
7343
|
-
host: {
|
|
7344
|
-
properties: {
|
|
7345
|
-
"class.opacity-100": "count() > 0",
|
|
7346
|
-
"class.-translate-y-24": "count() > 0"
|
|
7347
|
-
},
|
|
7348
|
-
classAttribute: "fixed -bottom-20 left-[50%] translate-x-[-50%] z-50 transition-[translate,opacity,discrete] duration-300 opacity-0"
|
|
8205
|
+
cleared: "cleared",
|
|
8206
|
+
addedToCollection: "addedToCollection"
|
|
7349
8207
|
},
|
|
8208
|
+
host: { properties: { "class": "hostClass()" } },
|
|
7350
8209
|
providers: [provideTranslocoScope("multi-selection-toolbar", "article", "collections", "export")],
|
|
8210
|
+
viewQueries: [{
|
|
8211
|
+
propertyName: "collectionTrigger",
|
|
8212
|
+
first: true,
|
|
8213
|
+
predicate: ["collectionTrigger"],
|
|
8214
|
+
descendants: true,
|
|
8215
|
+
isSignal: true
|
|
8216
|
+
}, {
|
|
8217
|
+
propertyName: "panel",
|
|
8218
|
+
first: true,
|
|
8219
|
+
predicate: ["panel"],
|
|
8220
|
+
descendants: true,
|
|
8221
|
+
read: ElementRef,
|
|
8222
|
+
isSignal: true
|
|
8223
|
+
}],
|
|
7351
8224
|
ngImport: i0,
|
|
7352
8225
|
template: `
|
|
7353
8226
|
<!-- Région de statut hors de la barre : celle-ci est inerte sans sélection, et une région
|
|
7354
|
-
inerte n'est pas annoncée. Le texte n'existe que tant que la sélection est non vide
|
|
8227
|
+
inerte n'est pas annoncée. Le texte n'existe que tant que la sélection est non vide, ou juste
|
|
8228
|
+
après un classement en collection (la sélection vient alors d'être vidée). -->
|
|
7355
8229
|
<span role="status" class="sr-only">
|
|
7356
8230
|
@if (count() > 0) {
|
|
7357
8231
|
{{ 'multiSelectionToolbar.itemsSelected' | transloco: { count: count() } }}
|
|
7358
8232
|
@if (showHint() && hint()) {
|
|
7359
8233
|
. {{ hint() }}
|
|
7360
8234
|
}
|
|
8235
|
+
} @else if (lastFiled(); as filed) {
|
|
8236
|
+
{{ 'collections.addedDocumentsTo' | transloco: filed }}
|
|
7361
8237
|
}
|
|
7362
8238
|
</span>
|
|
7363
8239
|
|
|
@@ -7370,40 +8246,97 @@ var MultiSelectionToolbarComponent = class MultiSelectionToolbarComponent {
|
|
|
7370
8246
|
[attr.aria-label]="'multiSelectionToolbar.label' | transloco"
|
|
7371
8247
|
[attr.inert]="count() === 0 ? '' : null"
|
|
7372
8248
|
(keydown.escape)="clearSelection()"
|
|
7373
|
-
[class]="
|
|
7374
|
-
|
|
7375
|
-
|
|
7376
|
-
|
|
7377
|
-
|
|
7378
|
-
|
|
7379
|
-
|
|
7380
|
-
|
|
7381
|
-
|
|
7382
|
-
|
|
7383
|
-
|
|
7384
|
-
|
|
8249
|
+
[class]="toolbarClass()">
|
|
8250
|
+
@if (variant() === 'floating') {
|
|
8251
|
+
<!-- Le décompte n'est pas répété : la page qui affiche les cases à cocher le montre déjà.
|
|
8252
|
+
Échap vide la sélection depuis n'importe quel bouton. -->
|
|
8253
|
+
<button
|
|
8254
|
+
#collectionTrigger
|
|
8255
|
+
type="button"
|
|
8256
|
+
variant="accent"
|
|
8257
|
+
size="md"
|
|
8258
|
+
aria-haspopup="dialog"
|
|
8259
|
+
[class]="floatingButton"
|
|
8260
|
+
[attr.aria-expanded]="panelOpen()"
|
|
8261
|
+
[attr.aria-controls]="panelOpen() ? panelId : null"
|
|
8262
|
+
(click)="togglePanel()">
|
|
8263
|
+
<bookmark-icon aria-hidden="true" />
|
|
8264
|
+
{{ 'multiSelectionToolbar.addToCollection' | transloco }}
|
|
7385
8265
|
</button>
|
|
7386
|
-
|
|
7387
|
-
|
|
7388
|
-
<div>
|
|
7389
|
-
<button class="cursor-pointer inline-flex items-center gap-1" (click)="openExportDialog()">
|
|
8266
|
+
<button type="button" variant="secondary" size="md" [class]="floatingButton + ' bg-(--bg-neutral-white)'" (click)="openExportDialog()">
|
|
7390
8267
|
<file-output-icon aria-hidden="true" />
|
|
7391
8268
|
{{ 'export.title' | transloco }}
|
|
7392
8269
|
</button>
|
|
7393
|
-
|
|
7394
|
-
|
|
7395
|
-
@if (showAssistantAction()) {
|
|
7396
|
-
<div class="pe-0!">
|
|
7397
|
-
<button class="cursor-pointer inline-flex items-center gap-1" (click)="attachToAssistant()">
|
|
8270
|
+
@if (showAssistantAction()) {
|
|
8271
|
+
<button type="button" variant="secondary" size="md" [class]="floatingButton + ' bg-(--bg-neutral-white)'" (click)="attachToAssistant()">
|
|
7398
8272
|
<sparkles-icon aria-hidden="true" />
|
|
7399
8273
|
{{ 'article.addToAIOverview' | transloco }}
|
|
7400
8274
|
</button>
|
|
8275
|
+
}
|
|
8276
|
+
} @else {
|
|
8277
|
+
<div class="ps-0!">
|
|
8278
|
+
<button variant="none" class="cursor-pointer inline-flex items-center gap-1" (click)="clearSelection()">
|
|
8279
|
+
{{ 'multiSelectionToolbar.itemsSelected' | transloco: { count: count() } }}
|
|
8280
|
+
<x-mark-icon aria-hidden="true" />
|
|
8281
|
+
</button>
|
|
8282
|
+
</div>
|
|
8283
|
+
|
|
8284
|
+
<div>
|
|
8285
|
+
<button variant="none" class="cursor-pointer inline-flex items-center gap-1" (click)="openCollectionDialog()">
|
|
8286
|
+
<inbox-icon aria-hidden="true" />
|
|
8287
|
+
{{ 'collections.label' | transloco }}
|
|
8288
|
+
</button>
|
|
8289
|
+
</div>
|
|
8290
|
+
|
|
8291
|
+
<div>
|
|
8292
|
+
<button variant="none" class="cursor-pointer inline-flex items-center gap-1" (click)="openExportDialog()">
|
|
8293
|
+
<file-output-icon aria-hidden="true" />
|
|
8294
|
+
{{ 'export.title' | transloco }}
|
|
8295
|
+
</button>
|
|
7401
8296
|
</div>
|
|
8297
|
+
|
|
8298
|
+
@if (showAssistantAction()) {
|
|
8299
|
+
<div class="pe-0!">
|
|
8300
|
+
<button variant="none" class="cursor-pointer inline-flex items-center gap-1" (click)="attachToAssistant()">
|
|
8301
|
+
<sparkles-icon aria-hidden="true" />
|
|
8302
|
+
{{ 'article.addToAIOverview' | transloco }}
|
|
8303
|
+
</button>
|
|
8304
|
+
</div>
|
|
8305
|
+
}
|
|
7402
8306
|
}
|
|
7403
8307
|
</div>
|
|
8308
|
+
|
|
8309
|
+
<!-- Hors de la barre : un Échap dans le panneau ne doit fermer que lui, pas vider la sélection.
|
|
8310
|
+
popover="auto" : clic à l'extérieur et Échap le ferment, et le navigateur rend alors le focus au
|
|
8311
|
+
bouton qui l'a ouvert. -->
|
|
8312
|
+
@if (panelOpen()) {
|
|
8313
|
+
<AddToCollectionPanel
|
|
8314
|
+
#panel
|
|
8315
|
+
popover="auto"
|
|
8316
|
+
class="fixed m-0 p-0"
|
|
8317
|
+
[id]="panelId"
|
|
8318
|
+
[articles]="panelArticles()"
|
|
8319
|
+
(toggle)="onPanelToggle($event)"
|
|
8320
|
+
(keydown.escape)="$event.stopPropagation()"
|
|
8321
|
+
(changed)="collectionsChanged = true"
|
|
8322
|
+
(done)="onFiled($event)"
|
|
8323
|
+
(closeRequested)="closePanel()" />
|
|
8324
|
+
}
|
|
7404
8325
|
`,
|
|
7405
8326
|
isInline: true,
|
|
7406
8327
|
dependencies: [
|
|
8328
|
+
{
|
|
8329
|
+
kind: "directive",
|
|
8330
|
+
type: ButtonComponent,
|
|
8331
|
+
selector: "button",
|
|
8332
|
+
inputs: [
|
|
8333
|
+
"class",
|
|
8334
|
+
"variant",
|
|
8335
|
+
"scheme",
|
|
8336
|
+
"iconOnly",
|
|
8337
|
+
"size"
|
|
8338
|
+
]
|
|
8339
|
+
},
|
|
7407
8340
|
{
|
|
7408
8341
|
kind: "component",
|
|
7409
8342
|
type: XMarkIcon,
|
|
@@ -7428,6 +8361,23 @@ var MultiSelectionToolbarComponent = class MultiSelectionToolbarComponent {
|
|
|
7428
8361
|
selector: "file-output, file-output-icon, FileOutput, FileOutputIcon",
|
|
7429
8362
|
inputs: ["class"]
|
|
7430
8363
|
},
|
|
8364
|
+
{
|
|
8365
|
+
kind: "component",
|
|
8366
|
+
type: BookmarkIcon,
|
|
8367
|
+
selector: "bookmark, bookmark-icon, Bookmark, BookmarkIcon",
|
|
8368
|
+
inputs: ["class", "solid"]
|
|
8369
|
+
},
|
|
8370
|
+
{
|
|
8371
|
+
kind: "component",
|
|
8372
|
+
type: AddToCollectionPanelComponent,
|
|
8373
|
+
selector: "AddToCollectionPanel, add-to-collection-panel",
|
|
8374
|
+
inputs: ["articles"],
|
|
8375
|
+
outputs: [
|
|
8376
|
+
"done",
|
|
8377
|
+
"changed",
|
|
8378
|
+
"closeRequested"
|
|
8379
|
+
]
|
|
8380
|
+
},
|
|
7431
8381
|
{
|
|
7432
8382
|
kind: "pipe",
|
|
7433
8383
|
type: TranslocoPipe,
|
|
@@ -7447,21 +8397,27 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
7447
8397
|
selector: "MultiSelectionToolbar, multi-selection-toolbar",
|
|
7448
8398
|
imports: [
|
|
7449
8399
|
TranslocoPipe,
|
|
8400
|
+
ButtonComponent,
|
|
7450
8401
|
XMarkIcon,
|
|
7451
8402
|
InboxIcon,
|
|
7452
8403
|
SparklesIcon,
|
|
7453
|
-
FileOutputIcon
|
|
8404
|
+
FileOutputIcon,
|
|
8405
|
+
BookmarkIcon,
|
|
8406
|
+
AddToCollectionPanelComponent
|
|
7454
8407
|
],
|
|
7455
8408
|
providers: [provideTranslocoScope("multi-selection-toolbar", "article", "collections", "export")],
|
|
7456
8409
|
template: `
|
|
7457
8410
|
<!-- Région de statut hors de la barre : celle-ci est inerte sans sélection, et une région
|
|
7458
|
-
inerte n'est pas annoncée. Le texte n'existe que tant que la sélection est non vide
|
|
8411
|
+
inerte n'est pas annoncée. Le texte n'existe que tant que la sélection est non vide, ou juste
|
|
8412
|
+
après un classement en collection (la sélection vient alors d'être vidée). -->
|
|
7459
8413
|
<span role="status" class="sr-only">
|
|
7460
8414
|
@if (count() > 0) {
|
|
7461
8415
|
{{ 'multiSelectionToolbar.itemsSelected' | transloco: { count: count() } }}
|
|
7462
8416
|
@if (showHint() && hint()) {
|
|
7463
8417
|
. {{ hint() }}
|
|
7464
8418
|
}
|
|
8419
|
+
} @else if (lastFiled(); as filed) {
|
|
8420
|
+
{{ 'collections.addedDocumentsTo' | transloco: filed }}
|
|
7465
8421
|
}
|
|
7466
8422
|
</span>
|
|
7467
8423
|
|
|
@@ -7474,43 +8430,84 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
7474
8430
|
[attr.aria-label]="'multiSelectionToolbar.label' | transloco"
|
|
7475
8431
|
[attr.inert]="count() === 0 ? '' : null"
|
|
7476
8432
|
(keydown.escape)="clearSelection()"
|
|
7477
|
-
[class]="
|
|
7478
|
-
|
|
7479
|
-
|
|
7480
|
-
|
|
7481
|
-
|
|
7482
|
-
|
|
7483
|
-
|
|
7484
|
-
|
|
7485
|
-
|
|
7486
|
-
|
|
7487
|
-
|
|
7488
|
-
|
|
8433
|
+
[class]="toolbarClass()">
|
|
8434
|
+
@if (variant() === 'floating') {
|
|
8435
|
+
<!-- Le décompte n'est pas répété : la page qui affiche les cases à cocher le montre déjà.
|
|
8436
|
+
Échap vide la sélection depuis n'importe quel bouton. -->
|
|
8437
|
+
<button
|
|
8438
|
+
#collectionTrigger
|
|
8439
|
+
type="button"
|
|
8440
|
+
variant="accent"
|
|
8441
|
+
size="md"
|
|
8442
|
+
aria-haspopup="dialog"
|
|
8443
|
+
[class]="floatingButton"
|
|
8444
|
+
[attr.aria-expanded]="panelOpen()"
|
|
8445
|
+
[attr.aria-controls]="panelOpen() ? panelId : null"
|
|
8446
|
+
(click)="togglePanel()">
|
|
8447
|
+
<bookmark-icon aria-hidden="true" />
|
|
8448
|
+
{{ 'multiSelectionToolbar.addToCollection' | transloco }}
|
|
7489
8449
|
</button>
|
|
7490
|
-
|
|
7491
|
-
|
|
7492
|
-
<div>
|
|
7493
|
-
<button class="cursor-pointer inline-flex items-center gap-1" (click)="openExportDialog()">
|
|
8450
|
+
<button type="button" variant="secondary" size="md" [class]="floatingButton + ' bg-(--bg-neutral-white)'" (click)="openExportDialog()">
|
|
7494
8451
|
<file-output-icon aria-hidden="true" />
|
|
7495
8452
|
{{ 'export.title' | transloco }}
|
|
7496
8453
|
</button>
|
|
7497
|
-
|
|
7498
|
-
|
|
7499
|
-
@if (showAssistantAction()) {
|
|
7500
|
-
<div class="pe-0!">
|
|
7501
|
-
<button class="cursor-pointer inline-flex items-center gap-1" (click)="attachToAssistant()">
|
|
8454
|
+
@if (showAssistantAction()) {
|
|
8455
|
+
<button type="button" variant="secondary" size="md" [class]="floatingButton + ' bg-(--bg-neutral-white)'" (click)="attachToAssistant()">
|
|
7502
8456
|
<sparkles-icon aria-hidden="true" />
|
|
7503
8457
|
{{ 'article.addToAIOverview' | transloco }}
|
|
7504
8458
|
</button>
|
|
8459
|
+
}
|
|
8460
|
+
} @else {
|
|
8461
|
+
<div class="ps-0!">
|
|
8462
|
+
<button variant="none" class="cursor-pointer inline-flex items-center gap-1" (click)="clearSelection()">
|
|
8463
|
+
{{ 'multiSelectionToolbar.itemsSelected' | transloco: { count: count() } }}
|
|
8464
|
+
<x-mark-icon aria-hidden="true" />
|
|
8465
|
+
</button>
|
|
8466
|
+
</div>
|
|
8467
|
+
|
|
8468
|
+
<div>
|
|
8469
|
+
<button variant="none" class="cursor-pointer inline-flex items-center gap-1" (click)="openCollectionDialog()">
|
|
8470
|
+
<inbox-icon aria-hidden="true" />
|
|
8471
|
+
{{ 'collections.label' | transloco }}
|
|
8472
|
+
</button>
|
|
7505
8473
|
</div>
|
|
8474
|
+
|
|
8475
|
+
<div>
|
|
8476
|
+
<button variant="none" class="cursor-pointer inline-flex items-center gap-1" (click)="openExportDialog()">
|
|
8477
|
+
<file-output-icon aria-hidden="true" />
|
|
8478
|
+
{{ 'export.title' | transloco }}
|
|
8479
|
+
</button>
|
|
8480
|
+
</div>
|
|
8481
|
+
|
|
8482
|
+
@if (showAssistantAction()) {
|
|
8483
|
+
<div class="pe-0!">
|
|
8484
|
+
<button variant="none" class="cursor-pointer inline-flex items-center gap-1" (click)="attachToAssistant()">
|
|
8485
|
+
<sparkles-icon aria-hidden="true" />
|
|
8486
|
+
{{ 'article.addToAIOverview' | transloco }}
|
|
8487
|
+
</button>
|
|
8488
|
+
</div>
|
|
8489
|
+
}
|
|
7506
8490
|
}
|
|
7507
8491
|
</div>
|
|
8492
|
+
|
|
8493
|
+
<!-- Hors de la barre : un Échap dans le panneau ne doit fermer que lui, pas vider la sélection.
|
|
8494
|
+
popover="auto" : clic à l'extérieur et Échap le ferment, et le navigateur rend alors le focus au
|
|
8495
|
+
bouton qui l'a ouvert. -->
|
|
8496
|
+
@if (panelOpen()) {
|
|
8497
|
+
<AddToCollectionPanel
|
|
8498
|
+
#panel
|
|
8499
|
+
popover="auto"
|
|
8500
|
+
class="fixed m-0 p-0"
|
|
8501
|
+
[id]="panelId"
|
|
8502
|
+
[articles]="panelArticles()"
|
|
8503
|
+
(toggle)="onPanelToggle($event)"
|
|
8504
|
+
(keydown.escape)="$event.stopPropagation()"
|
|
8505
|
+
(changed)="collectionsChanged = true"
|
|
8506
|
+
(done)="onFiled($event)"
|
|
8507
|
+
(closeRequested)="closePanel()" />
|
|
8508
|
+
}
|
|
7508
8509
|
`,
|
|
7509
|
-
host: {
|
|
7510
|
-
class: "fixed -bottom-20 left-[50%] translate-x-[-50%] z-50 transition-[translate,opacity,discrete] duration-300 opacity-0",
|
|
7511
|
-
"[class.opacity-100]": "count() > 0",
|
|
7512
|
-
"[class.-translate-y-24]": "count() > 0"
|
|
7513
|
-
}
|
|
8510
|
+
host: { "[class]": "hostClass()" }
|
|
7514
8511
|
}]
|
|
7515
8512
|
}],
|
|
7516
8513
|
ctorParameters: () => [],
|
|
@@ -7547,6 +8544,10 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
7547
8544
|
type: i0.Output,
|
|
7548
8545
|
args: ["cleared"]
|
|
7549
8546
|
}],
|
|
8547
|
+
addedToCollection: [{
|
|
8548
|
+
type: i0.Output,
|
|
8549
|
+
args: ["addedToCollection"]
|
|
8550
|
+
}],
|
|
7550
8551
|
allowAI: [{
|
|
7551
8552
|
type: i0.Input,
|
|
7552
8553
|
args: [{
|
|
@@ -7554,6 +8555,17 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
7554
8555
|
alias: "allowAI",
|
|
7555
8556
|
required: false
|
|
7556
8557
|
}]
|
|
8558
|
+
}],
|
|
8559
|
+
collectionTrigger: [{
|
|
8560
|
+
type: i0.ViewChild,
|
|
8561
|
+
args: ["collectionTrigger", { isSignal: true }]
|
|
8562
|
+
}],
|
|
8563
|
+
panel: [{
|
|
8564
|
+
type: i0.ViewChild,
|
|
8565
|
+
args: ["panel", {
|
|
8566
|
+
read: ElementRef,
|
|
8567
|
+
isSignal: true
|
|
8568
|
+
}]
|
|
7557
8569
|
}]
|
|
7558
8570
|
}
|
|
7559
8571
|
});
|
|
@@ -7962,11 +8974,16 @@ var OverflowManagerDirective = class OverflowManagerDirective {
|
|
|
7962
8974
|
});
|
|
7963
8975
|
target = input(...ngDevMode ? [void 0, { debugName: "target" }] : /* istanbul ignore next */ []);
|
|
7964
8976
|
margin = input(4, ...ngDevMode ? [{ debugName: "margin" }] : /* istanbul ignore next */ []);
|
|
8977
|
+
fitMargin = input(void 0, ...ngDevMode ? [{ debugName: "fitMargin" }] : /* istanbul ignore next */ []);
|
|
7965
8978
|
direction = input("horizontal", ...ngDevMode ? [{ debugName: "direction" }] : /* istanbul ignore next */ []);
|
|
7966
8979
|
reserveStop = input(false, {
|
|
7967
8980
|
...ngDevMode ? { debugName: "reserveStop" } : /* istanbul ignore next */ {},
|
|
7968
8981
|
transform: booleanAttribute
|
|
7969
8982
|
});
|
|
8983
|
+
animate = input(false, {
|
|
8984
|
+
...ngDevMode ? { debugName: "animate" } : /* istanbul ignore next */ {},
|
|
8985
|
+
transform: booleanAttribute
|
|
8986
|
+
});
|
|
7970
8987
|
count = output();
|
|
7971
8988
|
el = inject(ElementRef).nativeElement;
|
|
7972
8989
|
destroyRef = inject(DestroyRef);
|
|
@@ -7974,6 +8991,7 @@ var OverflowManagerDirective = class OverflowManagerDirective {
|
|
|
7974
8991
|
itemsResizeObserver = new ResizeObserver((entries) => {
|
|
7975
8992
|
if (entries.some((entry) => entry.target.style.display !== "none")) this.countItems();
|
|
7976
8993
|
});
|
|
8994
|
+
hiddenItems = /* @__PURE__ */ new WeakSet();
|
|
7977
8995
|
countSub;
|
|
7978
8996
|
_lastCount;
|
|
7979
8997
|
constructor() {
|
|
@@ -8006,7 +9024,8 @@ var OverflowManagerDirective = class OverflowManagerDirective {
|
|
|
8006
9024
|
const containerEnd = (horizontal ? containerRect.right : containerRect.bottom) - this.margin();
|
|
8007
9025
|
const itemEnd = (rect) => horizontal ? rect.right : rect.bottom;
|
|
8008
9026
|
let count;
|
|
8009
|
-
|
|
9027
|
+
const fitEnd = (horizontal ? containerRect.right : containerRect.bottom) - (this.fitMargin() ?? this.margin());
|
|
9028
|
+
if (!this.reserveStop() && itemEnd(itemsRects[itemsRects.length - 1]) <= fitEnd) count = itemsRects.length;
|
|
8010
9029
|
else {
|
|
8011
9030
|
const limit = containerEnd - (horizontal ? stopRect.width : stopRect.height);
|
|
8012
9031
|
count = 0;
|
|
@@ -8020,7 +9039,19 @@ var OverflowManagerDirective = class OverflowManagerDirective {
|
|
|
8020
9039
|
}
|
|
8021
9040
|
toggleToCount(count) {
|
|
8022
9041
|
this.items().forEach((item, index) => {
|
|
8023
|
-
item.nativeElement
|
|
9042
|
+
const el = item.nativeElement;
|
|
9043
|
+
const visible = index < count;
|
|
9044
|
+
el.style.display = visible ? "" : "none";
|
|
9045
|
+
if (!visible) this.hiddenItems.add(el);
|
|
9046
|
+
else if (this.hiddenItems.delete(el) && this.animate()) this.fadeIn(el);
|
|
9047
|
+
});
|
|
9048
|
+
}
|
|
9049
|
+
fadeIn(el) {
|
|
9050
|
+
if (typeof el.animate !== "function") return;
|
|
9051
|
+
if (typeof matchMedia === "function" && matchMedia("(prefers-reduced-motion: reduce)").matches) return;
|
|
9052
|
+
el.animate([{ opacity: 0 }, { opacity: 1 }], {
|
|
9053
|
+
duration: 160,
|
|
9054
|
+
easing: "ease-out"
|
|
8024
9055
|
});
|
|
8025
9056
|
}
|
|
8026
9057
|
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
@@ -8052,6 +9083,13 @@ var OverflowManagerDirective = class OverflowManagerDirective {
|
|
|
8052
9083
|
isRequired: false,
|
|
8053
9084
|
transformFunction: null
|
|
8054
9085
|
},
|
|
9086
|
+
fitMargin: {
|
|
9087
|
+
classPropertyName: "fitMargin",
|
|
9088
|
+
publicName: "fitMargin",
|
|
9089
|
+
isSignal: true,
|
|
9090
|
+
isRequired: false,
|
|
9091
|
+
transformFunction: null
|
|
9092
|
+
},
|
|
8055
9093
|
direction: {
|
|
8056
9094
|
classPropertyName: "direction",
|
|
8057
9095
|
publicName: "direction",
|
|
@@ -8065,6 +9103,13 @@ var OverflowManagerDirective = class OverflowManagerDirective {
|
|
|
8065
9103
|
isSignal: true,
|
|
8066
9104
|
isRequired: false,
|
|
8067
9105
|
transformFunction: null
|
|
9106
|
+
},
|
|
9107
|
+
animate: {
|
|
9108
|
+
classPropertyName: "animate",
|
|
9109
|
+
publicName: "animate",
|
|
9110
|
+
isSignal: true,
|
|
9111
|
+
isRequired: false,
|
|
9112
|
+
transformFunction: null
|
|
8068
9113
|
}
|
|
8069
9114
|
},
|
|
8070
9115
|
outputs: { count: "count" },
|
|
@@ -8128,6 +9173,14 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
8128
9173
|
required: false
|
|
8129
9174
|
}]
|
|
8130
9175
|
}],
|
|
9176
|
+
fitMargin: [{
|
|
9177
|
+
type: i0.Input,
|
|
9178
|
+
args: [{
|
|
9179
|
+
isSignal: true,
|
|
9180
|
+
alias: "fitMargin",
|
|
9181
|
+
required: false
|
|
9182
|
+
}]
|
|
9183
|
+
}],
|
|
8131
9184
|
direction: [{
|
|
8132
9185
|
type: i0.Input,
|
|
8133
9186
|
args: [{
|
|
@@ -8144,6 +9197,14 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
8144
9197
|
required: false
|
|
8145
9198
|
}]
|
|
8146
9199
|
}],
|
|
9200
|
+
animate: [{
|
|
9201
|
+
type: i0.Input,
|
|
9202
|
+
args: [{
|
|
9203
|
+
isSignal: true,
|
|
9204
|
+
alias: "animate",
|
|
9205
|
+
required: false
|
|
9206
|
+
}]
|
|
9207
|
+
}],
|
|
8147
9208
|
count: [{
|
|
8148
9209
|
type: i0.Output,
|
|
8149
9210
|
args: ["count"]
|
|
@@ -8841,8 +9902,10 @@ var NavbarTabsComponent = class NavbarTabsComponent {
|
|
|
8841
9902
|
inputs: [
|
|
8842
9903
|
"target",
|
|
8843
9904
|
"margin",
|
|
9905
|
+
"fitMargin",
|
|
8844
9906
|
"direction",
|
|
8845
|
-
"reserveStop"
|
|
9907
|
+
"reserveStop",
|
|
9908
|
+
"animate"
|
|
8846
9909
|
],
|
|
8847
9910
|
outputs: ["count"]
|
|
8848
9911
|
},
|
|
@@ -26208,6 +27271,8 @@ var AggregationDateComponent = class AggregationDateComponent {
|
|
|
26208
27271
|
allowCustomRange = inject(FILTER_DATE_ALLOW_CUSTOM_RANGE);
|
|
26209
27272
|
transloco = inject(TranslocoService);
|
|
26210
27273
|
injector = inject(Injector);
|
|
27274
|
+
breakpoints = inject(BreakpointObserverService);
|
|
27275
|
+
actionSize = computed(() => this.breakpoints.isTouch() ? "lg" : "md", ...ngDevMode ? [{ debugName: "actionSize" }] : /* istanbul ignore next */ []);
|
|
26211
27276
|
host = inject(ElementRef);
|
|
26212
27277
|
selection = signal(false, ...ngDevMode ? [{ debugName: "selection" }] : /* istanbul ignore next */ []);
|
|
26213
27278
|
validSelection = signal(false, ...ngDevMode ? [{ debugName: "validSelection" }] : /* istanbul ignore next */ []);
|
|
@@ -26766,7 +27831,7 @@ var AggregationDateComponent = class AggregationDateComponent {
|
|
|
26766
27831
|
host: { properties: { "class": "cn(\"@container flex h-[inherit] max-h-[inherit] flex-col\", class(), isEmpty() && \"hidden\")" } },
|
|
26767
27832
|
providers: [provideTranslocoScope("filters")],
|
|
26768
27833
|
ngImport: i0,
|
|
26769
|
-
template: "<!-- `<details>`/`<summary>` stay native (open/close, the `name`-based exclusive accordion). A facet is a\n disclosure, not a grid row: see `aggregation-panel.html` for the why (same pattern, duplicated here\n since this facet type doesn't go through `AggregationPanelComponent`). The `<summary>` itself is\n `tabindex=\"-1\"`: the header's chevron is the keyboard stop, see the chevron below. Clear and apply are not in the\n header: they are in the body, in a bar at the top of the facet. -->\n<ng-template #content>\n <!-- content wrapper -->\n <!-- RGAA 11.5 / WCAG 1.3.1: the radios below all share one `name`, so they are one set\n and have to be exposed as one. `role=\"group\"` here rather than `role=\"radiogroup\"`\n on the list: a radiogroup owns its radios directly, and the <li> in between would be\n invalid owned children — the list would also stop announcing how many options it\n holds. The name is the aggregation's own title, the words the header already shows;\n with no title the group stays unnamed rather than carrying an empty label. -->\n @let groupName = aggregation()?.display;\n <form\n class=\"flex min-h-0 flex-1 flex-col\"\n (keydown.enter)=\"onOptionEnter($event)\">\n <!-- The same bar as for the list and the tree, in a popover and in the filters drawer alike: clear (a button with a text, there but disabled when there is nothing\n to clear) and, while a choice is pending, apply, without an icon. There is no search field here to put them under:\n they sit at the top of the facet. -->\n <div class=\"flex shrink-0 items-center justify-end gap-1 pt-1 pl-1\">\n <button\n type=\"button\"\n variant=\"tertiary\"\n size=\"
|
|
27834
|
+
template: "<!-- `<details>`/`<summary>` stay native (open/close, the `name`-based exclusive accordion). A facet is a\n disclosure, not a grid row: see `aggregation-panel.html` for the why (same pattern, duplicated here\n since this facet type doesn't go through `AggregationPanelComponent`). The `<summary>` itself is\n `tabindex=\"-1\"`: the header's chevron is the keyboard stop, see the chevron below. Clear and apply are not in the\n header: they are in the body, in a bar at the top of the facet. -->\n<ng-template #content>\n <!-- content wrapper -->\n <!-- RGAA 11.5 / WCAG 1.3.1: the radios below all share one `name`, so they are one set\n and have to be exposed as one. `role=\"group\"` here rather than `role=\"radiogroup\"`\n on the list: a radiogroup owns its radios directly, and the <li> in between would be\n invalid owned children — the list would also stop announcing how many options it\n holds. The name is the aggregation's own title, the words the header already shows;\n with no title the group stays unnamed rather than carrying an empty label. -->\n @let groupName = aggregation()?.display;\n <form\n class=\"flex min-h-0 flex-1 flex-col\"\n (keydown.enter)=\"onOptionEnter($event)\">\n <!-- The same bar as for the list and the tree, in a popover and in the filters drawer alike: clear (a button with a text, there but disabled when there is nothing\n to clear) and, while a choice is pending, apply, without an icon. There is no search field here to put them under:\n they sit at the top of the facet. -->\n <div class=\"flex shrink-0 items-center justify-end gap-1 pt-1 pl-1\">\n <button\n type=\"button\"\n variant=\"tertiary\"\n [size]=\"actionSize()\"\n class=\"shrink-0\"\n [disabled]=\"!hasFilters() && !selection()\"\n [attr.aria-label]=\"'filters.clearFilters' | transloco\"\n (click)=\"clear()\">\n {{ \"filters.clearAll\" | transloco }}\n </button>\n @if (\n (!isControlled() || emitOn() === \"apply\") &&\n selection() &&\n validSelection()\n ) {\n <button\n type=\"button\"\n variant=\"accent\"\n [size]=\"actionSize()\"\n class=\"shrink-0 overflow-hidden\"\n (click)=\"apply()\">\n <span class=\"truncate\">{{ \"filters.apply\" | transloco }}</span>\n </button>\n }\n </div>\n <div\n class=\"flex min-h-0 flex-1 flex-col\"\n role=\"group\"\n [attr.aria-label]=\"groupName ? (groupName | syslang | transloco) : null\">\n <ul\n class=\"flex min-h-0 flex-1 snap-y snap-start scrollbar-thin flex-col gap-0.5 overflow-auto px-1 pt-1 pb-3\"\n role=\"list\">\n @for (option of dateOptions(); track option.display) {\n <li\n role=\"listitem\"\n [attr.aria-label]=\"\n maskedLabel(option) ?? (option.display | syslang | transloco)\n \"\n [class]=\"\n cn(\n itemStateClass,\n 'flex min-h-9 cursor-pointer items-center px-2 py-0.5 text-base text-(--font-neutral-base) select-none [&>radio>label]:min-h-8',\n dateModel().option === option.display &&\n 'bg-(--bg-primary-lighter)',\n option.hidden && 'hidden',\n option.disabled && 'pointer-events-none opacity-40'\n )\n \"\n [attr.aria-hidden]=\"option.disabled\">\n <radio\n name=\"date-filter\"\n class=\"grow items-center [&_.radio-label]:text-base [&_.radio-label]:leading-6 [&_.radio-label]:font-normal\"\n [checked]=\"dateModel().option === option.display\"\n [disabled]=\"option.disabled\"\n (checkedChange)=\"selectOption(option.display)\">\n {{\n maskedLabel(option) ?? (option.display | syslang | transloco)\n }}\n </radio>\n </li>\n }\n\n @if (allowCustomRange) {\n <li\n role=\"listitem\"\n aria-label=\"open date range picker\"\n [class]=\"\n cn(\n itemStateClass,\n 'flex min-h-9 cursor-pointer items-center gap-(--spacing-xs) px-2 py-0.5 text-base text-(--font-neutral-base) select-none [&>radio>label]:min-h-8 [&>radio>label]:max-w-full [&>radio>label]:min-w-0',\n dateModel().option === 'custom-range' &&\n 'bg-(--bg-primary-lighter)'\n )\n \">\n <radio\n name=\"date-filter\"\n class=\"grow items-center [&_.radio-label]:text-base [&_.radio-label]:leading-6 [&_.radio-label]:font-normal\"\n [checked]=\"dateModel().option === 'custom-range'\"\n (checkedChange)=\"selectOption('custom-range')\">\n <!-- `<radio>` is `display: contents`: its `<label>` is a child of the `<li>` in the box tree but not in the DOM, hence\n the `[&>radio>label]` of the row above. Every box of the chain down to the inputs may shrink (`min-w-0`, no fixed `min-w-[18ch]`): in the 15.5rem popover the\n label, the field and the radio do not fit side by side, and a box that cannot shrink spills out of it and is clipped.\n The fields have a definite width (`w-[18ch]`) that may shrink (`max-w-full min-w-0`). On a touch screen the text is 16px\n instead of 14px, which is what made the row wider than the 15.5rem popover. -->\n <div class=\"flex min-w-0 flex-wrap items-center gap-x-1 gap-y-1\">\n <div class=\"flex min-w-0 items-center gap-1\">\n <label\n [attr.for]=\"startId\"\n class=\"radio-label min-w-8 shrink-0 truncate\"\n >{{ \"filters.from\" | transloco }}</label\n >\n <input-group\n class=\"h-8 w-[18ch] max-w-full min-w-0 has-[[readonly]]:border-(--stroke-primary-muted)\">\n <input\n input-control\n [id]=\"startId\"\n name=\"start\"\n type=\"text\"\n readonly\n [value]=\"customRangeFrom()\"\n (click)=\"selectAndOpenDialog()\"\n (keydown.enter)=\"onRangeInputEnter($event)\" />\n </input-group>\n </div>\n <div class=\"flex min-w-0 items-center gap-1\">\n <label\n [attr.for]=\"endId\"\n class=\"radio-label min-w-8 shrink-0 truncate text-right\"\n >{{ \"filters.to\" | transloco }}</label\n >\n <input-group\n class=\"h-8 w-[18ch] max-w-full min-w-0 has-[[readonly]]:border-(--stroke-primary-muted)\">\n <input\n input-control\n [id]=\"endId\"\n name=\"end\"\n type=\"text\"\n readonly\n [value]=\"customRangeTo()\"\n (click)=\"selectAndOpenDialog()\"\n (keydown.enter)=\"onRangeInputEnter($event)\" />\n </input-group>\n </div>\n </div>\n </radio>\n </li>\n }\n </ul>\n </div>\n </form>\n</ng-template>\n\n@if (headless()) {\n <div class=\"flex min-h-0 flex-1 flex-col\">\n <ng-container [ngTemplateOutlet]=\"content\" />\n </div>\n} @else {\n <details\n [attr.open]=\"expanded()\"\n [attr.name]=\"id()\"\n class=\"group flex min-h-0 flex-1 flex-col space-y-2 p-0.5 details-content:flex details-content:min-h-0 details-content:flex-col\">\n <!-- `p-0.5` on the details: the one of AggregationPanel (the list and the tree), so the header and its chevron sit on the same\n lines as theirs in the aside filters and the filters panel — without it the chevron was 2px further right.\n scroll-mb-3/scroll-mt-16: see aggregation-panel-row.html for the full rationale\n (bottom margin against the container's edge, much bigger top margin to also clear\n <More>'s sticky facet-name search box when navigating ArrowUp). -->\n <summary\n tabindex=\"-1\"\n [class.cursor-pointer]=\"collapsible()\"\n [class]=\"rowStateClass\"\n class=\"m-0 flex h-8 w-full shrink-0 scroll-mt-16 scroll-mb-3 items-center gap-1 pl-1 font-semibold select-none\"\n (click)=\"onHeaderClick($event)\">\n <ng-content select=\"label\">\n @let icon = aggregation()?.icon;\n @if (icon) {\n <FaIcon [faClass]=\"icon\" class=\"mr-1 shrink-0\" />\n }\n <span class=\"grow\">{{\n aggregation()?.display | syslang | transloco\n }}</span>\n </ng-content>\n\n @if (collapsible()) {\n <!-- The `<summary>` is out of the tab order (`tabindex=\"-1\"`), so this button is the keyboard way to\n collapse the facet. Its click bubbles to the `<summary>`, whose handler does the toggle, and it\n exposes `aria-expanded`. -->\n <button\n type=\"button\"\n variant=\"tertiary\"\n [iconOnly]=\"true\"\n size=\"md\"\n [aria-label]=\"'filters.toggle' | transloco\"\n [attr.aria-expanded]=\"!isCollapsed()\"\n [tooltip]=\"'filters.toggle' | transloco\"\n class=\"shrink-0 cursor-pointer [&_svg]:transition-transform [&_svg]:duration-150 group-open:[&_svg]:rotate-90\">\n <chevron-right class=\"shrink-0\" />\n </button>\n }\n </summary>\n <ng-container [ngTemplateOutlet]=\"content\" />\n </details>\n}\n",
|
|
26770
27835
|
styles: [":host{interpolate-size:allow-keywords}details::details-content{flex:1 1 auto;block-size:0;overflow:clip;overflow-clip-margin:.25rem;transition:block-size .2s cubic-bezier(.32,.72,0,1),content-visibility .2s allow-discrete}details[open]::details-content{block-size:auto}@media(prefers-reduced-motion:reduce){details::details-content{transition:none}}\n", ":host{min-width:200px}ul[role=list]{scrollbar-width:thin}\n"],
|
|
26771
27836
|
dependencies: [
|
|
26772
27837
|
{
|
|
@@ -26898,7 +27963,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
26898
27963
|
TooltipDirective
|
|
26899
27964
|
],
|
|
26900
27965
|
host: { "[class]": "cn(\"@container flex h-[inherit] max-h-[inherit] flex-col\", class(), isEmpty() && \"hidden\")" },
|
|
26901
|
-
template: "<!-- `<details>`/`<summary>` stay native (open/close, the `name`-based exclusive accordion). A facet is a\n disclosure, not a grid row: see `aggregation-panel.html` for the why (same pattern, duplicated here\n since this facet type doesn't go through `AggregationPanelComponent`). The `<summary>` itself is\n `tabindex=\"-1\"`: the header's chevron is the keyboard stop, see the chevron below. Clear and apply are not in the\n header: they are in the body, in a bar at the top of the facet. -->\n<ng-template #content>\n <!-- content wrapper -->\n <!-- RGAA 11.5 / WCAG 1.3.1: the radios below all share one `name`, so they are one set\n and have to be exposed as one. `role=\"group\"` here rather than `role=\"radiogroup\"`\n on the list: a radiogroup owns its radios directly, and the <li> in between would be\n invalid owned children — the list would also stop announcing how many options it\n holds. The name is the aggregation's own title, the words the header already shows;\n with no title the group stays unnamed rather than carrying an empty label. -->\n @let groupName = aggregation()?.display;\n <form\n class=\"flex min-h-0 flex-1 flex-col\"\n (keydown.enter)=\"onOptionEnter($event)\">\n <!-- The same bar as for the list and the tree, in a popover and in the filters drawer alike: clear (a button with a text, there but disabled when there is nothing\n to clear) and, while a choice is pending, apply, without an icon. There is no search field here to put them under:\n they sit at the top of the facet. -->\n <div class=\"flex shrink-0 items-center justify-end gap-1 pt-1 pl-1\">\n <button\n type=\"button\"\n variant=\"tertiary\"\n size=\"
|
|
27966
|
+
template: "<!-- `<details>`/`<summary>` stay native (open/close, the `name`-based exclusive accordion). A facet is a\n disclosure, not a grid row: see `aggregation-panel.html` for the why (same pattern, duplicated here\n since this facet type doesn't go through `AggregationPanelComponent`). The `<summary>` itself is\n `tabindex=\"-1\"`: the header's chevron is the keyboard stop, see the chevron below. Clear and apply are not in the\n header: they are in the body, in a bar at the top of the facet. -->\n<ng-template #content>\n <!-- content wrapper -->\n <!-- RGAA 11.5 / WCAG 1.3.1: the radios below all share one `name`, so they are one set\n and have to be exposed as one. `role=\"group\"` here rather than `role=\"radiogroup\"`\n on the list: a radiogroup owns its radios directly, and the <li> in between would be\n invalid owned children — the list would also stop announcing how many options it\n holds. The name is the aggregation's own title, the words the header already shows;\n with no title the group stays unnamed rather than carrying an empty label. -->\n @let groupName = aggregation()?.display;\n <form\n class=\"flex min-h-0 flex-1 flex-col\"\n (keydown.enter)=\"onOptionEnter($event)\">\n <!-- The same bar as for the list and the tree, in a popover and in the filters drawer alike: clear (a button with a text, there but disabled when there is nothing\n to clear) and, while a choice is pending, apply, without an icon. There is no search field here to put them under:\n they sit at the top of the facet. -->\n <div class=\"flex shrink-0 items-center justify-end gap-1 pt-1 pl-1\">\n <button\n type=\"button\"\n variant=\"tertiary\"\n [size]=\"actionSize()\"\n class=\"shrink-0\"\n [disabled]=\"!hasFilters() && !selection()\"\n [attr.aria-label]=\"'filters.clearFilters' | transloco\"\n (click)=\"clear()\">\n {{ \"filters.clearAll\" | transloco }}\n </button>\n @if (\n (!isControlled() || emitOn() === \"apply\") &&\n selection() &&\n validSelection()\n ) {\n <button\n type=\"button\"\n variant=\"accent\"\n [size]=\"actionSize()\"\n class=\"shrink-0 overflow-hidden\"\n (click)=\"apply()\">\n <span class=\"truncate\">{{ \"filters.apply\" | transloco }}</span>\n </button>\n }\n </div>\n <div\n class=\"flex min-h-0 flex-1 flex-col\"\n role=\"group\"\n [attr.aria-label]=\"groupName ? (groupName | syslang | transloco) : null\">\n <ul\n class=\"flex min-h-0 flex-1 snap-y snap-start scrollbar-thin flex-col gap-0.5 overflow-auto px-1 pt-1 pb-3\"\n role=\"list\">\n @for (option of dateOptions(); track option.display) {\n <li\n role=\"listitem\"\n [attr.aria-label]=\"\n maskedLabel(option) ?? (option.display | syslang | transloco)\n \"\n [class]=\"\n cn(\n itemStateClass,\n 'flex min-h-9 cursor-pointer items-center px-2 py-0.5 text-base text-(--font-neutral-base) select-none [&>radio>label]:min-h-8',\n dateModel().option === option.display &&\n 'bg-(--bg-primary-lighter)',\n option.hidden && 'hidden',\n option.disabled && 'pointer-events-none opacity-40'\n )\n \"\n [attr.aria-hidden]=\"option.disabled\">\n <radio\n name=\"date-filter\"\n class=\"grow items-center [&_.radio-label]:text-base [&_.radio-label]:leading-6 [&_.radio-label]:font-normal\"\n [checked]=\"dateModel().option === option.display\"\n [disabled]=\"option.disabled\"\n (checkedChange)=\"selectOption(option.display)\">\n {{\n maskedLabel(option) ?? (option.display | syslang | transloco)\n }}\n </radio>\n </li>\n }\n\n @if (allowCustomRange) {\n <li\n role=\"listitem\"\n aria-label=\"open date range picker\"\n [class]=\"\n cn(\n itemStateClass,\n 'flex min-h-9 cursor-pointer items-center gap-(--spacing-xs) px-2 py-0.5 text-base text-(--font-neutral-base) select-none [&>radio>label]:min-h-8 [&>radio>label]:max-w-full [&>radio>label]:min-w-0',\n dateModel().option === 'custom-range' &&\n 'bg-(--bg-primary-lighter)'\n )\n \">\n <radio\n name=\"date-filter\"\n class=\"grow items-center [&_.radio-label]:text-base [&_.radio-label]:leading-6 [&_.radio-label]:font-normal\"\n [checked]=\"dateModel().option === 'custom-range'\"\n (checkedChange)=\"selectOption('custom-range')\">\n <!-- `<radio>` is `display: contents`: its `<label>` is a child of the `<li>` in the box tree but not in the DOM, hence\n the `[&>radio>label]` of the row above. Every box of the chain down to the inputs may shrink (`min-w-0`, no fixed `min-w-[18ch]`): in the 15.5rem popover the\n label, the field and the radio do not fit side by side, and a box that cannot shrink spills out of it and is clipped.\n The fields have a definite width (`w-[18ch]`) that may shrink (`max-w-full min-w-0`). On a touch screen the text is 16px\n instead of 14px, which is what made the row wider than the 15.5rem popover. -->\n <div class=\"flex min-w-0 flex-wrap items-center gap-x-1 gap-y-1\">\n <div class=\"flex min-w-0 items-center gap-1\">\n <label\n [attr.for]=\"startId\"\n class=\"radio-label min-w-8 shrink-0 truncate\"\n >{{ \"filters.from\" | transloco }}</label\n >\n <input-group\n class=\"h-8 w-[18ch] max-w-full min-w-0 has-[[readonly]]:border-(--stroke-primary-muted)\">\n <input\n input-control\n [id]=\"startId\"\n name=\"start\"\n type=\"text\"\n readonly\n [value]=\"customRangeFrom()\"\n (click)=\"selectAndOpenDialog()\"\n (keydown.enter)=\"onRangeInputEnter($event)\" />\n </input-group>\n </div>\n <div class=\"flex min-w-0 items-center gap-1\">\n <label\n [attr.for]=\"endId\"\n class=\"radio-label min-w-8 shrink-0 truncate text-right\"\n >{{ \"filters.to\" | transloco }}</label\n >\n <input-group\n class=\"h-8 w-[18ch] max-w-full min-w-0 has-[[readonly]]:border-(--stroke-primary-muted)\">\n <input\n input-control\n [id]=\"endId\"\n name=\"end\"\n type=\"text\"\n readonly\n [value]=\"customRangeTo()\"\n (click)=\"selectAndOpenDialog()\"\n (keydown.enter)=\"onRangeInputEnter($event)\" />\n </input-group>\n </div>\n </div>\n </radio>\n </li>\n }\n </ul>\n </div>\n </form>\n</ng-template>\n\n@if (headless()) {\n <div class=\"flex min-h-0 flex-1 flex-col\">\n <ng-container [ngTemplateOutlet]=\"content\" />\n </div>\n} @else {\n <details\n [attr.open]=\"expanded()\"\n [attr.name]=\"id()\"\n class=\"group flex min-h-0 flex-1 flex-col space-y-2 p-0.5 details-content:flex details-content:min-h-0 details-content:flex-col\">\n <!-- `p-0.5` on the details: the one of AggregationPanel (the list and the tree), so the header and its chevron sit on the same\n lines as theirs in the aside filters and the filters panel — without it the chevron was 2px further right.\n scroll-mb-3/scroll-mt-16: see aggregation-panel-row.html for the full rationale\n (bottom margin against the container's edge, much bigger top margin to also clear\n <More>'s sticky facet-name search box when navigating ArrowUp). -->\n <summary\n tabindex=\"-1\"\n [class.cursor-pointer]=\"collapsible()\"\n [class]=\"rowStateClass\"\n class=\"m-0 flex h-8 w-full shrink-0 scroll-mt-16 scroll-mb-3 items-center gap-1 pl-1 font-semibold select-none\"\n (click)=\"onHeaderClick($event)\">\n <ng-content select=\"label\">\n @let icon = aggregation()?.icon;\n @if (icon) {\n <FaIcon [faClass]=\"icon\" class=\"mr-1 shrink-0\" />\n }\n <span class=\"grow\">{{\n aggregation()?.display | syslang | transloco\n }}</span>\n </ng-content>\n\n @if (collapsible()) {\n <!-- The `<summary>` is out of the tab order (`tabindex=\"-1\"`), so this button is the keyboard way to\n collapse the facet. Its click bubbles to the `<summary>`, whose handler does the toggle, and it\n exposes `aria-expanded`. -->\n <button\n type=\"button\"\n variant=\"tertiary\"\n [iconOnly]=\"true\"\n size=\"md\"\n [aria-label]=\"'filters.toggle' | transloco\"\n [attr.aria-expanded]=\"!isCollapsed()\"\n [tooltip]=\"'filters.toggle' | transloco\"\n class=\"shrink-0 cursor-pointer [&_svg]:transition-transform [&_svg]:duration-150 group-open:[&_svg]:rotate-90\">\n <chevron-right class=\"shrink-0\" />\n </button>\n }\n </summary>\n <ng-container [ngTemplateOutlet]=\"content\" />\n </details>\n}\n",
|
|
26902
27967
|
styles: [":host{interpolate-size:allow-keywords}details::details-content{flex:1 1 auto;block-size:0;overflow:clip;overflow-clip-margin:.25rem;transition:block-size .2s cubic-bezier(.32,.72,0,1),content-visibility .2s allow-discrete}details[open]::details-content{block-size:auto}@media(prefers-reduced-motion:reduce){details::details-content{transition:none}}\n", ":host{min-width:200px}ul[role=list]{scrollbar-width:thin}\n"]
|
|
26903
27968
|
}]
|
|
26904
27969
|
}],
|
|
@@ -27230,6 +28295,8 @@ var AggregationPanelComponent = class AggregationPanelComponent {
|
|
|
27230
28295
|
searchBox = viewChild(SearchInputComponent, ...ngDevMode ? [{ debugName: "searchBox" }] : /* istanbul ignore next */ []);
|
|
27231
28296
|
searchToggle = viewChild("searchToggle", ...ngDevMode ? [{ debugName: "searchToggle" }] : /* istanbul ignore next */ []);
|
|
27232
28297
|
injector = inject(Injector);
|
|
28298
|
+
breakpoints = inject(BreakpointObserverService);
|
|
28299
|
+
actionSize = computed(() => this.breakpoints.isTouch() ? "lg" : "md", ...ngDevMode ? [{ debugName: "actionSize" }] : /* istanbul ignore next */ []);
|
|
27233
28300
|
isInPopover = !!inject(PopoverDirective, { optional: true });
|
|
27234
28301
|
static nextId = 0;
|
|
27235
28302
|
searchId = `aggregation-search-${AggregationPanelComponent.nextId++}`;
|
|
@@ -27434,7 +28501,7 @@ var AggregationPanelComponent = class AggregationPanelComponent {
|
|
|
27434
28501
|
isSignal: true
|
|
27435
28502
|
}],
|
|
27436
28503
|
ngImport: i0,
|
|
27437
|
-
template: "<!-- `<details>`/`<summary>` stay native (open/close, the `name`-based exclusive accordion): a facet is\n a disclosure, not a grid row. They used to sit in an `@angular/aria` grid so ArrowUp/ArrowDown could\n jump from one facet header to the next, but a grid without headers reads as a layout table\n (RGAA 5.3). The `<summary>` itself is `tabindex=\"-1\"`: Tab walks the header's chevron, never the header row, and the\n chevron is the keyboard way to collapse. Select all, clear and apply are not in the header: they are in the body, in a\n bar under the search field. Label, header actions (the count and the chevron) and body are `<ng-template>`s: `<ng-content select=\"…\">` can only be\n declared once, and the body is projected content. -->\n\n<ng-template #searchToggleSlot>\n <button\n #searchToggle\n type=\"button\"\n variant=\"tertiary\"\n [iconOnly]=\"true\"\n size=\"md\"\n class=\"shrink-0 cursor-pointer\"\n [attr.aria-expanded]=\"showSearch()\"\n [attr.aria-controls]=\"searchId\"\n [tooltip]=\"\n 'filters.searchInFacet'\n | transloco: { facet: (aggregation()?.display | syslang | transloco) }\n \"\n (click)=\"toggleSearch($event)\">\n <search-icon class=\"shrink-0\" />\n <span class=\"sr-only\">{{\n \"filters.searchInFacet\"\n | transloco: { facet: (aggregation()?.display | syslang | transloco) }\n }}</span>\n </button>\n</ng-template>\n\n<ng-template #labelSlot>\n <ng-content select=\"label\">\n @let icon = aggregation()?.icon;\n @if (icon) {\n <FaIcon [faClass]=\"icon\" class=\"mr-1 shrink-0\" />\n }\n <span class=\"grow truncate\">{{\n aggregation()?.display | syslang | transloco\n }}</span>\n </ng-content>\n</ng-template>\n\n<ng-template #headerActionsSlot>\n @if (showFiltersCount() && filtersCount() > 0) {\n <Badge variant=\"number\" fill=\"primary\" scheme=\"sage\" size=\"xs\" class=\"ml-1\">\n {{ filtersCount() }}\n </Badge>\n }\n @if (canSearch() && !isCollapsed()) {\n <!-- The magnifier opens the search field of the facet (and closes it): the field is not on screen until then. It is\n in the header, next to the chevron, and only while the facet is open — there is nothing to search in a closed\n one. Interactive content in a summary does not toggle the details by itself, and the click is stopped anyway. -->\n <ng-container [ngTemplateOutlet]=\"searchToggleSlot\" />\n }\n @if (collapsible()) {\n <!-- The `<summary>` is out of the tab order (`tabindex=\"-1\"`), so this button is the keyboard way to\n collapse the facet. Its click bubbles to the `<summary>`, whose handler does the toggle, and it\n exposes `aria-expanded`. -->\n <button\n type=\"button\"\n variant=\"tertiary\"\n [iconOnly]=\"true\"\n size=\"md\"\n [attr.aria-expanded]=\"!isCollapsed()\"\n [tooltip]=\"'filters.toggle' | transloco\"\n class=\"shrink-0 cursor-pointer [&_svg]:transition-transform [&_svg]:duration-150 group-open:[&_svg]:rotate-90\">\n <chevron-right class=\"shrink-0\" />\n <span class=\"sr-only\">{{ \"filters.toggle\" | transloco }}</span>\n </button>\n }\n</ng-template>\n\n<ng-template #bodySlot>\n <div class=\"flex min-h-0 flex-1 flex-col\">\n @if (canSearch()) {\n <!-- The field is always in the DOM and folded to nothing until it is asked for: a grid row that goes from 0fr to 1fr is\n the one height animation that needs no measuring. `inert` takes the folded field out of the tab order and of the\n accessibility tree. The margins live in the inner box: a padding on the folded element itself would keep it\n from reaching zero.\n\n No `hotkey`: this field is one of many facet search boxes on the page, so it must not advertise a global shortcut.\n A placeholder is not a label (RGAA 11.1): the name says WHICH facet this box filters — the one thing that tells a\n dozen identical fields apart. SearchInput hands its class to its inner field, so a margin on it would count twice,\n which is one more reason for the padding on the box around it. -->\n <div\n [id]=\"searchId\"\n class=\"grid shrink-0 transition-[grid-template-rows,opacity] duration-200 ease-[cubic-bezier(0.32,0.72,0,1)] motion-reduce:transition-none\"\n [class]=\"\n showSearch()\n ? 'grid-rows-[1fr] opacity-100'\n : 'grid-rows-[0fr] opacity-0'\n \"\n [inert]=\"!showSearch()\">\n <!-- `px-0.5`: the box clips what is outside it, and the focus ring of the field is drawn outside the field (1px past its\n border), so it needs a little room on each side. No negative margin to take it back: it pushed that room OUTSIDE\n the box, into the clipping of the popover or the drawer around, and the ring was cut on both sides. -->\n <div class=\"min-h-0 overflow-hidden px-0.5\">\n <div [class]=\"headless() ? 'pt-0.5 pb-1' : 'pt-2 pb-1'\">\n <SearchInput\n [placeholder]=\"'search' | transloco\"\n [clearLabel]=\"'filters.clearSearch' | transloco\"\n [aria-label]=\"\n 'filters.searchInFacet'\n | transloco\n : { facet: (aggregation()?.display | syslang | transloco) }\n \"\n [(value)]=\"searchText\"\n (keydown.escape)=\"onSearchEscape($event)\">\n <ng-content select=\"[search-addon]\" />\n </SearchInput>\n </div>\n </div>\n </div>\n }\n\n @if (itemsLength() > 0 || hasFilters() || selection()) {\n <!-- The bar under the search field, in a popover and in the filters drawer alike: clear and apply, and nothing else, so\n both keep their full text in the little room there is. Clear is a button with a text, not an icon, and stays in\n place (disabled) when there is nothing to clear. Apply only shows once something is pending, as it always did, and\n sits at the same level. -->\n <div\n data-bar=\"actions\"\n class=\"mb-1 flex shrink-0 items-center justify-end gap-1\">\n @if (headless() && canSearch()) {\n <ng-container [ngTemplateOutlet]=\"searchToggleSlot\" />\n }\n <button\n type=\"button\"\n variant=\"tertiary\"\n size=\"lg\"\n class=\"shrink-0\"\n [disabled]=\"!hasFilters() && selectedCount() === 0\"\n [attr.aria-label]=\"'filters.clearFilters' | transloco\"\n (click)=\"cleared.emit()\">\n {{ \"filters.clearAll\" | transloco }}\n </button>\n @if (selection()) {\n <!-- No icon: the room is short, and the word says it. -->\n <button\n type=\"button\"\n variant=\"accent\"\n size=\"lg\"\n class=\"shrink-0 overflow-hidden\"\n (click)=\"applied.emit()\">\n <span class=\"truncate\">{{ \"filters.apply\" | transloco }}</span>\n </button>\n }\n </div>\n }\n\n @if (itemsLength() > 0) {\n <!-- Select all is the first row of the list, written like one: the box lines up with the boxes of the items it drives and\n carries its own text, which a bare box next to two buttons never did. The text lines up with the items' too: same gap\n after the box (`gap-2`) and same size (`text-sm`, where the checkbox's own label would be 12px). The whole row is the label, so it is as easy\n to hit as an item. The count of checked items is part of that same label (\"Select all (3)\"), so the two can never\n overlap: when the room is short the label is cut with an ellipsis as a whole. It stays out of the scroller of the list, so it does not scroll away with the items. -->\n <div\n data-bar=\"select-all\"\n class=\"mb-1 flex shrink-0 items-center pr-3 pl-1.5 text-sm\">\n <checkbox\n class=\"min-w-0 flex-1 items-center gap-2 py-1.5 [&_.checkbox-label]:truncate [&_.checkbox-label]:text-base [&_.checkbox-label]:leading-6 [&_.checkbox-text-block]:min-w-0\"\n [checked]=\"isAllSelected()\"\n [indeterminate]=\"selectedCount() > 0 && !isAllSelected()\"\n (checkedChange)=\"$event ? allSelected.emit() : allUnselected.emit()\">\n {{\n (isAllSelected() ? \"filters.unselectAll\" : \"filters.selectAll\")\n | transloco\n }}\n @if (selectedCount() > 0) {\n <span class=\"text-(--font-primary-muted)\"\n >({{ selectedCount() }})</span\n >\n }\n </checkbox>\n <span class=\"sr-only\" aria-live=\"polite\">{{\n \"filters.selectedCount\" | transloco: { count: selectedCount() }\n }}</span>\n </div>\n }\n\n <ng-content />\n\n @if (hasMore() && searchedItemsLength() === 0) {\n <!-- The placeholder rows of a loading page are not here: they are rows of the scrolling area, in the list and the tree\n (AggregationLoadMoreSkeleton). Here, between the list and the button, they would shorten the list. -->\n <!-- `variant=\"none\"`: galactik's ButtonComponent matches every <button> and would otherwise dress this one as a primary\n button (filled, rounded, 36px high). `none` leaves the classes below as the only style. -->\n <!-- `aria-disabled`, not `disabled`: the focus stays on the button while the page loads. The accessible name stays\n \"load more\" and `aria-busy` tells that it is working, so no extra text has to be translated by the application. -->\n <button\n type=\"button\"\n data-load-more=\"button\"\n variant=\"none\"\n class=\"mt-1 flex w-full shrink-0 cursor-pointer items-center justify-center rounded-(--radius-xs) px-2 py-1.5 text-(--font-primary-muted) underline underline-offset-4 hover:bg-(--bg-primary-lighter) hover:text-(--font-primary-base) focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-(--stroke-focus) focus-visible:outline-solid aria-busy:cursor-progress aria-busy:no-underline aria-busy:hover:bg-transparent\"\n [attr.aria-label]=\"'loadMore' | transloco\"\n [attr.aria-busy]=\"loading() ? 'true' : null\"\n [attr.aria-disabled]=\"loading() ? 'true' : null\"\n (click)=\"requestMore()\">\n <!-- Both states share one grid cell: the button keeps its width and height when the text gives way to the dots. -->\n <span class=\"inline-grid\">\n <span class=\"col-start-1 row-start-1\" [class.invisible]=\"loading()\">\n {{ \"loadMore\" | transloco }}\n </span>\n @if (loading()) {\n <loading-dots size=\"sm\" class=\"col-start-1 row-start-1\" />\n }\n </span>\n </button>\n }\n </div>\n</ng-template>\n\n@if (headless()) {\n <div class=\"flex min-h-0 flex-1 flex-col p-0.5\">\n <ng-container [ngTemplateOutlet]=\"bodySlot\" />\n </div>\n} @else {\n <details\n [attr.open]=\"expanded()\"\n [attr.name]=\"id()\"\n class=\"group flex min-h-0 flex-1 flex-col p-0.5 details-content:flex details-content:min-h-0 details-content:flex-col\"\n (toggle)=\"onToggle($event)\">\n <summary\n tabindex=\"-1\"\n [class.cursor-pointer]=\"collapsible() && !isEmpty()\"\n [class]=\"\n (isEmpty() ? 'text-(--font-neutral-muted) ' : '') + rowStateClass\n \"\n class=\"m-0 flex h-8 w-full shrink-0 scroll-mt-16 scroll-mb-3 items-center gap-1 pl-1 font-semibold select-none\"\n (click)=\"onHeaderClick($event)\">\n <ng-container [ngTemplateOutlet]=\"labelSlot\" />\n <ng-container [ngTemplateOutlet]=\"headerActionsSlot\" />\n </summary>\n <ng-container [ngTemplateOutlet]=\"bodySlot\" />\n </details>\n}\n",
|
|
28504
|
+
template: "<!-- `<details>`/`<summary>` stay native (open/close, the `name`-based exclusive accordion): a facet is\n a disclosure, not a grid row. They used to sit in an `@angular/aria` grid so ArrowUp/ArrowDown could\n jump from one facet header to the next, but a grid without headers reads as a layout table\n (RGAA 5.3). The `<summary>` itself is `tabindex=\"-1\"`: Tab walks the header's chevron, never the header row, and the\n chevron is the keyboard way to collapse. Select all, clear and apply are not in the header: they are in the body, in a\n bar under the search field. Label, header actions (the count and the chevron) and body are `<ng-template>`s: `<ng-content select=\"…\">` can only be\n declared once, and the body is projected content. -->\n\n<ng-template #searchToggleSlot>\n <button\n #searchToggle\n type=\"button\"\n variant=\"tertiary\"\n [iconOnly]=\"true\"\n size=\"md\"\n class=\"shrink-0 cursor-pointer\"\n [attr.aria-expanded]=\"showSearch()\"\n [attr.aria-controls]=\"searchId\"\n [tooltip]=\"\n 'filters.searchInFacet'\n | transloco: { facet: (aggregation()?.display | syslang | transloco) }\n \"\n (click)=\"toggleSearch($event)\">\n <search-icon class=\"shrink-0\" />\n <span class=\"sr-only\">{{\n \"filters.searchInFacet\"\n | transloco: { facet: (aggregation()?.display | syslang | transloco) }\n }}</span>\n </button>\n</ng-template>\n\n<ng-template #labelSlot>\n <ng-content select=\"label\">\n @let icon = aggregation()?.icon;\n @if (icon) {\n <FaIcon [faClass]=\"icon\" class=\"mr-1 shrink-0\" />\n }\n <span class=\"grow truncate\">{{\n aggregation()?.display | syslang | transloco\n }}</span>\n </ng-content>\n</ng-template>\n\n<ng-template #headerActionsSlot>\n @if (showFiltersCount() && filtersCount() > 0) {\n <Badge variant=\"number\" fill=\"primary\" scheme=\"sage\" size=\"xs\" class=\"ml-1\">\n {{ filtersCount() }}\n </Badge>\n }\n @if (canSearch() && !isCollapsed()) {\n <!-- The magnifier opens the search field of the facet (and closes it): the field is not on screen until then. It is\n in the header, next to the chevron, and only while the facet is open — there is nothing to search in a closed\n one. Interactive content in a summary does not toggle the details by itself, and the click is stopped anyway. -->\n <ng-container [ngTemplateOutlet]=\"searchToggleSlot\" />\n }\n @if (collapsible()) {\n <!-- The `<summary>` is out of the tab order (`tabindex=\"-1\"`), so this button is the keyboard way to\n collapse the facet. Its click bubbles to the `<summary>`, whose handler does the toggle, and it\n exposes `aria-expanded`. -->\n <button\n type=\"button\"\n variant=\"tertiary\"\n [iconOnly]=\"true\"\n size=\"md\"\n [attr.aria-expanded]=\"!isCollapsed()\"\n [tooltip]=\"'filters.toggle' | transloco\"\n class=\"shrink-0 cursor-pointer [&_svg]:transition-transform [&_svg]:duration-150 group-open:[&_svg]:rotate-90\">\n <chevron-right class=\"shrink-0\" />\n <span class=\"sr-only\">{{ \"filters.toggle\" | transloco }}</span>\n </button>\n }\n</ng-template>\n\n<ng-template #bodySlot>\n <div class=\"flex min-h-0 flex-1 flex-col\">\n @if (canSearch()) {\n <!-- The field is always in the DOM and folded to nothing until it is asked for: a grid row that goes from 0fr to 1fr is\n the one height animation that needs no measuring. `inert` takes the folded field out of the tab order and of the\n accessibility tree. The margins live in the inner box: a padding on the folded element itself would keep it\n from reaching zero.\n\n No `hotkey`: this field is one of many facet search boxes on the page, so it must not advertise a global shortcut.\n A placeholder is not a label (RGAA 11.1): the name says WHICH facet this box filters — the one thing that tells a\n dozen identical fields apart. SearchInput hands its class to its inner field, so a margin on it would count twice,\n which is one more reason for the padding on the box around it. -->\n <div\n [id]=\"searchId\"\n class=\"grid shrink-0 transition-[grid-template-rows,opacity] duration-200 ease-[cubic-bezier(0.32,0.72,0,1)] motion-reduce:transition-none\"\n [class]=\"\n showSearch()\n ? 'grid-rows-[1fr] opacity-100'\n : 'grid-rows-[0fr] opacity-0'\n \"\n [inert]=\"!showSearch()\">\n <!-- `px-0.5`: the box clips what is outside it, and the focus ring of the field is drawn outside the field (1px past its\n border), so it needs a little room on each side. No negative margin to take it back: it pushed that room OUTSIDE\n the box, into the clipping of the popover or the drawer around, and the ring was cut on both sides. -->\n <div class=\"min-h-0 overflow-hidden px-0.5\">\n <!-- `pb-1.5`: the focus ring of the Clear all / Apply buttons just below sits 4px outside them (2px ring, 2px offset): the\n 6px leave 2px between that ring and the field. -->\n <div [class]=\"headless() ? 'pt-0.5 pb-1.5' : 'pt-2 pb-1.5'\">\n <SearchInput\n [placeholder]=\"'search' | transloco\"\n [clearLabel]=\"'filters.clearSearch' | transloco\"\n [aria-label]=\"\n 'filters.searchInFacet'\n | transloco\n : { facet: (aggregation()?.display | syslang | transloco) }\n \"\n [(value)]=\"searchText\"\n (keydown.escape)=\"onSearchEscape($event)\">\n <ng-content select=\"[search-addon]\" />\n </SearchInput>\n </div>\n </div>\n </div>\n }\n\n @if (itemsLength() > 0 || hasFilters() || selection()) {\n <!-- The bar under the search field, in a popover and in the filters drawer alike: clear and apply, and nothing else, so\n both keep their full text in the little room there is. Clear is a button with a text, not an icon, and stays in\n place (disabled) when there is nothing to clear. Apply only shows once something is pending, as it always did, and\n sits at the same level. -->\n <div\n data-bar=\"actions\"\n class=\"mb-1 flex shrink-0 items-center justify-end gap-1\">\n @if (headless() && canSearch()) {\n <ng-container [ngTemplateOutlet]=\"searchToggleSlot\" />\n }\n <button\n type=\"button\"\n variant=\"tertiary\"\n [size]=\"actionSize()\"\n class=\"shrink-0\"\n [disabled]=\"!hasFilters() && selectedCount() === 0\"\n [attr.aria-label]=\"'filters.clearFilters' | transloco\"\n (click)=\"cleared.emit()\">\n {{ \"filters.clearAll\" | transloco }}\n </button>\n @if (selection()) {\n <!-- No icon: the room is short, and the word says it. -->\n <button\n type=\"button\"\n variant=\"accent\"\n [size]=\"actionSize()\"\n class=\"shrink-0 overflow-hidden\"\n (click)=\"applied.emit()\">\n <span class=\"truncate\">{{ \"filters.apply\" | transloco }}</span>\n </button>\n }\n </div>\n }\n\n @if (itemsLength() > 0) {\n <!-- Select all is the first row of the list, written like one: the box lines up with the boxes of the items it drives and\n carries its own text, which a bare box next to two buttons never did. The text lines up with the items' too: same gap\n after the box (`gap-2`) and same size (`text-sm`, where the checkbox's own label would be 12px). The whole row is the label, so it is as easy\n to hit as an item. The count of checked items is part of that same label (\"Select all (3)\"), so the two can never\n overlap: when the room is short the label is cut with an ellipsis as a whole. It stays out of the scroller of the list, so it does not scroll away with the items. -->\n <div\n data-bar=\"select-all\"\n class=\"mb-1 flex shrink-0 items-center pr-3 pl-1.5 text-sm\">\n <checkbox\n class=\"min-w-0 flex-1 items-center gap-2 py-1.5 [&_.checkbox-label]:truncate [&_.checkbox-label]:text-base [&_.checkbox-label]:leading-6 [&_.checkbox-text-block]:min-w-0\"\n [checked]=\"isAllSelected()\"\n [indeterminate]=\"selectedCount() > 0 && !isAllSelected()\"\n (checkedChange)=\"$event ? allSelected.emit() : allUnselected.emit()\">\n {{\n (isAllSelected() ? \"filters.unselectAll\" : \"filters.selectAll\")\n | transloco\n }}\n @if (selectedCount() > 0) {\n <span class=\"text-(--font-primary-muted)\"\n >({{ selectedCount() }})</span\n >\n }\n </checkbox>\n <span class=\"sr-only\" aria-live=\"polite\">{{\n \"filters.selectedCount\" | transloco: { count: selectedCount() }\n }}</span>\n </div>\n }\n\n <ng-content />\n\n @if (hasMore() && searchedItemsLength() === 0) {\n <!-- The placeholder rows of a loading page are not here: they are rows of the scrolling area, in the list and the tree\n (AggregationLoadMoreSkeleton). Here, between the list and the button, they would shorten the list. -->\n <!-- `variant=\"none\"`: galactik's ButtonComponent matches every <button> and would otherwise dress this one as a primary\n button (filled, rounded, 36px high). `none` leaves the classes below as the only style. -->\n <!-- `aria-disabled`, not `disabled`: the focus stays on the button while the page loads. The accessible name stays\n \"load more\" and `aria-busy` tells that it is working, so no extra text has to be translated by the application. -->\n <button\n type=\"button\"\n data-load-more=\"button\"\n variant=\"none\"\n class=\"mt-1 flex w-full shrink-0 cursor-pointer items-center justify-center rounded-(--radius-xs) px-2 py-1.5 text-(--font-primary-muted) underline underline-offset-4 hover:bg-(--bg-primary-lighter) hover:text-(--font-primary-base) focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-(--stroke-focus) focus-visible:outline-solid aria-busy:cursor-progress aria-busy:no-underline aria-busy:hover:bg-transparent\"\n [attr.aria-label]=\"'loadMore' | transloco\"\n [attr.aria-busy]=\"loading() ? 'true' : null\"\n [attr.aria-disabled]=\"loading() ? 'true' : null\"\n (click)=\"requestMore()\">\n <!-- Both states share one grid cell: the button keeps its width and height when the text gives way to the dots. -->\n <span class=\"inline-grid\">\n <span class=\"col-start-1 row-start-1\" [class.invisible]=\"loading()\">\n {{ \"loadMore\" | transloco }}\n </span>\n @if (loading()) {\n <loading-dots size=\"sm\" class=\"col-start-1 row-start-1\" />\n }\n </span>\n </button>\n }\n </div>\n</ng-template>\n\n@if (headless()) {\n <div class=\"flex min-h-0 flex-1 flex-col p-0.5\">\n <ng-container [ngTemplateOutlet]=\"bodySlot\" />\n </div>\n} @else {\n <details\n [attr.open]=\"expanded()\"\n [attr.name]=\"id()\"\n class=\"group flex min-h-0 flex-1 flex-col p-0.5 details-content:flex details-content:min-h-0 details-content:flex-col\"\n (toggle)=\"onToggle($event)\">\n <summary\n tabindex=\"-1\"\n [class.cursor-pointer]=\"collapsible() && !isEmpty()\"\n [class]=\"\n (isEmpty() ? 'text-(--font-neutral-muted) ' : '') + rowStateClass\n \"\n class=\"m-0 flex h-8 w-full shrink-0 scroll-mt-16 scroll-mb-3 items-center gap-1 pl-1 font-semibold select-none\"\n (click)=\"onHeaderClick($event)\">\n <ng-container [ngTemplateOutlet]=\"labelSlot\" />\n <ng-container [ngTemplateOutlet]=\"headerActionsSlot\" />\n </summary>\n <ng-container [ngTemplateOutlet]=\"bodySlot\" />\n </details>\n}\n",
|
|
27438
28505
|
styles: [":host{interpolate-size:allow-keywords}details::details-content{flex:1 1 auto;block-size:0;overflow:clip;overflow-clip-margin:.25rem;transition:block-size .2s cubic-bezier(.32,.72,0,1),content-visibility .2s allow-discrete}details[open]::details-content{block-size:auto}@media(prefers-reduced-motion:reduce){details::details-content{transition:none}}\n"],
|
|
27439
28506
|
dependencies: [
|
|
27440
28507
|
{
|
|
@@ -27579,7 +28646,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
27579
28646
|
],
|
|
27580
28647
|
providers: [provideTranslocoScope("filters")],
|
|
27581
28648
|
host: { class: "flex min-h-0 flex-1 flex-col" },
|
|
27582
|
-
template: "<!-- `<details>`/`<summary>` stay native (open/close, the `name`-based exclusive accordion): a facet is\n a disclosure, not a grid row. They used to sit in an `@angular/aria` grid so ArrowUp/ArrowDown could\n jump from one facet header to the next, but a grid without headers reads as a layout table\n (RGAA 5.3). The `<summary>` itself is `tabindex=\"-1\"`: Tab walks the header's chevron, never the header row, and the\n chevron is the keyboard way to collapse. Select all, clear and apply are not in the header: they are in the body, in a\n bar under the search field. Label, header actions (the count and the chevron) and body are `<ng-template>`s: `<ng-content select=\"…\">` can only be\n declared once, and the body is projected content. -->\n\n<ng-template #searchToggleSlot>\n <button\n #searchToggle\n type=\"button\"\n variant=\"tertiary\"\n [iconOnly]=\"true\"\n size=\"md\"\n class=\"shrink-0 cursor-pointer\"\n [attr.aria-expanded]=\"showSearch()\"\n [attr.aria-controls]=\"searchId\"\n [tooltip]=\"\n 'filters.searchInFacet'\n | transloco: { facet: (aggregation()?.display | syslang | transloco) }\n \"\n (click)=\"toggleSearch($event)\">\n <search-icon class=\"shrink-0\" />\n <span class=\"sr-only\">{{\n \"filters.searchInFacet\"\n | transloco: { facet: (aggregation()?.display | syslang | transloco) }\n }}</span>\n </button>\n</ng-template>\n\n<ng-template #labelSlot>\n <ng-content select=\"label\">\n @let icon = aggregation()?.icon;\n @if (icon) {\n <FaIcon [faClass]=\"icon\" class=\"mr-1 shrink-0\" />\n }\n <span class=\"grow truncate\">{{\n aggregation()?.display | syslang | transloco\n }}</span>\n </ng-content>\n</ng-template>\n\n<ng-template #headerActionsSlot>\n @if (showFiltersCount() && filtersCount() > 0) {\n <Badge variant=\"number\" fill=\"primary\" scheme=\"sage\" size=\"xs\" class=\"ml-1\">\n {{ filtersCount() }}\n </Badge>\n }\n @if (canSearch() && !isCollapsed()) {\n <!-- The magnifier opens the search field of the facet (and closes it): the field is not on screen until then. It is\n in the header, next to the chevron, and only while the facet is open — there is nothing to search in a closed\n one. Interactive content in a summary does not toggle the details by itself, and the click is stopped anyway. -->\n <ng-container [ngTemplateOutlet]=\"searchToggleSlot\" />\n }\n @if (collapsible()) {\n <!-- The `<summary>` is out of the tab order (`tabindex=\"-1\"`), so this button is the keyboard way to\n collapse the facet. Its click bubbles to the `<summary>`, whose handler does the toggle, and it\n exposes `aria-expanded`. -->\n <button\n type=\"button\"\n variant=\"tertiary\"\n [iconOnly]=\"true\"\n size=\"md\"\n [attr.aria-expanded]=\"!isCollapsed()\"\n [tooltip]=\"'filters.toggle' | transloco\"\n class=\"shrink-0 cursor-pointer [&_svg]:transition-transform [&_svg]:duration-150 group-open:[&_svg]:rotate-90\">\n <chevron-right class=\"shrink-0\" />\n <span class=\"sr-only\">{{ \"filters.toggle\" | transloco }}</span>\n </button>\n }\n</ng-template>\n\n<ng-template #bodySlot>\n <div class=\"flex min-h-0 flex-1 flex-col\">\n @if (canSearch()) {\n <!-- The field is always in the DOM and folded to nothing until it is asked for: a grid row that goes from 0fr to 1fr is\n the one height animation that needs no measuring. `inert` takes the folded field out of the tab order and of the\n accessibility tree. The margins live in the inner box: a padding on the folded element itself would keep it\n from reaching zero.\n\n No `hotkey`: this field is one of many facet search boxes on the page, so it must not advertise a global shortcut.\n A placeholder is not a label (RGAA 11.1): the name says WHICH facet this box filters — the one thing that tells a\n dozen identical fields apart. SearchInput hands its class to its inner field, so a margin on it would count twice,\n which is one more reason for the padding on the box around it. -->\n <div\n [id]=\"searchId\"\n class=\"grid shrink-0 transition-[grid-template-rows,opacity] duration-200 ease-[cubic-bezier(0.32,0.72,0,1)] motion-reduce:transition-none\"\n [class]=\"\n showSearch()\n ? 'grid-rows-[1fr] opacity-100'\n : 'grid-rows-[0fr] opacity-0'\n \"\n [inert]=\"!showSearch()\">\n <!-- `px-0.5`: the box clips what is outside it, and the focus ring of the field is drawn outside the field (1px past its\n border), so it needs a little room on each side. No negative margin to take it back: it pushed that room OUTSIDE\n the box, into the clipping of the popover or the drawer around, and the ring was cut on both sides. -->\n <div class=\"min-h-0 overflow-hidden px-0.5\">\n <div [class]=\"headless() ? 'pt-0.5 pb-1' : 'pt-2 pb-1'\">\n <SearchInput\n [placeholder]=\"'search' | transloco\"\n [clearLabel]=\"'filters.clearSearch' | transloco\"\n [aria-label]=\"\n 'filters.searchInFacet'\n | transloco\n : { facet: (aggregation()?.display | syslang | transloco) }\n \"\n [(value)]=\"searchText\"\n (keydown.escape)=\"onSearchEscape($event)\">\n <ng-content select=\"[search-addon]\" />\n </SearchInput>\n </div>\n </div>\n </div>\n }\n\n @if (itemsLength() > 0 || hasFilters() || selection()) {\n <!-- The bar under the search field, in a popover and in the filters drawer alike: clear and apply, and nothing else, so\n both keep their full text in the little room there is. Clear is a button with a text, not an icon, and stays in\n place (disabled) when there is nothing to clear. Apply only shows once something is pending, as it always did, and\n sits at the same level. -->\n <div\n data-bar=\"actions\"\n class=\"mb-1 flex shrink-0 items-center justify-end gap-1\">\n @if (headless() && canSearch()) {\n <ng-container [ngTemplateOutlet]=\"searchToggleSlot\" />\n }\n <button\n type=\"button\"\n variant=\"tertiary\"\n size=\"lg\"\n class=\"shrink-0\"\n [disabled]=\"!hasFilters() && selectedCount() === 0\"\n [attr.aria-label]=\"'filters.clearFilters' | transloco\"\n (click)=\"cleared.emit()\">\n {{ \"filters.clearAll\" | transloco }}\n </button>\n @if (selection()) {\n <!-- No icon: the room is short, and the word says it. -->\n <button\n type=\"button\"\n variant=\"accent\"\n size=\"lg\"\n class=\"shrink-0 overflow-hidden\"\n (click)=\"applied.emit()\">\n <span class=\"truncate\">{{ \"filters.apply\" | transloco }}</span>\n </button>\n }\n </div>\n }\n\n @if (itemsLength() > 0) {\n <!-- Select all is the first row of the list, written like one: the box lines up with the boxes of the items it drives and\n carries its own text, which a bare box next to two buttons never did. The text lines up with the items' too: same gap\n after the box (`gap-2`) and same size (`text-sm`, where the checkbox's own label would be 12px). The whole row is the label, so it is as easy\n to hit as an item. The count of checked items is part of that same label (\"Select all (3)\"), so the two can never\n overlap: when the room is short the label is cut with an ellipsis as a whole. It stays out of the scroller of the list, so it does not scroll away with the items. -->\n <div\n data-bar=\"select-all\"\n class=\"mb-1 flex shrink-0 items-center pr-3 pl-1.5 text-sm\">\n <checkbox\n class=\"min-w-0 flex-1 items-center gap-2 py-1.5 [&_.checkbox-label]:truncate [&_.checkbox-label]:text-base [&_.checkbox-label]:leading-6 [&_.checkbox-text-block]:min-w-0\"\n [checked]=\"isAllSelected()\"\n [indeterminate]=\"selectedCount() > 0 && !isAllSelected()\"\n (checkedChange)=\"$event ? allSelected.emit() : allUnselected.emit()\">\n {{\n (isAllSelected() ? \"filters.unselectAll\" : \"filters.selectAll\")\n | transloco\n }}\n @if (selectedCount() > 0) {\n <span class=\"text-(--font-primary-muted)\"\n >({{ selectedCount() }})</span\n >\n }\n </checkbox>\n <span class=\"sr-only\" aria-live=\"polite\">{{\n \"filters.selectedCount\" | transloco: { count: selectedCount() }\n }}</span>\n </div>\n }\n\n <ng-content />\n\n @if (hasMore() && searchedItemsLength() === 0) {\n <!-- The placeholder rows of a loading page are not here: they are rows of the scrolling area, in the list and the tree\n (AggregationLoadMoreSkeleton). Here, between the list and the button, they would shorten the list. -->\n <!-- `variant=\"none\"`: galactik's ButtonComponent matches every <button> and would otherwise dress this one as a primary\n button (filled, rounded, 36px high). `none` leaves the classes below as the only style. -->\n <!-- `aria-disabled`, not `disabled`: the focus stays on the button while the page loads. The accessible name stays\n \"load more\" and `aria-busy` tells that it is working, so no extra text has to be translated by the application. -->\n <button\n type=\"button\"\n data-load-more=\"button\"\n variant=\"none\"\n class=\"mt-1 flex w-full shrink-0 cursor-pointer items-center justify-center rounded-(--radius-xs) px-2 py-1.5 text-(--font-primary-muted) underline underline-offset-4 hover:bg-(--bg-primary-lighter) hover:text-(--font-primary-base) focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-(--stroke-focus) focus-visible:outline-solid aria-busy:cursor-progress aria-busy:no-underline aria-busy:hover:bg-transparent\"\n [attr.aria-label]=\"'loadMore' | transloco\"\n [attr.aria-busy]=\"loading() ? 'true' : null\"\n [attr.aria-disabled]=\"loading() ? 'true' : null\"\n (click)=\"requestMore()\">\n <!-- Both states share one grid cell: the button keeps its width and height when the text gives way to the dots. -->\n <span class=\"inline-grid\">\n <span class=\"col-start-1 row-start-1\" [class.invisible]=\"loading()\">\n {{ \"loadMore\" | transloco }}\n </span>\n @if (loading()) {\n <loading-dots size=\"sm\" class=\"col-start-1 row-start-1\" />\n }\n </span>\n </button>\n }\n </div>\n</ng-template>\n\n@if (headless()) {\n <div class=\"flex min-h-0 flex-1 flex-col p-0.5\">\n <ng-container [ngTemplateOutlet]=\"bodySlot\" />\n </div>\n} @else {\n <details\n [attr.open]=\"expanded()\"\n [attr.name]=\"id()\"\n class=\"group flex min-h-0 flex-1 flex-col p-0.5 details-content:flex details-content:min-h-0 details-content:flex-col\"\n (toggle)=\"onToggle($event)\">\n <summary\n tabindex=\"-1\"\n [class.cursor-pointer]=\"collapsible() && !isEmpty()\"\n [class]=\"\n (isEmpty() ? 'text-(--font-neutral-muted) ' : '') + rowStateClass\n \"\n class=\"m-0 flex h-8 w-full shrink-0 scroll-mt-16 scroll-mb-3 items-center gap-1 pl-1 font-semibold select-none\"\n (click)=\"onHeaderClick($event)\">\n <ng-container [ngTemplateOutlet]=\"labelSlot\" />\n <ng-container [ngTemplateOutlet]=\"headerActionsSlot\" />\n </summary>\n <ng-container [ngTemplateOutlet]=\"bodySlot\" />\n </details>\n}\n",
|
|
28649
|
+
template: "<!-- `<details>`/`<summary>` stay native (open/close, the `name`-based exclusive accordion): a facet is\n a disclosure, not a grid row. They used to sit in an `@angular/aria` grid so ArrowUp/ArrowDown could\n jump from one facet header to the next, but a grid without headers reads as a layout table\n (RGAA 5.3). The `<summary>` itself is `tabindex=\"-1\"`: Tab walks the header's chevron, never the header row, and the\n chevron is the keyboard way to collapse. Select all, clear and apply are not in the header: they are in the body, in a\n bar under the search field. Label, header actions (the count and the chevron) and body are `<ng-template>`s: `<ng-content select=\"…\">` can only be\n declared once, and the body is projected content. -->\n\n<ng-template #searchToggleSlot>\n <button\n #searchToggle\n type=\"button\"\n variant=\"tertiary\"\n [iconOnly]=\"true\"\n size=\"md\"\n class=\"shrink-0 cursor-pointer\"\n [attr.aria-expanded]=\"showSearch()\"\n [attr.aria-controls]=\"searchId\"\n [tooltip]=\"\n 'filters.searchInFacet'\n | transloco: { facet: (aggregation()?.display | syslang | transloco) }\n \"\n (click)=\"toggleSearch($event)\">\n <search-icon class=\"shrink-0\" />\n <span class=\"sr-only\">{{\n \"filters.searchInFacet\"\n | transloco: { facet: (aggregation()?.display | syslang | transloco) }\n }}</span>\n </button>\n</ng-template>\n\n<ng-template #labelSlot>\n <ng-content select=\"label\">\n @let icon = aggregation()?.icon;\n @if (icon) {\n <FaIcon [faClass]=\"icon\" class=\"mr-1 shrink-0\" />\n }\n <span class=\"grow truncate\">{{\n aggregation()?.display | syslang | transloco\n }}</span>\n </ng-content>\n</ng-template>\n\n<ng-template #headerActionsSlot>\n @if (showFiltersCount() && filtersCount() > 0) {\n <Badge variant=\"number\" fill=\"primary\" scheme=\"sage\" size=\"xs\" class=\"ml-1\">\n {{ filtersCount() }}\n </Badge>\n }\n @if (canSearch() && !isCollapsed()) {\n <!-- The magnifier opens the search field of the facet (and closes it): the field is not on screen until then. It is\n in the header, next to the chevron, and only while the facet is open — there is nothing to search in a closed\n one. Interactive content in a summary does not toggle the details by itself, and the click is stopped anyway. -->\n <ng-container [ngTemplateOutlet]=\"searchToggleSlot\" />\n }\n @if (collapsible()) {\n <!-- The `<summary>` is out of the tab order (`tabindex=\"-1\"`), so this button is the keyboard way to\n collapse the facet. Its click bubbles to the `<summary>`, whose handler does the toggle, and it\n exposes `aria-expanded`. -->\n <button\n type=\"button\"\n variant=\"tertiary\"\n [iconOnly]=\"true\"\n size=\"md\"\n [attr.aria-expanded]=\"!isCollapsed()\"\n [tooltip]=\"'filters.toggle' | transloco\"\n class=\"shrink-0 cursor-pointer [&_svg]:transition-transform [&_svg]:duration-150 group-open:[&_svg]:rotate-90\">\n <chevron-right class=\"shrink-0\" />\n <span class=\"sr-only\">{{ \"filters.toggle\" | transloco }}</span>\n </button>\n }\n</ng-template>\n\n<ng-template #bodySlot>\n <div class=\"flex min-h-0 flex-1 flex-col\">\n @if (canSearch()) {\n <!-- The field is always in the DOM and folded to nothing until it is asked for: a grid row that goes from 0fr to 1fr is\n the one height animation that needs no measuring. `inert` takes the folded field out of the tab order and of the\n accessibility tree. The margins live in the inner box: a padding on the folded element itself would keep it\n from reaching zero.\n\n No `hotkey`: this field is one of many facet search boxes on the page, so it must not advertise a global shortcut.\n A placeholder is not a label (RGAA 11.1): the name says WHICH facet this box filters — the one thing that tells a\n dozen identical fields apart. SearchInput hands its class to its inner field, so a margin on it would count twice,\n which is one more reason for the padding on the box around it. -->\n <div\n [id]=\"searchId\"\n class=\"grid shrink-0 transition-[grid-template-rows,opacity] duration-200 ease-[cubic-bezier(0.32,0.72,0,1)] motion-reduce:transition-none\"\n [class]=\"\n showSearch()\n ? 'grid-rows-[1fr] opacity-100'\n : 'grid-rows-[0fr] opacity-0'\n \"\n [inert]=\"!showSearch()\">\n <!-- `px-0.5`: the box clips what is outside it, and the focus ring of the field is drawn outside the field (1px past its\n border), so it needs a little room on each side. No negative margin to take it back: it pushed that room OUTSIDE\n the box, into the clipping of the popover or the drawer around, and the ring was cut on both sides. -->\n <div class=\"min-h-0 overflow-hidden px-0.5\">\n <!-- `pb-1.5`: the focus ring of the Clear all / Apply buttons just below sits 4px outside them (2px ring, 2px offset): the\n 6px leave 2px between that ring and the field. -->\n <div [class]=\"headless() ? 'pt-0.5 pb-1.5' : 'pt-2 pb-1.5'\">\n <SearchInput\n [placeholder]=\"'search' | transloco\"\n [clearLabel]=\"'filters.clearSearch' | transloco\"\n [aria-label]=\"\n 'filters.searchInFacet'\n | transloco\n : { facet: (aggregation()?.display | syslang | transloco) }\n \"\n [(value)]=\"searchText\"\n (keydown.escape)=\"onSearchEscape($event)\">\n <ng-content select=\"[search-addon]\" />\n </SearchInput>\n </div>\n </div>\n </div>\n }\n\n @if (itemsLength() > 0 || hasFilters() || selection()) {\n <!-- The bar under the search field, in a popover and in the filters drawer alike: clear and apply, and nothing else, so\n both keep their full text in the little room there is. Clear is a button with a text, not an icon, and stays in\n place (disabled) when there is nothing to clear. Apply only shows once something is pending, as it always did, and\n sits at the same level. -->\n <div\n data-bar=\"actions\"\n class=\"mb-1 flex shrink-0 items-center justify-end gap-1\">\n @if (headless() && canSearch()) {\n <ng-container [ngTemplateOutlet]=\"searchToggleSlot\" />\n }\n <button\n type=\"button\"\n variant=\"tertiary\"\n [size]=\"actionSize()\"\n class=\"shrink-0\"\n [disabled]=\"!hasFilters() && selectedCount() === 0\"\n [attr.aria-label]=\"'filters.clearFilters' | transloco\"\n (click)=\"cleared.emit()\">\n {{ \"filters.clearAll\" | transloco }}\n </button>\n @if (selection()) {\n <!-- No icon: the room is short, and the word says it. -->\n <button\n type=\"button\"\n variant=\"accent\"\n [size]=\"actionSize()\"\n class=\"shrink-0 overflow-hidden\"\n (click)=\"applied.emit()\">\n <span class=\"truncate\">{{ \"filters.apply\" | transloco }}</span>\n </button>\n }\n </div>\n }\n\n @if (itemsLength() > 0) {\n <!-- Select all is the first row of the list, written like one: the box lines up with the boxes of the items it drives and\n carries its own text, which a bare box next to two buttons never did. The text lines up with the items' too: same gap\n after the box (`gap-2`) and same size (`text-sm`, where the checkbox's own label would be 12px). The whole row is the label, so it is as easy\n to hit as an item. The count of checked items is part of that same label (\"Select all (3)\"), so the two can never\n overlap: when the room is short the label is cut with an ellipsis as a whole. It stays out of the scroller of the list, so it does not scroll away with the items. -->\n <div\n data-bar=\"select-all\"\n class=\"mb-1 flex shrink-0 items-center pr-3 pl-1.5 text-sm\">\n <checkbox\n class=\"min-w-0 flex-1 items-center gap-2 py-1.5 [&_.checkbox-label]:truncate [&_.checkbox-label]:text-base [&_.checkbox-label]:leading-6 [&_.checkbox-text-block]:min-w-0\"\n [checked]=\"isAllSelected()\"\n [indeterminate]=\"selectedCount() > 0 && !isAllSelected()\"\n (checkedChange)=\"$event ? allSelected.emit() : allUnselected.emit()\">\n {{\n (isAllSelected() ? \"filters.unselectAll\" : \"filters.selectAll\")\n | transloco\n }}\n @if (selectedCount() > 0) {\n <span class=\"text-(--font-primary-muted)\"\n >({{ selectedCount() }})</span\n >\n }\n </checkbox>\n <span class=\"sr-only\" aria-live=\"polite\">{{\n \"filters.selectedCount\" | transloco: { count: selectedCount() }\n }}</span>\n </div>\n }\n\n <ng-content />\n\n @if (hasMore() && searchedItemsLength() === 0) {\n <!-- The placeholder rows of a loading page are not here: they are rows of the scrolling area, in the list and the tree\n (AggregationLoadMoreSkeleton). Here, between the list and the button, they would shorten the list. -->\n <!-- `variant=\"none\"`: galactik's ButtonComponent matches every <button> and would otherwise dress this one as a primary\n button (filled, rounded, 36px high). `none` leaves the classes below as the only style. -->\n <!-- `aria-disabled`, not `disabled`: the focus stays on the button while the page loads. The accessible name stays\n \"load more\" and `aria-busy` tells that it is working, so no extra text has to be translated by the application. -->\n <button\n type=\"button\"\n data-load-more=\"button\"\n variant=\"none\"\n class=\"mt-1 flex w-full shrink-0 cursor-pointer items-center justify-center rounded-(--radius-xs) px-2 py-1.5 text-(--font-primary-muted) underline underline-offset-4 hover:bg-(--bg-primary-lighter) hover:text-(--font-primary-base) focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-(--stroke-focus) focus-visible:outline-solid aria-busy:cursor-progress aria-busy:no-underline aria-busy:hover:bg-transparent\"\n [attr.aria-label]=\"'loadMore' | transloco\"\n [attr.aria-busy]=\"loading() ? 'true' : null\"\n [attr.aria-disabled]=\"loading() ? 'true' : null\"\n (click)=\"requestMore()\">\n <!-- Both states share one grid cell: the button keeps its width and height when the text gives way to the dots. -->\n <span class=\"inline-grid\">\n <span class=\"col-start-1 row-start-1\" [class.invisible]=\"loading()\">\n {{ \"loadMore\" | transloco }}\n </span>\n @if (loading()) {\n <loading-dots size=\"sm\" class=\"col-start-1 row-start-1\" />\n }\n </span>\n </button>\n }\n </div>\n</ng-template>\n\n@if (headless()) {\n <div class=\"flex min-h-0 flex-1 flex-col p-0.5\">\n <ng-container [ngTemplateOutlet]=\"bodySlot\" />\n </div>\n} @else {\n <details\n [attr.open]=\"expanded()\"\n [attr.name]=\"id()\"\n class=\"group flex min-h-0 flex-1 flex-col p-0.5 details-content:flex details-content:min-h-0 details-content:flex-col\"\n (toggle)=\"onToggle($event)\">\n <summary\n tabindex=\"-1\"\n [class.cursor-pointer]=\"collapsible() && !isEmpty()\"\n [class]=\"\n (isEmpty() ? 'text-(--font-neutral-muted) ' : '') + rowStateClass\n \"\n class=\"m-0 flex h-8 w-full shrink-0 scroll-mt-16 scroll-mb-3 items-center gap-1 pl-1 font-semibold select-none\"\n (click)=\"onHeaderClick($event)\">\n <ng-container [ngTemplateOutlet]=\"labelSlot\" />\n <ng-container [ngTemplateOutlet]=\"headerActionsSlot\" />\n </summary>\n <ng-container [ngTemplateOutlet]=\"bodySlot\" />\n </details>\n}\n",
|
|
27583
28650
|
styles: [":host{interpolate-size:allow-keywords}details::details-content{flex:1 1 auto;block-size:0;overflow:clip;overflow-clip-margin:.25rem;transition:block-size .2s cubic-bezier(.32,.72,0,1),content-visibility .2s allow-discrete}details[open]::details-content{block-size:auto}@media(prefers-reduced-motion:reduce){details::details-content{transition:none}}\n"]
|
|
27584
28651
|
}]
|
|
27585
28652
|
}],
|
|
@@ -30610,6 +31677,7 @@ function chipsForLeaf(leaf, source) {
|
|
|
30610
31677
|
}
|
|
30611
31678
|
var AppliedFiltersComponent = class AppliedFiltersComponent {
|
|
30612
31679
|
queryParamsStore = inject(QueryParamsStore);
|
|
31680
|
+
appStore = inject(AppStore);
|
|
30613
31681
|
static nextId = 0;
|
|
30614
31682
|
listId = `applied-filters-${AppliedFiltersComponent.nextId++}`;
|
|
30615
31683
|
list = viewChild("list", ...ngDevMode ? [{ debugName: "list" }] : /* istanbul ignore next */ []);
|
|
@@ -30630,6 +31698,10 @@ var AppliedFiltersComponent = class AppliedFiltersComponent {
|
|
|
30630
31698
|
...ngDevMode ? { debugName: "showField" } : /* istanbul ignore next */ {},
|
|
30631
31699
|
transform: booleanAttribute
|
|
30632
31700
|
});
|
|
31701
|
+
fieldIcon = input(true, {
|
|
31702
|
+
...ngDevMode ? { debugName: "fieldIcon" } : /* istanbul ignore next */ {},
|
|
31703
|
+
transform: booleanAttribute
|
|
31704
|
+
});
|
|
30633
31705
|
variant = input(void 0, ...ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []);
|
|
30634
31706
|
scheme = input("grey", ...ngDevMode ? [{ debugName: "scheme" }] : /* istanbul ignore next */ []);
|
|
30635
31707
|
size = input("sm", ...ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []);
|
|
@@ -30691,7 +31763,15 @@ var AppliedFiltersComponent = class AppliedFiltersComponent {
|
|
|
30691
31763
|
items.forEach((item) => item.inert = !this.expanded() && item.offsetTop - origin >= folded);
|
|
30692
31764
|
}
|
|
30693
31765
|
chips = computed(() => {
|
|
30694
|
-
return (this.filters() ?? this.queryParamsStore.filters()).flatMap((source) => filterLeaves(source).flatMap((leaf) =>
|
|
31766
|
+
return (this.filters() ?? this.queryParamsStore.filters()).flatMap((source) => filterLeaves(source).flatMap((leaf) => {
|
|
31767
|
+
const chips = chipsForLeaf(leaf, source);
|
|
31768
|
+
const column = chips[0]?.field;
|
|
31769
|
+
const icon = column ? this.appStore.getAggregationCustomization?.(column, chips[0].name)?.icon : void 0;
|
|
31770
|
+
return icon ? chips.map((chip) => ({
|
|
31771
|
+
...chip,
|
|
31772
|
+
icon
|
|
31773
|
+
})) : chips;
|
|
31774
|
+
}));
|
|
30695
31775
|
}, ...ngDevMode ? [{ debugName: "chips" }] : /* istanbul ignore next */ []);
|
|
30696
31776
|
remove(chip) {
|
|
30697
31777
|
const rebuilt = rebuildWithout(chip.source, chip);
|
|
@@ -30758,6 +31838,13 @@ var AppliedFiltersComponent = class AppliedFiltersComponent {
|
|
|
30758
31838
|
isRequired: false,
|
|
30759
31839
|
transformFunction: null
|
|
30760
31840
|
},
|
|
31841
|
+
fieldIcon: {
|
|
31842
|
+
classPropertyName: "fieldIcon",
|
|
31843
|
+
publicName: "fieldIcon",
|
|
31844
|
+
isSignal: true,
|
|
31845
|
+
isRequired: false,
|
|
31846
|
+
transformFunction: null
|
|
31847
|
+
},
|
|
30761
31848
|
variant: {
|
|
30762
31849
|
classPropertyName: "variant",
|
|
30763
31850
|
publicName: "variant",
|
|
@@ -30841,7 +31928,15 @@ var AppliedFiltersComponent = class AppliedFiltersComponent {
|
|
|
30841
31928
|
[class]="'max-w-full items-center gap-1 ' + chipClass()"
|
|
30842
31929
|
>
|
|
30843
31930
|
@if (showField()) {
|
|
30844
|
-
|
|
31931
|
+
@if (fieldIcon() && chip.icon) {
|
|
31932
|
+
<!-- The icon stands for the name: the name stays available as a tooltip and to screen readers. -->
|
|
31933
|
+
<span class="inline-flex shrink-0" [title]="(chip.name ?? chip.field) | syslang">
|
|
31934
|
+
<fa-icon [faClass]="chip.icon" />
|
|
31935
|
+
<span class="sr-only">{{ (chip.name ?? chip.field) | syslang }}:</span>
|
|
31936
|
+
</span>
|
|
31937
|
+
} @else {
|
|
31938
|
+
<span>{{ (chip.name ?? chip.field) | syslang }}:</span>
|
|
31939
|
+
}
|
|
30845
31940
|
}
|
|
30846
31941
|
<span class="truncate">{{ chip.display | syslang }}</span>
|
|
30847
31942
|
<button
|
|
@@ -30885,6 +31980,12 @@ var AppliedFiltersComponent = class AppliedFiltersComponent {
|
|
|
30885
31980
|
`,
|
|
30886
31981
|
isInline: true,
|
|
30887
31982
|
dependencies: [
|
|
31983
|
+
{
|
|
31984
|
+
kind: "component",
|
|
31985
|
+
type: FaIconComponent,
|
|
31986
|
+
selector: "fa-icon, FaIcon",
|
|
31987
|
+
inputs: ["faClass", "class"]
|
|
31988
|
+
},
|
|
30888
31989
|
{
|
|
30889
31990
|
kind: "directive",
|
|
30890
31991
|
type: TagComponent,
|
|
@@ -30941,6 +32042,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
30941
32042
|
imports: [
|
|
30942
32043
|
TranslocoPipe,
|
|
30943
32044
|
SyslangPipe,
|
|
32045
|
+
FaIconComponent,
|
|
30944
32046
|
TagComponent,
|
|
30945
32047
|
ButtonComponent,
|
|
30946
32048
|
XMarkIcon
|
|
@@ -30970,7 +32072,15 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
30970
32072
|
[class]="'max-w-full items-center gap-1 ' + chipClass()"
|
|
30971
32073
|
>
|
|
30972
32074
|
@if (showField()) {
|
|
30973
|
-
|
|
32075
|
+
@if (fieldIcon() && chip.icon) {
|
|
32076
|
+
<!-- The icon stands for the name: the name stays available as a tooltip and to screen readers. -->
|
|
32077
|
+
<span class="inline-flex shrink-0" [title]="(chip.name ?? chip.field) | syslang">
|
|
32078
|
+
<fa-icon [faClass]="chip.icon" />
|
|
32079
|
+
<span class="sr-only">{{ (chip.name ?? chip.field) | syslang }}:</span>
|
|
32080
|
+
</span>
|
|
32081
|
+
} @else {
|
|
32082
|
+
<span>{{ (chip.name ?? chip.field) | syslang }}:</span>
|
|
32083
|
+
}
|
|
30974
32084
|
}
|
|
30975
32085
|
<span class="truncate">{{ chip.display | syslang }}</span>
|
|
30976
32086
|
<button
|
|
@@ -31045,6 +32155,14 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
31045
32155
|
required: false
|
|
31046
32156
|
}]
|
|
31047
32157
|
}],
|
|
32158
|
+
fieldIcon: [{
|
|
32159
|
+
type: i0.Input,
|
|
32160
|
+
args: [{
|
|
32161
|
+
isSignal: true,
|
|
32162
|
+
alias: "fieldIcon",
|
|
32163
|
+
required: false
|
|
32164
|
+
}]
|
|
32165
|
+
}],
|
|
31048
32166
|
variant: [{
|
|
31049
32167
|
type: i0.Input,
|
|
31050
32168
|
args: [{
|
|
@@ -33808,10 +34926,10 @@ var FiltersBarComponent = class FiltersBarComponent {
|
|
|
33808
34926
|
height announced as "Filter controls". Every button in it is a native tab stop (no roving, no arrow keys). -->
|
|
33809
34927
|
<!-- Something of the host's own (a quick-filters pill, say) leads the bar. It sits beside the group and
|
|
33810
34928
|
not inside it, and it stays visible when the group below is not rendered. -->
|
|
33811
|
-
<div [class]="cn('flex min-w-0 items-center rounded-[inherit] bg-inherit', pillGap(), align() === 'center' && 'justify-center')">
|
|
34929
|
+
<div #filtersRow [class]="cn('flex min-w-0 items-center rounded-[inherit] bg-inherit', pillGap(), align() === 'center' && 'justify-center')">
|
|
33812
34930
|
<ng-content select="[filtersBarStart]" />
|
|
33813
34931
|
@if (hasContent()) {
|
|
33814
|
-
<div role="group" [attr.aria-label]="ariaLabel() ?? ('filters.filterControls' | transloco)" overflowManager [direction]="direction()" [reserveStop]="hasCappedFilters()" (count)="adjustFiltersCount($event)" [class]="cn('flex min-w-0 items-center rounded-[inherit] bg-inherit', pillGap(), align() === 'center' ? 'flex-initial' : 'flex-1')">
|
|
34932
|
+
<div role="group" [attr.aria-label]="ariaLabel() ?? ('filters.filterControls' | transloco)" overflowManager [direction]="direction()" [fitMargin]="-0.5" animate [target]="align() === 'center' ? filtersRow : undefined" [reserveStop]="hasCappedFilters()" (count)="adjustFiltersCount($event)" [class]="cn('relative flex min-w-0 items-center rounded-[inherit] bg-inherit', pillGap(), align() === 'center' ? 'flex-initial' : 'flex-1')">
|
|
33815
34933
|
@if (hasFilters() && showClearButtons()) {
|
|
33816
34934
|
<button
|
|
33817
34935
|
[attr.aria-label]="'filters.clearAllFilters' | transloco"
|
|
@@ -33862,7 +34980,10 @@ var FiltersBarComponent = class FiltersBarComponent {
|
|
|
33862
34980
|
}
|
|
33863
34981
|
</div>
|
|
33864
34982
|
|
|
33865
|
-
<!-- Always mounted so the
|
|
34983
|
+
<!-- Always mounted so the overflow manager can read its size; when all filters fit it is invisible AND out of
|
|
34984
|
+
the flow (absolute), otherwise its reserved width pushes the list aside and an align="center" bar
|
|
34985
|
+
ends up off-center. -->
|
|
34986
|
+
|
|
33866
34987
|
@if (showMoreFiltersButton()) {
|
|
33867
34988
|
<!-- No aria-label here: the host is a custom element with no role of its own, where ARIA
|
|
33868
34989
|
forbids the attribute. The name belongs to the <button> inside MoreButton, which
|
|
@@ -33870,7 +34991,7 @@ var FiltersBarComponent = class FiltersBarComponent {
|
|
|
33870
34991
|
<MoreButton
|
|
33871
34992
|
overflowStop
|
|
33872
34993
|
[disabled]="hasMoreFilters().length === 0"
|
|
33873
|
-
[class]="cn('shrink-0', hasMoreFilters().length === 0 && 'invisible pointer-events-none')"
|
|
34994
|
+
[class]="cn('shrink-0', hasMoreFilters().length === 0 && 'invisible pointer-events-none absolute top-0 left-0')"
|
|
33874
34995
|
[count]="visibleFiltersCount()"
|
|
33875
34996
|
[position]="morePosition()"
|
|
33876
34997
|
[lockPosition]="lockPosition()"
|
|
@@ -33947,8 +35068,10 @@ var FiltersBarComponent = class FiltersBarComponent {
|
|
|
33947
35068
|
inputs: [
|
|
33948
35069
|
"target",
|
|
33949
35070
|
"margin",
|
|
35071
|
+
"fitMargin",
|
|
33950
35072
|
"direction",
|
|
33951
|
-
"reserveStop"
|
|
35073
|
+
"reserveStop",
|
|
35074
|
+
"animate"
|
|
33952
35075
|
],
|
|
33953
35076
|
outputs: ["count"]
|
|
33954
35077
|
},
|
|
@@ -34008,10 +35131,10 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
34008
35131
|
height announced as "Filter controls". Every button in it is a native tab stop (no roving, no arrow keys). -->
|
|
34009
35132
|
<!-- Something of the host's own (a quick-filters pill, say) leads the bar. It sits beside the group and
|
|
34010
35133
|
not inside it, and it stays visible when the group below is not rendered. -->
|
|
34011
|
-
<div [class]="cn('flex min-w-0 items-center rounded-[inherit] bg-inherit', pillGap(), align() === 'center' && 'justify-center')">
|
|
35134
|
+
<div #filtersRow [class]="cn('flex min-w-0 items-center rounded-[inherit] bg-inherit', pillGap(), align() === 'center' && 'justify-center')">
|
|
34012
35135
|
<ng-content select="[filtersBarStart]" />
|
|
34013
35136
|
@if (hasContent()) {
|
|
34014
|
-
<div role="group" [attr.aria-label]="ariaLabel() ?? ('filters.filterControls' | transloco)" overflowManager [direction]="direction()" [reserveStop]="hasCappedFilters()" (count)="adjustFiltersCount($event)" [class]="cn('flex min-w-0 items-center rounded-[inherit] bg-inherit', pillGap(), align() === 'center' ? 'flex-initial' : 'flex-1')">
|
|
35137
|
+
<div role="group" [attr.aria-label]="ariaLabel() ?? ('filters.filterControls' | transloco)" overflowManager [direction]="direction()" [fitMargin]="-0.5" animate [target]="align() === 'center' ? filtersRow : undefined" [reserveStop]="hasCappedFilters()" (count)="adjustFiltersCount($event)" [class]="cn('relative flex min-w-0 items-center rounded-[inherit] bg-inherit', pillGap(), align() === 'center' ? 'flex-initial' : 'flex-1')">
|
|
34015
35138
|
@if (hasFilters() && showClearButtons()) {
|
|
34016
35139
|
<button
|
|
34017
35140
|
[attr.aria-label]="'filters.clearAllFilters' | transloco"
|
|
@@ -34062,7 +35185,10 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
34062
35185
|
}
|
|
34063
35186
|
</div>
|
|
34064
35187
|
|
|
34065
|
-
<!-- Always mounted so the
|
|
35188
|
+
<!-- Always mounted so the overflow manager can read its size; when all filters fit it is invisible AND out of
|
|
35189
|
+
the flow (absolute), otherwise its reserved width pushes the list aside and an align="center" bar
|
|
35190
|
+
ends up off-center. -->
|
|
35191
|
+
|
|
34066
35192
|
@if (showMoreFiltersButton()) {
|
|
34067
35193
|
<!-- No aria-label here: the host is a custom element with no role of its own, where ARIA
|
|
34068
35194
|
forbids the attribute. The name belongs to the <button> inside MoreButton, which
|
|
@@ -34070,7 +35196,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
34070
35196
|
<MoreButton
|
|
34071
35197
|
overflowStop
|
|
34072
35198
|
[disabled]="hasMoreFilters().length === 0"
|
|
34073
|
-
[class]="cn('shrink-0', hasMoreFilters().length === 0 && 'invisible pointer-events-none')"
|
|
35199
|
+
[class]="cn('shrink-0', hasMoreFilters().length === 0 && 'invisible pointer-events-none absolute top-0 left-0')"
|
|
34074
35200
|
[count]="visibleFiltersCount()"
|
|
34075
35201
|
[position]="morePosition()"
|
|
34076
35202
|
[lockPosition]="lockPosition()"
|
|
@@ -41746,6 +42872,6 @@ function provideSessionExpiry(options = {}) {
|
|
|
41746
42872
|
const queryNameResolver = () => {
|
|
41747
42873
|
return inject(AppStore).getDefaultQuery()?.name || "";
|
|
41748
42874
|
};
|
|
41749
|
-
export { AGGREGATIONS_NAMES, AGGREGATIONS_NAMES_PRESET_DEFAULT, APP_FEATURES, ATOMIC_CLIENT, ATOMIC_SCOPED_PROVIDERS, AddToCollection, AdvancedFiltersBodyComponent, AdvancedFiltersComponent, AdvancedSearch, AdvancedSearchTabs, AggregationComponent, AggregationDateComponent, AggregationDateRange, AggregationItemDirective, AggregationListComponent, AggregationPanelComponent, AggregationTreeComponent, AggregationsService, AggregationsStore, Alert, AlertDialog, AlertForm, AlertFormComponent, AlertsComponent, AppService, AppStore, ApplicationService, ApplicationStore, AppliedFiltersComponent, ArticleEntities, ArticleEntitiesTabPanel, ArticleExtracts, ArticleExtractsTabPanel, ArticleHighlights, ArticleLabels, ArticleLabelsTabPanel, ArticleMatchLocations, ArticleMatchLocationsTabPanel, ArticleSimilarDocuments, ArticleSimilarDocumentsTabPanel, AsideFiltersComponent, AuditFeedbackType, AuditService, AuthGuard, AuthPageComponent, AutocompleteService, BOOKMARKS_CONFIG, BOOKMARKS_OPTIONS, BackdropComponent, BackdropService, BookmarkButtonComponent, BookmarksComponent, COLLECTIONS_CONFIG, COLLECTIONS_OPTIONS, COMPONENTS_FOR_DOCUMENT_TYPE, ChangePasswordComponent, ChildMarkerDirective, CollectionsComponent, CollectionsDialog, ConverterSelectComponent, DeleteCollection, DeleteCollectionDialog, DidYouMeanComponent, DocumentLocatorComponent, EditLabels, EntityNavigationService, ErrorComponent, Export, ExportDialog, ExportService, FILTERS_BREAKPOINT, FILTER_DATE_ALLOW_CUSTOM_RANGE, FORM_ALERT_CLASS, FORM_BARE_CLASS, FORM_ERROR_CLASS, FORM_FIELD_CLASS, FORM_FOOTER_CLASS, FORM_LABEL_CLASS, FORM_SURFACE_CLASS, FaIconComponent, FeatureFlags, FeatureFlagsDialogComponent, Feedback, FeedbackDialogComponent, FileSizePipe, FilterButtonComponent, FiltersBarComponent, FiltersPanelComponent, FloatingToolbarComponent, ForgotPasswordComponent, HIGHLIGHTS, HeatmapComponent, HighlightWordPipe, HistoryPanelComponent, HistoryTitleMarqueeDirective, InfinityScrollDirective, InlineWorker, JsonMethodPluginService, KeyboardShortcutsDialog, KeyboardShortcutsDialogComponent, KeyboardShortcutsListComponent, KeyboardShortcutsService, LabelService, LabelsEditDialog, ListPanelItemDirective, LoadingComponent, LoadingDotsComponent, LocalizedNumberPipe, MarkdownPipe, MarkdownRendererService, MetadataComponent, MissingTermsComponent, MoreButtonComponent, MoreComponent, MultiSelectLabelsComponent, MultiSelectionToolbarComponent, NON_SEARCHABLE_COLUMNS, NON_SEARCHABLE_DEFAULTS, NavbarTabsComponent, NavigationService, NoResultComponent, OVERFLOW_ACTIONS_CONFIG, OpenArticleOnCtrlEnterDirective, OperatorPipe, OverflowActionsComponent, OverflowItemDirective, OverflowManagerDirective, OverflowStopDirective, OverrideUser, OverrideUserDialogComponent, PREVIEW_ASSISTANT_COMPONENT, PREVIEW_CONFIG, PagerComponent, PreviewActionsComponent, PreviewContentComponent, PreviewFindPanelComponent, PreviewHeaderComponent, PreviewNavigator, PreviewService, PrincipalService, PrincipalStore, QueryParamsStore, QueryService, QuickFiltersComponent, QuickFiltersListComponent, RECENT_SEARCHES_CONFIG, RECENT_SEARCHES_OPTIONS, ROUTE_COMPONENTS, RecentSearchesComponent, ResetUserSettings, ResetUserSettingsDialogComponent, SAVED_SEARCHES_CONFIG, SAVED_SEARCHES_OPTIONS, SEARCH_BOX_CATEGORIES_SORT, SEARCH_BOX_CATEGORY_ICONS, STARTUP_DATA_SOURCE, SavedSearch, SavedSearchDialog, SavedSearchPopover, SavedSearchesComponent, SavedSearchesService, SearchBoxComponent, SearchBoxPopupDirective, SearchFeedbackComponent, SearchInputFooter, SearchService, SelectArticleDirective, SelectionService, SelectionStore, Settings, SettingsAccountPanelComponent, SettingsAlertsPanelComponent, SettingsAppearancePanelComponent, SettingsDialogComponent, SettingsShortcutsPanelComponent, ShortcutDirective, ShowBookmarkDirective, SignInComponent, SignedOutComponent, SortSelectorComponent, SourceComponent, SourceIconPipe, SponsoredResultsComponent, SyslangPipe, THEMES, TagCloudComponent, TextChunkService, ThemeProviderDirective, ThemeSelectorComponent, ThemeStore, ThemeToggleComponent, TranslocoDateImpurePipe, UserOverrideService, UserProfileFormComponent, UserProfileService, UserSettingsPersistence, UserSettingsStore, WEIGHT_STEPS, WordCloudComponent, ZoomControlsComponent, __resetSignInMutexForTests, activateShortcutTarget, applyThemeToNativeElement, atomicClientProvider, auditInterceptorFn, authInterceptorFn, bodyInterceptorFn, bootstrapApp, buildHeatmap, buildQuery, buildTagCloud, candidatesFor, canonicalize, debouncedSignal, errorInterceptorFn, fieldErrorKey, fieldShowsError, filterKey, filterLeaves, filterValues, findAggregation, flagsFromWeekdays, focusWhenReady, galactikPrimitive, galactikSemantic, getCurrentPath, getCurrentQueryName, getQueryNameFromRoute, groupSearchesByDate, injectAdvancedFilters, injectAtomicClient, injectRouteNavigation, injectUserSettingsPatch, isAuthRoute, isSignInInFlight, itemLabel, layoutWordCloud, legacyFilterToFilter, makeWeightScale, multiSelectionToolbarVariants, pageNumberFromAnchor, paletteColor, processCssVars, provideAtomicClient, provideAtomicNotifications, provideAtomicScope, provideDocumentLang, provideKeyboardShortcuts, provideSessionExpiry, provideStartupAggregation, quantileScale, queryNameResolver, rebuildWithout, searchItemKey, seriesPalette, signIn, themeColorNameToCssVariable, themeColorsToCssVariables, timelinePalette, toAriaKeyshortcuts, toDisplayParts, toPercentages, toSeries, toastInterceptorFn, weekdaysFromFlags, withAggregationsFeatures, withAlertsFeatures, withAlpha, withAppFeatures, withApplicationFeatures, withAssistantFeatures, withBasketsFeatures, withBookmarkFeatures, withBootstrapApp, withExtractsFeatures, withFavoriteSearchesFeatures, withFetch, withMultiSelectionFeatures, withQueryParamsFeatures, withQuickFiltersFeatures, withRecentSearchesFeatures, withSavedSearchesFeatures, withSelectionFeatures, withThemeBodyHook, withThemes, withThemesFeatures, withUserSettingsFeatures };
|
|
42875
|
+
export { AGGREGATIONS_NAMES, AGGREGATIONS_NAMES_PRESET_DEFAULT, APP_FEATURES, ATOMIC_CLIENT, ATOMIC_SCOPED_PROVIDERS, AddToCollection, AddToCollectionPanelComponent, AdvancedFiltersBodyComponent, AdvancedFiltersComponent, AdvancedSearch, AdvancedSearchTabs, AggregationComponent, AggregationDateComponent, AggregationDateRange, AggregationItemDirective, AggregationListComponent, AggregationPanelComponent, AggregationTreeComponent, AggregationsService, AggregationsStore, Alert, AlertDialog, AlertForm, AlertFormComponent, AlertsComponent, AppService, AppStore, ApplicationService, ApplicationStore, AppliedFiltersComponent, ArticleEntities, ArticleEntitiesTabPanel, ArticleExtracts, ArticleExtractsTabPanel, ArticleHighlights, ArticleLabels, ArticleLabelsTabPanel, ArticleMatchLocations, ArticleMatchLocationsTabPanel, ArticleSimilarDocuments, ArticleSimilarDocumentsTabPanel, AsideFiltersComponent, AuditFeedbackType, AuditService, AuthGuard, AuthPageComponent, AutocompleteService, BOOKMARKS_CONFIG, BOOKMARKS_OPTIONS, BackdropComponent, BackdropService, BookmarkButtonComponent, BookmarksComponent, COLLECTIONS_CONFIG, COLLECTIONS_OPTIONS, COMPONENTS_FOR_DOCUMENT_TYPE, ChangePasswordComponent, ChildMarkerDirective, CollectionsComponent, CollectionsDialog, ConverterSelectComponent, DeleteCollection, DeleteCollectionDialog, DidYouMeanComponent, DocumentLocatorComponent, EditLabels, EntityNavigationService, ErrorComponent, Export, ExportDialog, ExportService, FILTERS_BREAKPOINT, FILTER_DATE_ALLOW_CUSTOM_RANGE, FORM_ALERT_CLASS, FORM_BARE_CLASS, FORM_ERROR_CLASS, FORM_FIELD_CLASS, FORM_FOOTER_CLASS, FORM_LABEL_CLASS, FORM_SURFACE_CLASS, FaIconComponent, FeatureFlags, FeatureFlagsDialogComponent, Feedback, FeedbackDialogComponent, FileSizePipe, FilterButtonComponent, FiltersBarComponent, FiltersPanelComponent, FloatingToolbarComponent, ForgotPasswordComponent, HIGHLIGHTS, HeatmapComponent, HighlightWordPipe, HistoryPanelComponent, HistoryTitleMarqueeDirective, InfinityScrollDirective, InlineWorker, JsonMethodPluginService, KeyboardShortcutsDialog, KeyboardShortcutsDialogComponent, KeyboardShortcutsListComponent, KeyboardShortcutsService, LabelService, LabelsEditDialog, ListPanelItemDirective, LoadingComponent, LoadingDotsComponent, LocalizedNumberPipe, MarkdownPipe, MarkdownRendererService, MetadataComponent, MissingTermsComponent, MoreButtonComponent, MoreComponent, MultiSelectLabelsComponent, MultiSelectionToolbarComponent, NON_SEARCHABLE_COLUMNS, NON_SEARCHABLE_DEFAULTS, NavbarTabsComponent, NavigationService, NoResultComponent, OVERFLOW_ACTIONS_CONFIG, OpenArticleOnCtrlEnterDirective, OperatorPipe, OverflowActionsComponent, OverflowItemDirective, OverflowManagerDirective, OverflowStopDirective, OverrideUser, OverrideUserDialogComponent, PREVIEW_ASSISTANT_COMPONENT, PREVIEW_CONFIG, PagerComponent, PreviewActionsComponent, PreviewContentComponent, PreviewFindPanelComponent, PreviewHeaderComponent, PreviewNavigator, PreviewService, PrincipalService, PrincipalStore, QueryParamsStore, QueryService, QuickFiltersComponent, QuickFiltersListComponent, RECENT_SEARCHES_CONFIG, RECENT_SEARCHES_OPTIONS, ROUTE_COMPONENTS, RecentSearchesComponent, ResetUserSettings, ResetUserSettingsDialogComponent, SAVED_SEARCHES_CONFIG, SAVED_SEARCHES_OPTIONS, SEARCH_BOX_CATEGORIES_SORT, SEARCH_BOX_CATEGORY_ICONS, STARTUP_DATA_SOURCE, SavedSearch, SavedSearchDialog, SavedSearchPopover, SavedSearchesComponent, SavedSearchesService, SearchBoxComponent, SearchBoxPopupDirective, SearchFeedbackComponent, SearchInputFooter, SearchService, SelectArticleDirective, SelectionService, SelectionStore, Settings, SettingsAccountPanelComponent, SettingsAlertsPanelComponent, SettingsAppearancePanelComponent, SettingsDialogComponent, SettingsShortcutsPanelComponent, ShortcutDirective, ShowBookmarkDirective, SignInComponent, SignedOutComponent, SortSelectorComponent, SourceComponent, SourceIconPipe, SponsoredResultsComponent, SyslangPipe, THEMES, TagCloudComponent, TextChunkService, ThemeProviderDirective, ThemeSelectorComponent, ThemeStore, ThemeToggleComponent, TranslocoDateImpurePipe, UserOverrideService, UserProfileFormComponent, UserProfileService, UserSettingsPersistence, UserSettingsStore, WEIGHT_STEPS, WordCloudComponent, ZoomControlsComponent, __resetSignInMutexForTests, activateShortcutTarget, applyThemeToNativeElement, atomicClientProvider, auditInterceptorFn, authInterceptorFn, bodyInterceptorFn, bootstrapApp, buildHeatmap, buildQuery, buildTagCloud, candidatesFor, canonicalize, debouncedSignal, errorInterceptorFn, fieldErrorKey, fieldShowsError, filterKey, filterLeaves, filterValues, findAggregation, flagsFromWeekdays, focusWhenReady, galactikPrimitive, galactikSemantic, getCurrentPath, getCurrentQueryName, getQueryNameFromRoute, groupSearchesByDate, injectAdvancedFilters, injectAtomicClient, injectRouteNavigation, injectUserSettingsPatch, isAuthRoute, isSignInInFlight, itemLabel, layoutWordCloud, legacyFilterToFilter, makeWeightScale, multiSelectionToolbarVariants, pageNumberFromAnchor, paletteColor, processCssVars, provideAtomicClient, provideAtomicNotifications, provideAtomicScope, provideDocumentLang, provideKeyboardShortcuts, provideSessionExpiry, provideStartupAggregation, quantileScale, queryNameResolver, rebuildWithout, searchItemKey, seriesPalette, signIn, themeColorNameToCssVariable, themeColorsToCssVariables, timelinePalette, toAriaKeyshortcuts, toDisplayParts, toPercentages, toSeries, toastInterceptorFn, weekdaysFromFlags, withAggregationsFeatures, withAlertsFeatures, withAlpha, withAppFeatures, withApplicationFeatures, withAssistantFeatures, withBasketsFeatures, withBookmarkFeatures, withBootstrapApp, withExtractsFeatures, withFavoriteSearchesFeatures, withFetch, withMultiSelectionFeatures, withQueryParamsFeatures, withQuickFiltersFeatures, withRecentSearchesFeatures, withSavedSearchesFeatures, withSelectionFeatures, withThemeBodyHook, withThemes, withThemesFeatures, withUserSettingsFeatures };
|
|
41750
42876
|
|
|
41751
42877
|
//# sourceMappingURL=sinequa-atomic-angular.mjs.map
|