@sinequa/atomic-angular 2.5.0 → 2.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/sinequa-atomic-angular.mjs +434 -156
- package/fesm2022/sinequa-atomic-angular.mjs.map +1 -1
- package/package.json +1 -1
- package/providers/session-expiry/i18n/de.json +4 -2
- package/providers/session-expiry/i18n/en.json +4 -2
- package/providers/session-expiry/i18n/fr.json +4 -2
- package/types/sinequa-atomic-angular-document-workspaces.d.ts +1 -1
- package/types/sinequa-atomic-angular.d.ts +292 -39
|
@@ -214,47 +214,55 @@ function withAppFeatures() {
|
|
|
214
214
|
data: {}
|
|
215
215
|
}), withMethods((store) => {
|
|
216
216
|
const client = inject(ATOMIC_CLIENT);
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
Object.
|
|
229
|
-
|
|
217
|
+
const hydrate = (app) => {
|
|
218
|
+
patchState(store, app);
|
|
219
|
+
const columnMap = {};
|
|
220
|
+
Object.values(extraColumns).forEach((col) => {
|
|
221
|
+
columnMap[col.name.toLocaleLowerCase()] = col;
|
|
222
|
+
if (col.aliases) col.aliases.forEach((alias) => {
|
|
223
|
+
columnMap[alias.toLocaleLowerCase()] = col;
|
|
224
|
+
});
|
|
225
|
+
});
|
|
226
|
+
const schema = app.indexes._?.columns;
|
|
227
|
+
if (schema) {
|
|
228
|
+
Object.keys(schema).forEach((schemaKey) => {
|
|
229
|
+
const col = schema[schemaKey.toLocaleLowerCase()];
|
|
230
|
+
if (!col) return;
|
|
231
|
+
columnMap[schemaKey.toLocaleLowerCase()] = col;
|
|
230
232
|
if (col.aliases) col.aliases.forEach((alias) => {
|
|
231
233
|
columnMap[alias.toLocaleLowerCase()] = col;
|
|
232
234
|
});
|
|
233
235
|
});
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
Object.
|
|
237
|
-
const col = schema[
|
|
236
|
+
Object.keys(app.queries).forEach((queryKey) => {
|
|
237
|
+
const query = app.queries[queryKey];
|
|
238
|
+
if (query.columnsInfo?.columns) Object.values(query.columnsInfo.columns).forEach((c) => {
|
|
239
|
+
const col = schema[c.name.toLocaleLowerCase()];
|
|
238
240
|
if (!col) return;
|
|
239
|
-
columnMap[
|
|
240
|
-
if (
|
|
241
|
+
columnMap[c.name.toLocaleLowerCase()] = col;
|
|
242
|
+
if (c.aliases) c.aliases.split(/[,;|]/).map((a) => a.trim()).forEach((alias) => {
|
|
241
243
|
columnMap[alias.toLocaleLowerCase()] = col;
|
|
242
244
|
});
|
|
243
245
|
});
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
246
|
+
});
|
|
247
|
+
patchState(store, { columnMap });
|
|
248
|
+
}
|
|
249
|
+
};
|
|
250
|
+
const fail = (error) => {
|
|
251
|
+
console.error("Error fetching app data:", error);
|
|
252
|
+
throw error;
|
|
253
|
+
};
|
|
254
|
+
return {
|
|
255
|
+
async initialize() {
|
|
256
|
+
let app;
|
|
257
|
+
try {
|
|
258
|
+
app = await client.api.app.get();
|
|
259
|
+
} catch (error) {
|
|
260
|
+
return fail(error);
|
|
256
261
|
}
|
|
262
|
+
hydrate(app);
|
|
257
263
|
},
|
|
264
|
+
hydrate,
|
|
265
|
+
fail,
|
|
258
266
|
async initializeWithAppName(appName) {
|
|
259
267
|
const app = await client.api.app.get(appName);
|
|
260
268
|
patchState(store, app);
|
|
@@ -500,7 +508,23 @@ const PrincipalStore = signalStore({ providedIn: "root" }, withDevtools("Princip
|
|
|
500
508
|
})), withMethods((store) => {
|
|
501
509
|
const client = inject(ATOMIC_CLIENT);
|
|
502
510
|
let pendingInitialization = null;
|
|
511
|
+
const hydrate = (principal) => {
|
|
512
|
+
const { userOverrideActive = false } = client.config;
|
|
513
|
+
patchState(store, {
|
|
514
|
+
...initialPrincipal,
|
|
515
|
+
...principal,
|
|
516
|
+
userOverrideActive,
|
|
517
|
+
state: "loaded"
|
|
518
|
+
});
|
|
519
|
+
};
|
|
520
|
+
const fail = (error) => {
|
|
521
|
+
console.error("Principal fetch failed", error);
|
|
522
|
+
patchState(store, { state: "error" });
|
|
523
|
+
throw error;
|
|
524
|
+
};
|
|
503
525
|
return {
|
|
526
|
+
hydrate,
|
|
527
|
+
fail,
|
|
504
528
|
principal() {
|
|
505
529
|
const { userOverrideActive: _, ...rest } = getState(store);
|
|
506
530
|
return Object.entries(rest).reduce((acc, [k, v]) => {
|
|
@@ -513,18 +537,9 @@ const PrincipalStore = signalStore({ providedIn: "root" }, withDevtools("Princip
|
|
|
513
537
|
pendingInitialization = (async () => {
|
|
514
538
|
patchState(store, { state: "loading" });
|
|
515
539
|
try {
|
|
516
|
-
|
|
517
|
-
const { userOverrideActive = false } = client.config;
|
|
518
|
-
patchState(store, {
|
|
519
|
-
...initialPrincipal,
|
|
520
|
-
...principal,
|
|
521
|
-
userOverrideActive,
|
|
522
|
-
state: "loaded"
|
|
523
|
-
});
|
|
540
|
+
hydrate(await client.api.principal.get());
|
|
524
541
|
} catch (error) {
|
|
525
|
-
|
|
526
|
-
patchState(store, { state: "error" });
|
|
527
|
-
throw error;
|
|
542
|
+
fail(error);
|
|
528
543
|
} finally {
|
|
529
544
|
pendingInitialization = null;
|
|
530
545
|
}
|
|
@@ -1256,6 +1271,16 @@ function AuthGuard() {
|
|
|
1256
1271
|
return true;
|
|
1257
1272
|
};
|
|
1258
1273
|
}
|
|
1274
|
+
const STARTUP_DATA_SOURCE = new InjectionToken("STARTUP_DATA_SOURCE", { factory: () => null });
|
|
1275
|
+
function provideStartupAggregation(endpoint = "bff/bootstrap") {
|
|
1276
|
+
return makeEnvironmentProviders([{
|
|
1277
|
+
provide: STARTUP_DATA_SOURCE,
|
|
1278
|
+
useFactory: () => {
|
|
1279
|
+
const client = inject(ATOMIC_CLIENT);
|
|
1280
|
+
return () => client.http.get(endpoint);
|
|
1281
|
+
}
|
|
1282
|
+
}]);
|
|
1283
|
+
}
|
|
1259
1284
|
var UserSettingsPersistence = class UserSettingsPersistence {
|
|
1260
1285
|
loaded = signal(false, ...ngDevMode ? [{ debugName: "loaded" }] : /* istanbul ignore next */ []);
|
|
1261
1286
|
isLoaded = this.loaded.asReadonly();
|
|
@@ -1735,18 +1760,25 @@ function withUserSettingsFeatures() {
|
|
|
1735
1760
|
}), withMethods((store) => {
|
|
1736
1761
|
const client = inject(ATOMIC_CLIENT);
|
|
1737
1762
|
const persistence = inject(UserSettingsPersistence);
|
|
1763
|
+
const hydrate = (settings) => {
|
|
1764
|
+
patchState(store, {
|
|
1765
|
+
...USER_SETTINGS_DEFAULTS,
|
|
1766
|
+
...settings
|
|
1767
|
+
});
|
|
1768
|
+
persistence.markLoaded();
|
|
1769
|
+
};
|
|
1770
|
+
const fail = (err) => {
|
|
1771
|
+
error("Error fetching user settings:", err);
|
|
1772
|
+
persistence.markUnloaded();
|
|
1773
|
+
};
|
|
1738
1774
|
return {
|
|
1775
|
+
hydrate,
|
|
1776
|
+
fail,
|
|
1739
1777
|
async initialize() {
|
|
1740
1778
|
try {
|
|
1741
|
-
|
|
1742
|
-
patchState(store, {
|
|
1743
|
-
...USER_SETTINGS_DEFAULTS,
|
|
1744
|
-
...settings
|
|
1745
|
-
});
|
|
1746
|
-
persistence.markLoaded();
|
|
1779
|
+
hydrate(await client.api.userSettings.get());
|
|
1747
1780
|
} catch (err) {
|
|
1748
|
-
|
|
1749
|
-
persistence.markUnloaded();
|
|
1781
|
+
fail(err);
|
|
1750
1782
|
}
|
|
1751
1783
|
},
|
|
1752
1784
|
async reset() {
|
|
@@ -1776,6 +1808,14 @@ function withAgentsFeatures() {
|
|
|
1776
1808
|
}));
|
|
1777
1809
|
}
|
|
1778
1810
|
const UserSettingsStore = signalStore({ providedIn: "root" }, withDevtools("UserSettings"), withBookmarkFeatures(), withRecentSearchesFeatures(), withSavedSearchesFeatures(), withBasketsFeatures(), withAssistantFeatures(), withUserSettingsFeatures(), withAlertsFeatures(), withAgentsFeatures(), withDarkModeFeatures(), withHighlightCategoriesFeatures());
|
|
1811
|
+
const toPart = (result) => result.status === "fulfilled" ? {
|
|
1812
|
+
ok: true,
|
|
1813
|
+
value: result.value
|
|
1814
|
+
} : {
|
|
1815
|
+
ok: false,
|
|
1816
|
+
error: result.reason
|
|
1817
|
+
};
|
|
1818
|
+
const provided = (part) => part && typeof part === "object" && part.ok === true ? Promise.resolve(part.value) : void 0;
|
|
1779
1819
|
const ROUTE_COMPONENTS = new InjectionToken("ROUTE_COMPONENTS", { factory: () => [] });
|
|
1780
1820
|
var ApplicationService = class ApplicationService {
|
|
1781
1821
|
userSettingsStore = inject(UserSettingsStore);
|
|
@@ -1785,6 +1825,7 @@ var ApplicationService = class ApplicationService {
|
|
|
1785
1825
|
router = inject(Router);
|
|
1786
1826
|
titleService = inject(Title);
|
|
1787
1827
|
client = inject(ATOMIC_CLIENT);
|
|
1828
|
+
startupDataSource = inject(STARTUP_DATA_SOURCE);
|
|
1788
1829
|
components = inject(ROUTE_COMPONENTS);
|
|
1789
1830
|
defaultComponent = computed(() => this.components.find((c) => c.path === "all")?.component, ...ngDevMode ? [{ debugName: "defaultComponent" }] : /* istanbul ignore next */ []);
|
|
1790
1831
|
defaultLayoutComponent = computed(() => this.components.find((c) => c.isRoot)?.component, ...ngDevMode ? [{ debugName: "defaultLayoutComponent" }] : /* istanbul ignore next */ []);
|
|
@@ -1807,18 +1848,46 @@ var ApplicationService = class ApplicationService {
|
|
|
1807
1848
|
}
|
|
1808
1849
|
async initializeStores(options) {
|
|
1809
1850
|
try {
|
|
1810
|
-
await this.
|
|
1851
|
+
const data = await this.loadStartupData();
|
|
1852
|
+
this.apply(data.app, this.appStore);
|
|
1811
1853
|
info("appStore", getState(this.appStore));
|
|
1812
|
-
|
|
1854
|
+
this.apply(data.principal, this.principalStore);
|
|
1813
1855
|
info("principalStore", getState(this.principalStore));
|
|
1814
1856
|
this.queryParamsStore.reset({ syncUrl: options?.syncUrl ?? !options?.isBootstrap });
|
|
1815
|
-
|
|
1857
|
+
this.apply(data.userSettings, this.userSettingsStore);
|
|
1816
1858
|
info("userSettingsStore", getState(this.userSettingsStore));
|
|
1817
1859
|
} catch (err) {
|
|
1818
1860
|
error("Error during application initialization", err);
|
|
1819
1861
|
throw err;
|
|
1820
1862
|
}
|
|
1821
1863
|
}
|
|
1864
|
+
async loadStartupData() {
|
|
1865
|
+
const source = await this.readStartupDataSource();
|
|
1866
|
+
const [app, principal, userSettings] = await Promise.allSettled([
|
|
1867
|
+
provided(source?.app) ?? this.client.api.app.get(),
|
|
1868
|
+
provided(source?.principal) ?? this.client.api.principal.get(),
|
|
1869
|
+
provided(source?.userSettings) ?? this.client.api.userSettings.get()
|
|
1870
|
+
]);
|
|
1871
|
+
return {
|
|
1872
|
+
app: toPart(app),
|
|
1873
|
+
principal: toPart(principal),
|
|
1874
|
+
userSettings: toPart(userSettings)
|
|
1875
|
+
};
|
|
1876
|
+
}
|
|
1877
|
+
async readStartupDataSource() {
|
|
1878
|
+
if (!this.startupDataSource) return void 0;
|
|
1879
|
+
try {
|
|
1880
|
+
const data = await this.startupDataSource();
|
|
1881
|
+
if (data && typeof data === "object") return data;
|
|
1882
|
+
warn("Start-up aggregation answered no data, reading each part instead", data);
|
|
1883
|
+
} catch (err) {
|
|
1884
|
+
warn("Start-up aggregation failed, reading each part instead", err);
|
|
1885
|
+
}
|
|
1886
|
+
}
|
|
1887
|
+
apply(part, store) {
|
|
1888
|
+
if (part.ok) store.hydrate(part.value);
|
|
1889
|
+
else store.fail(part.error);
|
|
1890
|
+
}
|
|
1822
1891
|
createRoutes() {
|
|
1823
1892
|
const { queries, data: custom, customJSONs = [] } = getState(this.appStore);
|
|
1824
1893
|
const queriesMap = Object.entries(queries).map(([key, value]) => ({
|
|
@@ -6652,7 +6721,9 @@ var MultiSelectionToolbarComponent = class MultiSelectionToolbarComponent {
|
|
|
6652
6721
|
}
|
|
6653
6722
|
return `search-results-assistant`;
|
|
6654
6723
|
}, ...ngDevMode ? [{ debugName: "instanceId" }] : /* istanbul ignore next */ []);
|
|
6655
|
-
enabledUserInput = computed(() => this.appStore.assistants()[this.instanceId()]?.modeSettings
|
|
6724
|
+
enabledUserInput = computed(() => this.appStore.assistants()[this.instanceId()]?.modeSettings?.enabledUserInput === true, ...ngDevMode ? [{ debugName: "enabledUserInput" }] : /* istanbul ignore next */ []);
|
|
6725
|
+
allowAI = input(false, ...ngDevMode ? [{ debugName: "allowAI" }] : /* istanbul ignore next */ []);
|
|
6726
|
+
showAssistantAction = computed(() => this.allowAI() && this.appStore.isAssistantAllowed(this.instanceId()) && this.enabledUserInput(), ...ngDevMode ? [{ debugName: "showAssistantAction" }] : /* istanbul ignore next */ []);
|
|
6656
6727
|
showHint = signal(false, ...ngDevMode ? [{ debugName: "showHint" }] : /* istanbul ignore next */ []);
|
|
6657
6728
|
armed = true;
|
|
6658
6729
|
constructor() {
|
|
@@ -6717,6 +6788,13 @@ var MultiSelectionToolbarComponent = class MultiSelectionToolbarComponent {
|
|
|
6717
6788
|
isSignal: true,
|
|
6718
6789
|
isRequired: false,
|
|
6719
6790
|
transformFunction: null
|
|
6791
|
+
},
|
|
6792
|
+
allowAI: {
|
|
6793
|
+
classPropertyName: "allowAI",
|
|
6794
|
+
publicName: "allowAI",
|
|
6795
|
+
isSignal: true,
|
|
6796
|
+
isRequired: false,
|
|
6797
|
+
transformFunction: null
|
|
6720
6798
|
}
|
|
6721
6799
|
},
|
|
6722
6800
|
outputs: {
|
|
@@ -6775,7 +6853,7 @@ var MultiSelectionToolbarComponent = class MultiSelectionToolbarComponent {
|
|
|
6775
6853
|
</button>
|
|
6776
6854
|
</div>
|
|
6777
6855
|
|
|
6778
|
-
@if (
|
|
6856
|
+
@if (showAssistantAction()) {
|
|
6779
6857
|
<div class="pe-0!">
|
|
6780
6858
|
<button class="cursor-pointer inline-flex items-center gap-1" (click)="attachToAssistant()">
|
|
6781
6859
|
<sparkles-icon aria-hidden="true" />
|
|
@@ -6879,7 +6957,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
6879
6957
|
</button>
|
|
6880
6958
|
</div>
|
|
6881
6959
|
|
|
6882
|
-
@if (
|
|
6960
|
+
@if (showAssistantAction()) {
|
|
6883
6961
|
<div class="pe-0!">
|
|
6884
6962
|
<button class="cursor-pointer inline-flex items-center gap-1" (click)="attachToAssistant()">
|
|
6885
6963
|
<sparkles-icon aria-hidden="true" />
|
|
@@ -6929,6 +7007,14 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
6929
7007
|
cleared: [{
|
|
6930
7008
|
type: i0.Output,
|
|
6931
7009
|
args: ["cleared"]
|
|
7010
|
+
}],
|
|
7011
|
+
allowAI: [{
|
|
7012
|
+
type: i0.Input,
|
|
7013
|
+
args: [{
|
|
7014
|
+
isSignal: true,
|
|
7015
|
+
alias: "allowAI",
|
|
7016
|
+
required: false
|
|
7017
|
+
}]
|
|
6932
7018
|
}]
|
|
6933
7019
|
}
|
|
6934
7020
|
});
|
|
@@ -23021,6 +23107,7 @@ var AggregationDateComponent = class AggregationDateComponent {
|
|
|
23021
23107
|
uid = nextAggregationDateId++;
|
|
23022
23108
|
startId = `datepicker-range-start-${this.uid}`;
|
|
23023
23109
|
endId = `datepicker-range-end-${this.uid}`;
|
|
23110
|
+
class = input("", ...ngDevMode ? [{ debugName: "class" }] : /* istanbul ignore next */ []);
|
|
23024
23111
|
name = input(null, ...ngDevMode ? [{ debugName: "name" }] : /* istanbul ignore next */ []);
|
|
23025
23112
|
column = input.required(...ngDevMode ? [{ debugName: "column" }] : /* istanbul ignore next */ []);
|
|
23026
23113
|
id = input(null, ...ngDevMode ? [{ debugName: "id" }] : /* istanbul ignore next */ []);
|
|
@@ -23507,6 +23594,13 @@ var AggregationDateComponent = class AggregationDateComponent {
|
|
|
23507
23594
|
isStandalone: true,
|
|
23508
23595
|
selector: "aggregation-date, AggregationDate, aggregationdate",
|
|
23509
23596
|
inputs: {
|
|
23597
|
+
class: {
|
|
23598
|
+
classPropertyName: "class",
|
|
23599
|
+
publicName: "class",
|
|
23600
|
+
isSignal: true,
|
|
23601
|
+
isRequired: false,
|
|
23602
|
+
transformFunction: null
|
|
23603
|
+
},
|
|
23510
23604
|
name: {
|
|
23511
23605
|
classPropertyName: "name",
|
|
23512
23606
|
publicName: "name",
|
|
@@ -23622,10 +23716,10 @@ var AggregationDateComponent = class AggregationDateComponent {
|
|
|
23622
23716
|
aggregationOverridesChange: "aggregationOverridesChange",
|
|
23623
23717
|
searchText: "searchTextChange"
|
|
23624
23718
|
},
|
|
23625
|
-
host: { properties: { "class": "cn(\"@container
|
|
23719
|
+
host: { properties: { "class": "cn(\"@container flex h-[inherit] max-h-[inherit] flex-col\", class(), isEmpty() && \"hidden\")" } },
|
|
23626
23720
|
providers: [provideTranslocoScope("filters")],
|
|
23627
23721
|
ngImport: i0,
|
|
23628
|
-
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 buttons (apply, clear, chevron) are the keyboard stops, see the\n chevron below. -->\n<details
|
|
23722
|
+
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 buttons (apply, clear, chevron) are the keyboard stops, see the\n chevron below. -->\n<details\n [attr.open]=\"expanded()\"\n [attr.name]=\"id()\"\n class=\"group flex min-h-0 flex-1 flex-col space-y-2 details-content:flex details-content:min-h-0 details-content:flex-1 details-content:flex-col\">\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 (hasFilters()) {\n @let clearLabel = \"filters.clearFilters\" | transloco;\n <button\n type=\"button\"\n variant=\"tertiary\"\n [iconOnly]=\"true\"\n size=\"sm\"\n class=\"shrink-0\"\n [aria-label]=\"clearLabel\"\n [tooltip]=\"clearLabel\"\n (click)=\"$event.stopPropagation(); clear()\">\n <filter-x-icon class=\"shrink-0\" />\n </button>\n }\n\n @if (\n (!isControlled() || emitOn() === \"apply\") &&\n selection() &&\n validSelection()\n ) {\n @let label = \"filters.apply\" | transloco;\n <button\n type=\"button\"\n variant=\"accent\"\n size=\"sm\"\n class=\"overflow-hidden\"\n [aria-label]=\"label\"\n [tooltip]=\"label\"\n (click)=\"$event.stopPropagation(); apply()\">\n <FilterIcon class=\"shrink-0\" />\n <span class=\"truncate\">{{ label }}</span>\n </button>\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=\"sm\"\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\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 <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 pt-2\"\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 cursor-pointer items-center p-2 text-sm text-(--font-neutral-base) select-none',\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\"\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 cursor-pointer items-center gap-(--spacing-xs) p-2 text-sm text-(--font-neutral-base) select-none',\n dateModel().option === 'custom-range' &&\n 'bg-(--bg-primary-lighter)'\n )\n \">\n <radio\n name=\"date-filter\"\n class=\"grow items-center\"\n [checked]=\"dateModel().option === 'custom-range'\"\n (checkedChange)=\"selectOption('custom-range')\">\n <div class=\"flex flex-wrap items-center gap-x-1 gap-y-1\">\n <div class=\"flex items-center gap-1\">\n <label\n [attr.for]=\"startId\"\n class=\"radio-label min-w-8 truncate\"\n >{{ \"filters.from\" | transloco }}</label\n >\n <input-group\n class=\"h-8 max-w-[18ch] min-w-[18ch] 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 items-center gap-1\">\n <label\n [attr.for]=\"endId\"\n class=\"radio-label min-w-8 truncate text-right\"\n >{{ \"filters.to\" | transloco }}</label\n >\n <input-group\n class=\"h-8 max-w-[18ch] min-w-[18ch] 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</details>\n",
|
|
23629
23723
|
styles: [":host{min-width:200px}ul[role=list]{scrollbar-width:thin}\n"],
|
|
23630
23724
|
dependencies: [
|
|
23631
23725
|
{
|
|
@@ -23759,13 +23853,21 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
23759
23853
|
RadioComponent,
|
|
23760
23854
|
TooltipDirective
|
|
23761
23855
|
],
|
|
23762
|
-
host: { "[class]": "cn(\"@container
|
|
23763
|
-
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 buttons (apply, clear, chevron) are the keyboard stops, see the\n chevron below. -->\n<details
|
|
23856
|
+
host: { "[class]": "cn(\"@container flex h-[inherit] max-h-[inherit] flex-col\", class(), isEmpty() && \"hidden\")" },
|
|
23857
|
+
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 buttons (apply, clear, chevron) are the keyboard stops, see the\n chevron below. -->\n<details\n [attr.open]=\"expanded()\"\n [attr.name]=\"id()\"\n class=\"group flex min-h-0 flex-1 flex-col space-y-2 details-content:flex details-content:min-h-0 details-content:flex-1 details-content:flex-col\">\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 (hasFilters()) {\n @let clearLabel = \"filters.clearFilters\" | transloco;\n <button\n type=\"button\"\n variant=\"tertiary\"\n [iconOnly]=\"true\"\n size=\"sm\"\n class=\"shrink-0\"\n [aria-label]=\"clearLabel\"\n [tooltip]=\"clearLabel\"\n (click)=\"$event.stopPropagation(); clear()\">\n <filter-x-icon class=\"shrink-0\" />\n </button>\n }\n\n @if (\n (!isControlled() || emitOn() === \"apply\") &&\n selection() &&\n validSelection()\n ) {\n @let label = \"filters.apply\" | transloco;\n <button\n type=\"button\"\n variant=\"accent\"\n size=\"sm\"\n class=\"overflow-hidden\"\n [aria-label]=\"label\"\n [tooltip]=\"label\"\n (click)=\"$event.stopPropagation(); apply()\">\n <FilterIcon class=\"shrink-0\" />\n <span class=\"truncate\">{{ label }}</span>\n </button>\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=\"sm\"\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\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 <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 pt-2\"\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 cursor-pointer items-center p-2 text-sm text-(--font-neutral-base) select-none',\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\"\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 cursor-pointer items-center gap-(--spacing-xs) p-2 text-sm text-(--font-neutral-base) select-none',\n dateModel().option === 'custom-range' &&\n 'bg-(--bg-primary-lighter)'\n )\n \">\n <radio\n name=\"date-filter\"\n class=\"grow items-center\"\n [checked]=\"dateModel().option === 'custom-range'\"\n (checkedChange)=\"selectOption('custom-range')\">\n <div class=\"flex flex-wrap items-center gap-x-1 gap-y-1\">\n <div class=\"flex items-center gap-1\">\n <label\n [attr.for]=\"startId\"\n class=\"radio-label min-w-8 truncate\"\n >{{ \"filters.from\" | transloco }}</label\n >\n <input-group\n class=\"h-8 max-w-[18ch] min-w-[18ch] 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 items-center gap-1\">\n <label\n [attr.for]=\"endId\"\n class=\"radio-label min-w-8 truncate text-right\"\n >{{ \"filters.to\" | transloco }}</label\n >\n <input-group\n class=\"h-8 max-w-[18ch] min-w-[18ch] 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</details>\n",
|
|
23764
23858
|
styles: [":host{min-width:200px}ul[role=list]{scrollbar-width:thin}\n"]
|
|
23765
23859
|
}]
|
|
23766
23860
|
}],
|
|
23767
23861
|
ctorParameters: () => [],
|
|
23768
23862
|
propDecorators: {
|
|
23863
|
+
class: [{
|
|
23864
|
+
type: i0.Input,
|
|
23865
|
+
args: [{
|
|
23866
|
+
isSignal: true,
|
|
23867
|
+
alias: "class",
|
|
23868
|
+
required: false
|
|
23869
|
+
}]
|
|
23870
|
+
}],
|
|
23769
23871
|
name: [{
|
|
23770
23872
|
type: i0.Input,
|
|
23771
23873
|
args: [{
|
|
@@ -24091,6 +24193,7 @@ var AggregationPanelComponent = class AggregationPanelComponent {
|
|
|
24091
24193
|
allUnselected: "allUnselected",
|
|
24092
24194
|
loadedMore: "loadedMore"
|
|
24093
24195
|
},
|
|
24196
|
+
host: { classAttribute: "flex min-h-0 flex-1 flex-col" },
|
|
24094
24197
|
providers: [provideTranslocoScope("filters")],
|
|
24095
24198
|
viewQueries: [{
|
|
24096
24199
|
propertyName: "searchBox",
|
|
@@ -24100,7 +24203,7 @@ var AggregationPanelComponent = class AggregationPanelComponent {
|
|
|
24100
24203
|
isSignal: true
|
|
24101
24204
|
}],
|
|
24102
24205
|
ngImport: i0,
|
|
24103
|
-
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 buttons (apply, clear,\n select-all, chevron), never the header row, and the chevron is the keyboard way to collapse.\n Label, header actions 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 #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 (!isCollapsed()) {\n @if (hasFilters()) {\n @let label = \"filters.clearFilters\" | transloco;\n <button\n type=\"button\"\n variant=\"tertiary\"\n [iconOnly]=\"true\"\n size=\"sm\"\n class=\"shrink-0\"\n [aria-label]=\"label\"\n [tooltip]=\"label\"\n (click)=\"$event.stopPropagation(); cleared.emit()\">\n <filter-x-icon class=\"shrink-0\" />\n </button>\n }\n @if (selection()) {\n @let label = \"filters.apply\" | transloco;\n <button\n type=\"button\"\n variant=\"accent\"\n size=\"sm\"\n class=\"overflow-hidden\"\n [aria-label]=\"label\"\n [tooltip]=\"label\"\n (click)=\"$event.stopPropagation(); applied.emit()\">\n <FilterIcon class=\"shrink-0\" />\n <span class=\"truncate\">{{ label }}</span>\n </button>\n }\n\n <!-- Nothing is projected into this box, so it had no accessible name at all (RGAA 11.1) —\n only its position next to the facet's title said what it selects. The name is stable\n whichever way it is about to act: `aria-checked` (true / mixed / false) is what tells the\n user where the selection stands. -->\n <checkbox\n class=\"shrink-0\"\n [checked]=\"isAllSelected()\"\n [indeterminate]=\"selection() && !isAllSelected()\"\n [aria-label]=\"'filters.selectAllFilters' | transloco\"\n (checkedChange)=\"$event ? allSelected.emit() : allUnselected.emit()\" />\n }\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=\"sm\"\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>\n @if (aggregation()?.searchable && itemsLength() > 0) {\n <!-- No `hotkey`: this field is one of many facet search boxes on the page, so it must not\n advertise a global shortcut. It used to pass `''` to neutralize SearchInput's old\n `\"shift+/\"` default, which left an empty `aria-keyshortcuts` attribute behind; the default\n is gone, so omitting the input is enough. -->\n <!-- A placeholder is not a label (RGAA 11.1): it goes away on the first keystroke, and it is\n the same word in every facet panel of the page. The name says WHICH facet this box\n filters — the one thing that tells a dozen identical fields apart. -->\n <!-- mt-2: without it, the search box sits flush under <summary>, and the header's focus ring reads as touching it. -->\n <SearchInput\n class=\"mt-2 mb-3\"\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 <ng-content select=\"[search-addon]\" />\n </SearchInput>\n }\n\n <ng-content />\n\n @if (hasMore() && searchedItemsLength() === 0) {\n <button\n type=\"button\"\n class=\"mt-1 flex w-full justify-center\"\n [attr.aria-label]=\"'loadMore' | transloco\"\n (click)=\"loadedMore.emit()\">\n {{ \"loadMore\" | transloco }}\n </button>\n }\n </div>\n</ng-template>\n\n<details\n [attr.open]=\"expanded()\"\n [attr.name]=\"id()\"\n class=\"group p-0.5\"\n (toggle)=\"onToggle($event)\">\n <summary\n tabindex=\"-1\"\n [class.cursor-pointer]=\"collapsible() && !isEmpty()\"\n [class]=\"(isEmpty() ? 'text-(--font-neutral-muted) ' : '') + rowStateClass\"\n class=\"m-0 flex h-8 w-full 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",
|
|
24206
|
+
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 buttons (apply, clear,\n select-all, chevron), never the header row, and the chevron is the keyboard way to collapse.\n Label, header actions 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 #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 (!isCollapsed()) {\n @if (hasFilters()) {\n @let label = \"filters.clearFilters\" | transloco;\n <button\n type=\"button\"\n variant=\"tertiary\"\n [iconOnly]=\"true\"\n size=\"sm\"\n class=\"shrink-0\"\n [aria-label]=\"label\"\n [tooltip]=\"label\"\n (click)=\"$event.stopPropagation(); cleared.emit()\">\n <filter-x-icon class=\"shrink-0\" />\n </button>\n }\n @if (selection()) {\n @let label = \"filters.apply\" | transloco;\n <button\n type=\"button\"\n variant=\"accent\"\n size=\"sm\"\n class=\"overflow-hidden\"\n [aria-label]=\"label\"\n [tooltip]=\"label\"\n (click)=\"$event.stopPropagation(); applied.emit()\">\n <FilterIcon class=\"shrink-0\" />\n <span class=\"truncate\">{{ label }}</span>\n </button>\n }\n\n <!-- Nothing is projected into this box, so it had no accessible name at all (RGAA 11.1) —\n only its position next to the facet's title said what it selects. The name is stable\n whichever way it is about to act: `aria-checked` (true / mixed / false) is what tells the\n user where the selection stands. -->\n <checkbox\n class=\"shrink-0\"\n [checked]=\"isAllSelected()\"\n [indeterminate]=\"selection() && !isAllSelected()\"\n [aria-label]=\"'filters.selectAllFilters' | transloco\"\n (checkedChange)=\"$event ? allSelected.emit() : allUnselected.emit()\" />\n }\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=\"sm\"\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 (aggregation()?.searchable && itemsLength() > 0) {\n <!-- No `hotkey`: this field is one of many facet search boxes on the page, so it must not\n advertise a global shortcut. It used to pass `''` to neutralize SearchInput's old\n `\"shift+/\"` default, which left an empty `aria-keyshortcuts` attribute behind; the default\n is gone, so omitting the input is enough. -->\n <!-- A placeholder is not a label (RGAA 11.1): it goes away on the first keystroke, and it is\n the same word in every facet panel of the page. The name says WHICH facet this box\n filters — the one thing that tells a dozen identical fields apart. -->\n <!-- mt-2: without it, the search box sits flush under <summary>, and the header's focus ring reads as touching it. -->\n <SearchInput\n class=\"mt-2 mb-3 shrink-0\"\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 <ng-content select=\"[search-addon]\" />\n </SearchInput>\n }\n\n <ng-content />\n\n @if (hasMore() && searchedItemsLength() === 0) {\n <button\n type=\"button\"\n class=\"mt-1 flex w-full shrink-0 justify-center\"\n [attr.aria-label]=\"'loadMore' | transloco\"\n (click)=\"loadedMore.emit()\">\n {{ \"loadMore\" | transloco }}\n </button>\n }\n </div>\n</ng-template>\n\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-1 details-content:flex-col\"\n (toggle)=\"onToggle($event)\">\n <summary\n tabindex=\"-1\"\n [class.cursor-pointer]=\"collapsible() && !isEmpty()\"\n [class]=\"(isEmpty() ? 'text-(--font-neutral-muted) ' : '') + 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-container [ngTemplateOutlet]=\"labelSlot\" />\n <ng-container [ngTemplateOutlet]=\"headerActionsSlot\" />\n </summary>\n <ng-container [ngTemplateOutlet]=\"bodySlot\" />\n</details>\n",
|
|
24104
24207
|
dependencies: [
|
|
24105
24208
|
{
|
|
24106
24209
|
kind: "directive",
|
|
@@ -24243,7 +24346,8 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
24243
24346
|
TooltipDirective
|
|
24244
24347
|
],
|
|
24245
24348
|
providers: [provideTranslocoScope("filters")],
|
|
24246
|
-
|
|
24349
|
+
host: { class: "flex min-h-0 flex-1 flex-col" },
|
|
24350
|
+
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 buttons (apply, clear,\n select-all, chevron), never the header row, and the chevron is the keyboard way to collapse.\n Label, header actions 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 #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 (!isCollapsed()) {\n @if (hasFilters()) {\n @let label = \"filters.clearFilters\" | transloco;\n <button\n type=\"button\"\n variant=\"tertiary\"\n [iconOnly]=\"true\"\n size=\"sm\"\n class=\"shrink-0\"\n [aria-label]=\"label\"\n [tooltip]=\"label\"\n (click)=\"$event.stopPropagation(); cleared.emit()\">\n <filter-x-icon class=\"shrink-0\" />\n </button>\n }\n @if (selection()) {\n @let label = \"filters.apply\" | transloco;\n <button\n type=\"button\"\n variant=\"accent\"\n size=\"sm\"\n class=\"overflow-hidden\"\n [aria-label]=\"label\"\n [tooltip]=\"label\"\n (click)=\"$event.stopPropagation(); applied.emit()\">\n <FilterIcon class=\"shrink-0\" />\n <span class=\"truncate\">{{ label }}</span>\n </button>\n }\n\n <!-- Nothing is projected into this box, so it had no accessible name at all (RGAA 11.1) —\n only its position next to the facet's title said what it selects. The name is stable\n whichever way it is about to act: `aria-checked` (true / mixed / false) is what tells the\n user where the selection stands. -->\n <checkbox\n class=\"shrink-0\"\n [checked]=\"isAllSelected()\"\n [indeterminate]=\"selection() && !isAllSelected()\"\n [aria-label]=\"'filters.selectAllFilters' | transloco\"\n (checkedChange)=\"$event ? allSelected.emit() : allUnselected.emit()\" />\n }\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=\"sm\"\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 (aggregation()?.searchable && itemsLength() > 0) {\n <!-- No `hotkey`: this field is one of many facet search boxes on the page, so it must not\n advertise a global shortcut. It used to pass `''` to neutralize SearchInput's old\n `\"shift+/\"` default, which left an empty `aria-keyshortcuts` attribute behind; the default\n is gone, so omitting the input is enough. -->\n <!-- A placeholder is not a label (RGAA 11.1): it goes away on the first keystroke, and it is\n the same word in every facet panel of the page. The name says WHICH facet this box\n filters — the one thing that tells a dozen identical fields apart. -->\n <!-- mt-2: without it, the search box sits flush under <summary>, and the header's focus ring reads as touching it. -->\n <SearchInput\n class=\"mt-2 mb-3 shrink-0\"\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 <ng-content select=\"[search-addon]\" />\n </SearchInput>\n }\n\n <ng-content />\n\n @if (hasMore() && searchedItemsLength() === 0) {\n <button\n type=\"button\"\n class=\"mt-1 flex w-full shrink-0 justify-center\"\n [attr.aria-label]=\"'loadMore' | transloco\"\n (click)=\"loadedMore.emit()\">\n {{ \"loadMore\" | transloco }}\n </button>\n }\n </div>\n</ng-template>\n\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-1 details-content:flex-col\"\n (toggle)=\"onToggle($event)\">\n <summary\n tabindex=\"-1\"\n [class.cursor-pointer]=\"collapsible() && !isEmpty()\"\n [class]=\"(isEmpty() ? 'text-(--font-neutral-muted) ' : '') + 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-container [ngTemplateOutlet]=\"labelSlot\" />\n <ng-container [ngTemplateOutlet]=\"headerActionsSlot\" />\n </summary>\n <ng-container [ngTemplateOutlet]=\"bodySlot\" />\n</details>\n"
|
|
24247
24351
|
}]
|
|
24248
24352
|
}],
|
|
24249
24353
|
ctorParameters: () => [],
|
|
@@ -25074,7 +25178,7 @@ var AggregationTreeComponent = class AggregationTreeComponent {
|
|
|
25074
25178
|
filtersChange: "filtersChange",
|
|
25075
25179
|
searchText: "searchTextChange"
|
|
25076
25180
|
},
|
|
25077
|
-
host: { properties: { "class": "cn(\"
|
|
25181
|
+
host: { properties: { "class": "cn(\"flex h-[inherit] max-h-[inherit] flex-col\", class(), (isMissing() || (hideWhenEmpty() && isHidden())) && \"hidden\")" } },
|
|
25078
25182
|
queries: [{
|
|
25079
25183
|
propertyName: "itemDirective",
|
|
25080
25184
|
first: true,
|
|
@@ -25083,7 +25187,7 @@ var AggregationTreeComponent = class AggregationTreeComponent {
|
|
|
25083
25187
|
isSignal: true
|
|
25084
25188
|
}],
|
|
25085
25189
|
ngImport: i0,
|
|
25086
|
-
template: "@if (!aggregation()?.isTree) {\n <div role=\"alert\" class=\"p-2 text-sm text-red-500\">\n <triangle-alert-icon class=\"mr-1 shrink-0\" />\n The aggregationTree component does not support list aggregations. Please use\n the <Aggregation /> component instead.\n </div>\n}\n<aggregation-panel\n [id]=\"id()\"\n [collapsible]=\"collapsible()\"\n [collapsed]=\"collapsed()\"\n [isEmpty]=\"isEmpty()\"\n [isDate]=\"isDate()\"\n [aggregation]=\"aggregation()\"\n [showFiltersCount]=\"showFiltersCount()\"\n [filtersCount]=\"filtersCount()\"\n [hasFilters]=\"hasFilters()\"\n [selection]=\"selection()\"\n [isAllSelected]=\"isAllSelected()\"\n [(searchText)]=\"searchText\"\n [itemsLength]=\"items().length\"\n [hasMore]=\"aggregation()?.$hasMore ?? false\"\n [searchedItemsLength]=\"searchedItems().length\"\n (cleared)=\"clear()\"\n (applied)=\"apply()\"\n (allSelected)=\"selectAll()\"\n (allUnselected)=\"unselectAll()\"\n (loadedMore)=\"loadMore()\">\n <!-- Relay the host's `label` projection into the panel's `label` slot. When the\n host projects nothing, the local <ng-content> falls back to the icon + display\n (mirrors AggregationPanel's own fallback), so the header is never empty. -->\n <ng-container ngProjectAs=\"label\">\n <ng-content select=\"label\">\n @let labelIcon = aggregation()?.icon;\n @if (labelIcon) {\n <FaIcon [faClass]=\"labelIcon\" class=\"mr-1 shrink-0\" />\n }\n <span class=\"grow truncate\">{{\n aggregation()?.display | syslang | transloco\n }}</span>\n </ng-content>\n </ng-container>\n <div\n class=\"max-h-(--scroll-height,20rem) w-full scrollbar-thin overflow-auto pb-3\">\n <ul\n ngTree\n #tree=\"ngTree\"\n [multi]=\"true\"\n [(value)]=\"selected\"\n (valueChange)=\"onSelectionChange($event)\"\n /* Translated like the flat list's own label (aggregation-list.html): this was the raw\n `display`, so the accessible name of a whole facet came out in the source language.\n The pipes apply to the whole nullish chain, `|` being the loosest operator Angular\n parses — no parentheses needed. */\n [attr.aria-label]=\"aggregation()?.display ?? name() | syslang | transloco\"\n class=\"basic-tree m-1\">\n <ng-template\n [ngTemplateOutlet]=\"treeNodes\"\n [ngTemplateOutletContext]=\"{ nodes: nodes(), parent: tree }\" />\n </ul>\n </div>\n</aggregation-panel>\n\n<ng-template #treeNodes let-nodes=\"nodes\" let-parent=\"parent\">\n @for (node of nodes; track node.$path) {\n @let label = node.display ?? node.value ?? \"\";\n <li\n ngTreeItem\n #treeItem=\"ngTreeItem\"\n [parent]=\"parent\"\n [value]=\"node.$path\"\n [label]=\"label\"\n [disabled]=\"node.disabled\"\n [(expanded)]=\"node.$opened\"\n (expandedChange)=\"onExpandedChange(node, $event)\"\n [attr.aria-label]=\"label\"\n [attr.aria-describedby]=\"\n nodeDescription(node) ? descriptionId(node.$path) : null\n \"\n [class]=\"cn('m-0 block w-full p-0', itemStateClass)\"\n (keydown.enter)=\"onTreeItemEnterKey(node, $event)\"\n (keydown.space)=\"onTreeItemSpaceKey(node, $event)\">\n <!-- 2. Ce div prend tout l'espace et intercepte tous les clics de la ligne -->\n <div\n class=\"flex w-full cursor-pointer items-center gap-2 py-0.5 text-sm leading-6\"\n (click)=\"onTreeItemRowClick(node, $event)\"\n (mousedown)=\"$event.stopPropagation()\"\n (pointerdown)=\"$event.stopPropagation()\">\n @if (showCheckbox()) {\n <!-- `inert` keeps the native input out of the tab order and out of hit-testing:\n a role=\"treeitem\" admits no focusable descendant, and the click must reach\n the row handler above. Selection is announced by the <li>'s aria-selected. -->\n <!-- --spacing-xs: 0 kills the gap the checkbox keeps between its box and its\n (here empty) text block. Set as a custom property rather than a utility\n class: the CVA already sets gap-(--spacing-xs), and two same-specificity\n classes would be resolved by stylesheet order, not by us. -->\n <span\n inert\n aria-hidden=\"true\"\n class=\"inline-flex shrink-0\"\n style=\"--spacing-xs: 0\">\n <checkbox\n [checked]=\"treeItem.selected() || node.$selectedVisually || false\"\n [disabled]=\"node.disabled\"\n [class]=\"\n cn(\n 'pointer-events-none',\n (treeItem.selected() || node.$selectedVisually) &&\n 'selected-icon'\n )\n \" />\n </span>\n }\n <!-- Depth indent sits on the chevron, after the checkbox: the checkboxes of every\n level stay flush left (aligned with a flat list's), and since this adds no extra\n flex child, the step between consecutive levels is exactly one indent. -->\n @let depthIndent =\n \"calc(var(--agg-tree-indent, 0.5rem) * \" +\n (treeItem.level() - 1) +\n \")\";\n @if (node.hasChildren) {\n <!-- Expand/collapse affordance for the mouse only, hence a <span> and not a <button>:\n the keyboard already expands with ArrowRight / ArrowLeft, handled by ngTreeItem, and\n a role=\"treeitem\" admits no focusable descendant — so this was a <button> nobody\n could reach, already carrying aria-hidden and tabindex=\"-1\" to say so. Every audit\n reads it as a button with no accessible name (RGAA 7.1, 11.9). Same shape as the leaf\n branch below. -->\n <span\n aria-hidden=\"true\"\n (click)=\"toggleTreeNode(treeItem, $event)\"\n [style.marginInlineStart]=\"depthIndent\"\n class=\"inline-flex cursor-pointer items-center justify-center\">\n <ChevronRightIcon\n [class]=\"\n cn('expand-icon shrink-0', node.$opened && 'rotate-90')\n \" />\n <FolderIcon class=\"shrink-0\" />\n </span>\n } @else {\n <span\n aria-hidden=\"true\"\n [style.marginInlineStart]=\"depthIndent\"\n class=\"inline-flex items-center justify-center\">\n <!-- Reserves the chevron's own width (`.expand-icon` is a styling hook with\n no rule of its own), so a leaf lines up with its parent nodes. -->\n <span class=\"expand-icon w-4 shrink-0\"></span>\n <FileIcon class=\"size-4 shrink-0\" />\n </span>\n }\n @if (resolvedItemTemplate(); as tpl) {\n <span\n class=\"grow truncate select-none\"\n (click)=\"onTreeItemTextClick(node, $event)\">\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{\n $implicit: node,\n field: aggregation()?.column,\n selected: treeItem.selected() ?? false,\n count: node.count,\n name: label,\n searchText: searchText(),\n level: node.$level ?? 0,\n expanded: node.$opened ?? false,\n hasChildren: node.hasChildren ?? false\n }\" />\n </span>\n } @else {\n <!-- ce span est essentiel pour le style -->\n @let appliesOnLabelClick = quickFilter() || applyOnSelect();\n <span\n [class]=\"\n cn(\n 'grow truncate select-none',\n appliesOnLabelClick && 'hover:underline'\n )\n \"\n [title]=\"\n appliesOnLabelClick\n ? ((isTreeItemFiltered(node)\n ? 'filters.removeFilter'\n : 'filters.addFilter'\n ) | transloco) +\n ': ' +\n label\n : label\n \"\n (click)=\"onTreeItemTextClick(node, $event)\">\n @for (\n chunk of label | highlightWord: searchText() : 10;\n track $index\n ) {\n <span [class]=\"{ 'font-bold': chunk.match }\" aria-hidden=\"true\">{{\n chunk.text\n }}</span>\n }\n </span>\n @if (showCount() && node.count > 0) {\n <span class=\"ml-auto px-1 text-xs\" aria-hidden=\"true\">{{\n node.count\n }}</span>\n }\n }\n @let description = nodeDescription(node);\n @if (description) {\n <!-- `hidden`, not `sr-only`: read through aria-describedby only. A visually-hidden\n span would also be counted in the treeitem's name (computed from its content). -->\n <span hidden [id]=\"descriptionId(node.$path)\">{{ description }}</span>\n }\n </div>\n </li>\n @if (node.hasChildren) {\n <!-- No indentation here: it would shift the checkbox too. Depth is applied\n inside the row, after the checkbox, so every checkbox stays flush left. -->\n <!-- The <ul> sits INSIDE the deferred content, not around it: `ngTreeItemGroup` only\n instantiates its view when the node opens, so a <ul> declared outside stayed in the DOM,\n empty, for every collapsed node — a structural tag with nothing to structure (RGAA 8.9).\n The @if cannot move onto the <ul> either: the directive registers itself with its tree\n item on init and has to exist for as long as the item does. -->\n <ng-template\n ngTreeItemGroup\n [ownedBy]=\"treeItem\"\n #group=\"ngTreeItemGroup\">\n <ul role=\"group\">\n <ng-template\n [ngTemplateOutlet]=\"treeNodes\"\n [ngTemplateOutletContext]=\"{ nodes: node.items, parent: group }\" />\n </ul>\n </ng-template>\n }\n }\n</ng-template>\n",
|
|
25190
|
+
template: "@if (!aggregation()?.isTree) {\n <div role=\"alert\" class=\"p-2 text-sm text-red-500\">\n <triangle-alert-icon class=\"mr-1 shrink-0\" />\n The aggregationTree component does not support list aggregations. Please use\n the <Aggregation /> component instead.\n </div>\n}\n<aggregation-panel\n [id]=\"id()\"\n [collapsible]=\"collapsible()\"\n [collapsed]=\"collapsed()\"\n [isEmpty]=\"isEmpty()\"\n [isDate]=\"isDate()\"\n [aggregation]=\"aggregation()\"\n [showFiltersCount]=\"showFiltersCount()\"\n [filtersCount]=\"filtersCount()\"\n [hasFilters]=\"hasFilters()\"\n [selection]=\"selection()\"\n [isAllSelected]=\"isAllSelected()\"\n [(searchText)]=\"searchText\"\n [itemsLength]=\"items().length\"\n [hasMore]=\"aggregation()?.$hasMore ?? false\"\n [searchedItemsLength]=\"searchedItems().length\"\n (cleared)=\"clear()\"\n (applied)=\"apply()\"\n (allSelected)=\"selectAll()\"\n (allUnselected)=\"unselectAll()\"\n (loadedMore)=\"loadMore()\">\n <!-- Relay the host's `label` projection into the panel's `label` slot. When the\n host projects nothing, the local <ng-content> falls back to the icon + display\n (mirrors AggregationPanel's own fallback), so the header is never empty. -->\n <ng-container ngProjectAs=\"label\">\n <ng-content select=\"label\">\n @let labelIcon = aggregation()?.icon;\n @if (labelIcon) {\n <FaIcon [faClass]=\"labelIcon\" class=\"mr-1 shrink-0\" />\n }\n <span class=\"grow truncate\">{{\n aggregation()?.display | syslang | transloco\n }}</span>\n </ng-content>\n </ng-container>\n <div class=\"min-h-0 w-full flex-1 scrollbar-thin overflow-auto pb-3\">\n <ul\n ngTree\n #tree=\"ngTree\"\n [multi]=\"true\"\n [(value)]=\"selected\"\n (valueChange)=\"onSelectionChange($event)\"\n /* Translated like the flat list's own label (aggregation-list.html): this was the raw\n `display`, so the accessible name of a whole facet came out in the source language.\n The pipes apply to the whole nullish chain, `|` being the loosest operator Angular\n parses — no parentheses needed. */\n [attr.aria-label]=\"aggregation()?.display ?? name() | syslang | transloco\"\n class=\"basic-tree m-1\">\n <ng-template\n [ngTemplateOutlet]=\"treeNodes\"\n [ngTemplateOutletContext]=\"{ nodes: nodes(), parent: tree }\" />\n </ul>\n </div>\n</aggregation-panel>\n\n<ng-template #treeNodes let-nodes=\"nodes\" let-parent=\"parent\">\n @for (node of nodes; track node.$path) {\n @let label = node.display ?? node.value ?? \"\";\n <li\n ngTreeItem\n #treeItem=\"ngTreeItem\"\n [parent]=\"parent\"\n [value]=\"node.$path\"\n [label]=\"label\"\n [disabled]=\"node.disabled\"\n [(expanded)]=\"node.$opened\"\n (expandedChange)=\"onExpandedChange(node, $event)\"\n [attr.aria-label]=\"label\"\n [attr.aria-describedby]=\"\n nodeDescription(node) ? descriptionId(node.$path) : null\n \"\n [class]=\"cn('m-0 block w-full p-0', itemStateClass)\"\n (keydown.enter)=\"onTreeItemEnterKey(node, $event)\"\n (keydown.space)=\"onTreeItemSpaceKey(node, $event)\">\n <!-- 2. Ce div prend tout l'espace et intercepte tous les clics de la ligne -->\n <div\n class=\"flex w-full cursor-pointer items-center gap-2 py-0.5 text-sm leading-6\"\n (click)=\"onTreeItemRowClick(node, $event)\"\n (mousedown)=\"$event.stopPropagation()\"\n (pointerdown)=\"$event.stopPropagation()\">\n @if (showCheckbox()) {\n <!-- `inert` keeps the native input out of the tab order and out of hit-testing:\n a role=\"treeitem\" admits no focusable descendant, and the click must reach\n the row handler above. Selection is announced by the <li>'s aria-selected. -->\n <!-- --spacing-xs: 0 kills the gap the checkbox keeps between its box and its\n (here empty) text block. Set as a custom property rather than a utility\n class: the CVA already sets gap-(--spacing-xs), and two same-specificity\n classes would be resolved by stylesheet order, not by us. -->\n <span\n inert\n aria-hidden=\"true\"\n class=\"inline-flex shrink-0\"\n style=\"--spacing-xs: 0\">\n <checkbox\n [checked]=\"treeItem.selected() || node.$selectedVisually || false\"\n [disabled]=\"node.disabled\"\n [class]=\"\n cn(\n 'pointer-events-none',\n (treeItem.selected() || node.$selectedVisually) &&\n 'selected-icon'\n )\n \" />\n </span>\n }\n <!-- Depth indent sits on the chevron, after the checkbox: the checkboxes of every\n level stay flush left (aligned with a flat list's), and since this adds no extra\n flex child, the step between consecutive levels is exactly one indent. -->\n @let depthIndent =\n \"calc(var(--agg-tree-indent, 0.5rem) * \" +\n (treeItem.level() - 1) +\n \")\";\n @if (node.hasChildren) {\n <!-- Expand/collapse affordance for the mouse only, hence a <span> and not a <button>:\n the keyboard already expands with ArrowRight / ArrowLeft, handled by ngTreeItem, and\n a role=\"treeitem\" admits no focusable descendant — so this was a <button> nobody\n could reach, already carrying aria-hidden and tabindex=\"-1\" to say so. Every audit\n reads it as a button with no accessible name (RGAA 7.1, 11.9). Same shape as the leaf\n branch below. -->\n <span\n aria-hidden=\"true\"\n (click)=\"toggleTreeNode(treeItem, $event)\"\n [style.marginInlineStart]=\"depthIndent\"\n class=\"inline-flex cursor-pointer items-center justify-center\">\n <ChevronRightIcon\n [class]=\"\n cn('expand-icon shrink-0', node.$opened && 'rotate-90')\n \" />\n <FolderIcon class=\"shrink-0\" />\n </span>\n } @else {\n <span\n aria-hidden=\"true\"\n [style.marginInlineStart]=\"depthIndent\"\n class=\"inline-flex items-center justify-center\">\n <!-- Reserves the chevron's own width (`.expand-icon` is a styling hook with\n no rule of its own), so a leaf lines up with its parent nodes. -->\n <span class=\"expand-icon w-4 shrink-0\"></span>\n <FileIcon class=\"size-4 shrink-0\" />\n </span>\n }\n @if (resolvedItemTemplate(); as tpl) {\n <span\n class=\"grow truncate select-none\"\n (click)=\"onTreeItemTextClick(node, $event)\">\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{\n $implicit: node,\n field: aggregation()?.column,\n selected: treeItem.selected() ?? false,\n count: node.count,\n name: label,\n searchText: searchText(),\n level: node.$level ?? 0,\n expanded: node.$opened ?? false,\n hasChildren: node.hasChildren ?? false\n }\" />\n </span>\n } @else {\n <!-- ce span est essentiel pour le style -->\n @let appliesOnLabelClick = quickFilter() || applyOnSelect();\n <span\n [class]=\"\n cn(\n 'grow truncate select-none',\n appliesOnLabelClick && 'hover:underline'\n )\n \"\n [title]=\"\n appliesOnLabelClick\n ? ((isTreeItemFiltered(node)\n ? 'filters.removeFilter'\n : 'filters.addFilter'\n ) | transloco) +\n ': ' +\n label\n : label\n \"\n (click)=\"onTreeItemTextClick(node, $event)\">\n @for (\n chunk of label | highlightWord: searchText() : 10;\n track $index\n ) {\n <span [class]=\"{ 'font-bold': chunk.match }\" aria-hidden=\"true\">{{\n chunk.text\n }}</span>\n }\n </span>\n @if (showCount() && node.count > 0) {\n <span class=\"ml-auto px-1 text-xs\" aria-hidden=\"true\">{{\n node.count\n }}</span>\n }\n }\n @let description = nodeDescription(node);\n @if (description) {\n <!-- `hidden`, not `sr-only`: read through aria-describedby only. A visually-hidden\n span would also be counted in the treeitem's name (computed from its content). -->\n <span hidden [id]=\"descriptionId(node.$path)\">{{ description }}</span>\n }\n </div>\n </li>\n @if (node.hasChildren) {\n <!-- No indentation here: it would shift the checkbox too. Depth is applied\n inside the row, after the checkbox, so every checkbox stays flush left. -->\n <!-- The <ul> sits INSIDE the deferred content, not around it: `ngTreeItemGroup` only\n instantiates its view when the node opens, so a <ul> declared outside stayed in the DOM,\n empty, for every collapsed node — a structural tag with nothing to structure (RGAA 8.9).\n The @if cannot move onto the <ul> either: the directive registers itself with its tree\n item on init and has to exist for as long as the item does. -->\n <ng-template\n ngTreeItemGroup\n [ownedBy]=\"treeItem\"\n #group=\"ngTreeItemGroup\">\n <ul role=\"group\">\n <ng-template\n [ngTemplateOutlet]=\"treeNodes\"\n [ngTemplateOutletContext]=\"{ nodes: node.items, parent: group }\" />\n </ul>\n </ng-template>\n }\n }\n</ng-template>\n",
|
|
25087
25191
|
dependencies: [
|
|
25088
25192
|
{
|
|
25089
25193
|
kind: "directive",
|
|
@@ -25257,8 +25361,8 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
25257
25361
|
TreeItemGroup,
|
|
25258
25362
|
AggregationPanelComponent
|
|
25259
25363
|
],
|
|
25260
|
-
host: { "[class]": "cn(\"
|
|
25261
|
-
template: "@if (!aggregation()?.isTree) {\n <div role=\"alert\" class=\"p-2 text-sm text-red-500\">\n <triangle-alert-icon class=\"mr-1 shrink-0\" />\n The aggregationTree component does not support list aggregations. Please use\n the <Aggregation /> component instead.\n </div>\n}\n<aggregation-panel\n [id]=\"id()\"\n [collapsible]=\"collapsible()\"\n [collapsed]=\"collapsed()\"\n [isEmpty]=\"isEmpty()\"\n [isDate]=\"isDate()\"\n [aggregation]=\"aggregation()\"\n [showFiltersCount]=\"showFiltersCount()\"\n [filtersCount]=\"filtersCount()\"\n [hasFilters]=\"hasFilters()\"\n [selection]=\"selection()\"\n [isAllSelected]=\"isAllSelected()\"\n [(searchText)]=\"searchText\"\n [itemsLength]=\"items().length\"\n [hasMore]=\"aggregation()?.$hasMore ?? false\"\n [searchedItemsLength]=\"searchedItems().length\"\n (cleared)=\"clear()\"\n (applied)=\"apply()\"\n (allSelected)=\"selectAll()\"\n (allUnselected)=\"unselectAll()\"\n (loadedMore)=\"loadMore()\">\n <!-- Relay the host's `label` projection into the panel's `label` slot. When the\n host projects nothing, the local <ng-content> falls back to the icon + display\n (mirrors AggregationPanel's own fallback), so the header is never empty. -->\n <ng-container ngProjectAs=\"label\">\n <ng-content select=\"label\">\n @let labelIcon = aggregation()?.icon;\n @if (labelIcon) {\n <FaIcon [faClass]=\"labelIcon\" class=\"mr-1 shrink-0\" />\n }\n <span class=\"grow truncate\">{{\n aggregation()?.display | syslang | transloco\n }}</span>\n </ng-content>\n </ng-container>\n <div\n class=\"max-h-(--scroll-height,20rem) w-full scrollbar-thin overflow-auto pb-3\">\n <ul\n ngTree\n #tree=\"ngTree\"\n [multi]=\"true\"\n [(value)]=\"selected\"\n (valueChange)=\"onSelectionChange($event)\"\n /* Translated like the flat list's own label (aggregation-list.html): this was the raw\n `display`, so the accessible name of a whole facet came out in the source language.\n The pipes apply to the whole nullish chain, `|` being the loosest operator Angular\n parses — no parentheses needed. */\n [attr.aria-label]=\"aggregation()?.display ?? name() | syslang | transloco\"\n class=\"basic-tree m-1\">\n <ng-template\n [ngTemplateOutlet]=\"treeNodes\"\n [ngTemplateOutletContext]=\"{ nodes: nodes(), parent: tree }\" />\n </ul>\n </div>\n</aggregation-panel>\n\n<ng-template #treeNodes let-nodes=\"nodes\" let-parent=\"parent\">\n @for (node of nodes; track node.$path) {\n @let label = node.display ?? node.value ?? \"\";\n <li\n ngTreeItem\n #treeItem=\"ngTreeItem\"\n [parent]=\"parent\"\n [value]=\"node.$path\"\n [label]=\"label\"\n [disabled]=\"node.disabled\"\n [(expanded)]=\"node.$opened\"\n (expandedChange)=\"onExpandedChange(node, $event)\"\n [attr.aria-label]=\"label\"\n [attr.aria-describedby]=\"\n nodeDescription(node) ? descriptionId(node.$path) : null\n \"\n [class]=\"cn('m-0 block w-full p-0', itemStateClass)\"\n (keydown.enter)=\"onTreeItemEnterKey(node, $event)\"\n (keydown.space)=\"onTreeItemSpaceKey(node, $event)\">\n <!-- 2. Ce div prend tout l'espace et intercepte tous les clics de la ligne -->\n <div\n class=\"flex w-full cursor-pointer items-center gap-2 py-0.5 text-sm leading-6\"\n (click)=\"onTreeItemRowClick(node, $event)\"\n (mousedown)=\"$event.stopPropagation()\"\n (pointerdown)=\"$event.stopPropagation()\">\n @if (showCheckbox()) {\n <!-- `inert` keeps the native input out of the tab order and out of hit-testing:\n a role=\"treeitem\" admits no focusable descendant, and the click must reach\n the row handler above. Selection is announced by the <li>'s aria-selected. -->\n <!-- --spacing-xs: 0 kills the gap the checkbox keeps between its box and its\n (here empty) text block. Set as a custom property rather than a utility\n class: the CVA already sets gap-(--spacing-xs), and two same-specificity\n classes would be resolved by stylesheet order, not by us. -->\n <span\n inert\n aria-hidden=\"true\"\n class=\"inline-flex shrink-0\"\n style=\"--spacing-xs: 0\">\n <checkbox\n [checked]=\"treeItem.selected() || node.$selectedVisually || false\"\n [disabled]=\"node.disabled\"\n [class]=\"\n cn(\n 'pointer-events-none',\n (treeItem.selected() || node.$selectedVisually) &&\n 'selected-icon'\n )\n \" />\n </span>\n }\n <!-- Depth indent sits on the chevron, after the checkbox: the checkboxes of every\n level stay flush left (aligned with a flat list's), and since this adds no extra\n flex child, the step between consecutive levels is exactly one indent. -->\n @let depthIndent =\n \"calc(var(--agg-tree-indent, 0.5rem) * \" +\n (treeItem.level() - 1) +\n \")\";\n @if (node.hasChildren) {\n <!-- Expand/collapse affordance for the mouse only, hence a <span> and not a <button>:\n the keyboard already expands with ArrowRight / ArrowLeft, handled by ngTreeItem, and\n a role=\"treeitem\" admits no focusable descendant — so this was a <button> nobody\n could reach, already carrying aria-hidden and tabindex=\"-1\" to say so. Every audit\n reads it as a button with no accessible name (RGAA 7.1, 11.9). Same shape as the leaf\n branch below. -->\n <span\n aria-hidden=\"true\"\n (click)=\"toggleTreeNode(treeItem, $event)\"\n [style.marginInlineStart]=\"depthIndent\"\n class=\"inline-flex cursor-pointer items-center justify-center\">\n <ChevronRightIcon\n [class]=\"\n cn('expand-icon shrink-0', node.$opened && 'rotate-90')\n \" />\n <FolderIcon class=\"shrink-0\" />\n </span>\n } @else {\n <span\n aria-hidden=\"true\"\n [style.marginInlineStart]=\"depthIndent\"\n class=\"inline-flex items-center justify-center\">\n <!-- Reserves the chevron's own width (`.expand-icon` is a styling hook with\n no rule of its own), so a leaf lines up with its parent nodes. -->\n <span class=\"expand-icon w-4 shrink-0\"></span>\n <FileIcon class=\"size-4 shrink-0\" />\n </span>\n }\n @if (resolvedItemTemplate(); as tpl) {\n <span\n class=\"grow truncate select-none\"\n (click)=\"onTreeItemTextClick(node, $event)\">\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{\n $implicit: node,\n field: aggregation()?.column,\n selected: treeItem.selected() ?? false,\n count: node.count,\n name: label,\n searchText: searchText(),\n level: node.$level ?? 0,\n expanded: node.$opened ?? false,\n hasChildren: node.hasChildren ?? false\n }\" />\n </span>\n } @else {\n <!-- ce span est essentiel pour le style -->\n @let appliesOnLabelClick = quickFilter() || applyOnSelect();\n <span\n [class]=\"\n cn(\n 'grow truncate select-none',\n appliesOnLabelClick && 'hover:underline'\n )\n \"\n [title]=\"\n appliesOnLabelClick\n ? ((isTreeItemFiltered(node)\n ? 'filters.removeFilter'\n : 'filters.addFilter'\n ) | transloco) +\n ': ' +\n label\n : label\n \"\n (click)=\"onTreeItemTextClick(node, $event)\">\n @for (\n chunk of label | highlightWord: searchText() : 10;\n track $index\n ) {\n <span [class]=\"{ 'font-bold': chunk.match }\" aria-hidden=\"true\">{{\n chunk.text\n }}</span>\n }\n </span>\n @if (showCount() && node.count > 0) {\n <span class=\"ml-auto px-1 text-xs\" aria-hidden=\"true\">{{\n node.count\n }}</span>\n }\n }\n @let description = nodeDescription(node);\n @if (description) {\n <!-- `hidden`, not `sr-only`: read through aria-describedby only. A visually-hidden\n span would also be counted in the treeitem's name (computed from its content). -->\n <span hidden [id]=\"descriptionId(node.$path)\">{{ description }}</span>\n }\n </div>\n </li>\n @if (node.hasChildren) {\n <!-- No indentation here: it would shift the checkbox too. Depth is applied\n inside the row, after the checkbox, so every checkbox stays flush left. -->\n <!-- The <ul> sits INSIDE the deferred content, not around it: `ngTreeItemGroup` only\n instantiates its view when the node opens, so a <ul> declared outside stayed in the DOM,\n empty, for every collapsed node — a structural tag with nothing to structure (RGAA 8.9).\n The @if cannot move onto the <ul> either: the directive registers itself with its tree\n item on init and has to exist for as long as the item does. -->\n <ng-template\n ngTreeItemGroup\n [ownedBy]=\"treeItem\"\n #group=\"ngTreeItemGroup\">\n <ul role=\"group\">\n <ng-template\n [ngTemplateOutlet]=\"treeNodes\"\n [ngTemplateOutletContext]=\"{ nodes: node.items, parent: group }\" />\n </ul>\n </ng-template>\n }\n }\n</ng-template>\n"
|
|
25364
|
+
host: { "[class]": "cn(\"flex h-[inherit] max-h-[inherit] flex-col\", class(), (isMissing() || (hideWhenEmpty() && isHidden())) && \"hidden\")" },
|
|
25365
|
+
template: "@if (!aggregation()?.isTree) {\n <div role=\"alert\" class=\"p-2 text-sm text-red-500\">\n <triangle-alert-icon class=\"mr-1 shrink-0\" />\n The aggregationTree component does not support list aggregations. Please use\n the <Aggregation /> component instead.\n </div>\n}\n<aggregation-panel\n [id]=\"id()\"\n [collapsible]=\"collapsible()\"\n [collapsed]=\"collapsed()\"\n [isEmpty]=\"isEmpty()\"\n [isDate]=\"isDate()\"\n [aggregation]=\"aggregation()\"\n [showFiltersCount]=\"showFiltersCount()\"\n [filtersCount]=\"filtersCount()\"\n [hasFilters]=\"hasFilters()\"\n [selection]=\"selection()\"\n [isAllSelected]=\"isAllSelected()\"\n [(searchText)]=\"searchText\"\n [itemsLength]=\"items().length\"\n [hasMore]=\"aggregation()?.$hasMore ?? false\"\n [searchedItemsLength]=\"searchedItems().length\"\n (cleared)=\"clear()\"\n (applied)=\"apply()\"\n (allSelected)=\"selectAll()\"\n (allUnselected)=\"unselectAll()\"\n (loadedMore)=\"loadMore()\">\n <!-- Relay the host's `label` projection into the panel's `label` slot. When the\n host projects nothing, the local <ng-content> falls back to the icon + display\n (mirrors AggregationPanel's own fallback), so the header is never empty. -->\n <ng-container ngProjectAs=\"label\">\n <ng-content select=\"label\">\n @let labelIcon = aggregation()?.icon;\n @if (labelIcon) {\n <FaIcon [faClass]=\"labelIcon\" class=\"mr-1 shrink-0\" />\n }\n <span class=\"grow truncate\">{{\n aggregation()?.display | syslang | transloco\n }}</span>\n </ng-content>\n </ng-container>\n <div class=\"min-h-0 w-full flex-1 scrollbar-thin overflow-auto pb-3\">\n <ul\n ngTree\n #tree=\"ngTree\"\n [multi]=\"true\"\n [(value)]=\"selected\"\n (valueChange)=\"onSelectionChange($event)\"\n /* Translated like the flat list's own label (aggregation-list.html): this was the raw\n `display`, so the accessible name of a whole facet came out in the source language.\n The pipes apply to the whole nullish chain, `|` being the loosest operator Angular\n parses — no parentheses needed. */\n [attr.aria-label]=\"aggregation()?.display ?? name() | syslang | transloco\"\n class=\"basic-tree m-1\">\n <ng-template\n [ngTemplateOutlet]=\"treeNodes\"\n [ngTemplateOutletContext]=\"{ nodes: nodes(), parent: tree }\" />\n </ul>\n </div>\n</aggregation-panel>\n\n<ng-template #treeNodes let-nodes=\"nodes\" let-parent=\"parent\">\n @for (node of nodes; track node.$path) {\n @let label = node.display ?? node.value ?? \"\";\n <li\n ngTreeItem\n #treeItem=\"ngTreeItem\"\n [parent]=\"parent\"\n [value]=\"node.$path\"\n [label]=\"label\"\n [disabled]=\"node.disabled\"\n [(expanded)]=\"node.$opened\"\n (expandedChange)=\"onExpandedChange(node, $event)\"\n [attr.aria-label]=\"label\"\n [attr.aria-describedby]=\"\n nodeDescription(node) ? descriptionId(node.$path) : null\n \"\n [class]=\"cn('m-0 block w-full p-0', itemStateClass)\"\n (keydown.enter)=\"onTreeItemEnterKey(node, $event)\"\n (keydown.space)=\"onTreeItemSpaceKey(node, $event)\">\n <!-- 2. Ce div prend tout l'espace et intercepte tous les clics de la ligne -->\n <div\n class=\"flex w-full cursor-pointer items-center gap-2 py-0.5 text-sm leading-6\"\n (click)=\"onTreeItemRowClick(node, $event)\"\n (mousedown)=\"$event.stopPropagation()\"\n (pointerdown)=\"$event.stopPropagation()\">\n @if (showCheckbox()) {\n <!-- `inert` keeps the native input out of the tab order and out of hit-testing:\n a role=\"treeitem\" admits no focusable descendant, and the click must reach\n the row handler above. Selection is announced by the <li>'s aria-selected. -->\n <!-- --spacing-xs: 0 kills the gap the checkbox keeps between its box and its\n (here empty) text block. Set as a custom property rather than a utility\n class: the CVA already sets gap-(--spacing-xs), and two same-specificity\n classes would be resolved by stylesheet order, not by us. -->\n <span\n inert\n aria-hidden=\"true\"\n class=\"inline-flex shrink-0\"\n style=\"--spacing-xs: 0\">\n <checkbox\n [checked]=\"treeItem.selected() || node.$selectedVisually || false\"\n [disabled]=\"node.disabled\"\n [class]=\"\n cn(\n 'pointer-events-none',\n (treeItem.selected() || node.$selectedVisually) &&\n 'selected-icon'\n )\n \" />\n </span>\n }\n <!-- Depth indent sits on the chevron, after the checkbox: the checkboxes of every\n level stay flush left (aligned with a flat list's), and since this adds no extra\n flex child, the step between consecutive levels is exactly one indent. -->\n @let depthIndent =\n \"calc(var(--agg-tree-indent, 0.5rem) * \" +\n (treeItem.level() - 1) +\n \")\";\n @if (node.hasChildren) {\n <!-- Expand/collapse affordance for the mouse only, hence a <span> and not a <button>:\n the keyboard already expands with ArrowRight / ArrowLeft, handled by ngTreeItem, and\n a role=\"treeitem\" admits no focusable descendant — so this was a <button> nobody\n could reach, already carrying aria-hidden and tabindex=\"-1\" to say so. Every audit\n reads it as a button with no accessible name (RGAA 7.1, 11.9). Same shape as the leaf\n branch below. -->\n <span\n aria-hidden=\"true\"\n (click)=\"toggleTreeNode(treeItem, $event)\"\n [style.marginInlineStart]=\"depthIndent\"\n class=\"inline-flex cursor-pointer items-center justify-center\">\n <ChevronRightIcon\n [class]=\"\n cn('expand-icon shrink-0', node.$opened && 'rotate-90')\n \" />\n <FolderIcon class=\"shrink-0\" />\n </span>\n } @else {\n <span\n aria-hidden=\"true\"\n [style.marginInlineStart]=\"depthIndent\"\n class=\"inline-flex items-center justify-center\">\n <!-- Reserves the chevron's own width (`.expand-icon` is a styling hook with\n no rule of its own), so a leaf lines up with its parent nodes. -->\n <span class=\"expand-icon w-4 shrink-0\"></span>\n <FileIcon class=\"size-4 shrink-0\" />\n </span>\n }\n @if (resolvedItemTemplate(); as tpl) {\n <span\n class=\"grow truncate select-none\"\n (click)=\"onTreeItemTextClick(node, $event)\">\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{\n $implicit: node,\n field: aggregation()?.column,\n selected: treeItem.selected() ?? false,\n count: node.count,\n name: label,\n searchText: searchText(),\n level: node.$level ?? 0,\n expanded: node.$opened ?? false,\n hasChildren: node.hasChildren ?? false\n }\" />\n </span>\n } @else {\n <!-- ce span est essentiel pour le style -->\n @let appliesOnLabelClick = quickFilter() || applyOnSelect();\n <span\n [class]=\"\n cn(\n 'grow truncate select-none',\n appliesOnLabelClick && 'hover:underline'\n )\n \"\n [title]=\"\n appliesOnLabelClick\n ? ((isTreeItemFiltered(node)\n ? 'filters.removeFilter'\n : 'filters.addFilter'\n ) | transloco) +\n ': ' +\n label\n : label\n \"\n (click)=\"onTreeItemTextClick(node, $event)\">\n @for (\n chunk of label | highlightWord: searchText() : 10;\n track $index\n ) {\n <span [class]=\"{ 'font-bold': chunk.match }\" aria-hidden=\"true\">{{\n chunk.text\n }}</span>\n }\n </span>\n @if (showCount() && node.count > 0) {\n <span class=\"ml-auto px-1 text-xs\" aria-hidden=\"true\">{{\n node.count\n }}</span>\n }\n }\n @let description = nodeDescription(node);\n @if (description) {\n <!-- `hidden`, not `sr-only`: read through aria-describedby only. A visually-hidden\n span would also be counted in the treeitem's name (computed from its content). -->\n <span hidden [id]=\"descriptionId(node.$path)\">{{ description }}</span>\n }\n </div>\n </li>\n @if (node.hasChildren) {\n <!-- No indentation here: it would shift the checkbox too. Depth is applied\n inside the row, after the checkbox, so every checkbox stays flush left. -->\n <!-- The <ul> sits INSIDE the deferred content, not around it: `ngTreeItemGroup` only\n instantiates its view when the node opens, so a <ul> declared outside stayed in the DOM,\n empty, for every collapsed node — a structural tag with nothing to structure (RGAA 8.9).\n The @if cannot move onto the <ul> either: the directive registers itself with its tree\n item on init and has to exist for as long as the item does. -->\n <ng-template\n ngTreeItemGroup\n [ownedBy]=\"treeItem\"\n #group=\"ngTreeItemGroup\">\n <ul role=\"group\">\n <ng-template\n [ngTemplateOutlet]=\"treeNodes\"\n [ngTemplateOutletContext]=\"{ nodes: node.items, parent: group }\" />\n </ul>\n </ng-template>\n }\n }\n</ng-template>\n"
|
|
25262
25366
|
}]
|
|
25263
25367
|
}],
|
|
25264
25368
|
ctorParameters: () => [],
|
|
@@ -25915,7 +26019,7 @@ var AggregationListComponent = class AggregationListComponent {
|
|
|
25915
26019
|
},
|
|
25916
26020
|
host: {
|
|
25917
26021
|
listeners: { "keydown.enter": "onHostEnterKey($event)" },
|
|
25918
|
-
properties: { "class": "cn(\"
|
|
26022
|
+
properties: { "class": "cn(\"flex h-[inherit] max-h-[inherit] flex-col\", class(), (isMissing() || (hideWhenEmpty() && isEmpty())) && \"hidden\")" }
|
|
25919
26023
|
},
|
|
25920
26024
|
queries: [{
|
|
25921
26025
|
propertyName: "itemDirective",
|
|
@@ -25947,7 +26051,7 @@ var AggregationListComponent = class AggregationListComponent {
|
|
|
25947
26051
|
}
|
|
25948
26052
|
],
|
|
25949
26053
|
ngImport: i0,
|
|
25950
|
-
template: "@if (aggregation()?.isTree) {\n <div class=\"p-2 text-sm text-red-500\">\n <triangle-alert-icon class=\"mr-1 shrink-0\" />\n The aggregation component no longer supports tree aggregations. Please use\n the <AggregationTree /> component instead.\n </div>\n}\n<aggregation-panel\n [id]=\"id()\"\n [collapsible]=\"collapsible()\"\n [collapsed]=\"collapsed()\"\n [isEmpty]=\"isEmpty()\"\n [isDate]=\"isDate()\"\n [aggregation]=\"aggregation()\"\n [showFiltersCount]=\"showFiltersCount()\"\n [filtersCount]=\"filtersCount()\"\n [hasFilters]=\"hasFilters()\"\n [selection]=\"selection()\"\n [isAllSelected]=\"isAllSelected()\"\n [(searchText)]=\"searchText\"\n [itemsLength]=\"items().length\"\n [hasMore]=\"aggregation()?.$hasMore ?? false\"\n [searchedItemsLength]=\"searchedItems().length\"\n (cleared)=\"clear()\"\n (applied)=\"apply()\"\n (allSelected)=\"selectAll()\"\n (allUnselected)=\"unselectAll()\"\n (loadedMore)=\"loadMore()\">\n <!-- Relay the host's `label` projection into the panel's `label` slot. When the\n host projects nothing, the local <ng-content> falls back to the icon + display\n (mirrors AggregationPanel's own fallback), so the header is never empty. -->\n <ng-container ngProjectAs=\"label\">\n <ng-content select=\"label\">\n @let labelIcon = aggregation()?.icon;\n @if (labelIcon) {\n <FaIcon [faClass]=\"labelIcon\" class=\"mr-1 shrink-0\" />\n }\n <span class=\"grow truncate\">{{\n aggregation()?.display | syslang | transloco\n }}</span>\n </ng-content>\n </ng-container>\n <div\n #scrollElement\n class=\"
|
|
26054
|
+
template: "@if (aggregation()?.isTree) {\n <div class=\"p-2 text-sm text-red-500\">\n <triangle-alert-icon class=\"mr-1 shrink-0\" />\n The aggregation component no longer supports tree aggregations. Please use\n the <AggregationTree /> component instead.\n </div>\n}\n<aggregation-panel\n [id]=\"id()\"\n [collapsible]=\"collapsible()\"\n [collapsed]=\"collapsed()\"\n [isEmpty]=\"isEmpty()\"\n [isDate]=\"isDate()\"\n [aggregation]=\"aggregation()\"\n [showFiltersCount]=\"showFiltersCount()\"\n [filtersCount]=\"filtersCount()\"\n [hasFilters]=\"hasFilters()\"\n [selection]=\"selection()\"\n [isAllSelected]=\"isAllSelected()\"\n [(searchText)]=\"searchText\"\n [itemsLength]=\"items().length\"\n [hasMore]=\"aggregation()?.$hasMore ?? false\"\n [searchedItemsLength]=\"searchedItems().length\"\n (cleared)=\"clear()\"\n (applied)=\"apply()\"\n (allSelected)=\"selectAll()\"\n (allUnselected)=\"unselectAll()\"\n (loadedMore)=\"loadMore()\">\n <!-- Relay the host's `label` projection into the panel's `label` slot. When the\n host projects nothing, the local <ng-content> falls back to the icon + display\n (mirrors AggregationPanel's own fallback), so the header is never empty. -->\n <ng-container ngProjectAs=\"label\">\n <ng-content select=\"label\">\n @let labelIcon = aggregation()?.icon;\n @if (labelIcon) {\n <FaIcon [faClass]=\"labelIcon\" class=\"mr-1 shrink-0\" />\n }\n <span class=\"grow truncate\">{{\n aggregation()?.display | syslang | transloco\n }}</span>\n </ng-content>\n </ng-container>\n <div\n #scrollElement\n class=\"min-h-0 w-full flex-1 scrollbar-thin overflow-auto px-1 pt-1 pb-3\">\n <div\n ngListbox\n multi\n selectionMode=\"explicit\"\n [value]=\"selectedValues()\"\n (valueChange)=\"syncListboxValue($event)\"\n [wrap]=\"false\"\n [softDisabled]=\"false\"\n class=\"relative w-full\"\n [style.height]=\"virtualizer.getTotalSize() + 'px'\"\n role=\"listbox\"\n aria-multiselectable=\"true\"\n [attr.aria-label]=\"aggregation()?.display | syslang | transloco\">\n @for (vItem of virtualizer.getVirtualItems(); track vItem.index) {\n @let item = items()[vItem.index];\n @let description = rowDescription(item);\n <div\n #row\n ngOption\n [attr.aria-describedby]=\"\n description ? descriptionId(vItem.index) : null\n \"\n [attr.data-index]=\"vItem.index\"\n [value]=\"item.value\"\n [disabled]=\"item.count === 0\"\n [class]=\"cn('absolute w-full', menuItemBaseClass)\"\n (keydown.enter)=\"onOptionEnterKey(item, $event)\"\n (keydown.space)=\"\n onListItemRowClick(item, $event); $event.preventDefault()\n \"\n [style.transform]=\"'translateY(' + vItem.start + 'px)'\"\n role=\"option\">\n <ng-container\n [ngTemplateOutlet]=\"listItemTpl\"\n [ngTemplateOutletContext]=\"{\n $implicit: item,\n field: aggregation()?.column\n }\">\n </ng-container>\n @if (description) {\n <!-- `hidden`, not `sr-only`: read through aria-describedby only. A visually-hidden\n span would also be counted in the option's name (computed from its content). -->\n <span hidden [id]=\"descriptionId(vItem.index)\">{{\n description\n }}</span>\n }\n </div>\n }\n </div>\n </div>\n</aggregation-panel>\n\n<ng-template #listItemTpl let-item let-field=\"field\">\n <a\n [attr.aria-label]=\"listItemName(item) | syslang\"\n [class]=\"\n cn(\n '-m-1.5 flex min-w-0 grow items-center gap-2 leading-6',\n item.count === 0 && 'pointer-events-none text-(--font-neutral-muted)'\n )\n \"\n (click)=\"onListItemRowClick(item, $event)\">\n @if (showCheckbox()) {\n <!-- `inert` keeps the native input out of the tab order and out of hit-testing:\n keyboard navigation belongs to ngListbox/ngOption (roving tabindex), the\n selection is already exposed by role=\"option\" + aria-selected, and the click\n must reach the <a> above. Same treatment as the tree.\n --spacing-xs: 0 kills the gap the checkbox keeps between its box and its\n (here empty) text block. -->\n <span\n inert\n aria-hidden=\"true\"\n class=\"inline-flex shrink-0\"\n style=\"--spacing-xs: 0\">\n <checkbox\n [checked]=\"item.$selected ?? false\"\n [disabled]=\"item.count === 0\"\n [class]=\"'pointer-events-none'\" />\n </span>\n }\n @if (resolvedItemTemplate(); as tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{\n $implicit: item,\n field: field,\n selected: item.$selected ?? false,\n count: item.count,\n name: (listItemName(item) | syslang) ?? '',\n searchText: searchText()\n }\" />\n } @else {\n @let icon = $any(item).icon;\n @if (icon) {\n <FaIcon\n [faClass]=\"icon\"\n class=\"shrink-0 self-center justify-self-center\" />\n }\n @let appliesOnLabelClick = quickFilter() || applyOnSelect();\n <span\n [class]=\"\n cn(\n 'line-clamp-1 cursor-pointer break-all text-ellipsis select-none',\n appliesOnLabelClick && 'hover:underline'\n )\n \"\n [title]=\"\n appliesOnLabelClick\n ? ((isListItemFiltered(item, field)\n ? 'filters.removeFilter'\n : 'filters.addFilter'\n ) | transloco) +\n ': ' +\n (listItemName(item) | syslang)\n : (listItemName(item) | syslang)\n \"\n (click)=\"onListItemTextClick(item, $event)\">\n @for (\n chunk of (listItemName(item) | syslang) ?? \"\"\n | highlightWord: searchText() : 10;\n track $index\n ) {\n <span [class]=\"{ 'font-bold': chunk.match }\" aria-hidden=\"true\">{{\n chunk.text\n }}</span>\n }\n </span>\n @if (showCount() && item.count > 0) {\n <span class=\"ml-auto px-1 text-xs empty:hidden\" aria-hidden=\"true\">{{\n item.count\n }}</span>\n }\n }\n </a>\n</ng-template>\n",
|
|
25951
26055
|
dependencies: [
|
|
25952
26056
|
{
|
|
25953
26057
|
kind: "directive",
|
|
@@ -26088,10 +26192,10 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
26088
26192
|
CheckboxComponent
|
|
26089
26193
|
],
|
|
26090
26194
|
host: {
|
|
26091
|
-
"[class]": "cn(\"
|
|
26195
|
+
"[class]": "cn(\"flex h-[inherit] max-h-[inherit] flex-col\", class(), (isMissing() || (hideWhenEmpty() && isEmpty())) && \"hidden\")",
|
|
26092
26196
|
"(keydown.enter)": "onHostEnterKey($event)"
|
|
26093
26197
|
},
|
|
26094
|
-
template: "@if (aggregation()?.isTree) {\n <div class=\"p-2 text-sm text-red-500\">\n <triangle-alert-icon class=\"mr-1 shrink-0\" />\n The aggregation component no longer supports tree aggregations. Please use\n the <AggregationTree /> component instead.\n </div>\n}\n<aggregation-panel\n [id]=\"id()\"\n [collapsible]=\"collapsible()\"\n [collapsed]=\"collapsed()\"\n [isEmpty]=\"isEmpty()\"\n [isDate]=\"isDate()\"\n [aggregation]=\"aggregation()\"\n [showFiltersCount]=\"showFiltersCount()\"\n [filtersCount]=\"filtersCount()\"\n [hasFilters]=\"hasFilters()\"\n [selection]=\"selection()\"\n [isAllSelected]=\"isAllSelected()\"\n [(searchText)]=\"searchText\"\n [itemsLength]=\"items().length\"\n [hasMore]=\"aggregation()?.$hasMore ?? false\"\n [searchedItemsLength]=\"searchedItems().length\"\n (cleared)=\"clear()\"\n (applied)=\"apply()\"\n (allSelected)=\"selectAll()\"\n (allUnselected)=\"unselectAll()\"\n (loadedMore)=\"loadMore()\">\n <!-- Relay the host's `label` projection into the panel's `label` slot. When the\n host projects nothing, the local <ng-content> falls back to the icon + display\n (mirrors AggregationPanel's own fallback), so the header is never empty. -->\n <ng-container ngProjectAs=\"label\">\n <ng-content select=\"label\">\n @let labelIcon = aggregation()?.icon;\n @if (labelIcon) {\n <FaIcon [faClass]=\"labelIcon\" class=\"mr-1 shrink-0\" />\n }\n <span class=\"grow truncate\">{{\n aggregation()?.display | syslang | transloco\n }}</span>\n </ng-content>\n </ng-container>\n <div\n #scrollElement\n class=\"
|
|
26198
|
+
template: "@if (aggregation()?.isTree) {\n <div class=\"p-2 text-sm text-red-500\">\n <triangle-alert-icon class=\"mr-1 shrink-0\" />\n The aggregation component no longer supports tree aggregations. Please use\n the <AggregationTree /> component instead.\n </div>\n}\n<aggregation-panel\n [id]=\"id()\"\n [collapsible]=\"collapsible()\"\n [collapsed]=\"collapsed()\"\n [isEmpty]=\"isEmpty()\"\n [isDate]=\"isDate()\"\n [aggregation]=\"aggregation()\"\n [showFiltersCount]=\"showFiltersCount()\"\n [filtersCount]=\"filtersCount()\"\n [hasFilters]=\"hasFilters()\"\n [selection]=\"selection()\"\n [isAllSelected]=\"isAllSelected()\"\n [(searchText)]=\"searchText\"\n [itemsLength]=\"items().length\"\n [hasMore]=\"aggregation()?.$hasMore ?? false\"\n [searchedItemsLength]=\"searchedItems().length\"\n (cleared)=\"clear()\"\n (applied)=\"apply()\"\n (allSelected)=\"selectAll()\"\n (allUnselected)=\"unselectAll()\"\n (loadedMore)=\"loadMore()\">\n <!-- Relay the host's `label` projection into the panel's `label` slot. When the\n host projects nothing, the local <ng-content> falls back to the icon + display\n (mirrors AggregationPanel's own fallback), so the header is never empty. -->\n <ng-container ngProjectAs=\"label\">\n <ng-content select=\"label\">\n @let labelIcon = aggregation()?.icon;\n @if (labelIcon) {\n <FaIcon [faClass]=\"labelIcon\" class=\"mr-1 shrink-0\" />\n }\n <span class=\"grow truncate\">{{\n aggregation()?.display | syslang | transloco\n }}</span>\n </ng-content>\n </ng-container>\n <div\n #scrollElement\n class=\"min-h-0 w-full flex-1 scrollbar-thin overflow-auto px-1 pt-1 pb-3\">\n <div\n ngListbox\n multi\n selectionMode=\"explicit\"\n [value]=\"selectedValues()\"\n (valueChange)=\"syncListboxValue($event)\"\n [wrap]=\"false\"\n [softDisabled]=\"false\"\n class=\"relative w-full\"\n [style.height]=\"virtualizer.getTotalSize() + 'px'\"\n role=\"listbox\"\n aria-multiselectable=\"true\"\n [attr.aria-label]=\"aggregation()?.display | syslang | transloco\">\n @for (vItem of virtualizer.getVirtualItems(); track vItem.index) {\n @let item = items()[vItem.index];\n @let description = rowDescription(item);\n <div\n #row\n ngOption\n [attr.aria-describedby]=\"\n description ? descriptionId(vItem.index) : null\n \"\n [attr.data-index]=\"vItem.index\"\n [value]=\"item.value\"\n [disabled]=\"item.count === 0\"\n [class]=\"cn('absolute w-full', menuItemBaseClass)\"\n (keydown.enter)=\"onOptionEnterKey(item, $event)\"\n (keydown.space)=\"\n onListItemRowClick(item, $event); $event.preventDefault()\n \"\n [style.transform]=\"'translateY(' + vItem.start + 'px)'\"\n role=\"option\">\n <ng-container\n [ngTemplateOutlet]=\"listItemTpl\"\n [ngTemplateOutletContext]=\"{\n $implicit: item,\n field: aggregation()?.column\n }\">\n </ng-container>\n @if (description) {\n <!-- `hidden`, not `sr-only`: read through aria-describedby only. A visually-hidden\n span would also be counted in the option's name (computed from its content). -->\n <span hidden [id]=\"descriptionId(vItem.index)\">{{\n description\n }}</span>\n }\n </div>\n }\n </div>\n </div>\n</aggregation-panel>\n\n<ng-template #listItemTpl let-item let-field=\"field\">\n <a\n [attr.aria-label]=\"listItemName(item) | syslang\"\n [class]=\"\n cn(\n '-m-1.5 flex min-w-0 grow items-center gap-2 leading-6',\n item.count === 0 && 'pointer-events-none text-(--font-neutral-muted)'\n )\n \"\n (click)=\"onListItemRowClick(item, $event)\">\n @if (showCheckbox()) {\n <!-- `inert` keeps the native input out of the tab order and out of hit-testing:\n keyboard navigation belongs to ngListbox/ngOption (roving tabindex), the\n selection is already exposed by role=\"option\" + aria-selected, and the click\n must reach the <a> above. Same treatment as the tree.\n --spacing-xs: 0 kills the gap the checkbox keeps between its box and its\n (here empty) text block. -->\n <span\n inert\n aria-hidden=\"true\"\n class=\"inline-flex shrink-0\"\n style=\"--spacing-xs: 0\">\n <checkbox\n [checked]=\"item.$selected ?? false\"\n [disabled]=\"item.count === 0\"\n [class]=\"'pointer-events-none'\" />\n </span>\n }\n @if (resolvedItemTemplate(); as tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{\n $implicit: item,\n field: field,\n selected: item.$selected ?? false,\n count: item.count,\n name: (listItemName(item) | syslang) ?? '',\n searchText: searchText()\n }\" />\n } @else {\n @let icon = $any(item).icon;\n @if (icon) {\n <FaIcon\n [faClass]=\"icon\"\n class=\"shrink-0 self-center justify-self-center\" />\n }\n @let appliesOnLabelClick = quickFilter() || applyOnSelect();\n <span\n [class]=\"\n cn(\n 'line-clamp-1 cursor-pointer break-all text-ellipsis select-none',\n appliesOnLabelClick && 'hover:underline'\n )\n \"\n [title]=\"\n appliesOnLabelClick\n ? ((isListItemFiltered(item, field)\n ? 'filters.removeFilter'\n : 'filters.addFilter'\n ) | transloco) +\n ': ' +\n (listItemName(item) | syslang)\n : (listItemName(item) | syslang)\n \"\n (click)=\"onListItemTextClick(item, $event)\">\n @for (\n chunk of (listItemName(item) | syslang) ?? \"\"\n | highlightWord: searchText() : 10;\n track $index\n ) {\n <span [class]=\"{ 'font-bold': chunk.match }\" aria-hidden=\"true\">{{\n chunk.text\n }}</span>\n }\n </span>\n @if (showCount() && item.count > 0) {\n <span class=\"ml-auto px-1 text-xs empty:hidden\" aria-hidden=\"true\">{{\n item.count\n }}</span>\n }\n }\n </a>\n</ng-template>\n"
|
|
26095
26199
|
}]
|
|
26096
26200
|
}],
|
|
26097
26201
|
ctorParameters: () => [],
|
|
@@ -26538,7 +26642,7 @@ var AggregationComponent = class AggregationComponent {
|
|
|
26538
26642
|
selectionChange: "selectionChange",
|
|
26539
26643
|
filtersChange: "filtersChange"
|
|
26540
26644
|
},
|
|
26541
|
-
host: { properties: { "class": "cn(\"
|
|
26645
|
+
host: { properties: { "class": "cn(\"flex h-[inherit] max-h-[inherit] flex-col\",class(), (isMissing() || (hideWhenEmpty() && isEmpty())) && \"hidden\")" } },
|
|
26542
26646
|
queries: [{
|
|
26543
26647
|
propertyName: "itemDirective",
|
|
26544
26648
|
first: true,
|
|
@@ -26574,6 +26678,7 @@ var AggregationComponent = class AggregationComponent {
|
|
|
26574
26678
|
@switch (resolvedType()) {
|
|
26575
26679
|
@case ("date") {
|
|
26576
26680
|
<AggregationDate
|
|
26681
|
+
class="min-h-0 flex-1"
|
|
26577
26682
|
[id]="id()"
|
|
26578
26683
|
[name]="name()"
|
|
26579
26684
|
[column]="column()"
|
|
@@ -26595,6 +26700,7 @@ var AggregationComponent = class AggregationComponent {
|
|
|
26595
26700
|
}
|
|
26596
26701
|
@case ("tree") {
|
|
26597
26702
|
<AggregationTree
|
|
26703
|
+
class="min-h-0 w-auto flex-1"
|
|
26598
26704
|
[id]="id()"
|
|
26599
26705
|
[name]="name()"
|
|
26600
26706
|
[column]="column()"
|
|
@@ -26621,6 +26727,7 @@ var AggregationComponent = class AggregationComponent {
|
|
|
26621
26727
|
}
|
|
26622
26728
|
@default {
|
|
26623
26729
|
<AggregationList
|
|
26730
|
+
class="min-h-0 flex-1"
|
|
26624
26731
|
[id]="id()"
|
|
26625
26732
|
[name]="name()"
|
|
26626
26733
|
[column]="column()"
|
|
@@ -26720,6 +26827,7 @@ var AggregationComponent = class AggregationComponent {
|
|
|
26720
26827
|
type: AggregationDateComponent,
|
|
26721
26828
|
selector: "aggregation-date, AggregationDate, aggregationdate",
|
|
26722
26829
|
inputs: [
|
|
26830
|
+
"class",
|
|
26723
26831
|
"name",
|
|
26724
26832
|
"column",
|
|
26725
26833
|
"id",
|
|
@@ -26767,6 +26875,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
26767
26875
|
@switch (resolvedType()) {
|
|
26768
26876
|
@case ("date") {
|
|
26769
26877
|
<AggregationDate
|
|
26878
|
+
class="min-h-0 flex-1"
|
|
26770
26879
|
[id]="id()"
|
|
26771
26880
|
[name]="name()"
|
|
26772
26881
|
[column]="column()"
|
|
@@ -26788,6 +26897,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
26788
26897
|
}
|
|
26789
26898
|
@case ("tree") {
|
|
26790
26899
|
<AggregationTree
|
|
26900
|
+
class="min-h-0 w-auto flex-1"
|
|
26791
26901
|
[id]="id()"
|
|
26792
26902
|
[name]="name()"
|
|
26793
26903
|
[column]="column()"
|
|
@@ -26814,6 +26924,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
26814
26924
|
}
|
|
26815
26925
|
@default {
|
|
26816
26926
|
<AggregationList
|
|
26927
|
+
class="min-h-0 flex-1"
|
|
26817
26928
|
[id]="id()"
|
|
26818
26929
|
[name]="name()"
|
|
26819
26930
|
[column]="column()"
|
|
@@ -26839,7 +26950,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
26839
26950
|
}
|
|
26840
26951
|
}
|
|
26841
26952
|
`,
|
|
26842
|
-
host: { "[class]": "cn(\"
|
|
26953
|
+
host: { "[class]": "cn(\"flex h-[inherit] max-h-[inherit] flex-col\",class(), (isMissing() || (hideWhenEmpty() && isEmpty())) && \"hidden\")" }
|
|
26843
26954
|
}]
|
|
26844
26955
|
}],
|
|
26845
26956
|
propDecorators: {
|
|
@@ -27699,6 +27810,10 @@ var FilterButtonComponent = class FilterButtonComponent {
|
|
|
27699
27810
|
...ngDevMode ? { debugName: "expandedLevel" } : /* istanbul ignore next */ {},
|
|
27700
27811
|
transform: numberAttribute
|
|
27701
27812
|
});
|
|
27813
|
+
overflowed = input(false, {
|
|
27814
|
+
...ngDevMode ? { debugName: "overflowed" } : /* istanbul ignore next */ {},
|
|
27815
|
+
transform: booleanAttribute
|
|
27816
|
+
});
|
|
27702
27817
|
variant = signal("tertiary", ...ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []);
|
|
27703
27818
|
filter = signal({
|
|
27704
27819
|
name: "",
|
|
@@ -27713,6 +27828,7 @@ var FilterButtonComponent = class FilterButtonComponent {
|
|
|
27713
27828
|
popoverId = `filter-popover-${popoverUid++}`;
|
|
27714
27829
|
popoverRef = viewChild(PopoverDirective, ...ngDevMode ? [{ debugName: "popoverRef" }] : /* istanbul ignore next */ []);
|
|
27715
27830
|
isOpen = computed(() => this.popoverRef()?.state() === "open", ...ngDevMode ? [{ debugName: "isOpen" }] : /* istanbul ignore next */ []);
|
|
27831
|
+
toolbar = inject(Toolbar, { optional: true });
|
|
27716
27832
|
nativeElement = inject(ElementRef).nativeElement;
|
|
27717
27833
|
aggregationsStore = inject(AggregationsStore);
|
|
27718
27834
|
queryParamsStore = inject(QueryParamsStore);
|
|
@@ -27825,6 +27941,13 @@ var FilterButtonComponent = class FilterButtonComponent {
|
|
|
27825
27941
|
isSignal: true,
|
|
27826
27942
|
isRequired: false,
|
|
27827
27943
|
transformFunction: null
|
|
27944
|
+
},
|
|
27945
|
+
overflowed: {
|
|
27946
|
+
classPropertyName: "overflowed",
|
|
27947
|
+
publicName: "overflowed",
|
|
27948
|
+
isSignal: true,
|
|
27949
|
+
isRequired: false,
|
|
27950
|
+
transformFunction: null
|
|
27828
27951
|
}
|
|
27829
27952
|
},
|
|
27830
27953
|
host: {
|
|
@@ -27846,13 +27969,7 @@ var FilterButtonComponent = class FilterButtonComponent {
|
|
|
27846
27969
|
}],
|
|
27847
27970
|
ngImport: i0,
|
|
27848
27971
|
template: `
|
|
27849
|
-
<
|
|
27850
|
-
[variant]="variant()"
|
|
27851
|
-
[attr.popovertarget]="popoverId"
|
|
27852
|
-
[class]="isOpen() ? 'border border-(--stroke-neutral-dark)/50' : ''"
|
|
27853
|
-
[attr.data-disabled]="filter().disabled"
|
|
27854
|
-
[disabled]="filter().disabled || null"
|
|
27855
|
-
>
|
|
27972
|
+
<ng-template #label>
|
|
27856
27973
|
<!-- display the filter icon if set -->
|
|
27857
27974
|
@let icon = filter().icon;
|
|
27858
27975
|
@if (icon) {
|
|
@@ -27872,7 +27989,35 @@ var FilterButtonComponent = class FilterButtonComponent {
|
|
|
27872
27989
|
@if (filter().count > 1) {
|
|
27873
27990
|
<Badge variant="number" fill="secondary" scheme="sage" size="xs">+{{ filter().count - 1 }}</Badge>
|
|
27874
27991
|
}
|
|
27875
|
-
</
|
|
27992
|
+
</ng-template>
|
|
27993
|
+
|
|
27994
|
+
@if (toolbar) {
|
|
27995
|
+
<!-- Inside a toolbar the BUTTON is the roving widget, not the host: the host is an element with
|
|
27996
|
+
no role of its own, so making it the widget gave two tab stops — an inert host that the
|
|
27997
|
+
roving focused, then this button with its own stop. A native disabled attribute would also make a
|
|
27998
|
+
widget unfocusable, so the toolbar's own disabled input (soft: still focusable, aria-disabled)
|
|
27999
|
+
takes over and the popover trigger is simply not wired. The same disabled state removes a filter
|
|
28000
|
+
hidden by the overflow manager (display: none) from the roving: arrow keys must not spend
|
|
28001
|
+
presses on filters nobody can see. -->
|
|
28002
|
+
<button
|
|
28003
|
+
ngToolbarWidget
|
|
28004
|
+
[variant]="variant()"
|
|
28005
|
+
[attr.popovertarget]="filter().disabled ? null : popoverId"
|
|
28006
|
+
[class]="isOpen() ? 'border border-(--stroke-neutral-dark)/50' : ''"
|
|
28007
|
+
[attr.data-disabled]="filter().disabled"
|
|
28008
|
+
[disabled]="filter().disabled || overflowed()">
|
|
28009
|
+
<ng-container *ngTemplateOutlet="label" />
|
|
28010
|
+
</button>
|
|
28011
|
+
} @else {
|
|
28012
|
+
<button
|
|
28013
|
+
[variant]="variant()"
|
|
28014
|
+
[attr.popovertarget]="popoverId"
|
|
28015
|
+
[class]="isOpen() ? 'border border-(--stroke-neutral-dark)/50' : ''"
|
|
28016
|
+
[attr.data-disabled]="filter().disabled"
|
|
28017
|
+
[disabled]="filter().disabled || null">
|
|
28018
|
+
<ng-container *ngTemplateOutlet="label" />
|
|
28019
|
+
</button>
|
|
28020
|
+
}
|
|
27876
28021
|
|
|
27877
28022
|
<!-- Native HTML Popover (top-layer). The popover content stays a DOM
|
|
27878
28023
|
descendant of the surrounding @angular/aria toolbar, so pointer/click
|
|
@@ -27886,8 +28031,10 @@ var FilterButtonComponent = class FilterButtonComponent {
|
|
|
27886
28031
|
trigger-width matching so the panel sizes to its content. overflow-hidden
|
|
27887
28032
|
resets the browser's default overflow:auto on [popover] elements, which
|
|
27888
28033
|
would otherwise scroll on its own in addition to Aggregation's own
|
|
27889
|
-
|
|
27890
|
-
|
|
28034
|
+
facet list (a double scrollbar) once its fit-content height would
|
|
28035
|
+
otherwise exceed the viewport. The facet list is the only thing that
|
|
28036
|
+
scrolls: the facet itself is capped by the room the popover has (see
|
|
28037
|
+
below). -->
|
|
27891
28038
|
<div
|
|
27892
28039
|
popover
|
|
27893
28040
|
[id]="popoverId"
|
|
@@ -27905,21 +28052,23 @@ var FilterButtonComponent = class FilterButtonComponent {
|
|
|
27905
28052
|
rings (2px outlines) of the facet header and its buttons sit flush against the wrapper's edges —
|
|
27906
28053
|
they were cut off on three sides. The 4px of padding gives them room, the matching negative
|
|
27907
28054
|
margin leaves the layout unchanged. Width and max-height grow by the 0.5rem of padding
|
|
27908
|
-
(15.5rem = the former w-60 + 0.5rem
|
|
27909
|
-
|
|
27910
|
-
|
|
27911
|
-
|
|
27912
|
-
|
|
27913
|
-
|
|
27914
|
-
|
|
27915
|
-
1.5rem subtracted is this popover's own vertical padding (p-3), which
|
|
27916
|
-
same available space
|
|
27917
|
-
|
|
28055
|
+
(15.5rem = the former w-60 + 0.5rem) because box-sizing is border-box here: the facet keeps
|
|
28056
|
+
its 15rem and the popover its size. The wrapper no longer scrolls (and no longer clips the
|
|
28057
|
+
rings): the facet's own list is the one scrollbar. -->
|
|
28058
|
+
<!-- The facet is capped by the smaller of two heights: its comfortable size (19 lines of list +
|
|
28059
|
+
7rem of header, search box and paddings), and the room the popover really has.
|
|
28060
|
+
size() (added to injectPopover) exposes that room, in the chosen direction, as the
|
|
28061
|
+
--popover-available-height CSS var — flip()/shift() alone only reposition the popover, they
|
|
28062
|
+
never shrink it. The 1.5rem subtracted is this popover's own vertical padding (p-3), which
|
|
28063
|
+
eats into that same available space (this wrapper's p-1 / -m-1 cancel out). The facet is a
|
|
28064
|
+
flex column whose list is min-h-0 flex-1, so it is the list that shrinks and scrolls — a
|
|
28065
|
+
capped wrapper with overflow-y-auto around it would add a second, outer scrollbar. -->
|
|
28066
|
+
<div class="-m-1 w-[15.5rem] p-1">
|
|
27918
28067
|
@let name = filter().name;
|
|
27919
28068
|
@let column = filter().column;
|
|
27920
28069
|
@if (name) {
|
|
27921
28070
|
<Aggregation
|
|
27922
|
-
class="
|
|
28071
|
+
class="w-full max-h-[min(calc(19lh+7rem),calc(var(--popover-available-height,55vh)_-_1.5rem))]"
|
|
27923
28072
|
id="filter-{{ filter().column }}"
|
|
27924
28073
|
[name]="name"
|
|
27925
28074
|
[column]="column"
|
|
@@ -27938,6 +28087,23 @@ var FilterButtonComponent = class FilterButtonComponent {
|
|
|
27938
28087
|
`,
|
|
27939
28088
|
isInline: true,
|
|
27940
28089
|
dependencies: [
|
|
28090
|
+
{
|
|
28091
|
+
kind: "directive",
|
|
28092
|
+
type: NgTemplateOutlet,
|
|
28093
|
+
selector: "[ngTemplateOutlet]",
|
|
28094
|
+
inputs: [
|
|
28095
|
+
"ngTemplateOutletContext",
|
|
28096
|
+
"ngTemplateOutlet",
|
|
28097
|
+
"ngTemplateOutletInjector"
|
|
28098
|
+
]
|
|
28099
|
+
},
|
|
28100
|
+
{
|
|
28101
|
+
kind: "directive",
|
|
28102
|
+
type: ToolbarWidget,
|
|
28103
|
+
selector: "[ngToolbarWidget]",
|
|
28104
|
+
inputs: ["id", "disabled"],
|
|
28105
|
+
exportAs: ["ngToolbarWidget"]
|
|
28106
|
+
},
|
|
27941
28107
|
{
|
|
27942
28108
|
kind: "directive",
|
|
27943
28109
|
type: ButtonComponent,
|
|
@@ -28045,6 +28211,8 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
28045
28211
|
args: [{
|
|
28046
28212
|
selector: "filter-button, FilterButton",
|
|
28047
28213
|
imports: [
|
|
28214
|
+
NgTemplateOutlet,
|
|
28215
|
+
ToolbarWidget,
|
|
28048
28216
|
ButtonComponent,
|
|
28049
28217
|
PopoverDirective,
|
|
28050
28218
|
OperatorPipe,
|
|
@@ -28055,13 +28223,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
28055
28223
|
FaIconComponent
|
|
28056
28224
|
],
|
|
28057
28225
|
template: `
|
|
28058
|
-
<
|
|
28059
|
-
[variant]="variant()"
|
|
28060
|
-
[attr.popovertarget]="popoverId"
|
|
28061
|
-
[class]="isOpen() ? 'border border-(--stroke-neutral-dark)/50' : ''"
|
|
28062
|
-
[attr.data-disabled]="filter().disabled"
|
|
28063
|
-
[disabled]="filter().disabled || null"
|
|
28064
|
-
>
|
|
28226
|
+
<ng-template #label>
|
|
28065
28227
|
<!-- display the filter icon if set -->
|
|
28066
28228
|
@let icon = filter().icon;
|
|
28067
28229
|
@if (icon) {
|
|
@@ -28081,7 +28243,35 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
28081
28243
|
@if (filter().count > 1) {
|
|
28082
28244
|
<Badge variant="number" fill="secondary" scheme="sage" size="xs">+{{ filter().count - 1 }}</Badge>
|
|
28083
28245
|
}
|
|
28084
|
-
</
|
|
28246
|
+
</ng-template>
|
|
28247
|
+
|
|
28248
|
+
@if (toolbar) {
|
|
28249
|
+
<!-- Inside a toolbar the BUTTON is the roving widget, not the host: the host is an element with
|
|
28250
|
+
no role of its own, so making it the widget gave two tab stops — an inert host that the
|
|
28251
|
+
roving focused, then this button with its own stop. A native disabled attribute would also make a
|
|
28252
|
+
widget unfocusable, so the toolbar's own disabled input (soft: still focusable, aria-disabled)
|
|
28253
|
+
takes over and the popover trigger is simply not wired. The same disabled state removes a filter
|
|
28254
|
+
hidden by the overflow manager (display: none) from the roving: arrow keys must not spend
|
|
28255
|
+
presses on filters nobody can see. -->
|
|
28256
|
+
<button
|
|
28257
|
+
ngToolbarWidget
|
|
28258
|
+
[variant]="variant()"
|
|
28259
|
+
[attr.popovertarget]="filter().disabled ? null : popoverId"
|
|
28260
|
+
[class]="isOpen() ? 'border border-(--stroke-neutral-dark)/50' : ''"
|
|
28261
|
+
[attr.data-disabled]="filter().disabled"
|
|
28262
|
+
[disabled]="filter().disabled || overflowed()">
|
|
28263
|
+
<ng-container *ngTemplateOutlet="label" />
|
|
28264
|
+
</button>
|
|
28265
|
+
} @else {
|
|
28266
|
+
<button
|
|
28267
|
+
[variant]="variant()"
|
|
28268
|
+
[attr.popovertarget]="popoverId"
|
|
28269
|
+
[class]="isOpen() ? 'border border-(--stroke-neutral-dark)/50' : ''"
|
|
28270
|
+
[attr.data-disabled]="filter().disabled"
|
|
28271
|
+
[disabled]="filter().disabled || null">
|
|
28272
|
+
<ng-container *ngTemplateOutlet="label" />
|
|
28273
|
+
</button>
|
|
28274
|
+
}
|
|
28085
28275
|
|
|
28086
28276
|
<!-- Native HTML Popover (top-layer). The popover content stays a DOM
|
|
28087
28277
|
descendant of the surrounding @angular/aria toolbar, so pointer/click
|
|
@@ -28095,8 +28285,10 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
28095
28285
|
trigger-width matching so the panel sizes to its content. overflow-hidden
|
|
28096
28286
|
resets the browser's default overflow:auto on [popover] elements, which
|
|
28097
28287
|
would otherwise scroll on its own in addition to Aggregation's own
|
|
28098
|
-
|
|
28099
|
-
|
|
28288
|
+
facet list (a double scrollbar) once its fit-content height would
|
|
28289
|
+
otherwise exceed the viewport. The facet list is the only thing that
|
|
28290
|
+
scrolls: the facet itself is capped by the room the popover has (see
|
|
28291
|
+
below). -->
|
|
28100
28292
|
<div
|
|
28101
28293
|
popover
|
|
28102
28294
|
[id]="popoverId"
|
|
@@ -28114,21 +28306,23 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
28114
28306
|
rings (2px outlines) of the facet header and its buttons sit flush against the wrapper's edges —
|
|
28115
28307
|
they were cut off on three sides. The 4px of padding gives them room, the matching negative
|
|
28116
28308
|
margin leaves the layout unchanged. Width and max-height grow by the 0.5rem of padding
|
|
28117
|
-
(15.5rem = the former w-60 + 0.5rem
|
|
28118
|
-
|
|
28119
|
-
|
|
28120
|
-
|
|
28121
|
-
|
|
28122
|
-
|
|
28123
|
-
|
|
28124
|
-
1.5rem subtracted is this popover's own vertical padding (p-3), which
|
|
28125
|
-
same available space
|
|
28126
|
-
|
|
28309
|
+
(15.5rem = the former w-60 + 0.5rem) because box-sizing is border-box here: the facet keeps
|
|
28310
|
+
its 15rem and the popover its size. The wrapper no longer scrolls (and no longer clips the
|
|
28311
|
+
rings): the facet's own list is the one scrollbar. -->
|
|
28312
|
+
<!-- The facet is capped by the smaller of two heights: its comfortable size (19 lines of list +
|
|
28313
|
+
7rem of header, search box and paddings), and the room the popover really has.
|
|
28314
|
+
size() (added to injectPopover) exposes that room, in the chosen direction, as the
|
|
28315
|
+
--popover-available-height CSS var — flip()/shift() alone only reposition the popover, they
|
|
28316
|
+
never shrink it. The 1.5rem subtracted is this popover's own vertical padding (p-3), which
|
|
28317
|
+
eats into that same available space (this wrapper's p-1 / -m-1 cancel out). The facet is a
|
|
28318
|
+
flex column whose list is min-h-0 flex-1, so it is the list that shrinks and scrolls — a
|
|
28319
|
+
capped wrapper with overflow-y-auto around it would add a second, outer scrollbar. -->
|
|
28320
|
+
<div class="-m-1 w-[15.5rem] p-1">
|
|
28127
28321
|
@let name = filter().name;
|
|
28128
28322
|
@let column = filter().column;
|
|
28129
28323
|
@if (name) {
|
|
28130
28324
|
<Aggregation
|
|
28131
|
-
class="
|
|
28325
|
+
class="w-full max-h-[min(calc(19lh+7rem),calc(var(--popover-available-height,55vh)_-_1.5rem))]"
|
|
28132
28326
|
id="filter-{{ filter().column }}"
|
|
28133
28327
|
[name]="name"
|
|
28134
28328
|
[column]="column"
|
|
@@ -28205,6 +28399,14 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
28205
28399
|
required: false
|
|
28206
28400
|
}]
|
|
28207
28401
|
}],
|
|
28402
|
+
overflowed: [{
|
|
28403
|
+
type: i0.Input,
|
|
28404
|
+
args: [{
|
|
28405
|
+
isSignal: true,
|
|
28406
|
+
alias: "overflowed",
|
|
28407
|
+
required: false
|
|
28408
|
+
}]
|
|
28409
|
+
}],
|
|
28208
28410
|
popoverRef: [{
|
|
28209
28411
|
type: i0.ViewChild,
|
|
28210
28412
|
args: [i0.forwardRef(() => PopoverDirective), { isSignal: true }]
|
|
@@ -28328,7 +28530,7 @@ var MoreComponent = class MoreComponent {
|
|
|
28328
28530
|
<div role="group" [attr.aria-label]="'filters.moreFilters' | transloco" class="divide-y divide-(--font-neutral-muted)/18 pt-1 pb-1">
|
|
28329
28531
|
@for (filter of filteredFilters(); track filter.name) {
|
|
28330
28532
|
<Aggregation
|
|
28331
|
-
class="w-full px-1 [
|
|
28533
|
+
class="w-full px-1 max-h-[calc(15lh+7rem)]"
|
|
28332
28534
|
id="more-filters"
|
|
28333
28535
|
[attr.title]="'filters.openFilter' | transloco: { filter: filter.name }"
|
|
28334
28536
|
showFiltersCount
|
|
@@ -28431,7 +28633,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
28431
28633
|
<div role="group" [attr.aria-label]="'filters.moreFilters' | transloco" class="divide-y divide-(--font-neutral-muted)/18 pt-1 pb-1">
|
|
28432
28634
|
@for (filter of filteredFilters(); track filter.name) {
|
|
28433
28635
|
<Aggregation
|
|
28434
|
-
class="w-full px-1 [
|
|
28636
|
+
class="w-full px-1 max-h-[calc(15lh+7rem)]"
|
|
28435
28637
|
id="more-filters"
|
|
28436
28638
|
[attr.title]="'filters.openFilter' | transloco: { filter: filter.name }"
|
|
28437
28639
|
showFiltersCount
|
|
@@ -28519,6 +28721,15 @@ var MoreButtonComponent = class MoreButtonComponent {
|
|
|
28519
28721
|
nativeElement = inject(ElementRef).nativeElement;
|
|
28520
28722
|
breakpointObserver = inject(BreakpointObserverService);
|
|
28521
28723
|
aggregationsService = inject(AggregationsService);
|
|
28724
|
+
toolbar = inject(Toolbar, { optional: true });
|
|
28725
|
+
disabled = input(false, {
|
|
28726
|
+
...ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {},
|
|
28727
|
+
transform: booleanAttribute
|
|
28728
|
+
});
|
|
28729
|
+
triggerClass = "gap-1 truncate font-semibold";
|
|
28730
|
+
openTriggerClass = "gap-1 truncate font-semibold border border-(--stroke-neutral-dark)/18";
|
|
28731
|
+
openSheet = () => this.sheetRef()?.open();
|
|
28732
|
+
openDialog = () => this.dialogRef()?.showModal();
|
|
28522
28733
|
count = input(2, {
|
|
28523
28734
|
...ngDevMode ? { debugName: "count" } : /* istanbul ignore next */ {},
|
|
28524
28735
|
transform: numberAttribute
|
|
@@ -28572,6 +28783,13 @@ var MoreButtonComponent = class MoreButtonComponent {
|
|
|
28572
28783
|
isStandalone: true,
|
|
28573
28784
|
selector: "more-button, MoreButton",
|
|
28574
28785
|
inputs: {
|
|
28786
|
+
disabled: {
|
|
28787
|
+
classPropertyName: "disabled",
|
|
28788
|
+
publicName: "disabled",
|
|
28789
|
+
isSignal: true,
|
|
28790
|
+
isRequired: false,
|
|
28791
|
+
transformFunction: null
|
|
28792
|
+
},
|
|
28575
28793
|
count: {
|
|
28576
28794
|
classPropertyName: "count",
|
|
28577
28795
|
publicName: "count",
|
|
@@ -28673,10 +28891,24 @@ var MoreButtonComponent = class MoreButtonComponent {
|
|
|
28673
28891
|
}
|
|
28674
28892
|
</ng-template>
|
|
28675
28893
|
|
|
28894
|
+
<!-- The trigger button, shared by the three variants below. Inside a toolbar the BUTTON is the
|
|
28895
|
+
roving widget and not the host: the host is an element with no role of its own and no key
|
|
28896
|
+
handler, so an arrow key landed on a dead element, then the button was a second tab stop.
|
|
28897
|
+
Outside a toolbar it is a plain button. -->
|
|
28898
|
+
<ng-template #button let-onClick="onClick" let-popoverTarget="popoverTarget" let-cls="cls">
|
|
28899
|
+
@if (toolbar) {
|
|
28900
|
+
<button ngToolbarWidget variant="tertiary" [attr.popovertarget]="popoverTarget" [class]="cls" aria-label="more filters" [disabled]="disabled()" (click)="onClick?.()">
|
|
28901
|
+
<ng-container *ngTemplateOutlet="trigger" />
|
|
28902
|
+
</button>
|
|
28903
|
+
} @else {
|
|
28904
|
+
<button variant="tertiary" [attr.popovertarget]="popoverTarget" [class]="cls" aria-label="more filters" [disabled]="disabled() || null" (click)="onClick?.()">
|
|
28905
|
+
<ng-container *ngTemplateOutlet="trigger" />
|
|
28906
|
+
</button>
|
|
28907
|
+
}
|
|
28908
|
+
</ng-template>
|
|
28909
|
+
|
|
28676
28910
|
@if (breakpointObserver.isMobile()) {
|
|
28677
|
-
<
|
|
28678
|
-
<ng-container *ngTemplateOutlet="trigger" />
|
|
28679
|
-
</button>
|
|
28911
|
+
<ng-container *ngTemplateOutlet="button; context: { onClick: openSheet, cls: triggerClass }" />
|
|
28680
28912
|
|
|
28681
28913
|
<Sheet side="bottom" size="lg">
|
|
28682
28914
|
<SheetHeader [closeLabel]="'filters.close' | transloco">
|
|
@@ -28696,9 +28928,7 @@ var MoreButtonComponent = class MoreButtonComponent {
|
|
|
28696
28928
|
</SheetBody>
|
|
28697
28929
|
</Sheet>
|
|
28698
28930
|
} @else if (isEnriched()) {
|
|
28699
|
-
<
|
|
28700
|
-
<ng-container *ngTemplateOutlet="trigger" />
|
|
28701
|
-
</button>
|
|
28931
|
+
<ng-container *ngTemplateOutlet="button; context: { onClick: openDialog, cls: triggerClass }" />
|
|
28702
28932
|
|
|
28703
28933
|
<dialog>
|
|
28704
28934
|
<DialogContent size="md">
|
|
@@ -28718,13 +28948,7 @@ var MoreButtonComponent = class MoreButtonComponent {
|
|
|
28718
28948
|
</DialogContent>
|
|
28719
28949
|
</dialog>
|
|
28720
28950
|
} @else {
|
|
28721
|
-
<button
|
|
28722
|
-
variant="tertiary"
|
|
28723
|
-
[attr.popovertarget]="popoverId"
|
|
28724
|
-
[class]="isOpen() ? 'gap-1 truncate font-semibold border border-(--stroke-neutral-dark)/18' : 'gap-1 truncate font-semibold'"
|
|
28725
|
-
aria-label="more filters">
|
|
28726
|
-
<ng-container *ngTemplateOutlet="trigger" />
|
|
28727
|
-
</button>
|
|
28951
|
+
<ng-container *ngTemplateOutlet="button; context: { popoverTarget: popoverId, cls: isOpen() ? openTriggerClass : triggerClass }" />
|
|
28728
28952
|
|
|
28729
28953
|
<!-- Native HTML Popover (top-layer). Fully isolate pointer/click events from
|
|
28730
28954
|
the surrounding @angular/aria toolbar (see FilterButton for the rationale:
|
|
@@ -28774,6 +28998,13 @@ var MoreButtonComponent = class MoreButtonComponent {
|
|
|
28774
28998
|
"ngTemplateOutletInjector"
|
|
28775
28999
|
]
|
|
28776
29000
|
},
|
|
29001
|
+
{
|
|
29002
|
+
kind: "directive",
|
|
29003
|
+
type: ToolbarWidget,
|
|
29004
|
+
selector: "[ngToolbarWidget]",
|
|
29005
|
+
inputs: ["id", "disabled"],
|
|
29006
|
+
exportAs: ["ngToolbarWidget"]
|
|
29007
|
+
},
|
|
28777
29008
|
{
|
|
28778
29009
|
kind: "directive",
|
|
28779
29010
|
type: ButtonComponent,
|
|
@@ -28919,6 +29150,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
28919
29150
|
selector: "more-button, MoreButton",
|
|
28920
29151
|
imports: [
|
|
28921
29152
|
NgTemplateOutlet,
|
|
29153
|
+
ToolbarWidget,
|
|
28922
29154
|
ButtonComponent,
|
|
28923
29155
|
PopoverDirective,
|
|
28924
29156
|
TranslocoPipe,
|
|
@@ -28946,10 +29178,24 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
28946
29178
|
}
|
|
28947
29179
|
</ng-template>
|
|
28948
29180
|
|
|
29181
|
+
<!-- The trigger button, shared by the three variants below. Inside a toolbar the BUTTON is the
|
|
29182
|
+
roving widget and not the host: the host is an element with no role of its own and no key
|
|
29183
|
+
handler, so an arrow key landed on a dead element, then the button was a second tab stop.
|
|
29184
|
+
Outside a toolbar it is a plain button. -->
|
|
29185
|
+
<ng-template #button let-onClick="onClick" let-popoverTarget="popoverTarget" let-cls="cls">
|
|
29186
|
+
@if (toolbar) {
|
|
29187
|
+
<button ngToolbarWidget variant="tertiary" [attr.popovertarget]="popoverTarget" [class]="cls" aria-label="more filters" [disabled]="disabled()" (click)="onClick?.()">
|
|
29188
|
+
<ng-container *ngTemplateOutlet="trigger" />
|
|
29189
|
+
</button>
|
|
29190
|
+
} @else {
|
|
29191
|
+
<button variant="tertiary" [attr.popovertarget]="popoverTarget" [class]="cls" aria-label="more filters" [disabled]="disabled() || null" (click)="onClick?.()">
|
|
29192
|
+
<ng-container *ngTemplateOutlet="trigger" />
|
|
29193
|
+
</button>
|
|
29194
|
+
}
|
|
29195
|
+
</ng-template>
|
|
29196
|
+
|
|
28949
29197
|
@if (breakpointObserver.isMobile()) {
|
|
28950
|
-
<
|
|
28951
|
-
<ng-container *ngTemplateOutlet="trigger" />
|
|
28952
|
-
</button>
|
|
29198
|
+
<ng-container *ngTemplateOutlet="button; context: { onClick: openSheet, cls: triggerClass }" />
|
|
28953
29199
|
|
|
28954
29200
|
<Sheet side="bottom" size="lg">
|
|
28955
29201
|
<SheetHeader [closeLabel]="'filters.close' | transloco">
|
|
@@ -28969,9 +29215,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
28969
29215
|
</SheetBody>
|
|
28970
29216
|
</Sheet>
|
|
28971
29217
|
} @else if (isEnriched()) {
|
|
28972
|
-
<
|
|
28973
|
-
<ng-container *ngTemplateOutlet="trigger" />
|
|
28974
|
-
</button>
|
|
29218
|
+
<ng-container *ngTemplateOutlet="button; context: { onClick: openDialog, cls: triggerClass }" />
|
|
28975
29219
|
|
|
28976
29220
|
<dialog>
|
|
28977
29221
|
<DialogContent size="md">
|
|
@@ -28991,13 +29235,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
28991
29235
|
</DialogContent>
|
|
28992
29236
|
</dialog>
|
|
28993
29237
|
} @else {
|
|
28994
|
-
<button
|
|
28995
|
-
variant="tertiary"
|
|
28996
|
-
[attr.popovertarget]="popoverId"
|
|
28997
|
-
[class]="isOpen() ? 'gap-1 truncate font-semibold border border-(--stroke-neutral-dark)/18' : 'gap-1 truncate font-semibold'"
|
|
28998
|
-
aria-label="more filters">
|
|
28999
|
-
<ng-container *ngTemplateOutlet="trigger" />
|
|
29000
|
-
</button>
|
|
29238
|
+
<ng-container *ngTemplateOutlet="button; context: { popoverTarget: popoverId, cls: isOpen() ? openTriggerClass : triggerClass }" />
|
|
29001
29239
|
|
|
29002
29240
|
<!-- Native HTML Popover (top-layer). Fully isolate pointer/click events from
|
|
29003
29241
|
the surrounding @angular/aria toolbar (see FilterButton for the rationale:
|
|
@@ -29039,6 +29277,14 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
29039
29277
|
}]
|
|
29040
29278
|
}],
|
|
29041
29279
|
propDecorators: {
|
|
29280
|
+
disabled: [{
|
|
29281
|
+
type: i0.Input,
|
|
29282
|
+
args: [{
|
|
29283
|
+
isSignal: true,
|
|
29284
|
+
alias: "disabled",
|
|
29285
|
+
required: false
|
|
29286
|
+
}]
|
|
29287
|
+
}],
|
|
29042
29288
|
count: [{
|
|
29043
29289
|
type: i0.Input,
|
|
29044
29290
|
args: [{
|
|
@@ -29353,7 +29599,7 @@ var FiltersBarComponent = class FiltersBarComponent {
|
|
|
29353
29599
|
tabindex with it: the keyboard stopped on an invisible strip of zero height, announced
|
|
29354
29600
|
"Filter controls" and disabled at once. -->
|
|
29355
29601
|
@if (hasFilters() || currentBasket() || hasAggregations()) {
|
|
29356
|
-
<div ngToolbar [attr.aria-label]="ariaLabel() ?? ('filters.filterControls' | transloco)" overflowManager [direction]="direction()" [reserveStop]="hasCappedFilters()" (count)="adjustFiltersCount($event)" class="flex items-end gap-2 rounded-[inherit] bg-inherit">
|
|
29602
|
+
<div ngToolbar [softDisabled]="false" [attr.aria-label]="ariaLabel() ?? ('filters.filterControls' | transloco)" overflowManager [direction]="direction()" [reserveStop]="hasCappedFilters()" (count)="adjustFiltersCount($event)" class="flex items-end gap-2 rounded-[inherit] bg-inherit">
|
|
29357
29603
|
@if (hasFilters()) {
|
|
29358
29604
|
<button
|
|
29359
29605
|
ngToolbarWidget
|
|
@@ -29391,10 +29637,13 @@ var FiltersBarComponent = class FiltersBarComponent {
|
|
|
29391
29637
|
: 'flex-row'
|
|
29392
29638
|
)">
|
|
29393
29639
|
|
|
29394
|
-
@for (filter of authorizedFilters(); track filter.name) {
|
|
29640
|
+
@for (filter of authorizedFilters(); track filter.name; let i = $index) {
|
|
29641
|
+
<!-- No ngToolbarWidget here: FilterButton makes its own inner button the roving widget, so the
|
|
29642
|
+
bar has one tab stop per filter and not two (host, then button). A filter hidden by the
|
|
29643
|
+
overflow manager is disabled, hence skipped by the roving (the toolbar is not soft-disabled). -->
|
|
29395
29644
|
<FilterButton
|
|
29396
|
-
ngToolbarWidget
|
|
29397
29645
|
overflowItem
|
|
29646
|
+
[overflowed]="i >= visibleFiltersCount()"
|
|
29398
29647
|
[name]="filter.name"
|
|
29399
29648
|
[column]="filter.column"
|
|
29400
29649
|
[position]="position()"
|
|
@@ -29410,8 +29659,8 @@ var FiltersBarComponent = class FiltersBarComponent {
|
|
|
29410
29659
|
forbids the attribute. The name belongs to the <button> inside MoreButton, which
|
|
29411
29660
|
already carries it. -->
|
|
29412
29661
|
<MoreButton
|
|
29413
|
-
ngToolbarWidget
|
|
29414
29662
|
overflowStop
|
|
29663
|
+
[disabled]="hasMoreFilters().length === 0"
|
|
29415
29664
|
[class]="cn('shrink-0', hasMoreFilters().length === 0 && 'invisible pointer-events-none')"
|
|
29416
29665
|
[count]="visibleFiltersCount()"
|
|
29417
29666
|
[position]="morePosition()"
|
|
@@ -29444,6 +29693,7 @@ var FiltersBarComponent = class FiltersBarComponent {
|
|
|
29444
29693
|
type: MoreButtonComponent,
|
|
29445
29694
|
selector: "more-button, MoreButton",
|
|
29446
29695
|
inputs: [
|
|
29696
|
+
"disabled",
|
|
29447
29697
|
"count",
|
|
29448
29698
|
"position",
|
|
29449
29699
|
"lockPosition",
|
|
@@ -29465,7 +29715,8 @@ var FiltersBarComponent = class FiltersBarComponent {
|
|
|
29465
29715
|
"position",
|
|
29466
29716
|
"offset",
|
|
29467
29717
|
"lockPosition",
|
|
29468
|
-
"expandedLevel"
|
|
29718
|
+
"expandedLevel",
|
|
29719
|
+
"overflowed"
|
|
29469
29720
|
]
|
|
29470
29721
|
},
|
|
29471
29722
|
{
|
|
@@ -29557,7 +29808,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
29557
29808
|
tabindex with it: the keyboard stopped on an invisible strip of zero height, announced
|
|
29558
29809
|
"Filter controls" and disabled at once. -->
|
|
29559
29810
|
@if (hasFilters() || currentBasket() || hasAggregations()) {
|
|
29560
|
-
<div ngToolbar [attr.aria-label]="ariaLabel() ?? ('filters.filterControls' | transloco)" overflowManager [direction]="direction()" [reserveStop]="hasCappedFilters()" (count)="adjustFiltersCount($event)" class="flex items-end gap-2 rounded-[inherit] bg-inherit">
|
|
29811
|
+
<div ngToolbar [softDisabled]="false" [attr.aria-label]="ariaLabel() ?? ('filters.filterControls' | transloco)" overflowManager [direction]="direction()" [reserveStop]="hasCappedFilters()" (count)="adjustFiltersCount($event)" class="flex items-end gap-2 rounded-[inherit] bg-inherit">
|
|
29561
29812
|
@if (hasFilters()) {
|
|
29562
29813
|
<button
|
|
29563
29814
|
ngToolbarWidget
|
|
@@ -29595,10 +29846,13 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
29595
29846
|
: 'flex-row'
|
|
29596
29847
|
)">
|
|
29597
29848
|
|
|
29598
|
-
@for (filter of authorizedFilters(); track filter.name) {
|
|
29849
|
+
@for (filter of authorizedFilters(); track filter.name; let i = $index) {
|
|
29850
|
+
<!-- No ngToolbarWidget here: FilterButton makes its own inner button the roving widget, so the
|
|
29851
|
+
bar has one tab stop per filter and not two (host, then button). A filter hidden by the
|
|
29852
|
+
overflow manager is disabled, hence skipped by the roving (the toolbar is not soft-disabled). -->
|
|
29599
29853
|
<FilterButton
|
|
29600
|
-
ngToolbarWidget
|
|
29601
29854
|
overflowItem
|
|
29855
|
+
[overflowed]="i >= visibleFiltersCount()"
|
|
29602
29856
|
[name]="filter.name"
|
|
29603
29857
|
[column]="filter.column"
|
|
29604
29858
|
[position]="position()"
|
|
@@ -29614,8 +29868,8 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
29614
29868
|
forbids the attribute. The name belongs to the <button> inside MoreButton, which
|
|
29615
29869
|
already carries it. -->
|
|
29616
29870
|
<MoreButton
|
|
29617
|
-
ngToolbarWidget
|
|
29618
29871
|
overflowStop
|
|
29872
|
+
[disabled]="hasMoreFilters().length === 0"
|
|
29619
29873
|
[class]="cn('shrink-0', hasMoreFilters().length === 0 && 'invisible pointer-events-none')"
|
|
29620
29874
|
[count]="visibleFiltersCount()"
|
|
29621
29875
|
[position]="morePosition()"
|
|
@@ -32975,10 +33229,12 @@ const SCOPE = "session-expiry";
|
|
|
32975
33229
|
const SCOPE_ALIAS = "sessionExpiry";
|
|
32976
33230
|
const FALLBACK = {
|
|
32977
33231
|
expiringTitle: "Your session is about to expire",
|
|
32978
|
-
expiringDescription: "It expires in about {{minutes}} min.
|
|
33232
|
+
expiringDescription: "It expires in about {{minutes}} min. Extend your session to keep it open.",
|
|
32979
33233
|
expiredTitle: "Your session has expired",
|
|
32980
33234
|
expiredDescription: "Sign in again to continue.",
|
|
32981
|
-
reload: "Sign in again"
|
|
33235
|
+
reload: "Sign in again",
|
|
33236
|
+
extend: "Extend session",
|
|
33237
|
+
extendedTitle: "Your session has been extended"
|
|
32982
33238
|
};
|
|
32983
33239
|
function provideSessionExpiry(options = {}) {
|
|
32984
33240
|
const warnBeforeMs = options.warnBeforeMs ?? DEFAULT_WARN_BEFORE_MS;
|
|
@@ -33016,14 +33272,36 @@ function provideSessionExpiry(options = {}) {
|
|
|
33016
33272
|
await settled;
|
|
33017
33273
|
if (!stillDue()) return;
|
|
33018
33274
|
const minutes = Math.max(1, Math.ceil((expiresAt - Date.now()) / 6e4));
|
|
33019
|
-
const [title, description] = await Promise.all([
|
|
33275
|
+
const [title, description, extendLabel] = await Promise.all([
|
|
33276
|
+
translate("expiringTitle"),
|
|
33277
|
+
translate("expiringDescription", { minutes }),
|
|
33278
|
+
translate("extend")
|
|
33279
|
+
]);
|
|
33020
33280
|
if (!stillDue()) return;
|
|
33021
33281
|
notify.warning(title, {
|
|
33022
33282
|
description,
|
|
33023
33283
|
closeButton: true,
|
|
33024
|
-
important: true
|
|
33284
|
+
important: true,
|
|
33285
|
+
action: {
|
|
33286
|
+
label: extendLabel,
|
|
33287
|
+
onClick: () => void extend()
|
|
33288
|
+
}
|
|
33025
33289
|
});
|
|
33026
33290
|
};
|
|
33291
|
+
const extend = async () => {
|
|
33292
|
+
if (options.onExtend) return options.onExtend();
|
|
33293
|
+
const before = expiresAt;
|
|
33294
|
+
try {
|
|
33295
|
+
await client.api.principal.get();
|
|
33296
|
+
} catch {
|
|
33297
|
+
return;
|
|
33298
|
+
}
|
|
33299
|
+
if (before !== null && expiresAt !== null && expiresAt > before) {
|
|
33300
|
+
notify.success(await translate("extendedTitle"), { closeButton: true });
|
|
33301
|
+
return;
|
|
33302
|
+
}
|
|
33303
|
+
onReconnect();
|
|
33304
|
+
};
|
|
33027
33305
|
const check = () => {
|
|
33028
33306
|
if (expiresAt === null || warned) return;
|
|
33029
33307
|
const delay = expiresAt - warnBeforeMs - Date.now();
|
|
@@ -33093,6 +33371,6 @@ function provideSessionExpiry(options = {}) {
|
|
|
33093
33371
|
const queryNameResolver = () => {
|
|
33094
33372
|
return inject(AppStore).getDefaultQuery()?.name || "";
|
|
33095
33373
|
};
|
|
33096
|
-
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, 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, 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, FloatingToolbarComponent, ForgotPasswordComponent, HIGHLIGHTS, HeatmapComponent, HighlightWordPipe, InfinityScrollDirective, InlineWorker, JsonMethodPluginService, KeyboardShortcutsDialog, KeyboardShortcutsDialogComponent, KeyboardShortcutsListComponent, KeyboardShortcutsService, LabelService, LabelsEditDialog, ListPanelItemDirective, LoadingComponent, MarkdownPipe, MarkdownRendererService, MetadataComponent, MissingTermsComponent, MoreButtonComponent, MoreComponent, MultiSelectLabelsComponent, MultiSelectionToolbarComponent, NON_SEARCHABLE_COLUMNS, NON_SEARCHABLE_DEFAULTS, NavbarTabsComponent, NavigationService, NoResultComponent, OpenArticleOnCtrlEnterDirective, OperatorPipe, OverflowItemDirective, OverflowManagerDirective, OverflowStopDirective, OverrideUser, OverrideUserDialogComponent, PREVIEW_ASSISTANT_COMPONENT, PREVIEW_CONFIG, PagerComponent, PreviewActionsComponent, PreviewContentComponent, PreviewHeaderComponent, PreviewNavigator, PreviewService, PrincipalService, PrincipalStore, QueryParamsStore, QueryService, RECENT_SEARCHES_CONFIG, RECENT_SEARCHES_OPTIONS, ROUTE_COMPONENTS, RecentSearchesComponent, ResetUserSettings, ResetUserSettingsDialogComponent, SAVED_SEARCHES_CONFIG, SAVED_SEARCHES_OPTIONS, SavedSearch, SavedSearchDialog, SavedSearchPopover, SavedSearchesComponent, SavedSearchesService, SearchFeedbackComponent, SearchInputFooter, SearchService, SelectArticleDirective, SelectionService, SelectionStore, Settings, SettingsAccountPanelComponent, 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, injectAdvancedFilters, injectAtomicClient, injectRouteNavigation, injectUserSettingsPatch, isAuthRoute, isSignInInFlight, itemLabel, layoutWordCloud, legacyFilterToFilter, makeWeightScale, multiSelectionToolbarVariants, paletteColor, processCssVars, provideAtomicClient, provideAtomicNotifications, provideAtomicScope, provideDocumentLang, provideKeyboardShortcuts, provideSessionExpiry, quantileScale, queryNameResolver, rebuildWithout, seriesPalette, signIn, themeColorNameToCssVariable, themeColorsToCssVariables, timelinePalette, toAriaKeyshortcuts, toDisplayParts, toPercentages, toSeries, toastInterceptorFn, weekdaysFromFlags, withAggregationsFeatures, withAlertsFeatures, withAlpha, withAppFeatures, withApplicationFeatures, withAssistantFeatures, withBasketsFeatures, withBookmarkFeatures, withBootstrapApp, withExtractsFeatures, withFetch, withMultiSelectionFeatures, withQueryParamsFeatures, withRecentSearchesFeatures, withSavedSearchesFeatures, withSelectionFeatures, withThemeBodyHook, withThemes, withThemesFeatures, withUserSettingsFeatures };
|
|
33374
|
+
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, 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, 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, FloatingToolbarComponent, ForgotPasswordComponent, HIGHLIGHTS, HeatmapComponent, HighlightWordPipe, InfinityScrollDirective, InlineWorker, JsonMethodPluginService, KeyboardShortcutsDialog, KeyboardShortcutsDialogComponent, KeyboardShortcutsListComponent, KeyboardShortcutsService, LabelService, LabelsEditDialog, ListPanelItemDirective, LoadingComponent, MarkdownPipe, MarkdownRendererService, MetadataComponent, MissingTermsComponent, MoreButtonComponent, MoreComponent, MultiSelectLabelsComponent, MultiSelectionToolbarComponent, NON_SEARCHABLE_COLUMNS, NON_SEARCHABLE_DEFAULTS, NavbarTabsComponent, NavigationService, NoResultComponent, OpenArticleOnCtrlEnterDirective, OperatorPipe, OverflowItemDirective, OverflowManagerDirective, OverflowStopDirective, OverrideUser, OverrideUserDialogComponent, PREVIEW_ASSISTANT_COMPONENT, PREVIEW_CONFIG, PagerComponent, PreviewActionsComponent, PreviewContentComponent, PreviewHeaderComponent, PreviewNavigator, PreviewService, PrincipalService, PrincipalStore, QueryParamsStore, QueryService, RECENT_SEARCHES_CONFIG, RECENT_SEARCHES_OPTIONS, ROUTE_COMPONENTS, RecentSearchesComponent, ResetUserSettings, ResetUserSettingsDialogComponent, SAVED_SEARCHES_CONFIG, SAVED_SEARCHES_OPTIONS, STARTUP_DATA_SOURCE, SavedSearch, SavedSearchDialog, SavedSearchPopover, SavedSearchesComponent, SavedSearchesService, SearchFeedbackComponent, SearchInputFooter, SearchService, SelectArticleDirective, SelectionService, SelectionStore, Settings, SettingsAccountPanelComponent, 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, injectAdvancedFilters, injectAtomicClient, injectRouteNavigation, injectUserSettingsPatch, isAuthRoute, isSignInInFlight, itemLabel, layoutWordCloud, legacyFilterToFilter, makeWeightScale, multiSelectionToolbarVariants, paletteColor, processCssVars, provideAtomicClient, provideAtomicNotifications, provideAtomicScope, provideDocumentLang, provideKeyboardShortcuts, provideSessionExpiry, provideStartupAggregation, quantileScale, queryNameResolver, rebuildWithout, seriesPalette, signIn, themeColorNameToCssVariable, themeColorsToCssVariables, timelinePalette, toAriaKeyshortcuts, toDisplayParts, toPercentages, toSeries, toastInterceptorFn, weekdaysFromFlags, withAggregationsFeatures, withAlertsFeatures, withAlpha, withAppFeatures, withApplicationFeatures, withAssistantFeatures, withBasketsFeatures, withBookmarkFeatures, withBootstrapApp, withExtractsFeatures, withFetch, withMultiSelectionFeatures, withQueryParamsFeatures, withRecentSearchesFeatures, withSavedSearchesFeatures, withSelectionFeatures, withThemeBodyHook, withThemes, withThemesFeatures, withUserSettingsFeatures };
|
|
33097
33375
|
|
|
33098
33376
|
//# sourceMappingURL=sinequa-atomic-angular.mjs.map
|