commons-shared-web-ui 0.0.72 → 0.0.74
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/commons-shared-web-ui.mjs +395 -48
- package/fesm2022/commons-shared-web-ui.mjs.map +1 -1
- package/index.d.ts +167 -18
- package/package.json +1 -1
|
@@ -55,6 +55,8 @@ import * as i1$1 from '@angular/platform-browser';
|
|
|
55
55
|
import * as i1$4 from '@angular/router';
|
|
56
56
|
import { RouterModule } from '@angular/router';
|
|
57
57
|
import { CdkVirtualScrollViewport, ScrollingModule } from '@angular/cdk/scrolling';
|
|
58
|
+
import * as i1$5 from '@angular/cdk/drag-drop';
|
|
59
|
+
import { moveItemInArray, DragDropModule } from '@angular/cdk/drag-drop';
|
|
58
60
|
|
|
59
61
|
class MaterialModule {
|
|
60
62
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: MaterialModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
@@ -1610,10 +1612,27 @@ class FormFieldComponent {
|
|
|
1610
1612
|
* object is reused across multiple allowMulti repeater instances.
|
|
1611
1613
|
*/
|
|
1612
1614
|
localOptionList = [];
|
|
1615
|
+
/** Snapshot of default (unsearched) options and pagination state for DROPDOWN / AUTOCOMPLETE fields */
|
|
1616
|
+
defaultStateSnapshot = { options: [], currentPage: 0, totalCount: 0, hasMorePages: false };
|
|
1617
|
+
/** Tracks whether the current localOptionList is filtered by an active server-side search query */
|
|
1618
|
+
_isServerSearchActive = false;
|
|
1613
1619
|
/** Dedicated cache of currently selected option objects */
|
|
1614
1620
|
selectedItems = [];
|
|
1615
1621
|
/** Cache of the latest dependency parameters for server-side autocomplete filtering */
|
|
1616
1622
|
_latestDependencyValues = {};
|
|
1623
|
+
/** True when this field has no optionConfig.dependencies (nothing to satisfy) OR every
|
|
1624
|
+
* dependency's current value is present — false while waiting on a parent field. Guards every
|
|
1625
|
+
* opportunistic reload path (dropdown-open, search-reset, search-clear) so a dependent
|
|
1626
|
+
* dropdown never re-fetches an unfiltered full list just because it was opened/searched before
|
|
1627
|
+
* its parent was chosen — only setupDependencies()'s own reactive load (which always supplies
|
|
1628
|
+
* the real dependency params) is allowed to populate it.
|
|
1629
|
+
* Defaults to true here (fields with no dependencies never get corrected otherwise), but
|
|
1630
|
+
* ngOnInit flips it to false up front for any field that DOES declare dependencies — closing
|
|
1631
|
+
* the window between component creation and setupDependencies()'s first (necessarily async,
|
|
1632
|
+
* via combineLatest) emission, during which a fast dropdown-open would otherwise still see
|
|
1633
|
+
* this stale `true` default and fire an unfiltered fetch before the parent-unmet state is
|
|
1634
|
+
* known. */
|
|
1635
|
+
_dependenciesSatisfied = true;
|
|
1617
1636
|
// ── GROUP / allowMulti support ──────────────────────────────────────────
|
|
1618
1637
|
/** For GROUP fields with allowMulti = true */
|
|
1619
1638
|
groupFormArray;
|
|
@@ -1707,6 +1726,12 @@ class FormFieldComponent {
|
|
|
1707
1726
|
// filteredOptionList mirrors localOptionList and is narrowed by search.
|
|
1708
1727
|
// Dynamic options loaded via API will replace this array via loadDropdownOptions.
|
|
1709
1728
|
this.localOptionList = [...(this.config.optionConfig?.optionList || [])];
|
|
1729
|
+
this.defaultStateSnapshot = {
|
|
1730
|
+
options: [...this.localOptionList],
|
|
1731
|
+
currentPage: 0,
|
|
1732
|
+
totalCount: 0,
|
|
1733
|
+
hasMorePages: false
|
|
1734
|
+
};
|
|
1710
1735
|
this.filteredOptionList = [...this.localOptionList];
|
|
1711
1736
|
this.registerControl();
|
|
1712
1737
|
this.setupRequiredExpression();
|
|
@@ -1717,6 +1742,11 @@ class FormFieldComponent {
|
|
|
1717
1742
|
this.setupMinTimeField();
|
|
1718
1743
|
this.setupGeneratedField();
|
|
1719
1744
|
this.setupFormulaValidation(); // Generic formula-based validation
|
|
1745
|
+
// A field with dependencies starts "not satisfied" until setupDependencies()'s own
|
|
1746
|
+
// (async) check proves otherwise — see _dependenciesSatisfied's doc comment. Without this,
|
|
1747
|
+
// a dropdown opened in the brief window before that first emission would still read the
|
|
1748
|
+
// stale `true` class-field default and fetch its full, unfiltered option list.
|
|
1749
|
+
this._dependenciesSatisfied = !this.config.optionConfig?.dependencies;
|
|
1720
1750
|
this.setupDependencies();
|
|
1721
1751
|
this.setupMatchValidation(); // cross-field match (e.g. confirmPassword)
|
|
1722
1752
|
if (!this.config.optionConfig?.dependencies) {
|
|
@@ -1793,9 +1823,11 @@ class FormFieldComponent {
|
|
|
1793
1823
|
get isSearchableDropdown() {
|
|
1794
1824
|
return !!this.config.optionConfig?.searchConfig?.enabled;
|
|
1795
1825
|
}
|
|
1796
|
-
/** Whether the custom single-select dropdown overlay is required
|
|
1826
|
+
/** Whether the custom single-select dropdown overlay is required — for search, pagination, or
|
|
1827
|
+
* when optionConfig.customUI opts in to the styled overlay purely for visual consistency with
|
|
1828
|
+
* sibling dropdowns (no search box, no pagination — just the same panel/chevron treatment). */
|
|
1797
1829
|
get isCustomSingleDropdown() {
|
|
1798
|
-
return this.isSearchableDropdown || !!this.config.optionConfig?.pagination?.enabled;
|
|
1830
|
+
return this.isSearchableDropdown || !!this.config.optionConfig?.pagination?.enabled || !!this.config.optionConfig?.customUI;
|
|
1799
1831
|
}
|
|
1800
1832
|
initGroupField() {
|
|
1801
1833
|
if (this.config.sectionConfig?.allowMulti) {
|
|
@@ -2498,6 +2530,7 @@ class FormFieldComponent {
|
|
|
2498
2530
|
const isFirstEmit = prevValues === null;
|
|
2499
2531
|
const parentChanged = !isFirstEmit && values.some((v, i) => v !== prevValues[i]);
|
|
2500
2532
|
prevValues = [...values];
|
|
2533
|
+
this._dependenciesSatisfied = allPresent;
|
|
2501
2534
|
if (allPresent) {
|
|
2502
2535
|
if (parentChanged) {
|
|
2503
2536
|
// Parent value changed by user interaction — reset child selection so the
|
|
@@ -2511,12 +2544,14 @@ class FormFieldComponent {
|
|
|
2511
2544
|
this.dropdownCurrentPage = 0;
|
|
2512
2545
|
this.dropdownTotalCount = 0;
|
|
2513
2546
|
this.hasMoreDropdownPages = false;
|
|
2547
|
+
this.defaultStateSnapshot = { options: [], currentPage: 0, totalCount: 0, hasMorePages: false };
|
|
2514
2548
|
this._latestDependencyValues = dependencyValues;
|
|
2515
2549
|
this.loadDropdownOptions(dependencyValues, 0, false);
|
|
2516
2550
|
}
|
|
2517
2551
|
else if (this.config.optionConfig) {
|
|
2518
2552
|
this._latestDependencyValues = {};
|
|
2519
2553
|
this.localOptionList = [];
|
|
2554
|
+
this.defaultStateSnapshot = { options: [], currentPage: 0, totalCount: 0, hasMorePages: false };
|
|
2520
2555
|
this.filteredOptionList = [];
|
|
2521
2556
|
this.dropdownCurrentPage = 0;
|
|
2522
2557
|
this.dropdownTotalCount = 0;
|
|
@@ -2784,6 +2819,14 @@ class FormFieldComponent {
|
|
|
2784
2819
|
else {
|
|
2785
2820
|
this.hasMoreDropdownPages = mappedOptions.length >= pageSize;
|
|
2786
2821
|
}
|
|
2822
|
+
if (!this._isServerSearchActive) {
|
|
2823
|
+
this.defaultStateSnapshot = {
|
|
2824
|
+
options: [...finalOptions],
|
|
2825
|
+
currentPage: this.dropdownCurrentPage,
|
|
2826
|
+
totalCount: this.dropdownTotalCount,
|
|
2827
|
+
hasMorePages: this.hasMoreDropdownPages
|
|
2828
|
+
};
|
|
2829
|
+
}
|
|
2787
2830
|
}
|
|
2788
2831
|
else {
|
|
2789
2832
|
// --- Non-paginated behavior (100% backward compatible) ---
|
|
@@ -2796,6 +2839,14 @@ class FormFieldComponent {
|
|
|
2796
2839
|
});
|
|
2797
2840
|
this.localOptionList = finalOptions;
|
|
2798
2841
|
this.hasMoreDropdownPages = false;
|
|
2842
|
+
if (!this._isServerSearchActive) {
|
|
2843
|
+
this.defaultStateSnapshot = {
|
|
2844
|
+
options: [...finalOptions],
|
|
2845
|
+
currentPage: this.dropdownCurrentPage,
|
|
2846
|
+
totalCount: this.dropdownTotalCount,
|
|
2847
|
+
hasMorePages: false
|
|
2848
|
+
};
|
|
2849
|
+
}
|
|
2799
2850
|
}
|
|
2800
2851
|
if (this.isAutocomplete) {
|
|
2801
2852
|
this.filteredOptions = [...this.localOptionList];
|
|
@@ -3167,17 +3218,28 @@ class FormFieldComponent {
|
|
|
3167
3218
|
const searchConfig = this.config.optionConfig?.searchConfig;
|
|
3168
3219
|
const mode = searchConfig?.mode || 'local';
|
|
3169
3220
|
if (mode === 'server') {
|
|
3221
|
+
// A dependent field (optionConfig.dependencies) with no parent value yet has nothing to
|
|
3222
|
+
// search against — searching now would fire with the parent filter missing entirely and
|
|
3223
|
+
// come back with an unfiltered full list. Wait for setupDependencies()'s own load instead.
|
|
3224
|
+
if (!this._dependenciesSatisfied)
|
|
3225
|
+
return;
|
|
3170
3226
|
const searchKey = searchConfig?.searchKey || (searchConfig?.handling === 'nested_string' ? 'SEARCH_TEXT' : 'search');
|
|
3171
3227
|
const minLen = searchConfig?.minSearchLength ?? 3;
|
|
3172
3228
|
if (query.length >= minLen) {
|
|
3229
|
+
this._isServerSearchActive = true;
|
|
3173
3230
|
const params = { ...this._latestDependencyValues, [searchKey]: query };
|
|
3174
3231
|
this.dropdownCurrentPage = 0;
|
|
3175
3232
|
this.loadDropdownOptions(params, 0, false);
|
|
3176
3233
|
}
|
|
3177
3234
|
else if (query.length === 0) {
|
|
3178
|
-
|
|
3179
|
-
this.
|
|
3180
|
-
|
|
3235
|
+
this._isServerSearchActive = false;
|
|
3236
|
+
if (this.defaultStateSnapshot.options.length > 0) {
|
|
3237
|
+
this.restoreDefaultOptionList();
|
|
3238
|
+
}
|
|
3239
|
+
else {
|
|
3240
|
+
this.dropdownCurrentPage = 0;
|
|
3241
|
+
this.loadDropdownOptions(this._latestDependencyValues, 0, false);
|
|
3242
|
+
}
|
|
3181
3243
|
}
|
|
3182
3244
|
}
|
|
3183
3245
|
else {
|
|
@@ -3192,15 +3254,45 @@ class FormFieldComponent {
|
|
|
3192
3254
|
}
|
|
3193
3255
|
}
|
|
3194
3256
|
}
|
|
3257
|
+
/** Restores localOptionList and pagination metadata from defaultStateSnapshot, preserving selected item(s) */
|
|
3258
|
+
restoreDefaultOptionList() {
|
|
3259
|
+
if (!this.defaultStateSnapshot.options.length)
|
|
3260
|
+
return;
|
|
3261
|
+
// 1. Restore pagination & metadata
|
|
3262
|
+
this.dropdownCurrentPage = this.defaultStateSnapshot.currentPage;
|
|
3263
|
+
this.dropdownTotalCount = this.defaultStateSnapshot.totalCount;
|
|
3264
|
+
this.hasMoreDropdownPages = this.defaultStateSnapshot.hasMorePages;
|
|
3265
|
+
// 2. Restore options array with selected items preserved
|
|
3266
|
+
const defaultCodes = new Set(this.defaultStateSnapshot.options.map(o => o.code));
|
|
3267
|
+
const merged = [...this.defaultStateSnapshot.options];
|
|
3268
|
+
this.selectedItems.forEach(opt => {
|
|
3269
|
+
if (!defaultCodes.has(opt.code)) {
|
|
3270
|
+
merged.push(opt);
|
|
3271
|
+
}
|
|
3272
|
+
});
|
|
3273
|
+
this.localOptionList = merged;
|
|
3274
|
+
this.filteredOptionList = [...this.localOptionList];
|
|
3275
|
+
if (this.isAutocomplete) {
|
|
3276
|
+
this.filteredOptions = [...this.localOptionList];
|
|
3277
|
+
}
|
|
3278
|
+
}
|
|
3195
3279
|
/** Resets the dropdown search text and filtered list. */
|
|
3196
3280
|
resetDropdownSearch(forceLoad = true, bypassCache = false) {
|
|
3281
|
+
const wasServerSearch = this._isServerSearchActive;
|
|
3197
3282
|
this.searchText = '';
|
|
3283
|
+
this._isServerSearchActive = false;
|
|
3198
3284
|
const searchConfig = this.config.optionConfig?.searchConfig;
|
|
3199
|
-
if (
|
|
3200
|
-
if (
|
|
3285
|
+
if (searchConfig?.enabled && searchConfig?.mode === 'server') {
|
|
3286
|
+
if (this.defaultStateSnapshot.options.length > 0) {
|
|
3287
|
+
this.restoreDefaultOptionList();
|
|
3288
|
+
}
|
|
3289
|
+
else if (forceLoad && this._dependenciesSatisfied && (bypassCache || wasServerSearch || this.localOptionList.length === 0)) {
|
|
3201
3290
|
this.dropdownCurrentPage = 0;
|
|
3202
3291
|
this.loadDropdownOptions(this._latestDependencyValues, 0, false);
|
|
3203
3292
|
}
|
|
3293
|
+
else {
|
|
3294
|
+
this.filteredOptionList = [...this.localOptionList];
|
|
3295
|
+
}
|
|
3204
3296
|
}
|
|
3205
3297
|
else {
|
|
3206
3298
|
this.filteredOptionList = [...this.localOptionList];
|
|
@@ -3315,11 +3407,15 @@ class FormFieldComponent {
|
|
|
3315
3407
|
options.forEach(opt => {
|
|
3316
3408
|
const exists = this.localOptionList.some(o => o.code === opt.code);
|
|
3317
3409
|
if (!exists) {
|
|
3318
|
-
|
|
3410
|
+
const item = {
|
|
3319
3411
|
label: opt.label,
|
|
3320
3412
|
code: opt.code,
|
|
3321
3413
|
value: opt.value || opt
|
|
3322
|
-
}
|
|
3414
|
+
};
|
|
3415
|
+
this.localOptionList.push(item);
|
|
3416
|
+
if (!this.defaultStateSnapshot.options.some(o => o.code === opt.code)) {
|
|
3417
|
+
this.defaultStateSnapshot.options.push(item);
|
|
3418
|
+
}
|
|
3323
3419
|
updated = true;
|
|
3324
3420
|
}
|
|
3325
3421
|
});
|
|
@@ -5718,6 +5814,8 @@ class SmartFormComponent {
|
|
|
5718
5814
|
nodes: fi['nodes'] || {},
|
|
5719
5815
|
branchSubType: fi['branchSubType'] || 'SINGLE',
|
|
5720
5816
|
showLoader: raw['showLoader'] ?? raw['field']?.['showLoader'] ?? false,
|
|
5817
|
+
searchConfig: fi['searchConfig'],
|
|
5818
|
+
pagination: fi['pagination'],
|
|
5721
5819
|
};
|
|
5722
5820
|
}
|
|
5723
5821
|
// Legacy flat format (backward compatibility with existing geographyConfig JSON)
|
|
@@ -5747,6 +5845,8 @@ class SmartFormComponent {
|
|
|
5747
5845
|
nodes,
|
|
5748
5846
|
branchSubType: 'SINGLE',
|
|
5749
5847
|
showLoader: raw['showLoader'] ?? false,
|
|
5848
|
+
searchConfig: raw['searchConfig'],
|
|
5849
|
+
pagination: raw['pagination'],
|
|
5750
5850
|
};
|
|
5751
5851
|
}
|
|
5752
5852
|
_fetchHierarchyTemplate(cfg) {
|
|
@@ -5822,6 +5922,13 @@ class SmartFormComponent {
|
|
|
5822
5922
|
valuePath: cfg.valuePath,
|
|
5823
5923
|
showLoader: cfg.showLoader,
|
|
5824
5924
|
};
|
|
5925
|
+
// Search/pagination are opt-in via geographyConfig.field.searchConfig/pagination — every
|
|
5926
|
+
// generated level (Country/State/District/…) gets the same behavior since they all hit
|
|
5927
|
+
// the same paginated MDM data API, just scoped by a different classCode/parentDataCode.
|
|
5928
|
+
if (cfg.searchConfig)
|
|
5929
|
+
optionConfig['searchConfig'] = cfg.searchConfig;
|
|
5930
|
+
if (cfg.pagination)
|
|
5931
|
+
optionConfig['pagination'] = cfg.pagination;
|
|
5825
5932
|
if (parentFieldName && !nodeOvr['noDependency']) {
|
|
5826
5933
|
optionConfig['dependencies'] = { [cfg.dependencyParam]: parentFieldName };
|
|
5827
5934
|
}
|
|
@@ -5860,7 +5967,10 @@ class SmartFormComponent {
|
|
|
5860
5967
|
subType: cfg.branchSubType,
|
|
5861
5968
|
colSpan,
|
|
5862
5969
|
isEnabled: true,
|
|
5863
|
-
|
|
5970
|
+
// customUI: true renders the same styled overlay/chevron as its sibling MDM-driven
|
|
5971
|
+
// dropdowns (Country/State/…) for visual consistency, without opting into a search box
|
|
5972
|
+
// — the branch list (e.g. Urban/Rural) is always short enough not to need one.
|
|
5973
|
+
optionConfig: { optionList: branchOptions, customUI: true },
|
|
5864
5974
|
};
|
|
5865
5975
|
if (visibilityExpression)
|
|
5866
5976
|
areaTypeField['visibilityExpression'] = visibilityExpression;
|
|
@@ -6473,6 +6583,15 @@ class DropdownComponent {
|
|
|
6473
6583
|
disabled = false;
|
|
6474
6584
|
required = false;
|
|
6475
6585
|
errorMessage = '';
|
|
6586
|
+
serverSearch = false;
|
|
6587
|
+
searchDebounceMs = 300;
|
|
6588
|
+
lazyLoad = false;
|
|
6589
|
+
// Live state for server-search/lazy-load — kept as plain inputs (not part of `config`)
|
|
6590
|
+
// since they change on every keystroke/scroll and shouldn't require replacing the whole
|
|
6591
|
+
// config object each time.
|
|
6592
|
+
loading = false;
|
|
6593
|
+
loadingMore = false;
|
|
6594
|
+
hasMore = false;
|
|
6476
6595
|
// Configurable styles
|
|
6477
6596
|
width;
|
|
6478
6597
|
height;
|
|
@@ -6497,6 +6616,8 @@ class DropdownComponent {
|
|
|
6497
6616
|
disabledColor;
|
|
6498
6617
|
boxShadow;
|
|
6499
6618
|
selectionChange = new EventEmitter();
|
|
6619
|
+
searchTermChange = new EventEmitter();
|
|
6620
|
+
loadMore = new EventEmitter();
|
|
6500
6621
|
viewport;
|
|
6501
6622
|
searchInput;
|
|
6502
6623
|
triggerEl;
|
|
@@ -6508,13 +6629,19 @@ class DropdownComponent {
|
|
|
6508
6629
|
menuPosition = { top: 0, left: 0, width: 0 };
|
|
6509
6630
|
onChange = () => { };
|
|
6510
6631
|
onTouched = () => { };
|
|
6632
|
+
search$ = new Subject();
|
|
6511
6633
|
constructor(el) {
|
|
6512
6634
|
this.el = el;
|
|
6635
|
+
this.search$.pipe(debounceTime(this.searchDebounceMs), distinctUntilChanged())
|
|
6636
|
+
.subscribe(term => this.searchTermChange.emit(term));
|
|
6513
6637
|
}
|
|
6514
6638
|
ngOnInit() {
|
|
6515
6639
|
this.updateFromConfig();
|
|
6516
6640
|
this.updateFromLabels();
|
|
6517
|
-
this.filteredOptions = this.validOptions;
|
|
6641
|
+
this.filteredOptions = this.serverSearch ? this.options : this.validOptions;
|
|
6642
|
+
}
|
|
6643
|
+
ngOnDestroy() {
|
|
6644
|
+
this.search$.complete();
|
|
6518
6645
|
}
|
|
6519
6646
|
ngOnChanges(changes) {
|
|
6520
6647
|
if (changes['config']) {
|
|
@@ -6524,7 +6651,7 @@ class DropdownComponent {
|
|
|
6524
6651
|
this.updateFromLabels();
|
|
6525
6652
|
}
|
|
6526
6653
|
if (changes['config'] || changes['options']) {
|
|
6527
|
-
this.filteredOptions = this.validOptions;
|
|
6654
|
+
this.filteredOptions = this.serverSearch ? this.options : this.validOptions;
|
|
6528
6655
|
}
|
|
6529
6656
|
if (changes['selectedValue']) {
|
|
6530
6657
|
const incoming = changes['selectedValue'].currentValue;
|
|
@@ -6543,6 +6670,9 @@ class DropdownComponent {
|
|
|
6543
6670
|
this.label = this.config.label ?? this.label;
|
|
6544
6671
|
this.multiple = this.config.multiple ?? this.multiple;
|
|
6545
6672
|
this.searchable = this.config.searchable ?? this.searchable;
|
|
6673
|
+
this.serverSearch = this.config.serverSearch ?? this.serverSearch;
|
|
6674
|
+
this.searchDebounceMs = this.config.searchDebounceMs ?? this.searchDebounceMs;
|
|
6675
|
+
this.lazyLoad = this.config.lazyLoad ?? this.lazyLoad;
|
|
6546
6676
|
this.clearable = this.config.clearable ?? this.clearable;
|
|
6547
6677
|
this.disabled = this.config.disabled ?? this.disabled;
|
|
6548
6678
|
this.required = this.config.required ?? this.required;
|
|
@@ -6667,6 +6797,11 @@ class DropdownComponent {
|
|
|
6667
6797
|
}
|
|
6668
6798
|
onSearch(term) {
|
|
6669
6799
|
this.searchTerm = term;
|
|
6800
|
+
if (this.serverSearch) {
|
|
6801
|
+
this.search$.next(term);
|
|
6802
|
+
this.focusedIndex = -1;
|
|
6803
|
+
return;
|
|
6804
|
+
}
|
|
6670
6805
|
if (!term) {
|
|
6671
6806
|
this.filteredOptions = this.validOptions;
|
|
6672
6807
|
}
|
|
@@ -6675,6 +6810,14 @@ class DropdownComponent {
|
|
|
6675
6810
|
}
|
|
6676
6811
|
this.focusedIndex = -1;
|
|
6677
6812
|
}
|
|
6813
|
+
onOptionsScroll(event) {
|
|
6814
|
+
if (!this.lazyLoad || !this.hasMore || this.loading || this.loadingMore)
|
|
6815
|
+
return;
|
|
6816
|
+
const el = event.target;
|
|
6817
|
+
if (el.scrollTop + el.clientHeight >= el.scrollHeight - 24) {
|
|
6818
|
+
this.loadMore.emit();
|
|
6819
|
+
}
|
|
6820
|
+
}
|
|
6678
6821
|
clearSelection(event) {
|
|
6679
6822
|
if (event) {
|
|
6680
6823
|
event.stopPropagation();
|
|
@@ -6790,13 +6933,13 @@ class DropdownComponent {
|
|
|
6790
6933
|
};
|
|
6791
6934
|
}
|
|
6792
6935
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DropdownComponent, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
6793
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: DropdownComponent, isStandalone: false, selector: "lib-dropdown", inputs: { config: "config", labels: "labels", options: "options", selectedValue: "selectedValue", placeholder: "placeholder", label: "label", multiple: "multiple", searchable: "searchable", clearable: "clearable", disabled: "disabled", required: "required", errorMessage: "errorMessage", width: "width", height: "height", borderRadius: "borderRadius", fontSize: "fontSize", gap: "gap", fontFamily: "fontFamily", labelColor: "labelColor", labelFontSize: "labelFontSize", labelFontWeight: "labelFontWeight", backgroundColor: "backgroundColor", borderColor: "borderColor", borderWidth: "borderWidth", padding: "padding", fontWeight: "fontWeight", color: "color", placeholderColor: "placeholderColor", focusBorderColor: "focusBorderColor", errorColor: "errorColor", disabledBackgroundColor: "disabledBackgroundColor", disabledColor: "disabledColor", boxShadow: "boxShadow" }, outputs: { selectionChange: "selectionChange" }, host: { listeners: { "keydown": "handleKeyboardEvent($event)" } }, providers: [
|
|
6936
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: DropdownComponent, isStandalone: false, selector: "lib-dropdown", inputs: { config: "config", labels: "labels", options: "options", selectedValue: "selectedValue", placeholder: "placeholder", label: "label", multiple: "multiple", searchable: "searchable", clearable: "clearable", disabled: "disabled", required: "required", errorMessage: "errorMessage", serverSearch: "serverSearch", searchDebounceMs: "searchDebounceMs", lazyLoad: "lazyLoad", loading: "loading", loadingMore: "loadingMore", hasMore: "hasMore", width: "width", height: "height", borderRadius: "borderRadius", fontSize: "fontSize", gap: "gap", fontFamily: "fontFamily", labelColor: "labelColor", labelFontSize: "labelFontSize", labelFontWeight: "labelFontWeight", backgroundColor: "backgroundColor", borderColor: "borderColor", borderWidth: "borderWidth", padding: "padding", fontWeight: "fontWeight", color: "color", placeholderColor: "placeholderColor", focusBorderColor: "focusBorderColor", errorColor: "errorColor", disabledBackgroundColor: "disabledBackgroundColor", disabledColor: "disabledColor", boxShadow: "boxShadow" }, outputs: { selectionChange: "selectionChange", searchTermChange: "searchTermChange", loadMore: "loadMore" }, host: { listeners: { "keydown": "handleKeyboardEvent($event)" } }, providers: [
|
|
6794
6937
|
{
|
|
6795
6938
|
provide: NG_VALUE_ACCESSOR,
|
|
6796
6939
|
useExisting: forwardRef(() => DropdownComponent),
|
|
6797
6940
|
multi: true
|
|
6798
6941
|
}
|
|
6799
|
-
], viewQueries: [{ propertyName: "viewport", first: true, predicate: CdkVirtualScrollViewport, descendants: true }, { propertyName: "searchInput", first: true, predicate: ["searchInput"], descendants: true }, { propertyName: "triggerEl", first: true, predicate: ["triggerEl"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"cc-dropdown-wrapper\" [ngStyle]=\"wrapperStyles\" libClickOutside (libClickOutside)=\"close()\">\r\n <!-- Label -->\r\n <label *ngIf=\"label\" class=\"cc-dropdown-label\" [ngStyle]=\"labelStyles\">\r\n {{ label }}\r\n <span *ngIf=\"required\" class=\"cc-required\">{{ resolvedLabels.requiredMarker }}</span>\r\n </label>\r\n\r\n <!-- Trigger -->\r\n <div #triggerEl class=\"cc-dropdown-trigger\" [class.disabled]=\"disabled\" [class.open]=\"isOpen\" [class.error]=\"errorMessage\"\r\n (click)=\"toggle()\" tabindex=\"0\" (keydown)=\"handleKeyboardEvent($event)\" [ngStyle]=\"fieldStyles\">\r\n\r\n <div class=\"cc-selected-value\" *ngIf=\"hasValue()\">\r\n {{ multiple ? value.length + ' ' + resolvedLabels.selectedSuffix : getSelectedLabel() }}\r\n </div>\r\n <div class=\"cc-placeholder\" *ngIf=\"!hasValue()\">{{ placeholder }}</div>\r\n\r\n <div class=\"cc-actions\">\r\n <span *ngIf=\"clearable && hasValue() && !disabled\" class=\"cc-clear-btn\" (click)=\"clearSelection($event)\"\r\n [attr.aria-label]=\"resolvedLabels.clearAriaLabel\">\r\n <span class=\"material-icons\">close</span>\r\n </span>\r\n <span class=\"cc-arrow material-icons\">expand_more</span>\r\n </div>\r\n </div>\r\n\r\n <!-- Dropdown Menu -->\r\n <div class=\"cc-dropdown-menu\" *ngIf=\"isOpen\"\r\n [ngStyle]=\"{ position: 'fixed', top: menuPosition.top + 'px', left: menuPosition.left + 'px', width: menuPosition.width + 'px', 'z-index': '9999' }\"\r\n (click)=\"$event.stopPropagation()\" (mousedown)=\"$event.stopPropagation()\">\r\n <!-- Search -->\r\n <div class=\"cc-search-container\" *ngIf=\"searchable\">\r\n <input type=\"text\" #searchInput [placeholder]=\"resolvedLabels.searchPlaceholder\"\r\n (input)=\"onSearch($any($event.target).value)\" (click)=\"$event.stopPropagation()\"\r\n class=\"cc-dropdown-search-input\" />\r\n </div>\r\n\r\n <!-- Options Virtual Scroll -->\r\n <cdk-virtual-scroll-viewport itemSize=\"40\" class=\"cc-virtual-scroll\"\r\n [style.height.px]=\"filteredOptions.length * 40 > 240 ? 240 : (filteredOptions.length * 40 || 40)\">\r\n\r\n <div *cdkVirtualFor=\"let option of filteredOptions; let i = index\" class=\"cc-option\"\r\n [class.selected]=\"isSelected(option)\" [class.focused]=\"i === focusedIndex\"\r\n [class.disabled]=\"option.disabled\" (click)=\"selectOption(option)\">\r\n\r\n <!-- Multi-select checkbox visual -->\r\n <span class=\"cc-multi-check\" *ngIf=\"multiple\">\r\n <span class=\"material-icons\" *ngIf=\"isSelected(option)\">check_box</span>\r\n <span class=\"material-icons\" *ngIf=\"!isSelected(option)\">check_box_outline_blank</span>\r\n </span>\r\n\r\n <!-- Icon -->\r\n <span class=\"cc-option-icon-wrapper\" *ngIf=\"option.icon\">\r\n <span class=\"material-icons\" *ngIf=\"getIconType(option.icon) === 'material'\">{{\r\n getIconValue(option.icon) }}</span>\r\n <i *ngIf=\"getIconType(option.icon) === 'fontawesome'\" [class]=\"getIconValue(option.icon)\"></i>\r\n <img *ngIf=\"getIconType(option.icon) === 'img'\" [src]=\"getIconValue(option.icon)\"\r\n class=\"cc-option-img\" alt=\"icon\" />\r\n </span>\r\n\r\n <span class=\"cc-option-label\">{{ option.label }}</span>\r\n\r\n <!-- Single-select check visual -->\r\n <span class=\"cc-single-check\" *ngIf=\"!multiple && isSelected(option)\">\r\n <span class=\"material-icons\">check</span>\r\n </span>\r\n </div>\r\n\r\n <div *ngIf=\"filteredOptions.length === 0\" class=\"cc-no-results\">{{ resolvedLabels.noResultsFound }}</div>\r\n </cdk-virtual-scroll-viewport>\r\n </div>\r\n\r\n <!-- Error Message -->\r\n <div class=\"cc-error-message\" *ngIf=\"errorMessage\">{{ errorMessage }}</div>\r\n</div>", styles: [".cc-dropdown-wrapper{display:flex;flex-direction:column;width:100%;position:relative;font-family:var(--cc-dropdown-font-family, inherit);gap:var(--cc-dropdown-label-gap, .5rem)}.cc-dropdown-label{font-size:var(--cc-dropdown-font-size, .875rem);font-weight:var(--cc-dropdown-font-weight, 500);color:var(--cc-dropdown-label-color, #202124);margin:0;line-height:1.4}.cc-required{color:var(--cc-dropdown-required-color, #D93025);margin-left:.25rem}.cc-dropdown-trigger{display:flex;align-items:center;justify-content:space-between;width:100%;min-height:var(--cc-dropdown-height, 2.5rem);padding:var(--cc-dropdown-padding, .5rem .75rem);background-color:var(--cc-dropdown-bg, #FEFEFE);border:var(--cc-dropdown-border-width, 1px) solid var(--cc-dropdown-border-color, #BDC1C6);border-radius:var(--cc-dropdown-border-radius, .4375rem);cursor:pointer;-webkit-user-select:none;user-select:none;box-sizing:border-box;transition:all .2s}.cc-dropdown-trigger:focus{outline:none;border-color:var(--cc-dropdown-focus-border-color, #1A73E8)}.cc-dropdown-trigger.open{border-color:var(--cc-dropdown-focus-border-color, #1A73E8)}.cc-dropdown-trigger.error{border-color:var(--cc-dropdown-error-color, #D93025)}.cc-dropdown-trigger.disabled{background-color:var(--cc-dropdown-disabled-bg, #F1F3F4);cursor:not-allowed;color:var(--cc-dropdown-disabled-color, #80868B)}.cc-dropdown-trigger.disabled .cc-arrow,.cc-dropdown-trigger.disabled .cc-clear-btn{color:var(--cc-dropdown-disabled-color, #80868B)}.cc-selected-value{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:var(--cc-dropdown-color, #202124);font-size:var(--cc-dropdown-font-size, .875rem);font-weight:var(--cc-dropdown-font-weight, 400)}.cc-placeholder{flex:1;color:var(--cc-dropdown-placeholder-color, #80868B);font-size:var(--cc-dropdown-font-size, .875rem)}.cc-actions{display:flex;align-items:center;gap:.5rem}.cc-arrow{color:var(--cc-dropdown-arrow-color, #5F6368);transition:transform .2s;font-size:1.25rem}.cc-dropdown-trigger.open .cc-arrow{transform:rotate(180deg)}.cc-clear-btn{display:flex;align-items:center;justify-content:center;color:var(--cc-dropdown-arrow-color, #5F6368);cursor:pointer}.cc-clear-btn:hover{color:#202124}.cc-clear-btn .material-icons{font-size:1.125rem}.cc-dropdown-menu{position:absolute;top:100%;left:0;width:100%;background-color:#fff;border:1px solid #BDC1C6;border-radius:0 0 4px 4px;box-shadow:0 2px 4px #0000001a;z-index:1000;margin-top:2px;overflow:hidden;animation:fadeIn .1s ease-out}@keyframes fadeIn{0%{opacity:0;transform:translateY(-5px)}to{opacity:1;transform:translateY(0)}}.cc-search-container{padding:.5rem;border-bottom:1px solid var(--cc-dropdown-divider-color, #E0E0E0)}.cc-dropdown-search-input{width:100%;padding:.5rem;border:1px solid #BDC1C6;border-radius:4px;outline:none;box-sizing:border-box;font-size:.875rem}.cc-dropdown-search-input:focus{border-color:var(--cc-dropdown-focus-border-color, #1A73E8)}.cc-virtual-scroll{width:100%;max-height:240px}.cc-option{display:flex;align-items:center;padding:0 .75rem;height:40px;cursor:pointer;color:var(--cc-dropdown-color, #202124);font-size:var(--cc-dropdown-font-size, .875rem);transition:background-color .1s;box-sizing:border-box}.cc-option:hover,.cc-option.focused{background-color:#f1f3f4}.cc-option.selected{background-color:#e8f0fe;color:#1a73e8}.cc-option.disabled{opacity:.5;cursor:not-allowed;background-color:transparent}.cc-multi-check{margin-right:.5rem;color:var(--cc-dropdown-arrow-color, #5F6368);display:flex;align-items:center}.cc-multi-check .material-icons{font-size:1.25rem}.cc-option.selected .cc-multi-check{color:#1a73e8}.cc-option-icon-wrapper{margin-right:.5rem;display:flex;align-items:center}.cc-option-icon-wrapper .material-icons{font-size:1.25rem}.cc-option-img{width:1.25rem;height:1.25rem;object-fit:contain}.cc-option-label{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.cc-single-check{margin-left:.5rem;color:#1a73e8;display:flex;align-items:center}.cc-single-check .material-icons{font-size:1.125rem}.cc-no-results{padding:.75rem;color:#80868b;text-align:center;font-size:.875rem}.cc-error-message{font-size:.75rem;color:var(--cc-dropdown-error-color, #D93025);margin-top:.25rem}\n"], dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: i4.ɵɵCdkFixedSizeVirtualScroll, selector: "cdk-virtual-scroll-viewport[itemSize]", inputs: ["itemSize", "minBufferPx", "maxBufferPx"] }, { kind: "directive", type: i4.ɵɵCdkVirtualForOf, selector: "[cdkVirtualFor][cdkVirtualForOf]", inputs: ["cdkVirtualForOf", "cdkVirtualForTrackBy", "cdkVirtualForTemplate", "cdkVirtualForTemplateCacheSize"] }, { kind: "component", type: i4.ɵɵCdkVirtualScrollViewport, selector: "cdk-virtual-scroll-viewport", inputs: ["orientation", "appendOnly"], outputs: ["scrolledIndexChange"] }, { kind: "directive", type: ClickOutsideDirective, selector: "[libClickOutside]", outputs: ["libClickOutside"] }] });
|
|
6942
|
+
], viewQueries: [{ propertyName: "viewport", first: true, predicate: CdkVirtualScrollViewport, descendants: true }, { propertyName: "searchInput", first: true, predicate: ["searchInput"], descendants: true }, { propertyName: "triggerEl", first: true, predicate: ["triggerEl"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"cc-dropdown-wrapper\" [ngStyle]=\"wrapperStyles\" libClickOutside (libClickOutside)=\"close()\">\r\n <!-- Label -->\r\n <label *ngIf=\"label\" class=\"cc-dropdown-label\" [ngStyle]=\"labelStyles\">\r\n {{ label }}\r\n <span *ngIf=\"required\" class=\"cc-required\">{{ resolvedLabels.requiredMarker }}</span>\r\n </label>\r\n\r\n <!-- Trigger -->\r\n <div #triggerEl class=\"cc-dropdown-trigger\" [class.disabled]=\"disabled\" [class.open]=\"isOpen\" [class.error]=\"errorMessage\"\r\n (click)=\"toggle()\" tabindex=\"0\" (keydown)=\"handleKeyboardEvent($event)\" [ngStyle]=\"fieldStyles\">\r\n\r\n <div class=\"cc-selected-value\" *ngIf=\"hasValue()\">\r\n {{ multiple ? value.length + ' ' + resolvedLabels.selectedSuffix : getSelectedLabel() }}\r\n </div>\r\n <div class=\"cc-placeholder\" *ngIf=\"!hasValue()\">{{ placeholder }}</div>\r\n\r\n <div class=\"cc-actions\">\r\n <span *ngIf=\"clearable && hasValue() && !disabled\" class=\"cc-clear-btn\" (click)=\"clearSelection($event)\"\r\n [attr.aria-label]=\"resolvedLabels.clearAriaLabel\">\r\n <span class=\"material-icons\">close</span>\r\n </span>\r\n <span class=\"cc-arrow material-icons\">expand_more</span>\r\n </div>\r\n </div>\r\n\r\n <!-- Dropdown Menu -->\r\n <div class=\"cc-dropdown-menu\" *ngIf=\"isOpen\"\r\n [ngStyle]=\"{ position: 'fixed', top: menuPosition.top + 'px', left: menuPosition.left + 'px', width: menuPosition.width + 'px', 'z-index': '9999' }\"\r\n (click)=\"$event.stopPropagation()\" (mousedown)=\"$event.stopPropagation()\">\r\n <!-- Search -->\r\n <div class=\"cc-search-container\" *ngIf=\"searchable\">\r\n <input type=\"text\" #searchInput [placeholder]=\"resolvedLabels.searchPlaceholder\"\r\n (input)=\"onSearch($any($event.target).value)\" (click)=\"$event.stopPropagation()\"\r\n class=\"cc-dropdown-search-input\" />\r\n </div>\r\n\r\n <!-- Options Virtual Scroll -->\r\n <cdk-virtual-scroll-viewport itemSize=\"40\" class=\"cc-virtual-scroll\"\r\n (scroll)=\"onOptionsScroll($event)\"\r\n [style.height.px]=\"filteredOptions.length * 40 > 240 ? 240 : (filteredOptions.length * 40 || 40)\">\r\n\r\n <div *ngIf=\"loading\" class=\"cc-status-row\">Loading...</div>\r\n\r\n <div *cdkVirtualFor=\"let option of filteredOptions; let i = index\" class=\"cc-option\"\r\n [class.selected]=\"isSelected(option)\" [class.focused]=\"i === focusedIndex\"\r\n [class.disabled]=\"option.disabled\" (click)=\"selectOption(option)\">\r\n\r\n <!-- Multi-select checkbox visual -->\r\n <span class=\"cc-multi-check\" *ngIf=\"multiple\">\r\n <span class=\"material-icons\" *ngIf=\"isSelected(option)\">check_box</span>\r\n <span class=\"material-icons\" *ngIf=\"!isSelected(option)\">check_box_outline_blank</span>\r\n </span>\r\n\r\n <!-- Icon -->\r\n <span class=\"cc-option-icon-wrapper\" *ngIf=\"option.icon\">\r\n <span class=\"material-icons\" *ngIf=\"getIconType(option.icon) === 'material'\">{{\r\n getIconValue(option.icon) }}</span>\r\n <i *ngIf=\"getIconType(option.icon) === 'fontawesome'\" [class]=\"getIconValue(option.icon)\"></i>\r\n <img *ngIf=\"getIconType(option.icon) === 'img'\" [src]=\"getIconValue(option.icon)\"\r\n class=\"cc-option-img\" alt=\"icon\" />\r\n </span>\r\n\r\n <span class=\"cc-option-label\">{{ option.label }}</span>\r\n\r\n <!-- Single-select check visual -->\r\n <span class=\"cc-single-check\" *ngIf=\"!multiple && isSelected(option)\">\r\n <span class=\"material-icons\">check</span>\r\n </span>\r\n </div>\r\n\r\n <div *ngIf=\"!loading && filteredOptions.length === 0\" class=\"cc-no-results\">{{ resolvedLabels.noResultsFound }}</div>\r\n <div *ngIf=\"loadingMore\" class=\"cc-status-row cc-loading-more\">Loading more...</div>\r\n </cdk-virtual-scroll-viewport>\r\n </div>\r\n\r\n <!-- Error Message -->\r\n <div class=\"cc-error-message\" *ngIf=\"errorMessage\">{{ errorMessage }}</div>\r\n</div>", styles: [".cc-dropdown-wrapper{display:flex;flex-direction:column;width:100%;position:relative;font-family:var(--cc-dropdown-font-family, inherit);gap:var(--cc-dropdown-label-gap, .5rem)}.cc-dropdown-label{font-size:var(--cc-dropdown-font-size, .875rem);font-weight:var(--cc-dropdown-font-weight, 500);color:var(--cc-dropdown-label-color, #202124);margin:0;line-height:1.4}.cc-required{color:var(--cc-dropdown-required-color, #D93025);margin-left:.25rem}.cc-dropdown-trigger{display:flex;align-items:center;justify-content:space-between;width:100%;min-height:var(--cc-dropdown-height, 2.5rem);padding:var(--cc-dropdown-padding, .5rem .75rem);background-color:var(--cc-dropdown-bg, #FEFEFE);border:var(--cc-dropdown-border-width, 1px) solid var(--cc-dropdown-border-color, #BDC1C6);border-radius:var(--cc-dropdown-border-radius, .4375rem);cursor:pointer;-webkit-user-select:none;user-select:none;box-sizing:border-box;transition:all .2s}.cc-dropdown-trigger:focus{outline:none;border-color:var(--cc-dropdown-focus-border-color, #1A73E8)}.cc-dropdown-trigger.open{border-color:var(--cc-dropdown-focus-border-color, #1A73E8)}.cc-dropdown-trigger.error{border-color:var(--cc-dropdown-error-color, #D93025)}.cc-dropdown-trigger.disabled{background-color:var(--cc-dropdown-disabled-bg, #F1F3F4);cursor:not-allowed;color:var(--cc-dropdown-disabled-color, #80868B)}.cc-dropdown-trigger.disabled .cc-arrow,.cc-dropdown-trigger.disabled .cc-clear-btn{color:var(--cc-dropdown-disabled-color, #80868B)}.cc-selected-value{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:var(--cc-dropdown-color, #202124);font-size:var(--cc-dropdown-font-size, .875rem);font-weight:var(--cc-dropdown-font-weight, 400)}.cc-placeholder{flex:1;color:var(--cc-dropdown-placeholder-color, #80868B);font-size:var(--cc-dropdown-font-size, .875rem)}.cc-actions{display:flex;align-items:center;gap:.5rem}.cc-arrow{color:var(--cc-dropdown-arrow-color, #5F6368);transition:transform .2s;font-size:1.25rem}.cc-dropdown-trigger.open .cc-arrow{transform:rotate(180deg)}.cc-clear-btn{display:flex;align-items:center;justify-content:center;color:var(--cc-dropdown-arrow-color, #5F6368);cursor:pointer}.cc-clear-btn:hover{color:#202124}.cc-clear-btn .material-icons{font-size:1.125rem}.cc-dropdown-menu{position:absolute;top:100%;left:0;width:100%;background-color:#fff;border:1px solid #BDC1C6;border-radius:0 0 4px 4px;box-shadow:0 2px 4px #0000001a;z-index:1000;margin-top:2px;overflow:hidden;animation:fadeIn .1s ease-out}@keyframes fadeIn{0%{opacity:0;transform:translateY(-5px)}to{opacity:1;transform:translateY(0)}}.cc-search-container{padding:.5rem;border-bottom:1px solid var(--cc-dropdown-divider-color, #E0E0E0)}.cc-dropdown-search-input{width:100%;padding:.5rem;border:1px solid #BDC1C6;border-radius:4px;outline:none;box-sizing:border-box;font-size:.875rem}.cc-dropdown-search-input:focus{border-color:var(--cc-dropdown-focus-border-color, #1A73E8)}.cc-virtual-scroll{width:100%;max-height:240px}.cc-option{display:flex;align-items:center;padding:0 .75rem;height:40px;cursor:pointer;color:var(--cc-dropdown-color, #202124);font-size:var(--cc-dropdown-font-size, .875rem);transition:background-color .1s;box-sizing:border-box}.cc-option:hover,.cc-option.focused{background-color:#f1f3f4}.cc-option.selected{background-color:#e8f0fe;color:#1a73e8}.cc-option.disabled{opacity:.5;cursor:not-allowed;background-color:transparent}.cc-multi-check{margin-right:.5rem;color:var(--cc-dropdown-arrow-color, #5F6368);display:flex;align-items:center}.cc-multi-check .material-icons{font-size:1.25rem}.cc-option.selected .cc-multi-check{color:#1a73e8}.cc-option-icon-wrapper{margin-right:.5rem;display:flex;align-items:center}.cc-option-icon-wrapper .material-icons{font-size:1.25rem}.cc-option-img{width:1.25rem;height:1.25rem;object-fit:contain}.cc-option-label{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.cc-single-check{margin-left:.5rem;color:#1a73e8;display:flex;align-items:center}.cc-single-check .material-icons{font-size:1.125rem}.cc-no-results{padding:.75rem;color:#80868b;text-align:center;font-size:.875rem}.cc-status-row{padding:.5rem .75rem;color:#80868b;text-align:center;font-size:.8125rem}.cc-loading-more{border-top:1px solid var(--cc-dropdown-divider-color, #E0E0E0)}.cc-error-message{font-size:.75rem;color:var(--cc-dropdown-error-color, #D93025);margin-top:.25rem}\n"], dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: i4.ɵɵCdkFixedSizeVirtualScroll, selector: "cdk-virtual-scroll-viewport[itemSize]", inputs: ["itemSize", "minBufferPx", "maxBufferPx"] }, { kind: "directive", type: i4.ɵɵCdkVirtualForOf, selector: "[cdkVirtualFor][cdkVirtualForOf]", inputs: ["cdkVirtualForOf", "cdkVirtualForTrackBy", "cdkVirtualForTemplate", "cdkVirtualForTemplateCacheSize"] }, { kind: "component", type: i4.ɵɵCdkVirtualScrollViewport, selector: "cdk-virtual-scroll-viewport", inputs: ["orientation", "appendOnly"], outputs: ["scrolledIndexChange"] }, { kind: "directive", type: ClickOutsideDirective, selector: "[libClickOutside]", outputs: ["libClickOutside"] }] });
|
|
6800
6943
|
}
|
|
6801
6944
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DropdownComponent, decorators: [{
|
|
6802
6945
|
type: Component,
|
|
@@ -6806,7 +6949,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
|
|
|
6806
6949
|
useExisting: forwardRef(() => DropdownComponent),
|
|
6807
6950
|
multi: true
|
|
6808
6951
|
}
|
|
6809
|
-
], template: "<div class=\"cc-dropdown-wrapper\" [ngStyle]=\"wrapperStyles\" libClickOutside (libClickOutside)=\"close()\">\r\n <!-- Label -->\r\n <label *ngIf=\"label\" class=\"cc-dropdown-label\" [ngStyle]=\"labelStyles\">\r\n {{ label }}\r\n <span *ngIf=\"required\" class=\"cc-required\">{{ resolvedLabels.requiredMarker }}</span>\r\n </label>\r\n\r\n <!-- Trigger -->\r\n <div #triggerEl class=\"cc-dropdown-trigger\" [class.disabled]=\"disabled\" [class.open]=\"isOpen\" [class.error]=\"errorMessage\"\r\n (click)=\"toggle()\" tabindex=\"0\" (keydown)=\"handleKeyboardEvent($event)\" [ngStyle]=\"fieldStyles\">\r\n\r\n <div class=\"cc-selected-value\" *ngIf=\"hasValue()\">\r\n {{ multiple ? value.length + ' ' + resolvedLabels.selectedSuffix : getSelectedLabel() }}\r\n </div>\r\n <div class=\"cc-placeholder\" *ngIf=\"!hasValue()\">{{ placeholder }}</div>\r\n\r\n <div class=\"cc-actions\">\r\n <span *ngIf=\"clearable && hasValue() && !disabled\" class=\"cc-clear-btn\" (click)=\"clearSelection($event)\"\r\n [attr.aria-label]=\"resolvedLabels.clearAriaLabel\">\r\n <span class=\"material-icons\">close</span>\r\n </span>\r\n <span class=\"cc-arrow material-icons\">expand_more</span>\r\n </div>\r\n </div>\r\n\r\n <!-- Dropdown Menu -->\r\n <div class=\"cc-dropdown-menu\" *ngIf=\"isOpen\"\r\n [ngStyle]=\"{ position: 'fixed', top: menuPosition.top + 'px', left: menuPosition.left + 'px', width: menuPosition.width + 'px', 'z-index': '9999' }\"\r\n (click)=\"$event.stopPropagation()\" (mousedown)=\"$event.stopPropagation()\">\r\n <!-- Search -->\r\n <div class=\"cc-search-container\" *ngIf=\"searchable\">\r\n <input type=\"text\" #searchInput [placeholder]=\"resolvedLabels.searchPlaceholder\"\r\n (input)=\"onSearch($any($event.target).value)\" (click)=\"$event.stopPropagation()\"\r\n class=\"cc-dropdown-search-input\" />\r\n </div>\r\n\r\n <!-- Options Virtual Scroll -->\r\n <cdk-virtual-scroll-viewport itemSize=\"40\" class=\"cc-virtual-scroll\"\r\n [style.height.px]=\"filteredOptions.length * 40 > 240 ? 240 : (filteredOptions.length * 40 || 40)\">\r\n\r\n <div *cdkVirtualFor=\"let option of filteredOptions; let i = index\" class=\"cc-option\"\r\n [class.selected]=\"isSelected(option)\" [class.focused]=\"i === focusedIndex\"\r\n [class.disabled]=\"option.disabled\" (click)=\"selectOption(option)\">\r\n\r\n <!-- Multi-select checkbox visual -->\r\n <span class=\"cc-multi-check\" *ngIf=\"multiple\">\r\n <span class=\"material-icons\" *ngIf=\"isSelected(option)\">check_box</span>\r\n <span class=\"material-icons\" *ngIf=\"!isSelected(option)\">check_box_outline_blank</span>\r\n </span>\r\n\r\n <!-- Icon -->\r\n <span class=\"cc-option-icon-wrapper\" *ngIf=\"option.icon\">\r\n <span class=\"material-icons\" *ngIf=\"getIconType(option.icon) === 'material'\">{{\r\n getIconValue(option.icon) }}</span>\r\n <i *ngIf=\"getIconType(option.icon) === 'fontawesome'\" [class]=\"getIconValue(option.icon)\"></i>\r\n <img *ngIf=\"getIconType(option.icon) === 'img'\" [src]=\"getIconValue(option.icon)\"\r\n class=\"cc-option-img\" alt=\"icon\" />\r\n </span>\r\n\r\n <span class=\"cc-option-label\">{{ option.label }}</span>\r\n\r\n <!-- Single-select check visual -->\r\n <span class=\"cc-single-check\" *ngIf=\"!multiple && isSelected(option)\">\r\n <span class=\"material-icons\">check</span>\r\n </span>\r\n </div>\r\n\r\n <div *ngIf=\"filteredOptions.length === 0\" class=\"cc-no-results\">{{ resolvedLabels.noResultsFound }}</div>\r\n </cdk-virtual-scroll-viewport>\r\n </div>\r\n\r\n <!-- Error Message -->\r\n <div class=\"cc-error-message\" *ngIf=\"errorMessage\">{{ errorMessage }}</div>\r\n</div>", styles: [".cc-dropdown-wrapper{display:flex;flex-direction:column;width:100%;position:relative;font-family:var(--cc-dropdown-font-family, inherit);gap:var(--cc-dropdown-label-gap, .5rem)}.cc-dropdown-label{font-size:var(--cc-dropdown-font-size, .875rem);font-weight:var(--cc-dropdown-font-weight, 500);color:var(--cc-dropdown-label-color, #202124);margin:0;line-height:1.4}.cc-required{color:var(--cc-dropdown-required-color, #D93025);margin-left:.25rem}.cc-dropdown-trigger{display:flex;align-items:center;justify-content:space-between;width:100%;min-height:var(--cc-dropdown-height, 2.5rem);padding:var(--cc-dropdown-padding, .5rem .75rem);background-color:var(--cc-dropdown-bg, #FEFEFE);border:var(--cc-dropdown-border-width, 1px) solid var(--cc-dropdown-border-color, #BDC1C6);border-radius:var(--cc-dropdown-border-radius, .4375rem);cursor:pointer;-webkit-user-select:none;user-select:none;box-sizing:border-box;transition:all .2s}.cc-dropdown-trigger:focus{outline:none;border-color:var(--cc-dropdown-focus-border-color, #1A73E8)}.cc-dropdown-trigger.open{border-color:var(--cc-dropdown-focus-border-color, #1A73E8)}.cc-dropdown-trigger.error{border-color:var(--cc-dropdown-error-color, #D93025)}.cc-dropdown-trigger.disabled{background-color:var(--cc-dropdown-disabled-bg, #F1F3F4);cursor:not-allowed;color:var(--cc-dropdown-disabled-color, #80868B)}.cc-dropdown-trigger.disabled .cc-arrow,.cc-dropdown-trigger.disabled .cc-clear-btn{color:var(--cc-dropdown-disabled-color, #80868B)}.cc-selected-value{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:var(--cc-dropdown-color, #202124);font-size:var(--cc-dropdown-font-size, .875rem);font-weight:var(--cc-dropdown-font-weight, 400)}.cc-placeholder{flex:1;color:var(--cc-dropdown-placeholder-color, #80868B);font-size:var(--cc-dropdown-font-size, .875rem)}.cc-actions{display:flex;align-items:center;gap:.5rem}.cc-arrow{color:var(--cc-dropdown-arrow-color, #5F6368);transition:transform .2s;font-size:1.25rem}.cc-dropdown-trigger.open .cc-arrow{transform:rotate(180deg)}.cc-clear-btn{display:flex;align-items:center;justify-content:center;color:var(--cc-dropdown-arrow-color, #5F6368);cursor:pointer}.cc-clear-btn:hover{color:#202124}.cc-clear-btn .material-icons{font-size:1.125rem}.cc-dropdown-menu{position:absolute;top:100%;left:0;width:100%;background-color:#fff;border:1px solid #BDC1C6;border-radius:0 0 4px 4px;box-shadow:0 2px 4px #0000001a;z-index:1000;margin-top:2px;overflow:hidden;animation:fadeIn .1s ease-out}@keyframes fadeIn{0%{opacity:0;transform:translateY(-5px)}to{opacity:1;transform:translateY(0)}}.cc-search-container{padding:.5rem;border-bottom:1px solid var(--cc-dropdown-divider-color, #E0E0E0)}.cc-dropdown-search-input{width:100%;padding:.5rem;border:1px solid #BDC1C6;border-radius:4px;outline:none;box-sizing:border-box;font-size:.875rem}.cc-dropdown-search-input:focus{border-color:var(--cc-dropdown-focus-border-color, #1A73E8)}.cc-virtual-scroll{width:100%;max-height:240px}.cc-option{display:flex;align-items:center;padding:0 .75rem;height:40px;cursor:pointer;color:var(--cc-dropdown-color, #202124);font-size:var(--cc-dropdown-font-size, .875rem);transition:background-color .1s;box-sizing:border-box}.cc-option:hover,.cc-option.focused{background-color:#f1f3f4}.cc-option.selected{background-color:#e8f0fe;color:#1a73e8}.cc-option.disabled{opacity:.5;cursor:not-allowed;background-color:transparent}.cc-multi-check{margin-right:.5rem;color:var(--cc-dropdown-arrow-color, #5F6368);display:flex;align-items:center}.cc-multi-check .material-icons{font-size:1.25rem}.cc-option.selected .cc-multi-check{color:#1a73e8}.cc-option-icon-wrapper{margin-right:.5rem;display:flex;align-items:center}.cc-option-icon-wrapper .material-icons{font-size:1.25rem}.cc-option-img{width:1.25rem;height:1.25rem;object-fit:contain}.cc-option-label{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.cc-single-check{margin-left:.5rem;color:#1a73e8;display:flex;align-items:center}.cc-single-check .material-icons{font-size:1.125rem}.cc-no-results{padding:.75rem;color:#80868b;text-align:center;font-size:.875rem}.cc-error-message{font-size:.75rem;color:var(--cc-dropdown-error-color, #D93025);margin-top:.25rem}\n"] }]
|
|
6952
|
+
], template: "<div class=\"cc-dropdown-wrapper\" [ngStyle]=\"wrapperStyles\" libClickOutside (libClickOutside)=\"close()\">\r\n <!-- Label -->\r\n <label *ngIf=\"label\" class=\"cc-dropdown-label\" [ngStyle]=\"labelStyles\">\r\n {{ label }}\r\n <span *ngIf=\"required\" class=\"cc-required\">{{ resolvedLabels.requiredMarker }}</span>\r\n </label>\r\n\r\n <!-- Trigger -->\r\n <div #triggerEl class=\"cc-dropdown-trigger\" [class.disabled]=\"disabled\" [class.open]=\"isOpen\" [class.error]=\"errorMessage\"\r\n (click)=\"toggle()\" tabindex=\"0\" (keydown)=\"handleKeyboardEvent($event)\" [ngStyle]=\"fieldStyles\">\r\n\r\n <div class=\"cc-selected-value\" *ngIf=\"hasValue()\">\r\n {{ multiple ? value.length + ' ' + resolvedLabels.selectedSuffix : getSelectedLabel() }}\r\n </div>\r\n <div class=\"cc-placeholder\" *ngIf=\"!hasValue()\">{{ placeholder }}</div>\r\n\r\n <div class=\"cc-actions\">\r\n <span *ngIf=\"clearable && hasValue() && !disabled\" class=\"cc-clear-btn\" (click)=\"clearSelection($event)\"\r\n [attr.aria-label]=\"resolvedLabels.clearAriaLabel\">\r\n <span class=\"material-icons\">close</span>\r\n </span>\r\n <span class=\"cc-arrow material-icons\">expand_more</span>\r\n </div>\r\n </div>\r\n\r\n <!-- Dropdown Menu -->\r\n <div class=\"cc-dropdown-menu\" *ngIf=\"isOpen\"\r\n [ngStyle]=\"{ position: 'fixed', top: menuPosition.top + 'px', left: menuPosition.left + 'px', width: menuPosition.width + 'px', 'z-index': '9999' }\"\r\n (click)=\"$event.stopPropagation()\" (mousedown)=\"$event.stopPropagation()\">\r\n <!-- Search -->\r\n <div class=\"cc-search-container\" *ngIf=\"searchable\">\r\n <input type=\"text\" #searchInput [placeholder]=\"resolvedLabels.searchPlaceholder\"\r\n (input)=\"onSearch($any($event.target).value)\" (click)=\"$event.stopPropagation()\"\r\n class=\"cc-dropdown-search-input\" />\r\n </div>\r\n\r\n <!-- Options Virtual Scroll -->\r\n <cdk-virtual-scroll-viewport itemSize=\"40\" class=\"cc-virtual-scroll\"\r\n (scroll)=\"onOptionsScroll($event)\"\r\n [style.height.px]=\"filteredOptions.length * 40 > 240 ? 240 : (filteredOptions.length * 40 || 40)\">\r\n\r\n <div *ngIf=\"loading\" class=\"cc-status-row\">Loading...</div>\r\n\r\n <div *cdkVirtualFor=\"let option of filteredOptions; let i = index\" class=\"cc-option\"\r\n [class.selected]=\"isSelected(option)\" [class.focused]=\"i === focusedIndex\"\r\n [class.disabled]=\"option.disabled\" (click)=\"selectOption(option)\">\r\n\r\n <!-- Multi-select checkbox visual -->\r\n <span class=\"cc-multi-check\" *ngIf=\"multiple\">\r\n <span class=\"material-icons\" *ngIf=\"isSelected(option)\">check_box</span>\r\n <span class=\"material-icons\" *ngIf=\"!isSelected(option)\">check_box_outline_blank</span>\r\n </span>\r\n\r\n <!-- Icon -->\r\n <span class=\"cc-option-icon-wrapper\" *ngIf=\"option.icon\">\r\n <span class=\"material-icons\" *ngIf=\"getIconType(option.icon) === 'material'\">{{\r\n getIconValue(option.icon) }}</span>\r\n <i *ngIf=\"getIconType(option.icon) === 'fontawesome'\" [class]=\"getIconValue(option.icon)\"></i>\r\n <img *ngIf=\"getIconType(option.icon) === 'img'\" [src]=\"getIconValue(option.icon)\"\r\n class=\"cc-option-img\" alt=\"icon\" />\r\n </span>\r\n\r\n <span class=\"cc-option-label\">{{ option.label }}</span>\r\n\r\n <!-- Single-select check visual -->\r\n <span class=\"cc-single-check\" *ngIf=\"!multiple && isSelected(option)\">\r\n <span class=\"material-icons\">check</span>\r\n </span>\r\n </div>\r\n\r\n <div *ngIf=\"!loading && filteredOptions.length === 0\" class=\"cc-no-results\">{{ resolvedLabels.noResultsFound }}</div>\r\n <div *ngIf=\"loadingMore\" class=\"cc-status-row cc-loading-more\">Loading more...</div>\r\n </cdk-virtual-scroll-viewport>\r\n </div>\r\n\r\n <!-- Error Message -->\r\n <div class=\"cc-error-message\" *ngIf=\"errorMessage\">{{ errorMessage }}</div>\r\n</div>", styles: [".cc-dropdown-wrapper{display:flex;flex-direction:column;width:100%;position:relative;font-family:var(--cc-dropdown-font-family, inherit);gap:var(--cc-dropdown-label-gap, .5rem)}.cc-dropdown-label{font-size:var(--cc-dropdown-font-size, .875rem);font-weight:var(--cc-dropdown-font-weight, 500);color:var(--cc-dropdown-label-color, #202124);margin:0;line-height:1.4}.cc-required{color:var(--cc-dropdown-required-color, #D93025);margin-left:.25rem}.cc-dropdown-trigger{display:flex;align-items:center;justify-content:space-between;width:100%;min-height:var(--cc-dropdown-height, 2.5rem);padding:var(--cc-dropdown-padding, .5rem .75rem);background-color:var(--cc-dropdown-bg, #FEFEFE);border:var(--cc-dropdown-border-width, 1px) solid var(--cc-dropdown-border-color, #BDC1C6);border-radius:var(--cc-dropdown-border-radius, .4375rem);cursor:pointer;-webkit-user-select:none;user-select:none;box-sizing:border-box;transition:all .2s}.cc-dropdown-trigger:focus{outline:none;border-color:var(--cc-dropdown-focus-border-color, #1A73E8)}.cc-dropdown-trigger.open{border-color:var(--cc-dropdown-focus-border-color, #1A73E8)}.cc-dropdown-trigger.error{border-color:var(--cc-dropdown-error-color, #D93025)}.cc-dropdown-trigger.disabled{background-color:var(--cc-dropdown-disabled-bg, #F1F3F4);cursor:not-allowed;color:var(--cc-dropdown-disabled-color, #80868B)}.cc-dropdown-trigger.disabled .cc-arrow,.cc-dropdown-trigger.disabled .cc-clear-btn{color:var(--cc-dropdown-disabled-color, #80868B)}.cc-selected-value{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:var(--cc-dropdown-color, #202124);font-size:var(--cc-dropdown-font-size, .875rem);font-weight:var(--cc-dropdown-font-weight, 400)}.cc-placeholder{flex:1;color:var(--cc-dropdown-placeholder-color, #80868B);font-size:var(--cc-dropdown-font-size, .875rem)}.cc-actions{display:flex;align-items:center;gap:.5rem}.cc-arrow{color:var(--cc-dropdown-arrow-color, #5F6368);transition:transform .2s;font-size:1.25rem}.cc-dropdown-trigger.open .cc-arrow{transform:rotate(180deg)}.cc-clear-btn{display:flex;align-items:center;justify-content:center;color:var(--cc-dropdown-arrow-color, #5F6368);cursor:pointer}.cc-clear-btn:hover{color:#202124}.cc-clear-btn .material-icons{font-size:1.125rem}.cc-dropdown-menu{position:absolute;top:100%;left:0;width:100%;background-color:#fff;border:1px solid #BDC1C6;border-radius:0 0 4px 4px;box-shadow:0 2px 4px #0000001a;z-index:1000;margin-top:2px;overflow:hidden;animation:fadeIn .1s ease-out}@keyframes fadeIn{0%{opacity:0;transform:translateY(-5px)}to{opacity:1;transform:translateY(0)}}.cc-search-container{padding:.5rem;border-bottom:1px solid var(--cc-dropdown-divider-color, #E0E0E0)}.cc-dropdown-search-input{width:100%;padding:.5rem;border:1px solid #BDC1C6;border-radius:4px;outline:none;box-sizing:border-box;font-size:.875rem}.cc-dropdown-search-input:focus{border-color:var(--cc-dropdown-focus-border-color, #1A73E8)}.cc-virtual-scroll{width:100%;max-height:240px}.cc-option{display:flex;align-items:center;padding:0 .75rem;height:40px;cursor:pointer;color:var(--cc-dropdown-color, #202124);font-size:var(--cc-dropdown-font-size, .875rem);transition:background-color .1s;box-sizing:border-box}.cc-option:hover,.cc-option.focused{background-color:#f1f3f4}.cc-option.selected{background-color:#e8f0fe;color:#1a73e8}.cc-option.disabled{opacity:.5;cursor:not-allowed;background-color:transparent}.cc-multi-check{margin-right:.5rem;color:var(--cc-dropdown-arrow-color, #5F6368);display:flex;align-items:center}.cc-multi-check .material-icons{font-size:1.25rem}.cc-option.selected .cc-multi-check{color:#1a73e8}.cc-option-icon-wrapper{margin-right:.5rem;display:flex;align-items:center}.cc-option-icon-wrapper .material-icons{font-size:1.25rem}.cc-option-img{width:1.25rem;height:1.25rem;object-fit:contain}.cc-option-label{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.cc-single-check{margin-left:.5rem;color:#1a73e8;display:flex;align-items:center}.cc-single-check .material-icons{font-size:1.125rem}.cc-no-results{padding:.75rem;color:#80868b;text-align:center;font-size:.875rem}.cc-status-row{padding:.5rem .75rem;color:#80868b;text-align:center;font-size:.8125rem}.cc-loading-more{border-top:1px solid var(--cc-dropdown-divider-color, #E0E0E0)}.cc-error-message{font-size:.75rem;color:var(--cc-dropdown-error-color, #D93025);margin-top:.25rem}\n"] }]
|
|
6810
6953
|
}], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { config: [{
|
|
6811
6954
|
type: Input
|
|
6812
6955
|
}], labels: [{
|
|
@@ -6831,6 +6974,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
|
|
|
6831
6974
|
type: Input
|
|
6832
6975
|
}], errorMessage: [{
|
|
6833
6976
|
type: Input
|
|
6977
|
+
}], serverSearch: [{
|
|
6978
|
+
type: Input
|
|
6979
|
+
}], searchDebounceMs: [{
|
|
6980
|
+
type: Input
|
|
6981
|
+
}], lazyLoad: [{
|
|
6982
|
+
type: Input
|
|
6983
|
+
}], loading: [{
|
|
6984
|
+
type: Input
|
|
6985
|
+
}], loadingMore: [{
|
|
6986
|
+
type: Input
|
|
6987
|
+
}], hasMore: [{
|
|
6988
|
+
type: Input
|
|
6834
6989
|
}], width: [{
|
|
6835
6990
|
type: Input
|
|
6836
6991
|
}], height: [{
|
|
@@ -6875,6 +7030,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
|
|
|
6875
7030
|
type: Input
|
|
6876
7031
|
}], selectionChange: [{
|
|
6877
7032
|
type: Output
|
|
7033
|
+
}], searchTermChange: [{
|
|
7034
|
+
type: Output
|
|
7035
|
+
}], loadMore: [{
|
|
7036
|
+
type: Output
|
|
6878
7037
|
}], viewport: [{
|
|
6879
7038
|
type: ViewChild,
|
|
6880
7039
|
args: [CdkVirtualScrollViewport]
|
|
@@ -10689,6 +10848,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
|
|
|
10689
10848
|
* clone, so `applyTreeToSchema` simply walks the tree and assigns the node state
|
|
10690
10849
|
* onto those references — there is no positional re-matching, which keeps it robust
|
|
10691
10850
|
* against ROWs, nested groups, and mixed leaf/section children.
|
|
10851
|
+
*
|
|
10852
|
+
* Field order is a plain property of the schema — there is no separate `sequence`
|
|
10853
|
+
* field. Reordering rewrites the schema's own children array in place, so render
|
|
10854
|
+
* order (which simply follows array order, as it always has) reflects the
|
|
10855
|
+
* configurator's choices with no extra sorting logic anywhere else.
|
|
10692
10856
|
*/
|
|
10693
10857
|
class ConfigSchemaTreeService {
|
|
10694
10858
|
// ── Parsing ─────────────────────────────────────────────────────────────────
|
|
@@ -10704,8 +10868,9 @@ class ConfigSchemaTreeService {
|
|
|
10704
10868
|
}
|
|
10705
10869
|
/**
|
|
10706
10870
|
* Write the current tree state back onto the schema the nodes reference.
|
|
10707
|
-
* Sets isEnabled/visible/disabled for visibility
|
|
10708
|
-
*
|
|
10871
|
+
* Sets isEnabled/visible/disabled for visibility, required for mandatory, and
|
|
10872
|
+
* colSpan; and physically reorders each section's own children array to match
|
|
10873
|
+
* the tree's current field order.
|
|
10709
10874
|
*/
|
|
10710
10875
|
applyTreeToSchema(sections) {
|
|
10711
10876
|
for (const section of sections) {
|
|
@@ -10715,11 +10880,12 @@ class ConfigSchemaTreeService {
|
|
|
10715
10880
|
// ── Private: parsing ──────────────────────────────────────────────────────────
|
|
10716
10881
|
_buildSections(children) {
|
|
10717
10882
|
const sections = [];
|
|
10883
|
+
const reorderable = !children.some(c => c.type === 'ROW');
|
|
10718
10884
|
let leafBundle = [];
|
|
10719
10885
|
for (const child of children) {
|
|
10720
10886
|
if (this._isSection(child)) {
|
|
10721
10887
|
if (leafBundle.length) {
|
|
10722
|
-
sections.push(this._createBundleSection(leafBundle));
|
|
10888
|
+
sections.push(this._createBundleSection(leafBundle, children, reorderable));
|
|
10723
10889
|
leafBundle = [];
|
|
10724
10890
|
}
|
|
10725
10891
|
sections.push(this._buildSection(child));
|
|
@@ -10733,11 +10899,12 @@ class ConfigSchemaTreeService {
|
|
|
10733
10899
|
}
|
|
10734
10900
|
}
|
|
10735
10901
|
if (leafBundle.length)
|
|
10736
|
-
sections.push(this._createBundleSection(leafBundle));
|
|
10902
|
+
sections.push(this._createBundleSection(leafBundle, children, reorderable));
|
|
10737
10903
|
return sections;
|
|
10738
10904
|
}
|
|
10739
10905
|
_buildSection(field) {
|
|
10740
10906
|
const children = field.sectionConfig?.children ?? field.children ?? [];
|
|
10907
|
+
const reorderable = !children.some(c => c.type === 'ROW');
|
|
10741
10908
|
const fields = [];
|
|
10742
10909
|
const subsections = [];
|
|
10743
10910
|
for (const child of children) {
|
|
@@ -10771,9 +10938,11 @@ class ConfigSchemaTreeService {
|
|
|
10771
10938
|
expanded: true,
|
|
10772
10939
|
fields,
|
|
10773
10940
|
subsections,
|
|
10941
|
+
fieldsSource: children,
|
|
10942
|
+
reorderable,
|
|
10774
10943
|
};
|
|
10775
10944
|
}
|
|
10776
|
-
_createBundleSection(fields) {
|
|
10945
|
+
_createBundleSection(fields, fieldsSource, reorderable) {
|
|
10777
10946
|
return {
|
|
10778
10947
|
label: 'Fields',
|
|
10779
10948
|
fieldConfig: null,
|
|
@@ -10783,6 +10952,8 @@ class ConfigSchemaTreeService {
|
|
|
10783
10952
|
expanded: true,
|
|
10784
10953
|
fields,
|
|
10785
10954
|
subsections: [],
|
|
10955
|
+
fieldsSource,
|
|
10956
|
+
reorderable,
|
|
10786
10957
|
};
|
|
10787
10958
|
}
|
|
10788
10959
|
_buildField(field) {
|
|
@@ -10793,6 +10964,7 @@ class ConfigSchemaTreeService {
|
|
|
10793
10964
|
type: field.type,
|
|
10794
10965
|
visible,
|
|
10795
10966
|
mandatory: visible ? field.required === true : false,
|
|
10967
|
+
colSpan: field.colSpan ?? 12,
|
|
10796
10968
|
lockVisibility: field.lockVisibility === true,
|
|
10797
10969
|
lockMandatory: field.lockMandatory === true,
|
|
10798
10970
|
parentName: field.optionConfig?.dependencies?.['parentDataCode'],
|
|
@@ -10809,15 +10981,34 @@ class ConfigSchemaTreeService {
|
|
|
10809
10981
|
section.fieldConfig.visible = section.visible; // backward compatibility
|
|
10810
10982
|
section.fieldConfig.disabled = !section.visible;
|
|
10811
10983
|
}
|
|
10984
|
+
if (section.reorderable && section.fieldsSource) {
|
|
10985
|
+
this._reorderChildren(section.fieldsSource, section.fields);
|
|
10986
|
+
}
|
|
10812
10987
|
for (const field of section.fields)
|
|
10813
10988
|
this._applyField(field);
|
|
10814
10989
|
for (const sub of section.subsections)
|
|
10815
10990
|
this._applySection(sub);
|
|
10816
10991
|
}
|
|
10992
|
+
/**
|
|
10993
|
+
* Rewrites `slots` in place so its leaf-field entries follow `fields`' current
|
|
10994
|
+
* order. Section entries (GROUP/SUBFIELDS) keep their original array position —
|
|
10995
|
+
* only the leaf fields move. Safe to call whenever `slots` contains no ROW
|
|
10996
|
+
* (guaranteed by the `reorderable` flag the caller checks).
|
|
10997
|
+
*/
|
|
10998
|
+
_reorderChildren(slots, fields) {
|
|
10999
|
+
const orderedLeaves = fields.map(f => f.fieldConfig);
|
|
11000
|
+
let cursor = 0;
|
|
11001
|
+
for (let i = 0; i < slots.length; i++) {
|
|
11002
|
+
if (!this._isSection(slots[i])) {
|
|
11003
|
+
slots[i] = orderedLeaves[cursor++];
|
|
11004
|
+
}
|
|
11005
|
+
}
|
|
11006
|
+
}
|
|
10817
11007
|
_applyField(field) {
|
|
10818
11008
|
field.fieldConfig.isEnabled = field.visible;
|
|
10819
11009
|
field.fieldConfig.visible = field.visible; // backward compatibility
|
|
10820
11010
|
field.fieldConfig.required = field.visible ? field.mandatory : false;
|
|
11011
|
+
field.fieldConfig.colSpan = field.colSpan;
|
|
10821
11012
|
}
|
|
10822
11013
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ConfigSchemaTreeService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
10823
11014
|
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ConfigSchemaTreeService, providedIn: 'root' });
|
|
@@ -10894,6 +11085,27 @@ class FieldConfigurationService {
|
|
|
10894
11085
|
return { ...f, mandatory: !f.mandatory };
|
|
10895
11086
|
});
|
|
10896
11087
|
}
|
|
11088
|
+
/** Set a field's column span, clamped to the 1-12 grid range. */
|
|
11089
|
+
setFieldColSpan(path, fieldIndex, colSpan) {
|
|
11090
|
+
const clamped = Math.min(12, Math.max(1, Math.round(colSpan) || 1));
|
|
11091
|
+
this._updateFieldAtPath(path, fieldIndex, f => ({ ...f, colSpan: clamped }));
|
|
11092
|
+
}
|
|
11093
|
+
/**
|
|
11094
|
+
* Reorder a field within its own section (drag-and-drop). Reordering is scoped to
|
|
11095
|
+
* one section's direct fields — dragging never moves a field across sections.
|
|
11096
|
+
* Rejected (no-op) if the move would place a field above the field it depends on
|
|
11097
|
+
* via `optionConfig.dependencies` (e.g. a "state" field can never sort above the
|
|
11098
|
+
* "country" field it depends on).
|
|
11099
|
+
*/
|
|
11100
|
+
reorderField(path, previousIndex, currentIndex) {
|
|
11101
|
+
if (previousIndex === currentIndex)
|
|
11102
|
+
return;
|
|
11103
|
+
this._updateSectionAtPath(path, section => {
|
|
11104
|
+
const fields = [...section.fields];
|
|
11105
|
+
moveItemInArray(fields, previousIndex, currentIndex);
|
|
11106
|
+
return this._isValidFieldOrder(fields) ? { ...section, fields } : section;
|
|
11107
|
+
});
|
|
11108
|
+
}
|
|
10897
11109
|
// ── Output ──────────────────────────────────────────────────────────────────
|
|
10898
11110
|
/**
|
|
10899
11111
|
* Produce the updated schema. Writes the current tree state onto the working
|
|
@@ -11001,6 +11213,25 @@ class FieldConfigurationService {
|
|
|
11001
11213
|
}));
|
|
11002
11214
|
return rebuildSections(sections);
|
|
11003
11215
|
}
|
|
11216
|
+
/**
|
|
11217
|
+
* True when every field with a dependency parent (`parentName`) sorts after that
|
|
11218
|
+
* parent within the given list. Fields whose parent isn't a sibling in this same
|
|
11219
|
+
* list (cross-section dependency, or no such field) are unconstrained here.
|
|
11220
|
+
*/
|
|
11221
|
+
_isValidFieldOrder(fields) {
|
|
11222
|
+
const indexByName = new Map();
|
|
11223
|
+
fields.forEach((f, i) => {
|
|
11224
|
+
const name = f.fieldConfig.name;
|
|
11225
|
+
if (name)
|
|
11226
|
+
indexByName.set(name, i);
|
|
11227
|
+
});
|
|
11228
|
+
return fields.every((f, i) => {
|
|
11229
|
+
if (!f.parentName)
|
|
11230
|
+
return true;
|
|
11231
|
+
const parentIndex = indexByName.get(f.parentName);
|
|
11232
|
+
return parentIndex === undefined || parentIndex < i;
|
|
11233
|
+
});
|
|
11234
|
+
}
|
|
11004
11235
|
/** Recursively set visibility on a section and all its descendants (respecting locks). */
|
|
11005
11236
|
_cascadeVisibility(section, visible) {
|
|
11006
11237
|
return {
|
|
@@ -11030,16 +11261,23 @@ class ConfigFieldNodeComponent {
|
|
|
11030
11261
|
translate;
|
|
11031
11262
|
toggleVisible = new EventEmitter();
|
|
11032
11263
|
toggleMandatory = new EventEmitter();
|
|
11264
|
+
colSpanChange = new EventEmitter();
|
|
11033
11265
|
get displayLabel() {
|
|
11034
11266
|
const label = this.field.label;
|
|
11035
11267
|
return this.translate ? this.translate(label) : label;
|
|
11036
11268
|
}
|
|
11269
|
+
onColSpanInput(value) {
|
|
11270
|
+
const parsed = Number(value);
|
|
11271
|
+
if (!Number.isFinite(parsed))
|
|
11272
|
+
return;
|
|
11273
|
+
this.colSpanChange.emit(parsed);
|
|
11274
|
+
}
|
|
11037
11275
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ConfigFieldNodeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
11038
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: ConfigFieldNodeComponent, isStandalone: false, selector: "lib-config-field-node", inputs: { field: "field", translate: "translate" }, outputs: { toggleVisible: "toggleVisible", toggleMandatory: "toggleMandatory" }, ngImport: i0, template: "<div\r\n class=\"ffc-field\"\r\n [class.ffc-field--hidden]=\"!field.visible\"\r\n [class.ffc-field--locked]=\"field.lockVisibility\"\r\n>\r\n <!-- Visibility indicator (eye / eye-off) -->\r\n <span class=\"ffc-field__eye\" [class.ffc-field__eye--off]=\"!field.visible\" aria-hidden=\"true\">\r\n @if (field.visible) {\r\n <svg width=\"17\" height=\"17\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <path d=\"M1 12s4-7 11-7 11 7 11 7-4 7-11 7-11-7-11-7z\"></path>\r\n <circle cx=\"12\" cy=\"12\" r=\"3\"></circle>\r\n </svg>\r\n } @else {\r\n <svg width=\"17\" height=\"17\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <path d=\"M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24\"></path>\r\n <line x1=\"1\" y1=\"1\" x2=\"23\" y2=\"23\"></line>\r\n </svg>\r\n }\r\n </span>\r\n\r\n <span class=\"ffc-field__label\" [title]=\"displayLabel\">{{ displayLabel }}</span>\r\n\r\n <!-- Mandatory control (only meaningful when visible) -->\r\n <button\r\n type=\"button\"\r\n class=\"ffc-field__mandatory\"\r\n [class.ffc-field__mandatory--disabled]=\"!field.visible || field.lockMandatory\"\r\n [disabled]=\"!field.visible || field.lockMandatory\"\r\n [attr.aria-pressed]=\"field.mandatory\"\r\n (click)=\"toggleMandatory.emit()\"\r\n >\r\n <span class=\"ffc-check\" [class.ffc-check--on]=\"field.mandatory\">\r\n <svg width=\"11\" height=\"11\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"3.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\r\n <polyline points=\"20 6 9 17 4 12\"></polyline>\r\n </svg>\r\n </span>\r\n <span class=\"ffc-field__mandatory-text\">Mandatory</span>\r\n </button>\r\n\r\n <!-- Visibility toggle / lock -->\r\n @if (field.lockVisibility) {\r\n <span class=\"ffc-lock\" title=\"This field is always visible\">\r\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\r\n <rect x=\"3\" y=\"11\" width=\"18\" height=\"11\" rx=\"2\" ry=\"2\"></rect>\r\n <path d=\"M7 11V7a5 5 0 0 1 10 0v4\"></path>\r\n </svg>\r\n </span>\r\n } @else {\r\n <button\r\n type=\"button\"\r\n class=\"ffc-toggle\"\r\n [class.ffc-toggle--on]=\"field.visible\"\r\n [class.ffc-toggle--disabled]=\"field.visibilityLockedByParent\"\r\n [disabled]=\"field.visibilityLockedByParent\"\r\n role=\"switch\"\r\n [attr.aria-checked]=\"field.visible\"\r\n [attr.aria-label]=\"'Show ' + displayLabel\"\r\n [attr.title]=\"field.visibilityLockedByParent ? 'Show the field it depends on first' : null\"\r\n (click)=\"toggleVisible.emit()\"\r\n >\r\n <span class=\"ffc-toggle__thumb\"></span>\r\n </button>\r\n }\r\n</div>\r\n", styles: [".ffc-toggle{position:relative;flex-shrink:0;width:var(--ffc-toggle-width, 38px);height:var(--ffc-toggle-height, 22px);padding:0;border:none;border-radius:999px;background:var(--ffc-toggle-off-bg, #cbd2d9);cursor:pointer;transition:background .18s ease}.ffc-toggle__thumb{position:absolute;top:2px;left:2px;width:calc(var(--ffc-toggle-height, 22px) - 4px);height:calc(var(--ffc-toggle-height, 22px) - 4px);border-radius:50%;background:var(--ffc-toggle-thumb, #ffffff);box-shadow:0 1px 2px #00000040;transition:left .18s ease}.ffc-toggle--on{background:var(--ffc-toggle-on-bg, #2f9e6f)}.ffc-toggle--on .ffc-toggle__thumb{left:calc(100% - (var(--ffc-toggle-height, 22px) - 2px))}.ffc-toggle:focus-visible{outline:2px solid var(--ffc-focus-ring, #2f9e6f);outline-offset:2px}.ffc-toggle--disabled{opacity:.45;cursor:not-allowed}.ffc-check{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:var(--ffc-check-size, 18px);height:var(--ffc-check-size, 18px);border-radius:4px;border:2px solid var(--ffc-check-border, #c3c9d0);background:var(--ffc-check-bg, #ffffff);color:transparent;transition:background .15s ease,border-color .15s ease,color .15s ease}.ffc-check svg{opacity:0;transition:opacity .15s ease}.ffc-check--on{background:var(--ffc-check-on-bg, #d97757);border-color:var(--ffc-check-on-bg, #d97757);color:#fff}.ffc-check--on svg{opacity:1}.ffc-lock{display:flex;align-items:center;justify-content:center;flex-shrink:0;width:var(--ffc-toggle-width, 38px);color:var(--ffc-lock-color, #9aa2ab)}.ffc-field{display:flex;align-items:center;gap:var(--ffc-field-gap, 12px);padding:var(--ffc-field-padding, 10px 14px);border-radius:var(--ffc-field-radius, 8px);background:var(--ffc-field-bg, #ffffff);border:1px solid var(--ffc-field-border, #eef0f2);transition:background .15s,border-color .15s,opacity .15s}.ffc-field:hover:not(.ffc-field--locked){background:var(--ffc-field-hover-bg, #f8fafc)}.ffc-field--hidden .ffc-field__eye,.ffc-field--hidden .ffc-field__label,.ffc-field--hidden .ffc-field__mandatory{opacity:.55}.ffc-field--locked{background:var(--ffc-field-locked-bg, #f6f7f8)}.ffc-field__eye{display:flex;align-items:center;color:var(--ffc-eye-color, #6b7280);flex-shrink:0}.ffc-field__eye--off{color:var(--ffc-eye-off-color, #b0b6be)}.ffc-field__label{flex:1 1 auto;min-width:0;font-size:var(--ffc-field-label-size, 14px);color:var(--ffc-field-label-color, #1f2933);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.ffc-field__mandatory{display:inline-flex;align-items:center;gap:7px;flex-shrink:0;padding:0;border:none;background:transparent;cursor:pointer;font:inherit}.ffc-field__mandatory--disabled{cursor:not-allowed}.ffc-field__mandatory-text{font-size:var(--ffc-mandatory-size, 13px);color:var(--ffc-mandatory-color, #52606d);white-space:nowrap}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
11276
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: ConfigFieldNodeComponent, isStandalone: false, selector: "lib-config-field-node", inputs: { field: "field", translate: "translate" }, outputs: { toggleVisible: "toggleVisible", toggleMandatory: "toggleMandatory", colSpanChange: "colSpanChange" }, ngImport: i0, template: "<div\r\n class=\"ffc-field\"\r\n [class.ffc-field--hidden]=\"!field.visible\"\r\n [class.ffc-field--locked]=\"field.lockVisibility\"\r\n>\r\n <!-- Drag handle (reorder within this section) -->\r\n <span class=\"ffc-field__grip\" title=\"Drag to reorder within this section\" aria-hidden=\"true\">\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\r\n <circle cx=\"8\" cy=\"5\" r=\"1.6\"></circle>\r\n <circle cx=\"16\" cy=\"5\" r=\"1.6\"></circle>\r\n <circle cx=\"8\" cy=\"12\" r=\"1.6\"></circle>\r\n <circle cx=\"16\" cy=\"12\" r=\"1.6\"></circle>\r\n <circle cx=\"8\" cy=\"19\" r=\"1.6\"></circle>\r\n <circle cx=\"16\" cy=\"19\" r=\"1.6\"></circle>\r\n </svg>\r\n </span>\r\n\r\n <!-- Visibility indicator (eye / eye-off) -->\r\n <span class=\"ffc-field__eye\" [class.ffc-field__eye--off]=\"!field.visible\" aria-hidden=\"true\">\r\n @if (field.visible) {\r\n <svg width=\"17\" height=\"17\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <path d=\"M1 12s4-7 11-7 11 7 11 7-4 7-11 7-11-7-11-7z\"></path>\r\n <circle cx=\"12\" cy=\"12\" r=\"3\"></circle>\r\n </svg>\r\n } @else {\r\n <svg width=\"17\" height=\"17\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <path d=\"M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24\"></path>\r\n <line x1=\"1\" y1=\"1\" x2=\"23\" y2=\"23\"></line>\r\n </svg>\r\n }\r\n </span>\r\n\r\n <span class=\"ffc-field__label\" [title]=\"displayLabel\">{{ displayLabel }}</span>\r\n\r\n <!-- Column span (1-12 grid) -->\r\n <label class=\"ffc-field__colspan\" [attr.title]=\"'Column span (1-12)'\">\r\n <span class=\"ffc-field__colspan-text\">Col</span>\r\n <input\r\n type=\"number\"\r\n min=\"1\"\r\n max=\"12\"\r\n step=\"1\"\r\n class=\"ffc-field__colspan-input\"\r\n [value]=\"field.colSpan\"\r\n (change)=\"onColSpanInput($any($event.target).value)\"\r\n (click)=\"$event.stopPropagation()\"\r\n (mousedown)=\"$event.stopPropagation()\"\r\n />\r\n </label>\r\n\r\n <!-- Mandatory control (only meaningful when visible) -->\r\n <button\r\n type=\"button\"\r\n class=\"ffc-field__mandatory\"\r\n [class.ffc-field__mandatory--disabled]=\"!field.visible || field.lockMandatory\"\r\n [disabled]=\"!field.visible || field.lockMandatory\"\r\n [attr.aria-pressed]=\"field.mandatory\"\r\n (click)=\"toggleMandatory.emit()\"\r\n >\r\n <span class=\"ffc-check\" [class.ffc-check--on]=\"field.mandatory\">\r\n <svg width=\"11\" height=\"11\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"3.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\r\n <polyline points=\"20 6 9 17 4 12\"></polyline>\r\n </svg>\r\n </span>\r\n <span class=\"ffc-field__mandatory-text\">Mandatory</span>\r\n </button>\r\n\r\n <!-- Visibility toggle / lock -->\r\n @if (field.lockVisibility) {\r\n <span class=\"ffc-lock\" title=\"This field is always visible\">\r\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\r\n <rect x=\"3\" y=\"11\" width=\"18\" height=\"11\" rx=\"2\" ry=\"2\"></rect>\r\n <path d=\"M7 11V7a5 5 0 0 1 10 0v4\"></path>\r\n </svg>\r\n </span>\r\n } @else {\r\n <button\r\n type=\"button\"\r\n class=\"ffc-toggle\"\r\n [class.ffc-toggle--on]=\"field.visible\"\r\n [class.ffc-toggle--disabled]=\"field.visibilityLockedByParent\"\r\n [disabled]=\"field.visibilityLockedByParent\"\r\n role=\"switch\"\r\n [attr.aria-checked]=\"field.visible\"\r\n [attr.aria-label]=\"'Show ' + displayLabel\"\r\n [attr.title]=\"field.visibilityLockedByParent ? 'Show the field it depends on first' : null\"\r\n (click)=\"toggleVisible.emit()\"\r\n >\r\n <span class=\"ffc-toggle__thumb\"></span>\r\n </button>\r\n }\r\n</div>\r\n", styles: [".ffc-toggle{position:relative;flex-shrink:0;width:var(--ffc-toggle-width, 38px);height:var(--ffc-toggle-height, 22px);padding:0;border:none;border-radius:999px;background:var(--ffc-toggle-off-bg, #cbd2d9);cursor:pointer;transition:background .18s ease}.ffc-toggle__thumb{position:absolute;top:2px;left:2px;width:calc(var(--ffc-toggle-height, 22px) - 4px);height:calc(var(--ffc-toggle-height, 22px) - 4px);border-radius:50%;background:var(--ffc-toggle-thumb, #ffffff);box-shadow:0 1px 2px #00000040;transition:left .18s ease}.ffc-toggle--on{background:var(--ffc-toggle-on-bg, #2f9e6f)}.ffc-toggle--on .ffc-toggle__thumb{left:calc(100% - (var(--ffc-toggle-height, 22px) - 2px))}.ffc-toggle:focus-visible{outline:2px solid var(--ffc-focus-ring, #2f9e6f);outline-offset:2px}.ffc-toggle--disabled{opacity:.45;cursor:not-allowed}.ffc-check{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:var(--ffc-check-size, 18px);height:var(--ffc-check-size, 18px);border-radius:4px;border:2px solid var(--ffc-check-border, #c3c9d0);background:var(--ffc-check-bg, #ffffff);color:transparent;transition:background .15s ease,border-color .15s ease,color .15s ease}.ffc-check svg{opacity:0;transition:opacity .15s ease}.ffc-check--on{background:var(--ffc-check-on-bg, #d97757);border-color:var(--ffc-check-on-bg, #d97757);color:#fff}.ffc-check--on svg{opacity:1}.ffc-lock{display:flex;align-items:center;justify-content:center;flex-shrink:0;width:var(--ffc-toggle-width, 38px);color:var(--ffc-lock-color, #9aa2ab)}:host{display:block;cursor:grab}:host.cdk-drag-dragging,:host.cdk-drag-placeholder{cursor:grabbing}.ffc-field{display:flex;align-items:center;gap:var(--ffc-field-gap, 12px);padding:var(--ffc-field-padding, 10px 14px);border-radius:var(--ffc-field-radius, 8px);background:var(--ffc-field-bg, #ffffff);border:1px solid var(--ffc-field-border, #eef0f2);transition:background .15s,border-color .15s,opacity .15s}.ffc-field:hover:not(.ffc-field--locked){background:var(--ffc-field-hover-bg, #f8fafc)}.ffc-field--hidden .ffc-field__eye,.ffc-field--hidden .ffc-field__label,.ffc-field--hidden .ffc-field__mandatory{opacity:.55}.ffc-field--locked{background:var(--ffc-field-locked-bg, #f6f7f8)}.ffc-field__grip{display:flex;align-items:center;color:var(--ffc-grip-color, #cbd2d9);flex-shrink:0}.ffc-field__eye{display:flex;align-items:center;color:var(--ffc-eye-color, #6b7280);flex-shrink:0}.ffc-field__eye--off{color:var(--ffc-eye-off-color, #b0b6be)}.ffc-field__label{flex:1 1 auto;min-width:0;font-size:var(--ffc-field-label-size, 14px);color:var(--ffc-field-label-color, #1f2933);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.ffc-field__colspan{display:inline-flex;align-items:center;gap:6px;flex-shrink:0;cursor:default}.ffc-field__colspan-text{font-size:var(--ffc-colspan-label-size, 12px);color:var(--ffc-colspan-label-color, #9aa2ab);padding-right:5px}.ffc-field__colspan-input{width:var(--ffc-colspan-input-width, 42px);padding:3px 4px;text-align:center;font-size:var(--ffc-colspan-input-size, 13px);color:var(--ffc-field-label-color, #1f2933);border:1px solid var(--ffc-field-border, #d7dce1);border-radius:5px;background:var(--ffc-colspan-input-bg, #ffffff);cursor:text}.ffc-field__colspan-input:focus{outline:none;border-color:var(--ffc-toggle-on-bg, #2f9e6f)}.ffc-field__colspan-input::-webkit-outer-spin-button,.ffc-field__colspan-input::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}.ffc-field__colspan-input[type=number]{-moz-appearance:textfield}.ffc-field__mandatory{display:inline-flex;align-items:center;gap:7px;flex-shrink:0;padding:0;border:none;background:transparent;cursor:pointer;font:inherit}.ffc-field__mandatory--disabled{cursor:not-allowed}.ffc-field__mandatory-text{font-size:var(--ffc-mandatory-size, 13px);color:var(--ffc-mandatory-color, #52606d);white-space:nowrap}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
11039
11277
|
}
|
|
11040
11278
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ConfigFieldNodeComponent, decorators: [{
|
|
11041
11279
|
type: Component,
|
|
11042
|
-
args: [{ selector: 'lib-config-field-node', standalone: false, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\r\n class=\"ffc-field\"\r\n [class.ffc-field--hidden]=\"!field.visible\"\r\n [class.ffc-field--locked]=\"field.lockVisibility\"\r\n>\r\n <!-- Visibility indicator (eye / eye-off) -->\r\n <span class=\"ffc-field__eye\" [class.ffc-field__eye--off]=\"!field.visible\" aria-hidden=\"true\">\r\n @if (field.visible) {\r\n <svg width=\"17\" height=\"17\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <path d=\"M1 12s4-7 11-7 11 7 11 7-4 7-11 7-11-7-11-7z\"></path>\r\n <circle cx=\"12\" cy=\"12\" r=\"3\"></circle>\r\n </svg>\r\n } @else {\r\n <svg width=\"17\" height=\"17\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <path d=\"M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24\"></path>\r\n <line x1=\"1\" y1=\"1\" x2=\"23\" y2=\"23\"></line>\r\n </svg>\r\n }\r\n </span>\r\n\r\n <span class=\"ffc-field__label\" [title]=\"displayLabel\">{{ displayLabel }}</span>\r\n\r\n <!-- Mandatory control (only meaningful when visible) -->\r\n <button\r\n type=\"button\"\r\n class=\"ffc-field__mandatory\"\r\n [class.ffc-field__mandatory--disabled]=\"!field.visible || field.lockMandatory\"\r\n [disabled]=\"!field.visible || field.lockMandatory\"\r\n [attr.aria-pressed]=\"field.mandatory\"\r\n (click)=\"toggleMandatory.emit()\"\r\n >\r\n <span class=\"ffc-check\" [class.ffc-check--on]=\"field.mandatory\">\r\n <svg width=\"11\" height=\"11\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"3.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\r\n <polyline points=\"20 6 9 17 4 12\"></polyline>\r\n </svg>\r\n </span>\r\n <span class=\"ffc-field__mandatory-text\">Mandatory</span>\r\n </button>\r\n\r\n <!-- Visibility toggle / lock -->\r\n @if (field.lockVisibility) {\r\n <span class=\"ffc-lock\" title=\"This field is always visible\">\r\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\r\n <rect x=\"3\" y=\"11\" width=\"18\" height=\"11\" rx=\"2\" ry=\"2\"></rect>\r\n <path d=\"M7 11V7a5 5 0 0 1 10 0v4\"></path>\r\n </svg>\r\n </span>\r\n } @else {\r\n <button\r\n type=\"button\"\r\n class=\"ffc-toggle\"\r\n [class.ffc-toggle--on]=\"field.visible\"\r\n [class.ffc-toggle--disabled]=\"field.visibilityLockedByParent\"\r\n [disabled]=\"field.visibilityLockedByParent\"\r\n role=\"switch\"\r\n [attr.aria-checked]=\"field.visible\"\r\n [attr.aria-label]=\"'Show ' + displayLabel\"\r\n [attr.title]=\"field.visibilityLockedByParent ? 'Show the field it depends on first' : null\"\r\n (click)=\"toggleVisible.emit()\"\r\n >\r\n <span class=\"ffc-toggle__thumb\"></span>\r\n </button>\r\n }\r\n</div>\r\n", styles: [".ffc-toggle{position:relative;flex-shrink:0;width:var(--ffc-toggle-width, 38px);height:var(--ffc-toggle-height, 22px);padding:0;border:none;border-radius:999px;background:var(--ffc-toggle-off-bg, #cbd2d9);cursor:pointer;transition:background .18s ease}.ffc-toggle__thumb{position:absolute;top:2px;left:2px;width:calc(var(--ffc-toggle-height, 22px) - 4px);height:calc(var(--ffc-toggle-height, 22px) - 4px);border-radius:50%;background:var(--ffc-toggle-thumb, #ffffff);box-shadow:0 1px 2px #00000040;transition:left .18s ease}.ffc-toggle--on{background:var(--ffc-toggle-on-bg, #2f9e6f)}.ffc-toggle--on .ffc-toggle__thumb{left:calc(100% - (var(--ffc-toggle-height, 22px) - 2px))}.ffc-toggle:focus-visible{outline:2px solid var(--ffc-focus-ring, #2f9e6f);outline-offset:2px}.ffc-toggle--disabled{opacity:.45;cursor:not-allowed}.ffc-check{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:var(--ffc-check-size, 18px);height:var(--ffc-check-size, 18px);border-radius:4px;border:2px solid var(--ffc-check-border, #c3c9d0);background:var(--ffc-check-bg, #ffffff);color:transparent;transition:background .15s ease,border-color .15s ease,color .15s ease}.ffc-check svg{opacity:0;transition:opacity .15s ease}.ffc-check--on{background:var(--ffc-check-on-bg, #d97757);border-color:var(--ffc-check-on-bg, #d97757);color:#fff}.ffc-check--on svg{opacity:1}.ffc-lock{display:flex;align-items:center;justify-content:center;flex-shrink:0;width:var(--ffc-toggle-width, 38px);color:var(--ffc-lock-color, #9aa2ab)}.ffc-field{display:flex;align-items:center;gap:var(--ffc-field-gap, 12px);padding:var(--ffc-field-padding, 10px 14px);border-radius:var(--ffc-field-radius, 8px);background:var(--ffc-field-bg, #ffffff);border:1px solid var(--ffc-field-border, #eef0f2);transition:background .15s,border-color .15s,opacity .15s}.ffc-field:hover:not(.ffc-field--locked){background:var(--ffc-field-hover-bg, #f8fafc)}.ffc-field--hidden .ffc-field__eye,.ffc-field--hidden .ffc-field__label,.ffc-field--hidden .ffc-field__mandatory{opacity:.55}.ffc-field--locked{background:var(--ffc-field-locked-bg, #f6f7f8)}.ffc-field__eye{display:flex;align-items:center;color:var(--ffc-eye-color, #6b7280);flex-shrink:0}.ffc-field__eye--off{color:var(--ffc-eye-off-color, #b0b6be)}.ffc-field__label{flex:1 1 auto;min-width:0;font-size:var(--ffc-field-label-size, 14px);color:var(--ffc-field-label-color, #1f2933);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.ffc-field__mandatory{display:inline-flex;align-items:center;gap:7px;flex-shrink:0;padding:0;border:none;background:transparent;cursor:pointer;font:inherit}.ffc-field__mandatory--disabled{cursor:not-allowed}.ffc-field__mandatory-text{font-size:var(--ffc-mandatory-size, 13px);color:var(--ffc-mandatory-color, #52606d);white-space:nowrap}\n"] }]
|
|
11280
|
+
args: [{ selector: 'lib-config-field-node', standalone: false, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\r\n class=\"ffc-field\"\r\n [class.ffc-field--hidden]=\"!field.visible\"\r\n [class.ffc-field--locked]=\"field.lockVisibility\"\r\n>\r\n <!-- Drag handle (reorder within this section) -->\r\n <span class=\"ffc-field__grip\" title=\"Drag to reorder within this section\" aria-hidden=\"true\">\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\r\n <circle cx=\"8\" cy=\"5\" r=\"1.6\"></circle>\r\n <circle cx=\"16\" cy=\"5\" r=\"1.6\"></circle>\r\n <circle cx=\"8\" cy=\"12\" r=\"1.6\"></circle>\r\n <circle cx=\"16\" cy=\"12\" r=\"1.6\"></circle>\r\n <circle cx=\"8\" cy=\"19\" r=\"1.6\"></circle>\r\n <circle cx=\"16\" cy=\"19\" r=\"1.6\"></circle>\r\n </svg>\r\n </span>\r\n\r\n <!-- Visibility indicator (eye / eye-off) -->\r\n <span class=\"ffc-field__eye\" [class.ffc-field__eye--off]=\"!field.visible\" aria-hidden=\"true\">\r\n @if (field.visible) {\r\n <svg width=\"17\" height=\"17\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <path d=\"M1 12s4-7 11-7 11 7 11 7-4 7-11 7-11-7-11-7z\"></path>\r\n <circle cx=\"12\" cy=\"12\" r=\"3\"></circle>\r\n </svg>\r\n } @else {\r\n <svg width=\"17\" height=\"17\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <path d=\"M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24\"></path>\r\n <line x1=\"1\" y1=\"1\" x2=\"23\" y2=\"23\"></line>\r\n </svg>\r\n }\r\n </span>\r\n\r\n <span class=\"ffc-field__label\" [title]=\"displayLabel\">{{ displayLabel }}</span>\r\n\r\n <!-- Column span (1-12 grid) -->\r\n <label class=\"ffc-field__colspan\" [attr.title]=\"'Column span (1-12)'\">\r\n <span class=\"ffc-field__colspan-text\">Col</span>\r\n <input\r\n type=\"number\"\r\n min=\"1\"\r\n max=\"12\"\r\n step=\"1\"\r\n class=\"ffc-field__colspan-input\"\r\n [value]=\"field.colSpan\"\r\n (change)=\"onColSpanInput($any($event.target).value)\"\r\n (click)=\"$event.stopPropagation()\"\r\n (mousedown)=\"$event.stopPropagation()\"\r\n />\r\n </label>\r\n\r\n <!-- Mandatory control (only meaningful when visible) -->\r\n <button\r\n type=\"button\"\r\n class=\"ffc-field__mandatory\"\r\n [class.ffc-field__mandatory--disabled]=\"!field.visible || field.lockMandatory\"\r\n [disabled]=\"!field.visible || field.lockMandatory\"\r\n [attr.aria-pressed]=\"field.mandatory\"\r\n (click)=\"toggleMandatory.emit()\"\r\n >\r\n <span class=\"ffc-check\" [class.ffc-check--on]=\"field.mandatory\">\r\n <svg width=\"11\" height=\"11\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"3.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\r\n <polyline points=\"20 6 9 17 4 12\"></polyline>\r\n </svg>\r\n </span>\r\n <span class=\"ffc-field__mandatory-text\">Mandatory</span>\r\n </button>\r\n\r\n <!-- Visibility toggle / lock -->\r\n @if (field.lockVisibility) {\r\n <span class=\"ffc-lock\" title=\"This field is always visible\">\r\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\r\n <rect x=\"3\" y=\"11\" width=\"18\" height=\"11\" rx=\"2\" ry=\"2\"></rect>\r\n <path d=\"M7 11V7a5 5 0 0 1 10 0v4\"></path>\r\n </svg>\r\n </span>\r\n } @else {\r\n <button\r\n type=\"button\"\r\n class=\"ffc-toggle\"\r\n [class.ffc-toggle--on]=\"field.visible\"\r\n [class.ffc-toggle--disabled]=\"field.visibilityLockedByParent\"\r\n [disabled]=\"field.visibilityLockedByParent\"\r\n role=\"switch\"\r\n [attr.aria-checked]=\"field.visible\"\r\n [attr.aria-label]=\"'Show ' + displayLabel\"\r\n [attr.title]=\"field.visibilityLockedByParent ? 'Show the field it depends on first' : null\"\r\n (click)=\"toggleVisible.emit()\"\r\n >\r\n <span class=\"ffc-toggle__thumb\"></span>\r\n </button>\r\n }\r\n</div>\r\n", styles: [".ffc-toggle{position:relative;flex-shrink:0;width:var(--ffc-toggle-width, 38px);height:var(--ffc-toggle-height, 22px);padding:0;border:none;border-radius:999px;background:var(--ffc-toggle-off-bg, #cbd2d9);cursor:pointer;transition:background .18s ease}.ffc-toggle__thumb{position:absolute;top:2px;left:2px;width:calc(var(--ffc-toggle-height, 22px) - 4px);height:calc(var(--ffc-toggle-height, 22px) - 4px);border-radius:50%;background:var(--ffc-toggle-thumb, #ffffff);box-shadow:0 1px 2px #00000040;transition:left .18s ease}.ffc-toggle--on{background:var(--ffc-toggle-on-bg, #2f9e6f)}.ffc-toggle--on .ffc-toggle__thumb{left:calc(100% - (var(--ffc-toggle-height, 22px) - 2px))}.ffc-toggle:focus-visible{outline:2px solid var(--ffc-focus-ring, #2f9e6f);outline-offset:2px}.ffc-toggle--disabled{opacity:.45;cursor:not-allowed}.ffc-check{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:var(--ffc-check-size, 18px);height:var(--ffc-check-size, 18px);border-radius:4px;border:2px solid var(--ffc-check-border, #c3c9d0);background:var(--ffc-check-bg, #ffffff);color:transparent;transition:background .15s ease,border-color .15s ease,color .15s ease}.ffc-check svg{opacity:0;transition:opacity .15s ease}.ffc-check--on{background:var(--ffc-check-on-bg, #d97757);border-color:var(--ffc-check-on-bg, #d97757);color:#fff}.ffc-check--on svg{opacity:1}.ffc-lock{display:flex;align-items:center;justify-content:center;flex-shrink:0;width:var(--ffc-toggle-width, 38px);color:var(--ffc-lock-color, #9aa2ab)}:host{display:block;cursor:grab}:host.cdk-drag-dragging,:host.cdk-drag-placeholder{cursor:grabbing}.ffc-field{display:flex;align-items:center;gap:var(--ffc-field-gap, 12px);padding:var(--ffc-field-padding, 10px 14px);border-radius:var(--ffc-field-radius, 8px);background:var(--ffc-field-bg, #ffffff);border:1px solid var(--ffc-field-border, #eef0f2);transition:background .15s,border-color .15s,opacity .15s}.ffc-field:hover:not(.ffc-field--locked){background:var(--ffc-field-hover-bg, #f8fafc)}.ffc-field--hidden .ffc-field__eye,.ffc-field--hidden .ffc-field__label,.ffc-field--hidden .ffc-field__mandatory{opacity:.55}.ffc-field--locked{background:var(--ffc-field-locked-bg, #f6f7f8)}.ffc-field__grip{display:flex;align-items:center;color:var(--ffc-grip-color, #cbd2d9);flex-shrink:0}.ffc-field__eye{display:flex;align-items:center;color:var(--ffc-eye-color, #6b7280);flex-shrink:0}.ffc-field__eye--off{color:var(--ffc-eye-off-color, #b0b6be)}.ffc-field__label{flex:1 1 auto;min-width:0;font-size:var(--ffc-field-label-size, 14px);color:var(--ffc-field-label-color, #1f2933);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.ffc-field__colspan{display:inline-flex;align-items:center;gap:6px;flex-shrink:0;cursor:default}.ffc-field__colspan-text{font-size:var(--ffc-colspan-label-size, 12px);color:var(--ffc-colspan-label-color, #9aa2ab);padding-right:5px}.ffc-field__colspan-input{width:var(--ffc-colspan-input-width, 42px);padding:3px 4px;text-align:center;font-size:var(--ffc-colspan-input-size, 13px);color:var(--ffc-field-label-color, #1f2933);border:1px solid var(--ffc-field-border, #d7dce1);border-radius:5px;background:var(--ffc-colspan-input-bg, #ffffff);cursor:text}.ffc-field__colspan-input:focus{outline:none;border-color:var(--ffc-toggle-on-bg, #2f9e6f)}.ffc-field__colspan-input::-webkit-outer-spin-button,.ffc-field__colspan-input::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}.ffc-field__colspan-input[type=number]{-moz-appearance:textfield}.ffc-field__mandatory{display:inline-flex;align-items:center;gap:7px;flex-shrink:0;padding:0;border:none;background:transparent;cursor:pointer;font:inherit}.ffc-field__mandatory--disabled{cursor:not-allowed}.ffc-field__mandatory-text{font-size:var(--ffc-mandatory-size, 13px);color:var(--ffc-mandatory-color, #52606d);white-space:nowrap}\n"] }]
|
|
11043
11281
|
}], propDecorators: { field: [{
|
|
11044
11282
|
type: Input,
|
|
11045
11283
|
args: [{ required: true }]
|
|
@@ -11049,6 +11287,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
|
|
|
11049
11287
|
type: Output
|
|
11050
11288
|
}], toggleMandatory: [{
|
|
11051
11289
|
type: Output
|
|
11290
|
+
}], colSpanChange: [{
|
|
11291
|
+
type: Output
|
|
11052
11292
|
}] } });
|
|
11053
11293
|
|
|
11054
11294
|
/**
|
|
@@ -11065,6 +11305,8 @@ class ConfigSectionNodeComponent {
|
|
|
11065
11305
|
toggleExpanded = new EventEmitter();
|
|
11066
11306
|
fieldToggleVisible = new EventEmitter();
|
|
11067
11307
|
fieldToggleMandatory = new EventEmitter();
|
|
11308
|
+
fieldColSpanChange = new EventEmitter();
|
|
11309
|
+
fieldReorder = new EventEmitter();
|
|
11068
11310
|
get displayLabel() {
|
|
11069
11311
|
return this.translate ? this.translate(this.section.label) : this.section.label;
|
|
11070
11312
|
}
|
|
@@ -11087,6 +11329,18 @@ class ConfigSectionNodeComponent {
|
|
|
11087
11329
|
onFieldToggleMandatory(fieldIndex) {
|
|
11088
11330
|
this.fieldToggleMandatory.emit({ sectionPath: [], fieldIndex });
|
|
11089
11331
|
}
|
|
11332
|
+
onFieldColSpanChange(fieldIndex, colSpan) {
|
|
11333
|
+
this.fieldColSpanChange.emit({ sectionPath: [], fieldIndex, colSpan });
|
|
11334
|
+
}
|
|
11335
|
+
onFieldDrop(event) {
|
|
11336
|
+
if (event.previousIndex === event.currentIndex)
|
|
11337
|
+
return;
|
|
11338
|
+
this.fieldReorder.emit({
|
|
11339
|
+
sectionPath: [],
|
|
11340
|
+
previousIndex: event.previousIndex,
|
|
11341
|
+
currentIndex: event.currentIndex,
|
|
11342
|
+
});
|
|
11343
|
+
}
|
|
11090
11344
|
// ── Subsection re-emits (prefix with the subsection index) ───
|
|
11091
11345
|
onSubToggleVisible(subIndex, subPath) {
|
|
11092
11346
|
this.toggleVisible.emit([subIndex, ...subPath]);
|
|
@@ -11106,15 +11360,29 @@ class ConfigSectionNodeComponent {
|
|
|
11106
11360
|
fieldIndex: payload.fieldIndex,
|
|
11107
11361
|
});
|
|
11108
11362
|
}
|
|
11363
|
+
onSubFieldColSpanChange(subIndex, payload) {
|
|
11364
|
+
this.fieldColSpanChange.emit({
|
|
11365
|
+
sectionPath: [subIndex, ...payload.sectionPath],
|
|
11366
|
+
fieldIndex: payload.fieldIndex,
|
|
11367
|
+
colSpan: payload.colSpan,
|
|
11368
|
+
});
|
|
11369
|
+
}
|
|
11370
|
+
onSubFieldReorder(subIndex, payload) {
|
|
11371
|
+
this.fieldReorder.emit({
|
|
11372
|
+
sectionPath: [subIndex, ...payload.sectionPath],
|
|
11373
|
+
previousIndex: payload.previousIndex,
|
|
11374
|
+
currentIndex: payload.currentIndex,
|
|
11375
|
+
});
|
|
11376
|
+
}
|
|
11109
11377
|
trackByIndex(index) {
|
|
11110
11378
|
return index;
|
|
11111
11379
|
}
|
|
11112
11380
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ConfigSectionNodeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
11113
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: ConfigSectionNodeComponent, isStandalone: false, selector: "lib-config-section-node", inputs: { section: "section", depth: "depth", translate: "translate" }, outputs: { toggleVisible: "toggleVisible", toggleExpanded: "toggleExpanded", fieldToggleVisible: "fieldToggleVisible", fieldToggleMandatory: "fieldToggleMandatory" }, ngImport: i0, template: "<div\r\n class=\"ffc-section\"\r\n [class.ffc-section--nested]=\"depth > 0\"\r\n [class.ffc-section--hidden]=\"hasToggle && !section.visible\"\r\n>\r\n <div class=\"ffc-section__header\">\r\n <button\r\n class=\"ffc-section__expand-btn\"\r\n type=\"button\"\r\n [attr.aria-expanded]=\"section.expanded\"\r\n (click)=\"onToggleExpanded()\"\r\n >\r\n <svg\r\n class=\"ffc-section__chevron\"\r\n [class.ffc-section__chevron--open]=\"section.expanded\"\r\n width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\"\r\n >\r\n <polyline points=\"6 9 12 15 18 9\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\" />\r\n </svg>\r\n </button>\r\n\r\n <span class=\"ffc-section__label\" [title]=\"displayLabel\">{{ displayLabel }}</span>\r\n\r\n @if (section.fields.length) {\r\n <span class=\"ffc-section__count\">{{ visibleFieldCount }}/{{ section.fields.length }} visible</span>\r\n }\r\n\r\n @if (hasToggle) {\r\n @if (section.lockVisibility) {\r\n <span class=\"ffc-lock\" title=\"This section is always visible\">\r\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\r\n <rect x=\"3\" y=\"11\" width=\"18\" height=\"11\" rx=\"2\" ry=\"2\"></rect>\r\n <path d=\"M7 11V7a5 5 0 0 1 10 0v4\"></path>\r\n </svg>\r\n </span>\r\n } @else {\r\n <button\r\n type=\"button\"\r\n class=\"ffc-toggle\"\r\n [class.ffc-toggle--on]=\"section.visible\"\r\n role=\"switch\"\r\n [attr.aria-checked]=\"section.visible\"\r\n [attr.aria-label]=\"'Show ' + displayLabel\"\r\n (click)=\"onToggleVisible()\"\r\n >\r\n <span class=\"ffc-toggle__thumb\"></span>\r\n </button>\r\n }\r\n }\r\n </div>\r\n\r\n @if (section.expanded) {\r\n <div class=\"ffc-section__body\">\r\n @for (field of section.fields; track trackByIndex($index); let fi = $index) {\r\n
|
|
11381
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: ConfigSectionNodeComponent, isStandalone: false, selector: "lib-config-section-node", inputs: { section: "section", depth: "depth", translate: "translate" }, outputs: { toggleVisible: "toggleVisible", toggleExpanded: "toggleExpanded", fieldToggleVisible: "fieldToggleVisible", fieldToggleMandatory: "fieldToggleMandatory", fieldColSpanChange: "fieldColSpanChange", fieldReorder: "fieldReorder" }, ngImport: i0, template: "<div\r\n class=\"ffc-section\"\r\n [class.ffc-section--nested]=\"depth > 0\"\r\n [class.ffc-section--hidden]=\"hasToggle && !section.visible\"\r\n>\r\n <div class=\"ffc-section__header\">\r\n <button\r\n class=\"ffc-section__expand-btn\"\r\n type=\"button\"\r\n [attr.aria-expanded]=\"section.expanded\"\r\n (click)=\"onToggleExpanded()\"\r\n >\r\n <svg\r\n class=\"ffc-section__chevron\"\r\n [class.ffc-section__chevron--open]=\"section.expanded\"\r\n width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\"\r\n >\r\n <polyline points=\"6 9 12 15 18 9\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\" />\r\n </svg>\r\n </button>\r\n\r\n <span class=\"ffc-section__label\" [title]=\"displayLabel\">{{ displayLabel }}</span>\r\n\r\n @if (section.fields.length) {\r\n <span class=\"ffc-section__count\">{{ visibleFieldCount }}/{{ section.fields.length }} visible</span>\r\n }\r\n\r\n @if (hasToggle) {\r\n @if (section.lockVisibility) {\r\n <span class=\"ffc-lock\" title=\"This section is always visible\">\r\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\r\n <rect x=\"3\" y=\"11\" width=\"18\" height=\"11\" rx=\"2\" ry=\"2\"></rect>\r\n <path d=\"M7 11V7a5 5 0 0 1 10 0v4\"></path>\r\n </svg>\r\n </span>\r\n } @else {\r\n <button\r\n type=\"button\"\r\n class=\"ffc-toggle\"\r\n [class.ffc-toggle--on]=\"section.visible\"\r\n role=\"switch\"\r\n [attr.aria-checked]=\"section.visible\"\r\n [attr.aria-label]=\"'Show ' + displayLabel\"\r\n (click)=\"onToggleVisible()\"\r\n >\r\n <span class=\"ffc-toggle__thumb\"></span>\r\n </button>\r\n }\r\n }\r\n </div>\r\n\r\n @if (section.expanded) {\r\n <div class=\"ffc-section__body\">\r\n <div\r\n class=\"ffc-section__fields\"\r\n cdkDropList\r\n [cdkDropListDisabled]=\"!section.reorderable\"\r\n (cdkDropListDropped)=\"onFieldDrop($event)\"\r\n >\r\n @for (field of section.fields; track trackByIndex($index); let fi = $index) {\r\n <lib-config-field-node\r\n cdkDrag\r\n [cdkDragDisabled]=\"!section.reorderable\"\r\n [field]=\"field\"\r\n [translate]=\"translate\"\r\n (toggleVisible)=\"onFieldToggleVisible(fi)\"\r\n (toggleMandatory)=\"onFieldToggleMandatory(fi)\"\r\n (colSpanChange)=\"onFieldColSpanChange(fi, $event)\"\r\n />\r\n }\r\n </div>\r\n\r\n @for (sub of section.subsections; track trackByIndex($index); let si = $index) {\r\n <lib-config-section-node\r\n [section]=\"sub\"\r\n [depth]=\"depth + 1\"\r\n [translate]=\"translate\"\r\n (toggleVisible)=\"onSubToggleVisible(si, $event)\"\r\n (toggleExpanded)=\"onSubToggleExpanded(si, $event)\"\r\n (fieldToggleVisible)=\"onSubFieldToggleVisible(si, $event)\"\r\n (fieldToggleMandatory)=\"onSubFieldToggleMandatory(si, $event)\"\r\n (fieldColSpanChange)=\"onSubFieldColSpanChange(si, $event)\"\r\n (fieldReorder)=\"onSubFieldReorder(si, $event)\"\r\n />\r\n }\r\n </div>\r\n }\r\n</div>\r\n", styles: [".ffc-toggle{position:relative;flex-shrink:0;width:var(--ffc-toggle-width, 38px);height:var(--ffc-toggle-height, 22px);padding:0;border:none;border-radius:999px;background:var(--ffc-toggle-off-bg, #cbd2d9);cursor:pointer;transition:background .18s ease}.ffc-toggle__thumb{position:absolute;top:2px;left:2px;width:calc(var(--ffc-toggle-height, 22px) - 4px);height:calc(var(--ffc-toggle-height, 22px) - 4px);border-radius:50%;background:var(--ffc-toggle-thumb, #ffffff);box-shadow:0 1px 2px #00000040;transition:left .18s ease}.ffc-toggle--on{background:var(--ffc-toggle-on-bg, #2f9e6f)}.ffc-toggle--on .ffc-toggle__thumb{left:calc(100% - (var(--ffc-toggle-height, 22px) - 2px))}.ffc-toggle:focus-visible{outline:2px solid var(--ffc-focus-ring, #2f9e6f);outline-offset:2px}.ffc-toggle--disabled{opacity:.45;cursor:not-allowed}.ffc-check{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:var(--ffc-check-size, 18px);height:var(--ffc-check-size, 18px);border-radius:4px;border:2px solid var(--ffc-check-border, #c3c9d0);background:var(--ffc-check-bg, #ffffff);color:transparent;transition:background .15s ease,border-color .15s ease,color .15s ease}.ffc-check svg{opacity:0;transition:opacity .15s ease}.ffc-check--on{background:var(--ffc-check-on-bg, #d97757);border-color:var(--ffc-check-on-bg, #d97757);color:#fff}.ffc-check--on svg{opacity:1}.ffc-lock{display:flex;align-items:center;justify-content:center;flex-shrink:0;width:var(--ffc-toggle-width, 38px);color:var(--ffc-lock-color, #9aa2ab)}.ffc-section{border:1px solid var(--ffc-section-border, #e5e7eb);border-radius:var(--ffc-section-radius, 10px);background:var(--ffc-section-bg, #ffffff);overflow:hidden}.ffc-section--nested{border-color:var(--ffc-section-nested-border, #eef0f2);background:var(--ffc-section-nested-bg, #fbfcfd)}.ffc-section--hidden .ffc-section__label,.ffc-section--hidden .ffc-section__count{opacity:.55}.ffc-section__header{display:flex;align-items:center;gap:10px;padding:var(--ffc-section-header-padding, 12px 14px);background:var(--ffc-section-header-bg, #f6f7f8);-webkit-user-select:none;user-select:none}.ffc-section--nested .ffc-section__header{background:var(--ffc-section-nested-header-bg, #f1f3f5)}.ffc-section__expand-btn{background:none;border:none;cursor:pointer;padding:2px;display:flex;color:var(--ffc-chevron-color, #6b7280);flex-shrink:0}.ffc-section__chevron{transform:rotate(-90deg);transition:transform .2s}.ffc-section__chevron--open{transform:rotate(0)}.ffc-section__label{flex:1 1 auto;min-width:0;font-size:var(--ffc-section-label-size, 14px);font-weight:600;color:var(--ffc-section-label-color, #1f2933);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.ffc-section__count{flex-shrink:0;font-size:var(--ffc-count-size, 12px);color:var(--ffc-count-color, #7b8794);white-space:nowrap}.ffc-section__body{padding:var(--ffc-section-body-padding, 8px 14px 14px 14px);display:flex;flex-direction:column;gap:var(--ffc-field-row-gap, 8px)}@media(max-width:640px){.ffc-section__body{padding:8px 10px 10px 18px;gap:6px}}.ffc-section__fields{display:flex;flex-direction:column;gap:var(--ffc-field-row-gap, 8px)}\n"], dependencies: [{ kind: "directive", type: i1$5.CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer", "cdkDropListHasAnchor"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: i1$5.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "component", type: ConfigSectionNodeComponent, selector: "lib-config-section-node", inputs: ["section", "depth", "translate"], outputs: ["toggleVisible", "toggleExpanded", "fieldToggleVisible", "fieldToggleMandatory", "fieldColSpanChange", "fieldReorder"] }, { kind: "component", type: ConfigFieldNodeComponent, selector: "lib-config-field-node", inputs: ["field", "translate"], outputs: ["toggleVisible", "toggleMandatory", "colSpanChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
11114
11382
|
}
|
|
11115
11383
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ConfigSectionNodeComponent, decorators: [{
|
|
11116
11384
|
type: Component,
|
|
11117
|
-
args: [{ selector: 'lib-config-section-node', standalone: false, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\r\n class=\"ffc-section\"\r\n [class.ffc-section--nested]=\"depth > 0\"\r\n [class.ffc-section--hidden]=\"hasToggle && !section.visible\"\r\n>\r\n <div class=\"ffc-section__header\">\r\n <button\r\n class=\"ffc-section__expand-btn\"\r\n type=\"button\"\r\n [attr.aria-expanded]=\"section.expanded\"\r\n (click)=\"onToggleExpanded()\"\r\n >\r\n <svg\r\n class=\"ffc-section__chevron\"\r\n [class.ffc-section__chevron--open]=\"section.expanded\"\r\n width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\"\r\n >\r\n <polyline points=\"6 9 12 15 18 9\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\" />\r\n </svg>\r\n </button>\r\n\r\n <span class=\"ffc-section__label\" [title]=\"displayLabel\">{{ displayLabel }}</span>\r\n\r\n @if (section.fields.length) {\r\n <span class=\"ffc-section__count\">{{ visibleFieldCount }}/{{ section.fields.length }} visible</span>\r\n }\r\n\r\n @if (hasToggle) {\r\n @if (section.lockVisibility) {\r\n <span class=\"ffc-lock\" title=\"This section is always visible\">\r\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\r\n <rect x=\"3\" y=\"11\" width=\"18\" height=\"11\" rx=\"2\" ry=\"2\"></rect>\r\n <path d=\"M7 11V7a5 5 0 0 1 10 0v4\"></path>\r\n </svg>\r\n </span>\r\n } @else {\r\n <button\r\n type=\"button\"\r\n class=\"ffc-toggle\"\r\n [class.ffc-toggle--on]=\"section.visible\"\r\n role=\"switch\"\r\n [attr.aria-checked]=\"section.visible\"\r\n [attr.aria-label]=\"'Show ' + displayLabel\"\r\n (click)=\"onToggleVisible()\"\r\n >\r\n <span class=\"ffc-toggle__thumb\"></span>\r\n </button>\r\n }\r\n }\r\n </div>\r\n\r\n @if (section.expanded) {\r\n <div class=\"ffc-section__body\">\r\n @for (field of section.fields; track trackByIndex($index); let fi = $index) {\r\n
|
|
11385
|
+
args: [{ selector: 'lib-config-section-node', standalone: false, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\r\n class=\"ffc-section\"\r\n [class.ffc-section--nested]=\"depth > 0\"\r\n [class.ffc-section--hidden]=\"hasToggle && !section.visible\"\r\n>\r\n <div class=\"ffc-section__header\">\r\n <button\r\n class=\"ffc-section__expand-btn\"\r\n type=\"button\"\r\n [attr.aria-expanded]=\"section.expanded\"\r\n (click)=\"onToggleExpanded()\"\r\n >\r\n <svg\r\n class=\"ffc-section__chevron\"\r\n [class.ffc-section__chevron--open]=\"section.expanded\"\r\n width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\"\r\n >\r\n <polyline points=\"6 9 12 15 18 9\" stroke=\"currentColor\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\" />\r\n </svg>\r\n </button>\r\n\r\n <span class=\"ffc-section__label\" [title]=\"displayLabel\">{{ displayLabel }}</span>\r\n\r\n @if (section.fields.length) {\r\n <span class=\"ffc-section__count\">{{ visibleFieldCount }}/{{ section.fields.length }} visible</span>\r\n }\r\n\r\n @if (hasToggle) {\r\n @if (section.lockVisibility) {\r\n <span class=\"ffc-lock\" title=\"This section is always visible\">\r\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\r\n <rect x=\"3\" y=\"11\" width=\"18\" height=\"11\" rx=\"2\" ry=\"2\"></rect>\r\n <path d=\"M7 11V7a5 5 0 0 1 10 0v4\"></path>\r\n </svg>\r\n </span>\r\n } @else {\r\n <button\r\n type=\"button\"\r\n class=\"ffc-toggle\"\r\n [class.ffc-toggle--on]=\"section.visible\"\r\n role=\"switch\"\r\n [attr.aria-checked]=\"section.visible\"\r\n [attr.aria-label]=\"'Show ' + displayLabel\"\r\n (click)=\"onToggleVisible()\"\r\n >\r\n <span class=\"ffc-toggle__thumb\"></span>\r\n </button>\r\n }\r\n }\r\n </div>\r\n\r\n @if (section.expanded) {\r\n <div class=\"ffc-section__body\">\r\n <div\r\n class=\"ffc-section__fields\"\r\n cdkDropList\r\n [cdkDropListDisabled]=\"!section.reorderable\"\r\n (cdkDropListDropped)=\"onFieldDrop($event)\"\r\n >\r\n @for (field of section.fields; track trackByIndex($index); let fi = $index) {\r\n <lib-config-field-node\r\n cdkDrag\r\n [cdkDragDisabled]=\"!section.reorderable\"\r\n [field]=\"field\"\r\n [translate]=\"translate\"\r\n (toggleVisible)=\"onFieldToggleVisible(fi)\"\r\n (toggleMandatory)=\"onFieldToggleMandatory(fi)\"\r\n (colSpanChange)=\"onFieldColSpanChange(fi, $event)\"\r\n />\r\n }\r\n </div>\r\n\r\n @for (sub of section.subsections; track trackByIndex($index); let si = $index) {\r\n <lib-config-section-node\r\n [section]=\"sub\"\r\n [depth]=\"depth + 1\"\r\n [translate]=\"translate\"\r\n (toggleVisible)=\"onSubToggleVisible(si, $event)\"\r\n (toggleExpanded)=\"onSubToggleExpanded(si, $event)\"\r\n (fieldToggleVisible)=\"onSubFieldToggleVisible(si, $event)\"\r\n (fieldToggleMandatory)=\"onSubFieldToggleMandatory(si, $event)\"\r\n (fieldColSpanChange)=\"onSubFieldColSpanChange(si, $event)\"\r\n (fieldReorder)=\"onSubFieldReorder(si, $event)\"\r\n />\r\n }\r\n </div>\r\n }\r\n</div>\r\n", styles: [".ffc-toggle{position:relative;flex-shrink:0;width:var(--ffc-toggle-width, 38px);height:var(--ffc-toggle-height, 22px);padding:0;border:none;border-radius:999px;background:var(--ffc-toggle-off-bg, #cbd2d9);cursor:pointer;transition:background .18s ease}.ffc-toggle__thumb{position:absolute;top:2px;left:2px;width:calc(var(--ffc-toggle-height, 22px) - 4px);height:calc(var(--ffc-toggle-height, 22px) - 4px);border-radius:50%;background:var(--ffc-toggle-thumb, #ffffff);box-shadow:0 1px 2px #00000040;transition:left .18s ease}.ffc-toggle--on{background:var(--ffc-toggle-on-bg, #2f9e6f)}.ffc-toggle--on .ffc-toggle__thumb{left:calc(100% - (var(--ffc-toggle-height, 22px) - 2px))}.ffc-toggle:focus-visible{outline:2px solid var(--ffc-focus-ring, #2f9e6f);outline-offset:2px}.ffc-toggle--disabled{opacity:.45;cursor:not-allowed}.ffc-check{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:var(--ffc-check-size, 18px);height:var(--ffc-check-size, 18px);border-radius:4px;border:2px solid var(--ffc-check-border, #c3c9d0);background:var(--ffc-check-bg, #ffffff);color:transparent;transition:background .15s ease,border-color .15s ease,color .15s ease}.ffc-check svg{opacity:0;transition:opacity .15s ease}.ffc-check--on{background:var(--ffc-check-on-bg, #d97757);border-color:var(--ffc-check-on-bg, #d97757);color:#fff}.ffc-check--on svg{opacity:1}.ffc-lock{display:flex;align-items:center;justify-content:center;flex-shrink:0;width:var(--ffc-toggle-width, 38px);color:var(--ffc-lock-color, #9aa2ab)}.ffc-section{border:1px solid var(--ffc-section-border, #e5e7eb);border-radius:var(--ffc-section-radius, 10px);background:var(--ffc-section-bg, #ffffff);overflow:hidden}.ffc-section--nested{border-color:var(--ffc-section-nested-border, #eef0f2);background:var(--ffc-section-nested-bg, #fbfcfd)}.ffc-section--hidden .ffc-section__label,.ffc-section--hidden .ffc-section__count{opacity:.55}.ffc-section__header{display:flex;align-items:center;gap:10px;padding:var(--ffc-section-header-padding, 12px 14px);background:var(--ffc-section-header-bg, #f6f7f8);-webkit-user-select:none;user-select:none}.ffc-section--nested .ffc-section__header{background:var(--ffc-section-nested-header-bg, #f1f3f5)}.ffc-section__expand-btn{background:none;border:none;cursor:pointer;padding:2px;display:flex;color:var(--ffc-chevron-color, #6b7280);flex-shrink:0}.ffc-section__chevron{transform:rotate(-90deg);transition:transform .2s}.ffc-section__chevron--open{transform:rotate(0)}.ffc-section__label{flex:1 1 auto;min-width:0;font-size:var(--ffc-section-label-size, 14px);font-weight:600;color:var(--ffc-section-label-color, #1f2933);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.ffc-section__count{flex-shrink:0;font-size:var(--ffc-count-size, 12px);color:var(--ffc-count-color, #7b8794);white-space:nowrap}.ffc-section__body{padding:var(--ffc-section-body-padding, 8px 14px 14px 14px);display:flex;flex-direction:column;gap:var(--ffc-field-row-gap, 8px)}@media(max-width:640px){.ffc-section__body{padding:8px 10px 10px 18px;gap:6px}}.ffc-section__fields{display:flex;flex-direction:column;gap:var(--ffc-field-row-gap, 8px)}\n"] }]
|
|
11118
11386
|
}], propDecorators: { section: [{
|
|
11119
11387
|
type: Input,
|
|
11120
11388
|
args: [{ required: true }]
|
|
@@ -11130,22 +11398,34 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
|
|
|
11130
11398
|
type: Output
|
|
11131
11399
|
}], fieldToggleMandatory: [{
|
|
11132
11400
|
type: Output
|
|
11401
|
+
}], fieldColSpanChange: [{
|
|
11402
|
+
type: Output
|
|
11403
|
+
}], fieldReorder: [{
|
|
11404
|
+
type: Output
|
|
11133
11405
|
}] } });
|
|
11134
11406
|
|
|
11135
11407
|
/**
|
|
11136
11408
|
* Form Field Configuration
|
|
11137
11409
|
* ------------------------
|
|
11138
11410
|
* Renders a compact tree of a form schema's sections and fields, each with a
|
|
11139
|
-
* **visibility** toggle
|
|
11140
|
-
*
|
|
11411
|
+
* **visibility** toggle, a **mandatory** control, an editable **column span**,
|
|
11412
|
+
* and a drag handle to **reorder** fields within their own section. Intended to
|
|
11413
|
+
* be embedded inside a `cc-confirmation-modal` on a host page ("Configure fields").
|
|
11141
11414
|
*
|
|
11142
11415
|
* Pass a `FormSchema` via `[schema]`. The input is deep-cloned, so it is never
|
|
11143
11416
|
* mutated. When the user confirms, call `getUpdatedSchema()` to read back the
|
|
11144
|
-
* modified schema (visible/isEnabled/disabled and
|
|
11417
|
+
* modified schema (visible/isEnabled/disabled, required, and colSpan flags
|
|
11418
|
+
* updated, and each section's own children reordered to match the tree).
|
|
11145
11419
|
*
|
|
11146
11420
|
* Fields/sections carrying `lockVisibility: true` cannot be hidden, and
|
|
11147
11421
|
* `lockMandatory: true` freezes their required state.
|
|
11148
11422
|
*
|
|
11423
|
+
* Reordering is scoped to one section's direct fields — a field can never be
|
|
11424
|
+
* dragged into another section, and a field can never be dragged above a field
|
|
11425
|
+
* it depends on via `optionConfig.dependencies` (e.g. "state" can't sort above
|
|
11426
|
+
* "country"). Sections whose children include a `ROW` wrapper can't be
|
|
11427
|
+
* reordered at all (dragging is disabled) to avoid flattening the row layout.
|
|
11428
|
+
*
|
|
11149
11429
|
* @example
|
|
11150
11430
|
* ```html
|
|
11151
11431
|
* <cc-confirmation-modal [isOpen]="open" (confirm)="save()" (cancel)="open = false">
|
|
@@ -11190,15 +11470,21 @@ class FormFieldConfigurationComponent {
|
|
|
11190
11470
|
onFieldToggleMandatory(sectionIndex, payload) {
|
|
11191
11471
|
this.store.toggleFieldMandatory([sectionIndex, ...payload.sectionPath], payload.fieldIndex);
|
|
11192
11472
|
}
|
|
11473
|
+
onFieldColSpanChange(sectionIndex, payload) {
|
|
11474
|
+
this.store.setFieldColSpan([sectionIndex, ...payload.sectionPath], payload.fieldIndex, payload.colSpan);
|
|
11475
|
+
}
|
|
11476
|
+
onFieldReorder(sectionIndex, payload) {
|
|
11477
|
+
this.store.reorderField([sectionIndex, ...payload.sectionPath], payload.previousIndex, payload.currentIndex);
|
|
11478
|
+
}
|
|
11193
11479
|
trackByIndex(index) {
|
|
11194
11480
|
return index;
|
|
11195
11481
|
}
|
|
11196
11482
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FormFieldConfigurationComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
11197
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: FormFieldConfigurationComponent, isStandalone: false, selector: "lib-form-field-configuration", inputs: { schema: "schema", translate: "translate", showLegend: "showLegend" }, providers: [FieldConfigurationService], usesOnChanges: true, ngImport: i0, template: "<div class=\"ffc-root\">\r\n @if (showLegend) {\r\n <div class=\"ffc-legend\">\r\n <span class=\"ffc-legend__item\">\r\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\r\n <path d=\"M1 12s4-7 11-7 11 7 11 7-4 7-11 7-11-7-11-7z\"></path>\r\n <circle cx=\"12\" cy=\"12\" r=\"3\"></circle>\r\n </svg>\r\n <span>Visible</span>\r\n </span>\r\n <span class=\"ffc-legend__item\">\r\n <span class=\"ffc-legend__asterisk\" aria-hidden=\"true\">✱</span>\r\n <span>Mandatory (only if visible)</span>\r\n </span>\r\n </div>\r\n }\r\n\r\n <div class=\"ffc-tree\">\r\n @for (section of store.sections(); track trackByIndex($index); let si = $index) {\r\n <lib-config-section-node\r\n [section]=\"section\"\r\n [depth]=\"0\"\r\n [translate]=\"translate\"\r\n (toggleVisible)=\"onToggleVisible(si, $event)\"\r\n (toggleExpanded)=\"onToggleExpanded(si, $event)\"\r\n (fieldToggleVisible)=\"onFieldToggleVisible(si, $event)\"\r\n (fieldToggleMandatory)=\"onFieldToggleMandatory(si, $event)\"\r\n />\r\n }\r\n\r\n @if (store.sections().length === 0) {\r\n <div class=\"ffc-empty\">\r\n <p>No sections or fields found in the schema.</p>\r\n </div>\r\n }\r\n </div>\r\n</div>\r\n", styles: [".ffc-root{display:flex;flex-direction:column;gap:var(--ffc-root-gap, 12px);font-family:var(--ffc-font-family, inherit)}.ffc-legend{display:flex;align-items:center;gap:var(--ffc-legend-gap, 24px);padding:var(--ffc-legend-padding, 4px 2px 8px);border-bottom:1px solid var(--ffc-legend-border, #eef0f2);flex-wrap:wrap}.ffc-legend__item{display:inline-flex;align-items:center;gap:6px;font-size:var(--ffc-legend-size, 13px);color:var(--ffc-legend-color, #52606d)}.ffc-legend__asterisk{color:var(--ffc-asterisk-color, #d97757);font-size:14px;line-height:1}.ffc-tree{display:flex;flex-direction:column;gap:var(--ffc-tree-gap, 12px)}.ffc-empty{padding:24px;text-align:center;color:var(--ffc-empty-color, #9aa2ab);font-size:13px}\n"], dependencies: [{ kind: "component", type: ConfigSectionNodeComponent, selector: "lib-config-section-node", inputs: ["section", "depth", "translate"], outputs: ["toggleVisible", "toggleExpanded", "fieldToggleVisible", "fieldToggleMandatory"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
11483
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: FormFieldConfigurationComponent, isStandalone: false, selector: "lib-form-field-configuration", inputs: { schema: "schema", translate: "translate", showLegend: "showLegend" }, providers: [FieldConfigurationService], usesOnChanges: true, ngImport: i0, template: "<div class=\"ffc-root\">\r\n @if (showLegend) {\r\n <div class=\"ffc-legend\">\r\n <span class=\"ffc-legend__item\">\r\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\r\n <path d=\"M1 12s4-7 11-7 11 7 11 7-4 7-11 7-11-7-11-7z\"></path>\r\n <circle cx=\"12\" cy=\"12\" r=\"3\"></circle>\r\n </svg>\r\n <span>Visible</span>\r\n </span>\r\n <span class=\"ffc-legend__item\">\r\n <span class=\"ffc-legend__asterisk\" aria-hidden=\"true\">✱</span>\r\n <span>Mandatory (only if visible)</span>\r\n </span>\r\n </div>\r\n }\r\n\r\n <div class=\"ffc-tree\">\r\n @for (section of store.sections(); track trackByIndex($index); let si = $index) {\r\n <lib-config-section-node\r\n [section]=\"section\"\r\n [depth]=\"0\"\r\n [translate]=\"translate\"\r\n (toggleVisible)=\"onToggleVisible(si, $event)\"\r\n (toggleExpanded)=\"onToggleExpanded(si, $event)\"\r\n (fieldToggleVisible)=\"onFieldToggleVisible(si, $event)\"\r\n (fieldToggleMandatory)=\"onFieldToggleMandatory(si, $event)\"\r\n (fieldColSpanChange)=\"onFieldColSpanChange(si, $event)\"\r\n (fieldReorder)=\"onFieldReorder(si, $event)\"\r\n />\r\n }\r\n\r\n @if (store.sections().length === 0) {\r\n <div class=\"ffc-empty\">\r\n <p>No sections or fields found in the schema.</p>\r\n </div>\r\n }\r\n </div>\r\n</div>\r\n", styles: [".ffc-root{display:flex;flex-direction:column;gap:var(--ffc-root-gap, 12px);font-family:var(--ffc-font-family, inherit)}.ffc-legend{display:flex;align-items:center;gap:var(--ffc-legend-gap, 24px);padding:var(--ffc-legend-padding, 4px 2px 8px);border-bottom:1px solid var(--ffc-legend-border, #eef0f2);flex-wrap:wrap}.ffc-legend__item{display:inline-flex;align-items:center;gap:6px;font-size:var(--ffc-legend-size, 13px);color:var(--ffc-legend-color, #52606d)}.ffc-legend__asterisk{color:var(--ffc-asterisk-color, #d97757);font-size:14px;line-height:1}.ffc-tree{display:flex;flex-direction:column;gap:var(--ffc-tree-gap, 12px)}.ffc-empty{padding:24px;text-align:center;color:var(--ffc-empty-color, #9aa2ab);font-size:13px}\n"], dependencies: [{ kind: "component", type: ConfigSectionNodeComponent, selector: "lib-config-section-node", inputs: ["section", "depth", "translate"], outputs: ["toggleVisible", "toggleExpanded", "fieldToggleVisible", "fieldToggleMandatory", "fieldColSpanChange", "fieldReorder"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
11198
11484
|
}
|
|
11199
11485
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FormFieldConfigurationComponent, decorators: [{
|
|
11200
11486
|
type: Component,
|
|
11201
|
-
args: [{ selector: 'lib-form-field-configuration', standalone: false, providers: [FieldConfigurationService], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"ffc-root\">\r\n @if (showLegend) {\r\n <div class=\"ffc-legend\">\r\n <span class=\"ffc-legend__item\">\r\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\r\n <path d=\"M1 12s4-7 11-7 11 7 11 7-4 7-11 7-11-7-11-7z\"></path>\r\n <circle cx=\"12\" cy=\"12\" r=\"3\"></circle>\r\n </svg>\r\n <span>Visible</span>\r\n </span>\r\n <span class=\"ffc-legend__item\">\r\n <span class=\"ffc-legend__asterisk\" aria-hidden=\"true\">✱</span>\r\n <span>Mandatory (only if visible)</span>\r\n </span>\r\n </div>\r\n }\r\n\r\n <div class=\"ffc-tree\">\r\n @for (section of store.sections(); track trackByIndex($index); let si = $index) {\r\n <lib-config-section-node\r\n [section]=\"section\"\r\n [depth]=\"0\"\r\n [translate]=\"translate\"\r\n (toggleVisible)=\"onToggleVisible(si, $event)\"\r\n (toggleExpanded)=\"onToggleExpanded(si, $event)\"\r\n (fieldToggleVisible)=\"onFieldToggleVisible(si, $event)\"\r\n (fieldToggleMandatory)=\"onFieldToggleMandatory(si, $event)\"\r\n />\r\n }\r\n\r\n @if (store.sections().length === 0) {\r\n <div class=\"ffc-empty\">\r\n <p>No sections or fields found in the schema.</p>\r\n </div>\r\n }\r\n </div>\r\n</div>\r\n", styles: [".ffc-root{display:flex;flex-direction:column;gap:var(--ffc-root-gap, 12px);font-family:var(--ffc-font-family, inherit)}.ffc-legend{display:flex;align-items:center;gap:var(--ffc-legend-gap, 24px);padding:var(--ffc-legend-padding, 4px 2px 8px);border-bottom:1px solid var(--ffc-legend-border, #eef0f2);flex-wrap:wrap}.ffc-legend__item{display:inline-flex;align-items:center;gap:6px;font-size:var(--ffc-legend-size, 13px);color:var(--ffc-legend-color, #52606d)}.ffc-legend__asterisk{color:var(--ffc-asterisk-color, #d97757);font-size:14px;line-height:1}.ffc-tree{display:flex;flex-direction:column;gap:var(--ffc-tree-gap, 12px)}.ffc-empty{padding:24px;text-align:center;color:var(--ffc-empty-color, #9aa2ab);font-size:13px}\n"] }]
|
|
11487
|
+
args: [{ selector: 'lib-form-field-configuration', standalone: false, providers: [FieldConfigurationService], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"ffc-root\">\r\n @if (showLegend) {\r\n <div class=\"ffc-legend\">\r\n <span class=\"ffc-legend__item\">\r\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\r\n <path d=\"M1 12s4-7 11-7 11 7 11 7-4 7-11 7-11-7-11-7z\"></path>\r\n <circle cx=\"12\" cy=\"12\" r=\"3\"></circle>\r\n </svg>\r\n <span>Visible</span>\r\n </span>\r\n <span class=\"ffc-legend__item\">\r\n <span class=\"ffc-legend__asterisk\" aria-hidden=\"true\">✱</span>\r\n <span>Mandatory (only if visible)</span>\r\n </span>\r\n </div>\r\n }\r\n\r\n <div class=\"ffc-tree\">\r\n @for (section of store.sections(); track trackByIndex($index); let si = $index) {\r\n <lib-config-section-node\r\n [section]=\"section\"\r\n [depth]=\"0\"\r\n [translate]=\"translate\"\r\n (toggleVisible)=\"onToggleVisible(si, $event)\"\r\n (toggleExpanded)=\"onToggleExpanded(si, $event)\"\r\n (fieldToggleVisible)=\"onFieldToggleVisible(si, $event)\"\r\n (fieldToggleMandatory)=\"onFieldToggleMandatory(si, $event)\"\r\n (fieldColSpanChange)=\"onFieldColSpanChange(si, $event)\"\r\n (fieldReorder)=\"onFieldReorder(si, $event)\"\r\n />\r\n }\r\n\r\n @if (store.sections().length === 0) {\r\n <div class=\"ffc-empty\">\r\n <p>No sections or fields found in the schema.</p>\r\n </div>\r\n }\r\n </div>\r\n</div>\r\n", styles: [".ffc-root{display:flex;flex-direction:column;gap:var(--ffc-root-gap, 12px);font-family:var(--ffc-font-family, inherit)}.ffc-legend{display:flex;align-items:center;gap:var(--ffc-legend-gap, 24px);padding:var(--ffc-legend-padding, 4px 2px 8px);border-bottom:1px solid var(--ffc-legend-border, #eef0f2);flex-wrap:wrap}.ffc-legend__item{display:inline-flex;align-items:center;gap:6px;font-size:var(--ffc-legend-size, 13px);color:var(--ffc-legend-color, #52606d)}.ffc-legend__asterisk{color:var(--ffc-asterisk-color, #d97757);font-size:14px;line-height:1}.ffc-tree{display:flex;flex-direction:column;gap:var(--ffc-tree-gap, 12px)}.ffc-empty{padding:24px;text-align:center;color:var(--ffc-empty-color, #9aa2ab);font-size:13px}\n"] }]
|
|
11202
11488
|
}], propDecorators: { schema: [{
|
|
11203
11489
|
type: Input,
|
|
11204
11490
|
args: [{ required: true }]
|
|
@@ -11217,8 +11503,10 @@ class FormFieldConfigurationModule {
|
|
|
11217
11503
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FormFieldConfigurationModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
11218
11504
|
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.15", ngImport: i0, type: FormFieldConfigurationModule, declarations: [FormFieldConfigurationComponent,
|
|
11219
11505
|
ConfigSectionNodeComponent,
|
|
11220
|
-
ConfigFieldNodeComponent], imports: [CommonModule
|
|
11221
|
-
|
|
11506
|
+
ConfigFieldNodeComponent], imports: [CommonModule,
|
|
11507
|
+
DragDropModule], exports: [FormFieldConfigurationComponent] });
|
|
11508
|
+
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FormFieldConfigurationModule, imports: [CommonModule,
|
|
11509
|
+
DragDropModule] });
|
|
11222
11510
|
}
|
|
11223
11511
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FormFieldConfigurationModule, decorators: [{
|
|
11224
11512
|
type: NgModule,
|
|
@@ -11226,6 +11514,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
|
|
|
11226
11514
|
declarations: [...COMPONENTS$1],
|
|
11227
11515
|
imports: [
|
|
11228
11516
|
CommonModule,
|
|
11517
|
+
DragDropModule,
|
|
11229
11518
|
],
|
|
11230
11519
|
exports: [
|
|
11231
11520
|
FormFieldConfigurationComponent,
|
|
@@ -11251,7 +11540,8 @@ class TableColumnConfigurationService {
|
|
|
11251
11540
|
*/
|
|
11252
11541
|
loadConfig(config) {
|
|
11253
11542
|
const workingConfig = JSON.parse(JSON.stringify(config));
|
|
11254
|
-
|
|
11543
|
+
workingConfig.columns = this._sortBySequence(workingConfig.columns ?? []);
|
|
11544
|
+
const columns = workingConfig.columns.map(col => this._buildColumn(col));
|
|
11255
11545
|
this._state.set({ columns, workingConfig });
|
|
11256
11546
|
}
|
|
11257
11547
|
// ── Mutations ─────────────────────────────────────────────────────────────
|
|
@@ -11262,6 +11552,14 @@ class TableColumnConfigurationService {
|
|
|
11262
11552
|
columns: state.columns.map((c, i) => i === index && !c.lockVisibility ? { ...c, visible: !c.visible } : c),
|
|
11263
11553
|
}));
|
|
11264
11554
|
}
|
|
11555
|
+
/** Move a column from `previousIndex` to `currentIndex` (drag-and-drop reorder). */
|
|
11556
|
+
reorderColumn(previousIndex, currentIndex) {
|
|
11557
|
+
this._state.update(state => {
|
|
11558
|
+
const columns = [...state.columns];
|
|
11559
|
+
moveItemInArray(columns, previousIndex, currentIndex);
|
|
11560
|
+
return { ...state, columns };
|
|
11561
|
+
});
|
|
11562
|
+
}
|
|
11265
11563
|
// ── Output ────────────────────────────────────────────────────────────────
|
|
11266
11564
|
/**
|
|
11267
11565
|
* Produce the updated config. Writes the current node state onto the working
|
|
@@ -11272,10 +11570,13 @@ class TableColumnConfigurationService {
|
|
|
11272
11570
|
const { columns, workingConfig } = this._state();
|
|
11273
11571
|
if (!workingConfig)
|
|
11274
11572
|
return null;
|
|
11275
|
-
|
|
11573
|
+
columns.forEach((node, index) => {
|
|
11276
11574
|
node.column.isEnabled = node.visible;
|
|
11277
11575
|
node.column.visible = node.visible; // backward compatibility
|
|
11278
|
-
|
|
11576
|
+
node.column.sequence = index;
|
|
11577
|
+
});
|
|
11578
|
+
// Keep the working config's columns array in sync with the (possibly reordered) node list.
|
|
11579
|
+
workingConfig.columns = columns.map(node => node.column);
|
|
11279
11580
|
return JSON.parse(JSON.stringify(workingConfig));
|
|
11280
11581
|
}
|
|
11281
11582
|
// ── Private helpers ─────────────────────────────────────────────────────────
|
|
@@ -11288,6 +11589,21 @@ class TableColumnConfigurationService {
|
|
|
11288
11589
|
lockVisibility: column.lockVisibility === true,
|
|
11289
11590
|
};
|
|
11290
11591
|
}
|
|
11592
|
+
/**
|
|
11593
|
+
* Orders columns by `sequence` (ascending). Columns without a `sequence` keep their
|
|
11594
|
+
* original relative order, placed after any columns that do have one — so configs that
|
|
11595
|
+
* never set `sequence` come back untouched (stable sort).
|
|
11596
|
+
*/
|
|
11597
|
+
_sortBySequence(columns) {
|
|
11598
|
+
const hasSequence = columns.some(c => c.sequence !== undefined && c.sequence !== null);
|
|
11599
|
+
if (!hasSequence)
|
|
11600
|
+
return columns;
|
|
11601
|
+
return [...columns].sort((a, b) => {
|
|
11602
|
+
const aSeq = a.sequence ?? Number.MAX_SAFE_INTEGER;
|
|
11603
|
+
const bSeq = b.sequence ?? Number.MAX_SAFE_INTEGER;
|
|
11604
|
+
return aSeq - bSeq;
|
|
11605
|
+
});
|
|
11606
|
+
}
|
|
11291
11607
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TableColumnConfigurationService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
11292
11608
|
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TableColumnConfigurationService });
|
|
11293
11609
|
}
|
|
@@ -11310,11 +11626,11 @@ class ConfigColumnNodeComponent {
|
|
|
11310
11626
|
return this.translate ? this.translate(label) : label;
|
|
11311
11627
|
}
|
|
11312
11628
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ConfigColumnNodeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
11313
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: ConfigColumnNodeComponent, isStandalone: false, selector: "lib-config-column-node", inputs: { column: "column", translate: "translate" }, outputs: { toggleVisible: "toggleVisible" }, ngImport: i0, template: "<div\r\n class=\"tcc-col\"\r\n [class.tcc-col--hidden]=\"!column.visible\"\r\n [class.tcc-col--locked]=\"column.lockVisibility\"\r\n>\r\n <!-- Visibility indicator (eye / eye-off) -->\r\n <span class=\"tcc-col__eye\" [class.tcc-col__eye--off]=\"!column.visible\" aria-hidden=\"true\">\r\n @if (column.visible) {\r\n <svg width=\"17\" height=\"17\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <path d=\"M1 12s4-7 11-7 11 7 11 7-4 7-11 7-11-7-11-7z\"></path>\r\n <circle cx=\"12\" cy=\"12\" r=\"3\"></circle>\r\n </svg>\r\n } @else {\r\n <svg width=\"17\" height=\"17\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <path d=\"M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24\"></path>\r\n <line x1=\"1\" y1=\"1\" x2=\"23\" y2=\"23\"></line>\r\n </svg>\r\n }\r\n </span>\r\n\r\n <span class=\"tcc-col__label\" [title]=\"displayLabel\">{{ displayLabel }}</span>\r\n\r\n <!-- Visibility toggle / lock -->\r\n @if (column.lockVisibility) {\r\n <span class=\"tcc-lock\" title=\"This column is always visible\">\r\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\r\n <rect x=\"3\" y=\"11\" width=\"18\" height=\"11\" rx=\"2\" ry=\"2\"></rect>\r\n <path d=\"M7 11V7a5 5 0 0 1 10 0v4\"></path>\r\n </svg>\r\n </span>\r\n } @else {\r\n <button\r\n type=\"button\"\r\n class=\"tcc-toggle\"\r\n [class.tcc-toggle--on]=\"column.visible\"\r\n role=\"switch\"\r\n [attr.aria-checked]=\"column.visible\"\r\n [attr.aria-label]=\"'Show ' + displayLabel\"\r\n (click)=\"toggleVisible.emit()\"\r\n >\r\n <span class=\"tcc-toggle__thumb\"></span>\r\n </button>\r\n }\r\n</div>\r\n", styles: [".tcc-toggle{position:relative;flex-shrink:0;width:var(--tcc-toggle-width, 38px);height:var(--tcc-toggle-height, 22px);padding:0;border:none;border-radius:999px;background:var(--tcc-toggle-off-bg, #cbd2d9);cursor:pointer;transition:background .18s ease}.tcc-toggle__thumb{position:absolute;top:2px;left:2px;width:calc(var(--tcc-toggle-height, 22px) - 4px);height:calc(var(--tcc-toggle-height, 22px) - 4px);border-radius:50%;background:var(--tcc-toggle-thumb, #ffffff);box-shadow:0 1px 2px #00000040;transition:left .18s ease}.tcc-toggle--on{background:var(--tcc-toggle-on-bg, #2f9e6f)}.tcc-toggle--on .tcc-toggle__thumb{left:calc(100% - (var(--tcc-toggle-height, 22px) - 2px))}.tcc-toggle:focus-visible{outline:2px solid var(--tcc-focus-ring, #2f9e6f);outline-offset:2px}.tcc-lock{display:flex;align-items:center;justify-content:center;flex-shrink:0;width:var(--tcc-toggle-width, 38px);color:var(--tcc-lock-color, #9aa2ab)}.tcc-col{display:flex;align-items:center;gap:var(--tcc-col-gap, 12px);padding:var(--tcc-col-padding, 10px 14px);border-radius:var(--tcc-col-radius, 8px);background:var(--tcc-col-bg, #ffffff);border:1px solid var(--tcc-col-border, #eef0f2);transition:background .15s,border-color .15s,opacity .15s}.tcc-col:hover:not(.tcc-col--locked){background:var(--tcc-col-hover-bg, #f8fafc)}.tcc-col--hidden .tcc-col__eye,.tcc-col--hidden .tcc-col__label{opacity:.55}.tcc-col--locked{background:var(--tcc-col-locked-bg, #f6f7f8)}.tcc-col__eye{display:flex;align-items:center;color:var(--tcc-eye-color, #6b7280);flex-shrink:0}.tcc-col__eye--off{color:var(--tcc-eye-off-color, #b0b6be)}.tcc-col__label{flex:1 1 auto;min-width:0;font-size:var(--tcc-col-label-size, 14px);color:var(--tcc-col-label-color, #1f2933);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
11629
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: ConfigColumnNodeComponent, isStandalone: false, selector: "lib-config-column-node", inputs: { column: "column", translate: "translate" }, outputs: { toggleVisible: "toggleVisible" }, ngImport: i0, template: "<div\r\n class=\"tcc-col\"\r\n [class.tcc-col--hidden]=\"!column.visible\"\r\n [class.tcc-col--locked]=\"column.lockVisibility\"\r\n>\r\n <!-- Drag handle (reorder via the sequence field) -->\r\n <span class=\"tcc-col__grip\" title=\"Drag to reorder\" aria-hidden=\"true\">\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\r\n <circle cx=\"8\" cy=\"5\" r=\"1.6\"></circle>\r\n <circle cx=\"16\" cy=\"5\" r=\"1.6\"></circle>\r\n <circle cx=\"8\" cy=\"12\" r=\"1.6\"></circle>\r\n <circle cx=\"16\" cy=\"12\" r=\"1.6\"></circle>\r\n <circle cx=\"8\" cy=\"19\" r=\"1.6\"></circle>\r\n <circle cx=\"16\" cy=\"19\" r=\"1.6\"></circle>\r\n </svg>\r\n </span>\r\n\r\n <!-- Visibility indicator (eye / eye-off) -->\r\n <span class=\"tcc-col__eye\" [class.tcc-col__eye--off]=\"!column.visible\" aria-hidden=\"true\">\r\n @if (column.visible) {\r\n <svg width=\"17\" height=\"17\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <path d=\"M1 12s4-7 11-7 11 7 11 7-4 7-11 7-11-7-11-7z\"></path>\r\n <circle cx=\"12\" cy=\"12\" r=\"3\"></circle>\r\n </svg>\r\n } @else {\r\n <svg width=\"17\" height=\"17\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <path d=\"M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24\"></path>\r\n <line x1=\"1\" y1=\"1\" x2=\"23\" y2=\"23\"></line>\r\n </svg>\r\n }\r\n </span>\r\n\r\n <span class=\"tcc-col__label\" [title]=\"displayLabel\">{{ displayLabel }}</span>\r\n\r\n <!-- Visibility toggle / lock -->\r\n @if (column.lockVisibility) {\r\n <span class=\"tcc-lock\" title=\"This column is always visible\">\r\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\r\n <rect x=\"3\" y=\"11\" width=\"18\" height=\"11\" rx=\"2\" ry=\"2\"></rect>\r\n <path d=\"M7 11V7a5 5 0 0 1 10 0v4\"></path>\r\n </svg>\r\n </span>\r\n } @else {\r\n <button\r\n type=\"button\"\r\n class=\"tcc-toggle\"\r\n [class.tcc-toggle--on]=\"column.visible\"\r\n role=\"switch\"\r\n [attr.aria-checked]=\"column.visible\"\r\n [attr.aria-label]=\"'Show ' + displayLabel\"\r\n (click)=\"toggleVisible.emit()\"\r\n >\r\n <span class=\"tcc-toggle__thumb\"></span>\r\n </button>\r\n }\r\n</div>\r\n", styles: [".tcc-toggle{position:relative;flex-shrink:0;width:var(--tcc-toggle-width, 38px);height:var(--tcc-toggle-height, 22px);padding:0;border:none;border-radius:999px;background:var(--tcc-toggle-off-bg, #cbd2d9);cursor:pointer;transition:background .18s ease}.tcc-toggle__thumb{position:absolute;top:2px;left:2px;width:calc(var(--tcc-toggle-height, 22px) - 4px);height:calc(var(--tcc-toggle-height, 22px) - 4px);border-radius:50%;background:var(--tcc-toggle-thumb, #ffffff);box-shadow:0 1px 2px #00000040;transition:left .18s ease}.tcc-toggle--on{background:var(--tcc-toggle-on-bg, #2f9e6f)}.tcc-toggle--on .tcc-toggle__thumb{left:calc(100% - (var(--tcc-toggle-height, 22px) - 2px))}.tcc-toggle:focus-visible{outline:2px solid var(--tcc-focus-ring, #2f9e6f);outline-offset:2px}.tcc-lock{display:flex;align-items:center;justify-content:center;flex-shrink:0;width:var(--tcc-toggle-width, 38px);color:var(--tcc-lock-color, #9aa2ab)}:host{display:block;cursor:grab}:host.cdk-drag-dragging,:host.cdk-drag-placeholder{cursor:grabbing}.tcc-col{display:flex;align-items:center;gap:var(--tcc-col-gap, 12px);padding:var(--tcc-col-padding, 10px 14px);border-radius:var(--tcc-col-radius, 8px);background:var(--tcc-col-bg, #ffffff);border:1px solid var(--tcc-col-border, #eef0f2);transition:background .15s,border-color .15s,opacity .15s}.tcc-col:hover:not(.tcc-col--locked){background:var(--tcc-col-hover-bg, #f8fafc)}.tcc-col__grip{display:flex;align-items:center;color:var(--tcc-grip-color, #cbd2d9);flex-shrink:0}.tcc-col--hidden .tcc-col__eye,.tcc-col--hidden .tcc-col__label{opacity:.55}.tcc-col--locked{background:var(--tcc-col-locked-bg, #f6f7f8)}.tcc-col__eye{display:flex;align-items:center;color:var(--tcc-eye-color, #6b7280);flex-shrink:0}.tcc-col__eye--off{color:var(--tcc-eye-off-color, #b0b6be)}.tcc-col__label{flex:1 1 auto;min-width:0;font-size:var(--tcc-col-label-size, 14px);color:var(--tcc-col-label-color, #1f2933);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
11314
11630
|
}
|
|
11315
11631
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ConfigColumnNodeComponent, decorators: [{
|
|
11316
11632
|
type: Component,
|
|
11317
|
-
args: [{ selector: 'lib-config-column-node', standalone: false, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\r\n class=\"tcc-col\"\r\n [class.tcc-col--hidden]=\"!column.visible\"\r\n [class.tcc-col--locked]=\"column.lockVisibility\"\r\n>\r\n <!-- Visibility indicator (eye / eye-off) -->\r\n <span class=\"tcc-col__eye\" [class.tcc-col__eye--off]=\"!column.visible\" aria-hidden=\"true\">\r\n @if (column.visible) {\r\n <svg width=\"17\" height=\"17\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <path d=\"M1 12s4-7 11-7 11 7 11 7-4 7-11 7-11-7-11-7z\"></path>\r\n <circle cx=\"12\" cy=\"12\" r=\"3\"></circle>\r\n </svg>\r\n } @else {\r\n <svg width=\"17\" height=\"17\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <path d=\"M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24\"></path>\r\n <line x1=\"1\" y1=\"1\" x2=\"23\" y2=\"23\"></line>\r\n </svg>\r\n }\r\n </span>\r\n\r\n <span class=\"tcc-col__label\" [title]=\"displayLabel\">{{ displayLabel }}</span>\r\n\r\n <!-- Visibility toggle / lock -->\r\n @if (column.lockVisibility) {\r\n <span class=\"tcc-lock\" title=\"This column is always visible\">\r\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\r\n <rect x=\"3\" y=\"11\" width=\"18\" height=\"11\" rx=\"2\" ry=\"2\"></rect>\r\n <path d=\"M7 11V7a5 5 0 0 1 10 0v4\"></path>\r\n </svg>\r\n </span>\r\n } @else {\r\n <button\r\n type=\"button\"\r\n class=\"tcc-toggle\"\r\n [class.tcc-toggle--on]=\"column.visible\"\r\n role=\"switch\"\r\n [attr.aria-checked]=\"column.visible\"\r\n [attr.aria-label]=\"'Show ' + displayLabel\"\r\n (click)=\"toggleVisible.emit()\"\r\n >\r\n <span class=\"tcc-toggle__thumb\"></span>\r\n </button>\r\n }\r\n</div>\r\n", styles: [".tcc-toggle{position:relative;flex-shrink:0;width:var(--tcc-toggle-width, 38px);height:var(--tcc-toggle-height, 22px);padding:0;border:none;border-radius:999px;background:var(--tcc-toggle-off-bg, #cbd2d9);cursor:pointer;transition:background .18s ease}.tcc-toggle__thumb{position:absolute;top:2px;left:2px;width:calc(var(--tcc-toggle-height, 22px) - 4px);height:calc(var(--tcc-toggle-height, 22px) - 4px);border-radius:50%;background:var(--tcc-toggle-thumb, #ffffff);box-shadow:0 1px 2px #00000040;transition:left .18s ease}.tcc-toggle--on{background:var(--tcc-toggle-on-bg, #2f9e6f)}.tcc-toggle--on .tcc-toggle__thumb{left:calc(100% - (var(--tcc-toggle-height, 22px) - 2px))}.tcc-toggle:focus-visible{outline:2px solid var(--tcc-focus-ring, #2f9e6f);outline-offset:2px}.tcc-lock{display:flex;align-items:center;justify-content:center;flex-shrink:0;width:var(--tcc-toggle-width, 38px);color:var(--tcc-lock-color, #9aa2ab)}.tcc-col{display:flex;align-items:center;gap:var(--tcc-col-gap, 12px);padding:var(--tcc-col-padding, 10px 14px);border-radius:var(--tcc-col-radius, 8px);background:var(--tcc-col-bg, #ffffff);border:1px solid var(--tcc-col-border, #eef0f2);transition:background .15s,border-color .15s,opacity .15s}.tcc-col:hover:not(.tcc-col--locked){background:var(--tcc-col-hover-bg, #f8fafc)}.tcc-col--hidden .tcc-col__eye,.tcc-col--hidden .tcc-col__label{opacity:.55}.tcc-col--locked{background:var(--tcc-col-locked-bg, #f6f7f8)}.tcc-col__eye{display:flex;align-items:center;color:var(--tcc-eye-color, #6b7280);flex-shrink:0}.tcc-col__eye--off{color:var(--tcc-eye-off-color, #b0b6be)}.tcc-col__label{flex:1 1 auto;min-width:0;font-size:var(--tcc-col-label-size, 14px);color:var(--tcc-col-label-color, #1f2933);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n"] }]
|
|
11633
|
+
args: [{ selector: 'lib-config-column-node', standalone: false, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\r\n class=\"tcc-col\"\r\n [class.tcc-col--hidden]=\"!column.visible\"\r\n [class.tcc-col--locked]=\"column.lockVisibility\"\r\n>\r\n <!-- Drag handle (reorder via the sequence field) -->\r\n <span class=\"tcc-col__grip\" title=\"Drag to reorder\" aria-hidden=\"true\">\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\r\n <circle cx=\"8\" cy=\"5\" r=\"1.6\"></circle>\r\n <circle cx=\"16\" cy=\"5\" r=\"1.6\"></circle>\r\n <circle cx=\"8\" cy=\"12\" r=\"1.6\"></circle>\r\n <circle cx=\"16\" cy=\"12\" r=\"1.6\"></circle>\r\n <circle cx=\"8\" cy=\"19\" r=\"1.6\"></circle>\r\n <circle cx=\"16\" cy=\"19\" r=\"1.6\"></circle>\r\n </svg>\r\n </span>\r\n\r\n <!-- Visibility indicator (eye / eye-off) -->\r\n <span class=\"tcc-col__eye\" [class.tcc-col__eye--off]=\"!column.visible\" aria-hidden=\"true\">\r\n @if (column.visible) {\r\n <svg width=\"17\" height=\"17\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <path d=\"M1 12s4-7 11-7 11 7 11 7-4 7-11 7-11-7-11-7z\"></path>\r\n <circle cx=\"12\" cy=\"12\" r=\"3\"></circle>\r\n </svg>\r\n } @else {\r\n <svg width=\"17\" height=\"17\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <path d=\"M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24\"></path>\r\n <line x1=\"1\" y1=\"1\" x2=\"23\" y2=\"23\"></line>\r\n </svg>\r\n }\r\n </span>\r\n\r\n <span class=\"tcc-col__label\" [title]=\"displayLabel\">{{ displayLabel }}</span>\r\n\r\n <!-- Visibility toggle / lock -->\r\n @if (column.lockVisibility) {\r\n <span class=\"tcc-lock\" title=\"This column is always visible\">\r\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\r\n <rect x=\"3\" y=\"11\" width=\"18\" height=\"11\" rx=\"2\" ry=\"2\"></rect>\r\n <path d=\"M7 11V7a5 5 0 0 1 10 0v4\"></path>\r\n </svg>\r\n </span>\r\n } @else {\r\n <button\r\n type=\"button\"\r\n class=\"tcc-toggle\"\r\n [class.tcc-toggle--on]=\"column.visible\"\r\n role=\"switch\"\r\n [attr.aria-checked]=\"column.visible\"\r\n [attr.aria-label]=\"'Show ' + displayLabel\"\r\n (click)=\"toggleVisible.emit()\"\r\n >\r\n <span class=\"tcc-toggle__thumb\"></span>\r\n </button>\r\n }\r\n</div>\r\n", styles: [".tcc-toggle{position:relative;flex-shrink:0;width:var(--tcc-toggle-width, 38px);height:var(--tcc-toggle-height, 22px);padding:0;border:none;border-radius:999px;background:var(--tcc-toggle-off-bg, #cbd2d9);cursor:pointer;transition:background .18s ease}.tcc-toggle__thumb{position:absolute;top:2px;left:2px;width:calc(var(--tcc-toggle-height, 22px) - 4px);height:calc(var(--tcc-toggle-height, 22px) - 4px);border-radius:50%;background:var(--tcc-toggle-thumb, #ffffff);box-shadow:0 1px 2px #00000040;transition:left .18s ease}.tcc-toggle--on{background:var(--tcc-toggle-on-bg, #2f9e6f)}.tcc-toggle--on .tcc-toggle__thumb{left:calc(100% - (var(--tcc-toggle-height, 22px) - 2px))}.tcc-toggle:focus-visible{outline:2px solid var(--tcc-focus-ring, #2f9e6f);outline-offset:2px}.tcc-lock{display:flex;align-items:center;justify-content:center;flex-shrink:0;width:var(--tcc-toggle-width, 38px);color:var(--tcc-lock-color, #9aa2ab)}:host{display:block;cursor:grab}:host.cdk-drag-dragging,:host.cdk-drag-placeholder{cursor:grabbing}.tcc-col{display:flex;align-items:center;gap:var(--tcc-col-gap, 12px);padding:var(--tcc-col-padding, 10px 14px);border-radius:var(--tcc-col-radius, 8px);background:var(--tcc-col-bg, #ffffff);border:1px solid var(--tcc-col-border, #eef0f2);transition:background .15s,border-color .15s,opacity .15s}.tcc-col:hover:not(.tcc-col--locked){background:var(--tcc-col-hover-bg, #f8fafc)}.tcc-col__grip{display:flex;align-items:center;color:var(--tcc-grip-color, #cbd2d9);flex-shrink:0}.tcc-col--hidden .tcc-col__eye,.tcc-col--hidden .tcc-col__label{opacity:.55}.tcc-col--locked{background:var(--tcc-col-locked-bg, #f6f7f8)}.tcc-col__eye{display:flex;align-items:center;color:var(--tcc-eye-color, #6b7280);flex-shrink:0}.tcc-col__eye--off{color:var(--tcc-eye-off-color, #b0b6be)}.tcc-col__label{flex:1 1 auto;min-width:0;font-size:var(--tcc-col-label-size, 14px);color:var(--tcc-col-label-color, #1f2933);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n"] }]
|
|
11318
11634
|
}], propDecorators: { column: [{
|
|
11319
11635
|
type: Input,
|
|
11320
11636
|
args: [{ required: true }]
|
|
@@ -11328,15 +11644,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
|
|
|
11328
11644
|
* Table Column Configuration
|
|
11329
11645
|
* --------------------------
|
|
11330
11646
|
* Renders a compact list of a table config's columns, each with a **visibility**
|
|
11331
|
-
* toggle
|
|
11332
|
-
* ("Configure columns").
|
|
11647
|
+
* toggle and a drag handle for **reordering**. Intended to be embedded inside a
|
|
11648
|
+
* `cc-confirmation-modal` on a host page ("Configure columns").
|
|
11333
11649
|
*
|
|
11334
11650
|
* Pass a `TableConfig` via `[config]`. The input is deep-cloned, so it is never
|
|
11335
|
-
* mutated.
|
|
11336
|
-
*
|
|
11651
|
+
* mutated. Columns load pre-sorted by `sequence` (if set); columns without a
|
|
11652
|
+
* `sequence` keep their original relative order. When the user confirms, call
|
|
11653
|
+
* `getUpdatedConfig()` to read back the modified config (isEnabled/visible flags
|
|
11654
|
+
* and `sequence` updated per column, in the new order).
|
|
11337
11655
|
*
|
|
11338
11656
|
* Columns carrying `lockVisibility: true` cannot be hidden — their toggle is
|
|
11339
|
-
* replaced by a lock icon.
|
|
11657
|
+
* replaced by a lock icon. They can still be dragged to reorder.
|
|
11340
11658
|
*
|
|
11341
11659
|
* @example
|
|
11342
11660
|
* ```html
|
|
@@ -11372,15 +11690,21 @@ class TableColumnConfigurationComponent {
|
|
|
11372
11690
|
onToggleVisible(index) {
|
|
11373
11691
|
this.store.toggleColumnVisible(index);
|
|
11374
11692
|
}
|
|
11693
|
+
/** Drag-and-drop reorder. Written back as `sequence` on each column by `getUpdatedConfig()`. */
|
|
11694
|
+
onDrop(event) {
|
|
11695
|
+
if (event.previousIndex === event.currentIndex)
|
|
11696
|
+
return;
|
|
11697
|
+
this.store.reorderColumn(event.previousIndex, event.currentIndex);
|
|
11698
|
+
}
|
|
11375
11699
|
trackByIndex(index) {
|
|
11376
11700
|
return index;
|
|
11377
11701
|
}
|
|
11378
11702
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TableColumnConfigurationComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
11379
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: TableColumnConfigurationComponent, isStandalone: false, selector: "lib-table-column-configuration", inputs: { config: "config", translate: "translate", showLegend: "showLegend" }, providers: [TableColumnConfigurationService], usesOnChanges: true, ngImport: i0, template: "<div class=\"tcc-root\">\r\n @if (showLegend) {\r\n <div class=\"tcc-legend\">\r\n <span class=\"tcc-legend__item\">\r\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\r\n <path d=\"M1 12s4-7 11-7 11 7 11 7-4 7-11 7-11-7-11-7z\"></path>\r\n <circle cx=\"12\" cy=\"12\" r=\"3\"></circle>\r\n </svg>\r\n <span>Visible</span>\r\n </span>\r\n </div>\r\n }\r\n\r\n <div class=\"tcc-list\">\r\n @for (column of store.columns(); track trackByIndex($index); let ci = $index) {\r\n <lib-config-column-node\r\n [column]=\"column\"\r\n [translate]=\"translate\"\r\n (toggleVisible)=\"onToggleVisible(ci)\"\r\n />\r\n }\r\n\r\n @if (store.columns().length === 0) {\r\n <div class=\"tcc-empty\">\r\n <p>No columns found in the config.</p>\r\n </div>\r\n }\r\n </div>\r\n</div>\r\n", styles: [".tcc-root{display:flex;flex-direction:column;gap:var(--tcc-root-gap, 12px);font-family:var(--tcc-font-family, inherit)}.tcc-legend{display:flex;align-items:center;gap:var(--tcc-legend-gap, 24px);padding:var(--tcc-legend-padding, 4px 2px 8px);border-bottom:1px solid var(--tcc-legend-border, #eef0f2);flex-wrap:wrap}.tcc-legend__item{display:inline-flex;align-items:center;gap:6px;font-size:var(--tcc-legend-size, 13px);color:var(--tcc-legend-color, #52606d)}.tcc-list{display:flex;flex-direction:column;gap:var(--tcc-list-gap, 10px)}.tcc-empty{padding:24px;text-align:center;color:var(--tcc-empty-color, #9aa2ab);font-size:13px}\n"], dependencies: [{ kind: "component", type: ConfigColumnNodeComponent, selector: "lib-config-column-node", inputs: ["column", "translate"], outputs: ["toggleVisible"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
11703
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: TableColumnConfigurationComponent, isStandalone: false, selector: "lib-table-column-configuration", inputs: { config: "config", translate: "translate", showLegend: "showLegend" }, providers: [TableColumnConfigurationService], usesOnChanges: true, ngImport: i0, template: "<div class=\"tcc-root\">\r\n @if (showLegend) {\r\n <div class=\"tcc-legend\">\r\n <span class=\"tcc-legend__item\">\r\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\r\n <path d=\"M1 12s4-7 11-7 11 7 11 7-4 7-11 7-11-7-11-7z\"></path>\r\n <circle cx=\"12\" cy=\"12\" r=\"3\"></circle>\r\n </svg>\r\n <span>Visible</span>\r\n </span>\r\n </div>\r\n }\r\n\r\n <div class=\"tcc-list\" cdkDropList (cdkDropListDropped)=\"onDrop($event)\">\r\n @for (column of store.columns(); track trackByIndex($index); let ci = $index) {\r\n <lib-config-column-node\r\n cdkDrag\r\n [column]=\"column\"\r\n [translate]=\"translate\"\r\n (toggleVisible)=\"onToggleVisible(ci)\"\r\n />\r\n }\r\n\r\n @if (store.columns().length === 0) {\r\n <div class=\"tcc-empty\">\r\n <p>No columns found in the config.</p>\r\n </div>\r\n }\r\n </div>\r\n</div>\r\n", styles: [".tcc-root{display:flex;flex-direction:column;gap:var(--tcc-root-gap, 12px);font-family:var(--tcc-font-family, inherit)}.tcc-legend{display:flex;align-items:center;gap:var(--tcc-legend-gap, 24px);padding:var(--tcc-legend-padding, 4px 2px 8px);border-bottom:1px solid var(--tcc-legend-border, #eef0f2);flex-wrap:wrap}.tcc-legend__item{display:inline-flex;align-items:center;gap:6px;font-size:var(--tcc-legend-size, 13px);color:var(--tcc-legend-color, #52606d)}.tcc-list{display:flex;flex-direction:column;gap:var(--tcc-list-gap, 10px)}.tcc-empty{padding:24px;text-align:center;color:var(--tcc-empty-color, #9aa2ab);font-size:13px}\n"], dependencies: [{ kind: "directive", type: i1$5.CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer", "cdkDropListHasAnchor"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: i1$5.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "component", type: ConfigColumnNodeComponent, selector: "lib-config-column-node", inputs: ["column", "translate"], outputs: ["toggleVisible"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
11380
11704
|
}
|
|
11381
11705
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TableColumnConfigurationComponent, decorators: [{
|
|
11382
11706
|
type: Component,
|
|
11383
|
-
args: [{ selector: 'lib-table-column-configuration', standalone: false, providers: [TableColumnConfigurationService], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"tcc-root\">\r\n @if (showLegend) {\r\n <div class=\"tcc-legend\">\r\n <span class=\"tcc-legend__item\">\r\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\r\n <path d=\"M1 12s4-7 11-7 11 7 11 7-4 7-11 7-11-7-11-7z\"></path>\r\n <circle cx=\"12\" cy=\"12\" r=\"3\"></circle>\r\n </svg>\r\n <span>Visible</span>\r\n </span>\r\n </div>\r\n }\r\n\r\n <div class=\"tcc-list\">\r\n @for (column of store.columns(); track trackByIndex($index); let ci = $index) {\r\n <lib-config-column-node\r\n [column]=\"column\"\r\n [translate]=\"translate\"\r\n (toggleVisible)=\"onToggleVisible(ci)\"\r\n />\r\n }\r\n\r\n @if (store.columns().length === 0) {\r\n <div class=\"tcc-empty\">\r\n <p>No columns found in the config.</p>\r\n </div>\r\n }\r\n </div>\r\n</div>\r\n", styles: [".tcc-root{display:flex;flex-direction:column;gap:var(--tcc-root-gap, 12px);font-family:var(--tcc-font-family, inherit)}.tcc-legend{display:flex;align-items:center;gap:var(--tcc-legend-gap, 24px);padding:var(--tcc-legend-padding, 4px 2px 8px);border-bottom:1px solid var(--tcc-legend-border, #eef0f2);flex-wrap:wrap}.tcc-legend__item{display:inline-flex;align-items:center;gap:6px;font-size:var(--tcc-legend-size, 13px);color:var(--tcc-legend-color, #52606d)}.tcc-list{display:flex;flex-direction:column;gap:var(--tcc-list-gap, 10px)}.tcc-empty{padding:24px;text-align:center;color:var(--tcc-empty-color, #9aa2ab);font-size:13px}\n"] }]
|
|
11707
|
+
args: [{ selector: 'lib-table-column-configuration', standalone: false, providers: [TableColumnConfigurationService], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"tcc-root\">\r\n @if (showLegend) {\r\n <div class=\"tcc-legend\">\r\n <span class=\"tcc-legend__item\">\r\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\r\n <path d=\"M1 12s4-7 11-7 11 7 11 7-4 7-11 7-11-7-11-7z\"></path>\r\n <circle cx=\"12\" cy=\"12\" r=\"3\"></circle>\r\n </svg>\r\n <span>Visible</span>\r\n </span>\r\n </div>\r\n }\r\n\r\n <div class=\"tcc-list\" cdkDropList (cdkDropListDropped)=\"onDrop($event)\">\r\n @for (column of store.columns(); track trackByIndex($index); let ci = $index) {\r\n <lib-config-column-node\r\n cdkDrag\r\n [column]=\"column\"\r\n [translate]=\"translate\"\r\n (toggleVisible)=\"onToggleVisible(ci)\"\r\n />\r\n }\r\n\r\n @if (store.columns().length === 0) {\r\n <div class=\"tcc-empty\">\r\n <p>No columns found in the config.</p>\r\n </div>\r\n }\r\n </div>\r\n</div>\r\n", styles: [".tcc-root{display:flex;flex-direction:column;gap:var(--tcc-root-gap, 12px);font-family:var(--tcc-font-family, inherit)}.tcc-legend{display:flex;align-items:center;gap:var(--tcc-legend-gap, 24px);padding:var(--tcc-legend-padding, 4px 2px 8px);border-bottom:1px solid var(--tcc-legend-border, #eef0f2);flex-wrap:wrap}.tcc-legend__item{display:inline-flex;align-items:center;gap:6px;font-size:var(--tcc-legend-size, 13px);color:var(--tcc-legend-color, #52606d)}.tcc-list{display:flex;flex-direction:column;gap:var(--tcc-list-gap, 10px)}.tcc-empty{padding:24px;text-align:center;color:var(--tcc-empty-color, #9aa2ab);font-size:13px}\n"] }]
|
|
11384
11708
|
}], propDecorators: { config: [{
|
|
11385
11709
|
type: Input,
|
|
11386
11710
|
args: [{ required: true }]
|
|
@@ -11397,8 +11721,10 @@ const COMPONENTS = [
|
|
|
11397
11721
|
class TableColumnConfigurationModule {
|
|
11398
11722
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TableColumnConfigurationModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
11399
11723
|
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.15", ngImport: i0, type: TableColumnConfigurationModule, declarations: [TableColumnConfigurationComponent,
|
|
11400
|
-
ConfigColumnNodeComponent], imports: [CommonModule
|
|
11401
|
-
|
|
11724
|
+
ConfigColumnNodeComponent], imports: [CommonModule,
|
|
11725
|
+
DragDropModule], exports: [TableColumnConfigurationComponent] });
|
|
11726
|
+
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TableColumnConfigurationModule, imports: [CommonModule,
|
|
11727
|
+
DragDropModule] });
|
|
11402
11728
|
}
|
|
11403
11729
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TableColumnConfigurationModule, decorators: [{
|
|
11404
11730
|
type: NgModule,
|
|
@@ -11406,6 +11732,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
|
|
|
11406
11732
|
declarations: [...COMPONENTS],
|
|
11407
11733
|
imports: [
|
|
11408
11734
|
CommonModule,
|
|
11735
|
+
DragDropModule,
|
|
11409
11736
|
],
|
|
11410
11737
|
exports: [
|
|
11411
11738
|
TableColumnConfigurationComponent,
|
|
@@ -12015,7 +12342,7 @@ class FilterSidebarComponent {
|
|
|
12015
12342
|
useExisting: forwardRef(() => FilterSidebarComponent),
|
|
12016
12343
|
multi: true
|
|
12017
12344
|
}
|
|
12018
|
-
], ngImport: i0, template: "<div class=\"cc-filter-sidebar\" [ngStyle]=\"sidebarStyles\" [class.collapsed]=\"isCollapsed\">\r\n\r\n <!-- Header -->\r\n <div class=\"cc-filter-header\" *ngIf=\"config.header?.visible !== false\">\r\n <div class=\"cc-header-content\">\r\n <span class=\"cc-header-title\" *ngIf=\"config.header?.title\">\r\n <span *ngIf=\"config.header?.icon\" [class]=\"config.header?.icon\" class=\"cc-header-icon material-icons\">\r\n <!-- {{config.header?.icon }} -->\r\n </span>\r\n {{ config.header?.title }}\r\n </span>\r\n <ng-content select=\"[header-actions]\"></ng-content>\r\n </div>\r\n <button type=\"button\" *ngIf=\"config.settings?.collapsible\" (click)=\"toggleCollapse()\" class=\"cc-icon-btn\"\r\n [attr.aria-label]=\"isCollapsed ? config.labels?.expandAriaLabel : config.labels?.collapseAriaLabel\">\r\n <span class=\"material-icons\">{{ isCollapsed ? 'menu_open' : 'menu' }}</span>\r\n </button>\r\n <button type=\"button\" *ngIf=\"config.header?.showClose && !isCollapsed\" (click)=\"onClose()\"\r\n class=\"cc-icon-btn cc-close-btn\" [attr.aria-label]=\"config.labels?.closeAriaLabel\">\r\n <span class=\"material-icons\">close</span>\r\n </button>\r\n <!-- Code snippet debug (optional) -->\r\n <button type=\"button\" *ngIf=\"config.settings?.showCodeSnippet\" (click)=\"onShowCodeSnippet()\" class=\"cc-icon-btn\"\r\n [attr.aria-label]=\"config.labels?.codeSnippetAriaLabel\">\r\n <span class=\"material-icons\">code</span>\r\n </button>\r\n </div>\r\n\r\n <!-- Content (Scrollable) -->\r\n <div class=\"cc-filter-content\" [class.hidden]=\"isCollapsed\">\r\n <ng-container *ngFor=\"let item of config.items; trackBy: trackByFn\">\r\n <ng-container *ngTemplateOutlet=\"itemTemplate; context: { item: item }\"></ng-container>\r\n </ng-container>\r\n </div>\r\n\r\n <!-- Footer -->\r\n <div class=\"cc-filter-footer\" *ngIf=\"config.footer?.visible !== false && !isCollapsed\">\r\n <lib-button variant=\"outline\" color=\"warn\" class=\"cc-btn-clear\"\r\n *ngIf=\"config.footer?.clearButton?.visible !== false\" (click)=\"clearFilters()\">\r\n {{ config.footer?.clearButton?.label }}\r\n </lib-button>\r\n <lib-button variant=\"primary\" color=\"warn\" class=\"cc-btn-apply\"\r\n *ngIf=\"config.footer?.applyButton?.visible !== false\" [disabled]=\"config.footer?.applyButton?.disabled ?? false\"\r\n (click)=\"applyFilters()\">\r\n {{ config.footer?.applyButton?.label }}\r\n </lib-button>\r\n </div>\r\n</div>\r\n\r\n<!-- Recursive Template for Items -->\r\n<ng-template #itemTemplate let-item=\"item\">\r\n <div class=\"cc-filter-item\" [ngClass]=\"['type-' + item.type]\"\r\n [style.display]=\"item.visible === false ? 'none' : 'block'\" [ngStyle]=\"item.styles\">\r\n\r\n <ng-container [ngSwitch]=\"item.type\">\r\n\r\n <!-- Input -->\r\n <lib-input *ngSwitchCase=\"'input'\" [config]=\"item.inputConfig\" [label]=\"item.label\"\r\n [ngModel]=\"filters[item.key]\" (valueChange)=\"onValueChange(item.key, $event)\">\r\n </lib-input>\r\n\r\n <!-- Dropdown -->\r\n <lib-dropdown *ngSwitchCase=\"'dropdown'\" [config]=\"item.dropdownConfig\" [label]=\"item.label\"\r\n [ngModel]=\"filters[item.key]\" (selectionChange)=\"onValueChange(item.key, $event)\">\r\n </lib-dropdown>\r\n\r\n <!-- Checkbox -->\r\n <lib-checkbox *ngSwitchCase=\"'checkbox'\" [config]=\"item.checkboxConfig\" [label]=\"item.label\"\r\n [checked]=\"!!filters[item.key]\" (checkedChange)=\"onValueChange(item.key, $event)\">\r\n </lib-checkbox>\r\n\r\n <!-- Radio -->\r\n <lib-radio *ngSwitchCase=\"'radio'\" [config]=\"item.radioConfig\" [label]=\"item.label\"\r\n [ngModel]=\"filters[item.key]\" (selectionChange)=\"onValueChange(item.key, $event)\">\r\n </lib-radio>\r\n\r\n <!-- Toggle -->\r\n <lib-toggle *ngSwitchCase=\"'toggle'\" [config]=\"item.toggleConfig\" [label]=\"item.label\"\r\n [checked]=\"filters[item.key]\" (toggleChange)=\"onValueChange(item.key, $event)\">\r\n </lib-toggle>\r\n\r\n <!-- Datepicker -->\r\n <lib-datepicker *ngSwitchCase=\"'datepicker'\" [config]=\"item.datepickerConfig\" [label]=\"item.label\"\r\n [ngModel]=\"filters[item.key]\" (dateChange)=\"onValueChange(item.key, $event)\">\r\n </lib-datepicker>\r\n\r\n <!-- Search -->\r\n <lib-search *ngSwitchCase=\"'active-search'\" [config]=\"item.searchConfig\" [label]=\"item.label\"\r\n [ngModel]=\"filters[item.key]\" (search)=\"onValueChange(item.key, $event)\">\r\n </lib-search>\r\n\r\n <!-- Group / Accordion -->\r\n <div *ngSwitchCase=\"'group'\" class=\"cc-accordion-item\" [class.expanded]=\"item.expanded\">\r\n <button type=\"button\" class=\"cc-accordion-header\" (click)=\"item.expanded = !item.expanded\">\r\n <span class=\"cc-accordion-title\">{{ item.label }}</span>\r\n <span class=\"material-icons cc-accordion-icon\">{{ item.expanded ? 'expand_less' : 'expand_more'\r\n }}</span>\r\n </button>\r\n\r\n <div class=\"cc-accordion-body\" *ngIf=\"item.expanded\">\r\n <ng-container *ngFor=\"let child of item.children; trackBy: trackByFn\">\r\n <ng-container *ngTemplateOutlet=\"itemTemplate; context: { item: child }\"></ng-container>\r\n </ng-container>\r\n </div>\r\n </div>\r\n\r\n <!-- Custom Divider -->\r\n <div *ngSwitchCase=\"'divider'\" class=\"cc-filter-divider\"></div>\r\n\r\n </ng-container>\r\n </div>\r\n</ng-template>", styles: [":host{display:block;height:100%;--cc-filter-sidebar-width: 100%;--cc-filter-sidebar-padding: 1.5rem;--cc-filter-sidebar-gap: 1.5rem;--cc-filter-sidebar-bg: #FEFEFE;--cc-filter-sidebar-border-radius: 0;--cc-filter-header-height: 3rem;--cc-filter-header-title-size: 1.125rem;--cc-filter-header-title-weight: 500;--cc-filter-header-title-color: #202124;--cc-filter-footer-padding: 1rem 0 0 0;--cc-filter-footer-gap: 1rem}.cc-filter-sidebar{display:flex;flex-direction:column;height:100%;width:var(--cc-filter-sidebar-width, 280px);background-color:var(--cc-filter-sidebar-bg, #FEFEFE);padding:var(--cc-filter-sidebar-padding, 1.5rem);box-sizing:border-box;overflow:hidden;border-radius:var(--cc-filter-sidebar-border-radius, 0);transition:width .3s ease,padding .3s ease}.cc-filter-sidebar.collapsed{width:60px!important;padding:1.5rem .5rem}.cc-filter-sidebar.collapsed .cc-filter-header{justify-content:center;margin-bottom:0}.cc-filter-sidebar.collapsed .cc-filter-header .cc-header-content,.cc-filter-sidebar.collapsed .cc-filter-header .cc-close-btn,.cc-filter-sidebar.collapsed .cc-filter-content{display:none}.cc-filter-header{display:flex;align-items:center;justify-content:space-between;min-height:var(--cc-filter-header-height, 3rem);margin-bottom:1rem;flex-shrink:0}.cc-filter-header .cc-header-content{display:flex;align-items:center;gap:.5rem;flex:1}.cc-filter-header .cc-header-title{font-size:var(--cc-filter-header-title-size, 1.125rem);font-weight:var(--cc-filter-header-title-weight, 500);color:var(--cc-filter-header-title-color, #202124);display:flex;align-items:center;gap:.5rem}.cc-filter-content{flex:1;overflow-y:auto;display:flex;flex-direction:column;gap:var(--cc-filter-sidebar-gap, 1.5rem);padding-right:.25rem}.cc-filter-content::-webkit-scrollbar{width:6px}.cc-filter-content::-webkit-scrollbar-thumb{background-color:#e0e0e0;border-radius:3px}.cc-accordion-item{border-bottom:1px solid #E0E0E0}.cc-accordion-item:last-child{border-bottom:none}.cc-accordion-item .cc-accordion-header{display:flex;align-items:center;justify-content:space-between;width:100%;padding:.75rem 0;background:none;border:none;cursor:pointer;text-align:left;outline:none}.cc-accordion-item .cc-accordion-header .cc-accordion-title{font-size:.875rem;font-weight:500;color:#202124}.cc-accordion-item .cc-accordion-header .cc-accordion-icon{color:#5f6368;transition:transform .2s}.cc-accordion-item .cc-accordion-body{padding:0 0 1rem;display:flex;flex-direction:column;gap:1rem;animation:slideDown .2s ease-out}@keyframes slideDown{0%{opacity:0;transform:translateY(-5px)}to{opacity:1;transform:translateY(0)}}.cc-group-content{display:flex;flex-direction:column;gap:1rem}.cc-filter-divider{height:1px;background-color:#e0e0e0;margin:.5rem 0}.cc-filter-footer{display:flex;gap:var(--cc-filter-footer-gap, 1rem);padding:var(--cc-filter-footer-padding, 1rem 0 0 0);margin-top:auto;flex-shrink:0}.cc-filter-footer button{flex:1}.cc-icon-btn{background:none;border:none;cursor:pointer;color:#5f6368;padding:.5rem;border-radius:50%;display:flex;align-items:center;justify-content:center}.cc-icon-btn:hover{background-color:#0000000a}.cc-close-btn{margin-right:-.5rem}\n"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: i1.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i1.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: InputComponent, selector: "lib-input", inputs: ["config", "labels", "type", "label", "placeholder", "disabled", "required", "readonly", "clearable", "maxLength", "minLength", "min", "max", "pattern", "errorMessage", "helperText", "rows", "prefixIcon", "suffixIcon", "value", "width", "height", "borderRadius", "fontSize", "gap", "fontFamily", "labelColor", "labelFontSize", "labelFontWeight", "backgroundColor", "borderColor", "borderWidth", "padding", "fontWeight", "color", "placeholderColor", "focusBorderColor", "errorColor", "disabledBackgroundColor", "disabledColor", "boxShadow"], outputs: ["valueChange", "inputBlur", "inputFocus"] }, { kind: "component", type: DropdownComponent, selector: "lib-dropdown", inputs: ["config", "labels", "options", "selectedValue", "placeholder", "label", "multiple", "searchable", "clearable", "disabled", "required", "errorMessage", "width", "height", "borderRadius", "fontSize", "gap", "fontFamily", "labelColor", "labelFontSize", "labelFontWeight", "backgroundColor", "borderColor", "borderWidth", "padding", "fontWeight", "color", "placeholderColor", "focusBorderColor", "errorColor", "disabledBackgroundColor", "disabledColor", "boxShadow"], outputs: ["selectionChange"] }, { kind: "component", type: CheckboxComponent, selector: "lib-checkbox", inputs: ["config", "labels", "label", "checked", "disabled", "required", "indeterminate", "options", "labelPosition", "color", "borderRadius", "value", "errorMessage", "width", "height", "fontSize", "fontWeight", "labelColor", "labelFontSize", "labelFontWeight", "gap", "fontFamily", "backgroundColor", "borderColor", "borderWidth", "padding", "placeholderColor", "focusBorderColor", "errorColor", "disabledBackgroundColor", "disabledColor", "boxShadow", "size", "checkedColor", "uncheckedColor", "groupLabelColor", "groupLabelFontSize", "groupLabelFontWeight"], outputs: ["checkedChange"] }, { kind: "component", type: RadioComponent, selector: "lib-radio", inputs: ["config", "label", "options", "disabled", "required", "labelPosition", "color", "layout", "labels", "gap", "labelColor", "checkedColor", "uncheckedColor", "fontSize", "fontWeight", "fontFamily", "groupLabelColor", "groupLabelFontSize", "groupLabelFontWeight", "disabledColor", "errorColor", "size", "borderRadius", "labelFontSize", "labelFontWeight"], outputs: ["selectionChange"] }, { kind: "component", type: ToggleComponent, selector: "lib-toggle", inputs: ["config", "labels", "label", "checked", "disabled", "required", "labelPosition", "color", "labelColor", "uncheckedColor", "checkedColor", "thumbColor", "checkedThumbColor", "fontSize", "fontWeight", "fontFamily", "toggleWidth", "toggleHeight", "gap", "sliderColor", "labelFontSize", "labelFontWeight", "disabledColor"], outputs: ["toggleChange"] }, { kind: "component", type: DatepickerComponent, selector: "lib-datepicker", inputs: ["config", "labels", "label", "placeholder", "disabled", "required", "minDate", "maxDate", "isRange", "startView", "value", "startDate", "endDate", "errorMessage", "width", "height", "borderRadius", "fontSize", "gap", "fontFamily", "labelColor", "labelFontSize", "labelFontWeight", "backgroundColor", "borderColor", "borderWidth", "padding", "fontWeight", "color", "placeholderColor", "focusBorderColor", "errorColor", "disabledBackgroundColor", "disabledColor", "boxShadow"], outputs: ["dateChange"] }, { kind: "component", type: SearchComponent, selector: "lib-search", inputs: ["config", "labels", "placeholder", "label", "disabled", "debounceMs", "clearable", "value", "width", "height", "borderRadius", "fontSize", "gap", "fontFamily", "labelColor", "labelFontSize", "labelFontWeight", "backgroundColor", "borderColor", "borderWidth", "border", "padding", "fontWeight", "color", "textColor", "iconColor", "placeholderColor", "focusBorderColor", "disabledBackgroundColor", "disabledColor", "boxShadow"], outputs: ["search", "clear"] }, { kind: "component", type: ButtonComponent, selector: "lib-button", inputs: ["variant", "type", "disabled", "width", "height", "borderRadius", "fontSize", "fontWeight", "backgroundColor", "color", "border", "icon", "labels"] }] });
|
|
12345
|
+
], ngImport: i0, template: "<div class=\"cc-filter-sidebar\" [ngStyle]=\"sidebarStyles\" [class.collapsed]=\"isCollapsed\">\r\n\r\n <!-- Header -->\r\n <div class=\"cc-filter-header\" *ngIf=\"config.header?.visible !== false\">\r\n <div class=\"cc-header-content\">\r\n <span class=\"cc-header-title\" *ngIf=\"config.header?.title\">\r\n <span *ngIf=\"config.header?.icon\" [class]=\"config.header?.icon\" class=\"cc-header-icon material-icons\">\r\n <!-- {{config.header?.icon }} -->\r\n </span>\r\n {{ config.header?.title }}\r\n </span>\r\n <ng-content select=\"[header-actions]\"></ng-content>\r\n </div>\r\n <button type=\"button\" *ngIf=\"config.settings?.collapsible\" (click)=\"toggleCollapse()\" class=\"cc-icon-btn\"\r\n [attr.aria-label]=\"isCollapsed ? config.labels?.expandAriaLabel : config.labels?.collapseAriaLabel\">\r\n <span class=\"material-icons\">{{ isCollapsed ? 'menu_open' : 'menu' }}</span>\r\n </button>\r\n <button type=\"button\" *ngIf=\"config.header?.showClose && !isCollapsed\" (click)=\"onClose()\"\r\n class=\"cc-icon-btn cc-close-btn\" [attr.aria-label]=\"config.labels?.closeAriaLabel\">\r\n <span class=\"material-icons\">close</span>\r\n </button>\r\n <!-- Code snippet debug (optional) -->\r\n <button type=\"button\" *ngIf=\"config.settings?.showCodeSnippet\" (click)=\"onShowCodeSnippet()\" class=\"cc-icon-btn\"\r\n [attr.aria-label]=\"config.labels?.codeSnippetAriaLabel\">\r\n <span class=\"material-icons\">code</span>\r\n </button>\r\n </div>\r\n\r\n <!-- Content (Scrollable) -->\r\n <div class=\"cc-filter-content\" [class.hidden]=\"isCollapsed\">\r\n <ng-container *ngFor=\"let item of config.items; trackBy: trackByFn\">\r\n <ng-container *ngTemplateOutlet=\"itemTemplate; context: { item: item }\"></ng-container>\r\n </ng-container>\r\n </div>\r\n\r\n <!-- Footer -->\r\n <div class=\"cc-filter-footer\" *ngIf=\"config.footer?.visible !== false && !isCollapsed\">\r\n <lib-button variant=\"outline\" color=\"warn\" class=\"cc-btn-clear\"\r\n *ngIf=\"config.footer?.clearButton?.visible !== false\" (click)=\"clearFilters()\">\r\n {{ config.footer?.clearButton?.label }}\r\n </lib-button>\r\n <lib-button variant=\"primary\" color=\"warn\" class=\"cc-btn-apply\"\r\n *ngIf=\"config.footer?.applyButton?.visible !== false\" [disabled]=\"config.footer?.applyButton?.disabled ?? false\"\r\n (click)=\"applyFilters()\">\r\n {{ config.footer?.applyButton?.label }}\r\n </lib-button>\r\n </div>\r\n</div>\r\n\r\n<!-- Recursive Template for Items -->\r\n<ng-template #itemTemplate let-item=\"item\">\r\n <div class=\"cc-filter-item\" [ngClass]=\"['type-' + item.type]\"\r\n [style.display]=\"item.visible === false ? 'none' : 'block'\" [ngStyle]=\"item.styles\">\r\n\r\n <ng-container [ngSwitch]=\"item.type\">\r\n\r\n <!-- Input -->\r\n <lib-input *ngSwitchCase=\"'input'\" [config]=\"item.inputConfig\" [label]=\"item.label\"\r\n [ngModel]=\"filters[item.key]\" (valueChange)=\"onValueChange(item.key, $event)\">\r\n </lib-input>\r\n\r\n <!-- Dropdown -->\r\n <lib-dropdown *ngSwitchCase=\"'dropdown'\" [config]=\"item.dropdownConfig\" [label]=\"item.label\"\r\n [ngModel]=\"filters[item.key]\" (selectionChange)=\"onValueChange(item.key, $event)\">\r\n </lib-dropdown>\r\n\r\n <!-- Checkbox -->\r\n <lib-checkbox *ngSwitchCase=\"'checkbox'\" [config]=\"item.checkboxConfig\" [label]=\"item.label\"\r\n [checked]=\"!!filters[item.key]\" (checkedChange)=\"onValueChange(item.key, $event)\">\r\n </lib-checkbox>\r\n\r\n <!-- Radio -->\r\n <lib-radio *ngSwitchCase=\"'radio'\" [config]=\"item.radioConfig\" [label]=\"item.label\"\r\n [ngModel]=\"filters[item.key]\" (selectionChange)=\"onValueChange(item.key, $event)\">\r\n </lib-radio>\r\n\r\n <!-- Toggle -->\r\n <lib-toggle *ngSwitchCase=\"'toggle'\" [config]=\"item.toggleConfig\" [label]=\"item.label\"\r\n [checked]=\"filters[item.key]\" (toggleChange)=\"onValueChange(item.key, $event)\">\r\n </lib-toggle>\r\n\r\n <!-- Datepicker -->\r\n <lib-datepicker *ngSwitchCase=\"'datepicker'\" [config]=\"item.datepickerConfig\" [label]=\"item.label\"\r\n [ngModel]=\"filters[item.key]\" (dateChange)=\"onValueChange(item.key, $event)\">\r\n </lib-datepicker>\r\n\r\n <!-- Search -->\r\n <lib-search *ngSwitchCase=\"'active-search'\" [config]=\"item.searchConfig\" [label]=\"item.label\"\r\n [ngModel]=\"filters[item.key]\" (search)=\"onValueChange(item.key, $event)\">\r\n </lib-search>\r\n\r\n <!-- Group / Accordion -->\r\n <div *ngSwitchCase=\"'group'\" class=\"cc-accordion-item\" [class.expanded]=\"item.expanded\">\r\n <button type=\"button\" class=\"cc-accordion-header\" (click)=\"item.expanded = !item.expanded\">\r\n <span class=\"cc-accordion-title\">{{ item.label }}</span>\r\n <span class=\"material-icons cc-accordion-icon\">{{ item.expanded ? 'expand_less' : 'expand_more'\r\n }}</span>\r\n </button>\r\n\r\n <div class=\"cc-accordion-body\" *ngIf=\"item.expanded\">\r\n <ng-container *ngFor=\"let child of item.children; trackBy: trackByFn\">\r\n <ng-container *ngTemplateOutlet=\"itemTemplate; context: { item: child }\"></ng-container>\r\n </ng-container>\r\n </div>\r\n </div>\r\n\r\n <!-- Custom Divider -->\r\n <div *ngSwitchCase=\"'divider'\" class=\"cc-filter-divider\"></div>\r\n\r\n </ng-container>\r\n </div>\r\n</ng-template>", styles: [":host{display:block;height:100%;--cc-filter-sidebar-width: 100%;--cc-filter-sidebar-padding: 1.5rem;--cc-filter-sidebar-gap: 1.5rem;--cc-filter-sidebar-bg: #FEFEFE;--cc-filter-sidebar-border-radius: 0;--cc-filter-header-height: 3rem;--cc-filter-header-title-size: 1.125rem;--cc-filter-header-title-weight: 500;--cc-filter-header-title-color: #202124;--cc-filter-footer-padding: 1rem 0 0 0;--cc-filter-footer-gap: 1rem}.cc-filter-sidebar{display:flex;flex-direction:column;height:100%;width:var(--cc-filter-sidebar-width, 280px);background-color:var(--cc-filter-sidebar-bg, #FEFEFE);padding:var(--cc-filter-sidebar-padding, 1.5rem);box-sizing:border-box;overflow:hidden;border-radius:var(--cc-filter-sidebar-border-radius, 0);transition:width .3s ease,padding .3s ease}.cc-filter-sidebar.collapsed{width:60px!important;padding:1.5rem .5rem}.cc-filter-sidebar.collapsed .cc-filter-header{justify-content:center;margin-bottom:0}.cc-filter-sidebar.collapsed .cc-filter-header .cc-header-content,.cc-filter-sidebar.collapsed .cc-filter-header .cc-close-btn,.cc-filter-sidebar.collapsed .cc-filter-content{display:none}.cc-filter-header{display:flex;align-items:center;justify-content:space-between;min-height:var(--cc-filter-header-height, 3rem);margin-bottom:1rem;flex-shrink:0}.cc-filter-header .cc-header-content{display:flex;align-items:center;gap:.5rem;flex:1}.cc-filter-header .cc-header-title{font-size:var(--cc-filter-header-title-size, 1.125rem);font-weight:var(--cc-filter-header-title-weight, 500);color:var(--cc-filter-header-title-color, #202124);display:flex;align-items:center;gap:.5rem}.cc-filter-content{flex:1;overflow-y:auto;display:flex;flex-direction:column;gap:var(--cc-filter-sidebar-gap, 1.5rem);padding-right:.25rem}.cc-filter-content::-webkit-scrollbar{width:6px}.cc-filter-content::-webkit-scrollbar-thumb{background-color:#e0e0e0;border-radius:3px}.cc-accordion-item{border-bottom:1px solid #E0E0E0}.cc-accordion-item:last-child{border-bottom:none}.cc-accordion-item .cc-accordion-header{display:flex;align-items:center;justify-content:space-between;width:100%;padding:.75rem 0;background:none;border:none;cursor:pointer;text-align:left;outline:none}.cc-accordion-item .cc-accordion-header .cc-accordion-title{font-size:.875rem;font-weight:500;color:#202124}.cc-accordion-item .cc-accordion-header .cc-accordion-icon{color:#5f6368;transition:transform .2s}.cc-accordion-item .cc-accordion-body{padding:0 0 1rem;display:flex;flex-direction:column;gap:1rem;animation:slideDown .2s ease-out}@keyframes slideDown{0%{opacity:0;transform:translateY(-5px)}to{opacity:1;transform:translateY(0)}}.cc-group-content{display:flex;flex-direction:column;gap:1rem}.cc-filter-divider{height:1px;background-color:#e0e0e0;margin:.5rem 0}.cc-filter-footer{display:flex;gap:var(--cc-filter-footer-gap, 1rem);padding:var(--cc-filter-footer-padding, 1rem 0 0 0);margin-top:auto;flex-shrink:0}.cc-filter-footer button{flex:1}.cc-icon-btn{background:none;border:none;cursor:pointer;color:#5f6368;padding:.5rem;border-radius:50%;display:flex;align-items:center;justify-content:center}.cc-icon-btn:hover{background-color:#0000000a}.cc-close-btn{margin-right:-.5rem}\n"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: i1.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i1.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: InputComponent, selector: "lib-input", inputs: ["config", "labels", "type", "label", "placeholder", "disabled", "required", "readonly", "clearable", "maxLength", "minLength", "min", "max", "pattern", "errorMessage", "helperText", "rows", "prefixIcon", "suffixIcon", "value", "width", "height", "borderRadius", "fontSize", "gap", "fontFamily", "labelColor", "labelFontSize", "labelFontWeight", "backgroundColor", "borderColor", "borderWidth", "padding", "fontWeight", "color", "placeholderColor", "focusBorderColor", "errorColor", "disabledBackgroundColor", "disabledColor", "boxShadow"], outputs: ["valueChange", "inputBlur", "inputFocus"] }, { kind: "component", type: DropdownComponent, selector: "lib-dropdown", inputs: ["config", "labels", "options", "selectedValue", "placeholder", "label", "multiple", "searchable", "clearable", "disabled", "required", "errorMessage", "serverSearch", "searchDebounceMs", "lazyLoad", "loading", "loadingMore", "hasMore", "width", "height", "borderRadius", "fontSize", "gap", "fontFamily", "labelColor", "labelFontSize", "labelFontWeight", "backgroundColor", "borderColor", "borderWidth", "padding", "fontWeight", "color", "placeholderColor", "focusBorderColor", "errorColor", "disabledBackgroundColor", "disabledColor", "boxShadow"], outputs: ["selectionChange", "searchTermChange", "loadMore"] }, { kind: "component", type: CheckboxComponent, selector: "lib-checkbox", inputs: ["config", "labels", "label", "checked", "disabled", "required", "indeterminate", "options", "labelPosition", "color", "borderRadius", "value", "errorMessage", "width", "height", "fontSize", "fontWeight", "labelColor", "labelFontSize", "labelFontWeight", "gap", "fontFamily", "backgroundColor", "borderColor", "borderWidth", "padding", "placeholderColor", "focusBorderColor", "errorColor", "disabledBackgroundColor", "disabledColor", "boxShadow", "size", "checkedColor", "uncheckedColor", "groupLabelColor", "groupLabelFontSize", "groupLabelFontWeight"], outputs: ["checkedChange"] }, { kind: "component", type: RadioComponent, selector: "lib-radio", inputs: ["config", "label", "options", "disabled", "required", "labelPosition", "color", "layout", "labels", "gap", "labelColor", "checkedColor", "uncheckedColor", "fontSize", "fontWeight", "fontFamily", "groupLabelColor", "groupLabelFontSize", "groupLabelFontWeight", "disabledColor", "errorColor", "size", "borderRadius", "labelFontSize", "labelFontWeight"], outputs: ["selectionChange"] }, { kind: "component", type: ToggleComponent, selector: "lib-toggle", inputs: ["config", "labels", "label", "checked", "disabled", "required", "labelPosition", "color", "labelColor", "uncheckedColor", "checkedColor", "thumbColor", "checkedThumbColor", "fontSize", "fontWeight", "fontFamily", "toggleWidth", "toggleHeight", "gap", "sliderColor", "labelFontSize", "labelFontWeight", "disabledColor"], outputs: ["toggleChange"] }, { kind: "component", type: DatepickerComponent, selector: "lib-datepicker", inputs: ["config", "labels", "label", "placeholder", "disabled", "required", "minDate", "maxDate", "isRange", "startView", "value", "startDate", "endDate", "errorMessage", "width", "height", "borderRadius", "fontSize", "gap", "fontFamily", "labelColor", "labelFontSize", "labelFontWeight", "backgroundColor", "borderColor", "borderWidth", "padding", "fontWeight", "color", "placeholderColor", "focusBorderColor", "errorColor", "disabledBackgroundColor", "disabledColor", "boxShadow"], outputs: ["dateChange"] }, { kind: "component", type: SearchComponent, selector: "lib-search", inputs: ["config", "labels", "placeholder", "label", "disabled", "debounceMs", "clearable", "value", "width", "height", "borderRadius", "fontSize", "gap", "fontFamily", "labelColor", "labelFontSize", "labelFontWeight", "backgroundColor", "borderColor", "borderWidth", "border", "padding", "fontWeight", "color", "textColor", "iconColor", "placeholderColor", "focusBorderColor", "disabledBackgroundColor", "disabledColor", "boxShadow"], outputs: ["search", "clear"] }, { kind: "component", type: ButtonComponent, selector: "lib-button", inputs: ["variant", "type", "disabled", "width", "height", "borderRadius", "fontSize", "fontWeight", "backgroundColor", "color", "border", "icon", "labels"] }] });
|
|
12019
12346
|
}
|
|
12020
12347
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FilterSidebarComponent, decorators: [{
|
|
12021
12348
|
type: Component,
|
|
@@ -13008,7 +13335,7 @@ class FilterComponent {
|
|
|
13008
13335
|
return item.key || index;
|
|
13009
13336
|
}
|
|
13010
13337
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FilterComponent, deps: [{ token: i0.ElementRef }, { token: i1$4.Router }, { token: i1$4.ActivatedRoute }], target: i0.ɵɵFactoryTarget.Component });
|
|
13011
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: FilterComponent, isStandalone: false, selector: "lib-filter", inputs: { config: "config", activeFilters: "activeFilters", columns: "columns", labels: "labels", theme: "theme" }, outputs: { filterChange: "filterChange", columnChange: "columnChange", toggle: "toggle" }, host: { listeners: { "document:click": "onClickOutside($event)" } }, ngImport: i0, template: "<div class=\"cc-filter-container\" [class.is-open]=\"isOpen\" [ngStyle]=\"containerStyles\">\r\n\r\n <!-- Trigger Button -->\r\n <lib-button variant=\"outline\" (click)=\"togglePanel()\" class=\"cc-filter-trigger\"\r\n [class.active]=\"activeFilterCount > 0\">\r\n <span class=\"fas fa-filter\"></span> {{ labels?.filterBtn || 'Filter' }}\r\n <span *ngIf=\"activeFilterCount > 0\" class=\"cc-badge\">{{ activeFilterCount }}</span>\r\n </lib-button>\r\n\r\n <!-- Dropdown Panel -->\r\n <div class=\"cc-filter-panel mat-elevation-z4\" *ngIf=\"isOpen\" (click)=\"$event.stopPropagation()\">\r\n\r\n <!-- Header / Tabs -->\r\n <div class=\"cc-panel-header\">\r\n <div class=\"cc-tabs\">\r\n <div class=\"cc-tab\" [class.active]=\"activeTab === 'filters'\" (click)=\"setActiveTab('filters')\">\r\n {{ labels.filterBtn }}\r\n </div>\r\n <!-- Hide columns tab if no columns config provided -->\r\n <div class=\"cc-tab\" [class.active]=\"activeTab === 'columns'\" (click)=\"setActiveTab('columns')\"\r\n *ngIf=\"columns?.length\">\r\n {{ labels.columns }}\r\n </div>\r\n </div>\r\n <button type=\"button\" class=\"cc-icon-btn\" (click)=\"togglePanel()\">\r\n <span class=\"material-icons\">close</span>\r\n </button>\r\n </div>\r\n\r\n <!-- Filters Tab Content -->\r\n <div class=\"cc-panel-content\" *ngIf=\"activeTab === 'filters'\">\r\n\r\n <!-- Dynamic Items -->\r\n <ng-container *ngFor=\"let item of config.items; trackBy: trackByFn\">\r\n <ng-container *ngTemplateOutlet=\"itemTemplate; context: { item: item }\"></ng-container>\r\n </ng-container>\r\n\r\n </div>\r\n\r\n <!-- Columns Tab Content -->\r\n <div class=\"cc-panel-content\" *ngIf=\"activeTab === 'columns'\">\r\n <div class=\"cc-columns-actions\">\r\n <lib-button variant=\"outline\" class=\"cc-btn-text\" (click)=\"toggleAllColumns(true)\">{{ labels.showAll\r\n }}</lib-button>\r\n <lib-button variant=\"outline\" class=\"cc-btn-text\" (click)=\"toggleAllColumns(false)\">{{ labels.hideAll\r\n }}</lib-button>\r\n </div>\r\n <div class=\"cc-columns-list\">\r\n <div *ngFor=\"let col of tempColumns\" class=\"cc-column-item\">\r\n <lib-checkbox [label]=\"col.label\" [checked]=\"col.visible\" (checkedChange)=\"toggleColumn(col.id)\">\r\n </lib-checkbox>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Footer Actions -->\r\n <div class=\"cc-panel-footer\">\r\n <lib-button variant=\"outline\" color=\"warn\" class=\"cc-btn-text text-danger\" (click)=\"clearAll()\">\r\n {{ labels.clear }}\r\n </lib-button>\r\n <lib-button class=\"ms-2\" variant=\"primary\" (click)=\"apply()\">\r\n {{ labels.apply }}\r\n </lib-button>\r\n </div>\r\n\r\n </div>\r\n</div>\r\n\r\n<!-- Recursive Template for Items -->\r\n<ng-template #itemTemplate let-item=\"item\">\r\n <div class=\"cc-filter-item\" [ngClass]=\"['type-' + item.type]\"\r\n [style.display]=\"item.visible === false ? 'none' : 'block'\" [ngStyle]=\"item.styles\">\r\n\r\n <ng-container [ngSwitch]=\"item.type\">\r\n\r\n <!-- Input -->\r\n <lib-input *ngSwitchCase=\"'input'\" [config]=\"item.inputConfig\" [label]=\"item.label\"\r\n [ngModel]=\"tempFilters[item.key]\" (valueChange)=\"onFilterChange(item.key, $event)\">\r\n </lib-input>\r\n\r\n <!-- Dropdown -->\r\n <lib-dropdown *ngSwitchCase=\"'dropdown'\" [config]=\"item.dropdownConfig\" [label]=\"item.label\"\r\n [ngModel]=\"tempFilters[item.key]\" (selectionChange)=\"onFilterChange(item.key, $event)\">\r\n </lib-dropdown>\r\n\r\n <!-- Checkbox -->\r\n <lib-checkbox *ngSwitchCase=\"'checkbox'\" [config]=\"item.checkboxConfig\" [label]=\"item.label\"\r\n [ngModel]=\"tempFilters[item.key]\" (checkedChange)=\"onFilterChange(item.key, $event)\">\r\n </lib-checkbox>\r\n\r\n <!-- Radio -->\r\n <lib-radio *ngSwitchCase=\"'radio'\" [config]=\"item.radioConfig\" [label]=\"item.label\"\r\n [ngModel]=\"tempFilters[item.key]\" (selectionChange)=\"onFilterChange(item.key, $event)\">\r\n </lib-radio>\r\n\r\n <!-- Toggle -->\r\n <lib-toggle *ngSwitchCase=\"'toggle'\" [config]=\"item.toggleConfig\" [label]=\"item.label\"\r\n [checked]=\"tempFilters[item.key]\" (toggleChange)=\"onFilterChange(item.key, $event)\">\r\n </lib-toggle>\r\n\r\n <!-- Datepicker -->\r\n <lib-datepicker *ngSwitchCase=\"'datepicker'\" [config]=\"item.datepickerConfig\" [label]=\"item.label\"\r\n [ngModel]=\"tempFilters[item.key]\" (dateChange)=\"onFilterChange(item.key, $event)\">\r\n </lib-datepicker>\r\n\r\n <!-- Search -->\r\n <lib-search *ngSwitchCase=\"'active-search'\" [config]=\"item.searchConfig\" [label]=\"item.label\"\r\n [ngModel]=\"tempFilters[item.key]\" (search)=\"onFilterChange(item.key, $event)\">\r\n </lib-search>\r\n\r\n <!-- Group / Accordion -->\r\n <div *ngSwitchCase=\"'group'\" class=\"cc-accordion-item\" [class.expanded]=\"item.expanded\">\r\n <button type=\"button\" class=\"cc-accordion-header\" (click)=\"item.expanded = !item.expanded\">\r\n <span class=\"cc-accordion-title\">{{ item.label }}</span>\r\n <span class=\"material-icons cc-accordion-icon\">{{ item.expanded ? 'expand_less' : 'expand_more'\r\n }}</span>\r\n </button>\r\n\r\n <div class=\"cc-accordion-body\" *ngIf=\"item.expanded\">\r\n <ng-container *ngFor=\"let child of item.children; trackBy: trackByFn\">\r\n <ng-container *ngTemplateOutlet=\"itemTemplate; context: { item: child }\"></ng-container>\r\n </ng-container>\r\n </div>\r\n </div>\r\n\r\n <!-- Custom Divider -->\r\n <div *ngSwitchCase=\"'divider'\" class=\"cc-filter-divider\"></div>\r\n\r\n </ng-container>\r\n </div>\r\n</ng-template>", styles: [".cc-filter-container{position:relative;display:inline-block;font-family:var(--cc-filter-font-family, \"Roboto\", sans-serif)}.cc-filter-container .cc-filter-trigger ::ng-deep button{display:inline-flex;align-items:center;justify-content:center;gap:8px;width:var(--cc-filter-btn-width, 103px);height:var(--cc-filter-btn-height, 44px);padding:0 16px;background-color:var(--cc-filter-btn-bg, #FCFCFB);border:var(--cc-filter-btn-border, 1px solid #E8EAED);border-radius:var(--cc-filter-btn-radius, 8px);color:var(--cc-filter-btn-text-color, #5F6368);font-size:14px;font-weight:500;transition:all .2s ease}.cc-filter-container .cc-filter-trigger ::ng-deep button mat-icon,.cc-filter-container .cc-filter-trigger ::ng-deep button .material-icons{color:#5f6368}.cc-filter-container .cc-filter-trigger ::ng-deep button:hover{background-color:var(--cc-filter-btn-hover-bg, #f1f3f4)}.cc-filter-container .cc-filter-trigger.active ::ng-deep button{background-color:var(--cc-filter-btn-active-bg, #e3f2fd);color:var(--cc-filter-btn-active-text, #1976d2);border-color:var(--cc-filter-btn-active-text, #1976d2)}.cc-filter-container .cc-filter-trigger.active ::ng-deep button mat-icon,.cc-filter-container .cc-filter-trigger.active ::ng-deep button .material-icons{color:var(--cc-filter-btn-active-text, #1976d2)}.cc-filter-container .cc-filter-trigger .cc-badge{background-color:var(--cc-filter-btn-badge-bg, #f44336);color:var(--cc-filter-btn-badge-text, #fff);font-size:10px;font-weight:700;padding:2px 6px;border-radius:10px;min-width:16px;text-align:center;margin-left:4px;line-height:1}.cc-filter-container .cc-filter-panel{position:absolute;top:calc(100% + 8px);right:0;z-index:1000;width:var(--cc-filter-panel-width, 320px);min-width:var(--cc-filter-panel-min-width, 480px)!important;padding:var(--cc-filter-panel-padding, 0);background-color:var(--cc-filter-panel-bg, #fff);border:var(--cc-filter-panel-border, 1px solid #e0e0e0);box-shadow:var(--cc-filter-panel-shadow, 0 4px 12px rgba(0, 0, 0, .15));border-radius:var(--cc-filter-panel-radius, 8px);display:flex;flex-direction:column;overflow:hidden}.cc-filter-container .cc-filter-panel.hidden{display:none}.cc-filter-container .cc-filter-panel .cc-panel-header{display:flex;align-items:center;justify-content:space-between;padding:0 1rem;height:var(--cc-filter-panel-header-height, 48px);border-bottom:1px solid #E0E0E0;background-color:var(--cc-filter-panel-header-bg, #fafafa)}.cc-filter-container .cc-tabs{display:flex;gap:1rem}.cc-filter-container .cc-tabs .cc-tab{cursor:pointer;padding:.5rem 0;font-weight:500;color:#5f6368;border-bottom:2px solid transparent;font-size:14px}.cc-filter-container .cc-tabs .cc-tab.active{color:var(--cc-filter-tab-active-text, #1976d2);border-bottom:var(--cc-filter-tab-border-bottom, 2px solid #1976d2)}.cc-filter-container .cc-icon-btn{background:none;border:none;cursor:pointer;color:#5f6368;padding:.25rem;border-radius:50%;display:flex;align-items:center;justify-content:center}.cc-filter-container .cc-icon-btn:hover{background-color:#0000000a}.cc-filter-container .cc-panel-content{padding:16px;max-height:400px;overflow-y:auto;display:flex;flex-direction:column;gap:var(--cc-filter-panel-gap, 1rem)}.cc-filter-container .cc-filter-section{margin-bottom:16px}.cc-filter-container .cc-filter-section .cc-section-title{font-size:13px;font-weight:600;margin-bottom:8px;color:var(--cc-filter-section-title, #333);text-transform:uppercase;letter-spacing:.5px}.cc-filter-container .cc-filter-section .cc-control-group{display:flex;flex-direction:column;gap:8px}.cc-filter-container .cc-filter-section .cc-control-group label{display:flex;align-items:center;gap:8px;font-size:14px;color:var(--cc-filter-option-text, #555);cursor:pointer}.cc-filter-container .cc-filter-section .cc-control-group label:hover{color:#000}.cc-filter-container .cc-accordion-item{border-bottom:1px solid #E0E0E0}.cc-filter-container .cc-accordion-item:last-child{border-bottom:none}.cc-filter-container .cc-accordion-item .cc-accordion-header{display:flex;align-items:center;justify-content:space-between;width:100%;padding:.75rem 0;background:none;border:none;cursor:pointer;text-align:left;outline:none}.cc-filter-container .cc-accordion-item .cc-accordion-header .cc-accordion-title{font-size:.875rem;font-weight:500;color:#202124}.cc-filter-container .cc-accordion-item .cc-accordion-header .cc-accordion-icon{color:#5f6368;transition:transform .2s}.cc-filter-container .cc-accordion-item .cc-accordion-body{padding:0 0 1rem;display:flex;flex-direction:column;gap:1rem;animation:slideDown .2s ease-out}.cc-filter-container .cc-filter-divider{height:1px;background-color:#e0e0e0;margin:.5rem 0}.cc-filter-container .cc-panel-footer{padding:12px 16px;background-color:var(--cc-filter-footer-bg, #fff);border-top:var(--cc-filter-footer-border-top, 1px solid #e0e0e0);display:flex;justify-content:flex-end;align-items:center;gap:10px}.cc-filter-container .cc-columns-actions{display:flex;gap:.5rem;margin-bottom:.5rem}.cc-filter-container .cc-columns-list{display:flex;flex-direction:column;gap:.5rem}\n"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: i1.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i1.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: ButtonComponent, selector: "lib-button", inputs: ["variant", "type", "disabled", "width", "height", "borderRadius", "fontSize", "fontWeight", "backgroundColor", "color", "border", "icon", "labels"] }, { kind: "component", type: InputComponent, selector: "lib-input", inputs: ["config", "labels", "type", "label", "placeholder", "disabled", "required", "readonly", "clearable", "maxLength", "minLength", "min", "max", "pattern", "errorMessage", "helperText", "rows", "prefixIcon", "suffixIcon", "value", "width", "height", "borderRadius", "fontSize", "gap", "fontFamily", "labelColor", "labelFontSize", "labelFontWeight", "backgroundColor", "borderColor", "borderWidth", "padding", "fontWeight", "color", "placeholderColor", "focusBorderColor", "errorColor", "disabledBackgroundColor", "disabledColor", "boxShadow"], outputs: ["valueChange", "inputBlur", "inputFocus"] }, { kind: "component", type: DropdownComponent, selector: "lib-dropdown", inputs: ["config", "labels", "options", "selectedValue", "placeholder", "label", "multiple", "searchable", "clearable", "disabled", "required", "errorMessage", "width", "height", "borderRadius", "fontSize", "gap", "fontFamily", "labelColor", "labelFontSize", "labelFontWeight", "backgroundColor", "borderColor", "borderWidth", "padding", "fontWeight", "color", "placeholderColor", "focusBorderColor", "errorColor", "disabledBackgroundColor", "disabledColor", "boxShadow"], outputs: ["selectionChange"] }, { kind: "component", type: CheckboxComponent, selector: "lib-checkbox", inputs: ["config", "labels", "label", "checked", "disabled", "required", "indeterminate", "options", "labelPosition", "color", "borderRadius", "value", "errorMessage", "width", "height", "fontSize", "fontWeight", "labelColor", "labelFontSize", "labelFontWeight", "gap", "fontFamily", "backgroundColor", "borderColor", "borderWidth", "padding", "placeholderColor", "focusBorderColor", "errorColor", "disabledBackgroundColor", "disabledColor", "boxShadow", "size", "checkedColor", "uncheckedColor", "groupLabelColor", "groupLabelFontSize", "groupLabelFontWeight"], outputs: ["checkedChange"] }, { kind: "component", type: RadioComponent, selector: "lib-radio", inputs: ["config", "label", "options", "disabled", "required", "labelPosition", "color", "layout", "labels", "gap", "labelColor", "checkedColor", "uncheckedColor", "fontSize", "fontWeight", "fontFamily", "groupLabelColor", "groupLabelFontSize", "groupLabelFontWeight", "disabledColor", "errorColor", "size", "borderRadius", "labelFontSize", "labelFontWeight"], outputs: ["selectionChange"] }, { kind: "component", type: ToggleComponent, selector: "lib-toggle", inputs: ["config", "labels", "label", "checked", "disabled", "required", "labelPosition", "color", "labelColor", "uncheckedColor", "checkedColor", "thumbColor", "checkedThumbColor", "fontSize", "fontWeight", "fontFamily", "toggleWidth", "toggleHeight", "gap", "sliderColor", "labelFontSize", "labelFontWeight", "disabledColor"], outputs: ["toggleChange"] }, { kind: "component", type: DatepickerComponent, selector: "lib-datepicker", inputs: ["config", "labels", "label", "placeholder", "disabled", "required", "minDate", "maxDate", "isRange", "startView", "value", "startDate", "endDate", "errorMessage", "width", "height", "borderRadius", "fontSize", "gap", "fontFamily", "labelColor", "labelFontSize", "labelFontWeight", "backgroundColor", "borderColor", "borderWidth", "padding", "fontWeight", "color", "placeholderColor", "focusBorderColor", "errorColor", "disabledBackgroundColor", "disabledColor", "boxShadow"], outputs: ["dateChange"] }, { kind: "component", type: SearchComponent, selector: "lib-search", inputs: ["config", "labels", "placeholder", "label", "disabled", "debounceMs", "clearable", "value", "width", "height", "borderRadius", "fontSize", "gap", "fontFamily", "labelColor", "labelFontSize", "labelFontWeight", "backgroundColor", "borderColor", "borderWidth", "border", "padding", "fontWeight", "color", "textColor", "iconColor", "placeholderColor", "focusBorderColor", "disabledBackgroundColor", "disabledColor", "boxShadow"], outputs: ["search", "clear"] }] });
|
|
13338
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: FilterComponent, isStandalone: false, selector: "lib-filter", inputs: { config: "config", activeFilters: "activeFilters", columns: "columns", labels: "labels", theme: "theme" }, outputs: { filterChange: "filterChange", columnChange: "columnChange", toggle: "toggle" }, host: { listeners: { "document:click": "onClickOutside($event)" } }, ngImport: i0, template: "<div class=\"cc-filter-container\" [class.is-open]=\"isOpen\" [ngStyle]=\"containerStyles\">\r\n\r\n <!-- Trigger Button -->\r\n <lib-button variant=\"outline\" (click)=\"togglePanel()\" class=\"cc-filter-trigger\"\r\n [class.active]=\"activeFilterCount > 0\">\r\n <span class=\"fas fa-filter\"></span> {{ labels?.filterBtn || 'Filter' }}\r\n <span *ngIf=\"activeFilterCount > 0\" class=\"cc-badge\">{{ activeFilterCount }}</span>\r\n </lib-button>\r\n\r\n <!-- Dropdown Panel -->\r\n <div class=\"cc-filter-panel mat-elevation-z4\" *ngIf=\"isOpen\" (click)=\"$event.stopPropagation()\">\r\n\r\n <!-- Header / Tabs -->\r\n <div class=\"cc-panel-header\">\r\n <div class=\"cc-tabs\">\r\n <div class=\"cc-tab\" [class.active]=\"activeTab === 'filters'\" (click)=\"setActiveTab('filters')\">\r\n {{ labels.filterBtn }}\r\n </div>\r\n <!-- Hide columns tab if no columns config provided -->\r\n <div class=\"cc-tab\" [class.active]=\"activeTab === 'columns'\" (click)=\"setActiveTab('columns')\"\r\n *ngIf=\"columns?.length\">\r\n {{ labels.columns }}\r\n </div>\r\n </div>\r\n <button type=\"button\" class=\"cc-icon-btn\" (click)=\"togglePanel()\">\r\n <span class=\"material-icons\">close</span>\r\n </button>\r\n </div>\r\n\r\n <!-- Filters Tab Content -->\r\n <div class=\"cc-panel-content\" *ngIf=\"activeTab === 'filters'\">\r\n\r\n <!-- Dynamic Items -->\r\n <ng-container *ngFor=\"let item of config.items; trackBy: trackByFn\">\r\n <ng-container *ngTemplateOutlet=\"itemTemplate; context: { item: item }\"></ng-container>\r\n </ng-container>\r\n\r\n </div>\r\n\r\n <!-- Columns Tab Content -->\r\n <div class=\"cc-panel-content\" *ngIf=\"activeTab === 'columns'\">\r\n <div class=\"cc-columns-actions\">\r\n <lib-button variant=\"outline\" class=\"cc-btn-text\" (click)=\"toggleAllColumns(true)\">{{ labels.showAll\r\n }}</lib-button>\r\n <lib-button variant=\"outline\" class=\"cc-btn-text\" (click)=\"toggleAllColumns(false)\">{{ labels.hideAll\r\n }}</lib-button>\r\n </div>\r\n <div class=\"cc-columns-list\">\r\n <div *ngFor=\"let col of tempColumns\" class=\"cc-column-item\">\r\n <lib-checkbox [label]=\"col.label\" [checked]=\"col.visible\" (checkedChange)=\"toggleColumn(col.id)\">\r\n </lib-checkbox>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Footer Actions -->\r\n <div class=\"cc-panel-footer\">\r\n <lib-button variant=\"outline\" color=\"warn\" class=\"cc-btn-text text-danger\" (click)=\"clearAll()\">\r\n {{ labels.clear }}\r\n </lib-button>\r\n <lib-button class=\"ms-2\" variant=\"primary\" (click)=\"apply()\">\r\n {{ labels.apply }}\r\n </lib-button>\r\n </div>\r\n\r\n </div>\r\n</div>\r\n\r\n<!-- Recursive Template for Items -->\r\n<ng-template #itemTemplate let-item=\"item\">\r\n <div class=\"cc-filter-item\" [ngClass]=\"['type-' + item.type]\"\r\n [style.display]=\"item.visible === false ? 'none' : 'block'\" [ngStyle]=\"item.styles\">\r\n\r\n <ng-container [ngSwitch]=\"item.type\">\r\n\r\n <!-- Input -->\r\n <lib-input *ngSwitchCase=\"'input'\" [config]=\"item.inputConfig\" [label]=\"item.label\"\r\n [ngModel]=\"tempFilters[item.key]\" (valueChange)=\"onFilterChange(item.key, $event)\">\r\n </lib-input>\r\n\r\n <!-- Dropdown -->\r\n <lib-dropdown *ngSwitchCase=\"'dropdown'\" [config]=\"item.dropdownConfig\" [label]=\"item.label\"\r\n [ngModel]=\"tempFilters[item.key]\" (selectionChange)=\"onFilterChange(item.key, $event)\">\r\n </lib-dropdown>\r\n\r\n <!-- Checkbox -->\r\n <lib-checkbox *ngSwitchCase=\"'checkbox'\" [config]=\"item.checkboxConfig\" [label]=\"item.label\"\r\n [ngModel]=\"tempFilters[item.key]\" (checkedChange)=\"onFilterChange(item.key, $event)\">\r\n </lib-checkbox>\r\n\r\n <!-- Radio -->\r\n <lib-radio *ngSwitchCase=\"'radio'\" [config]=\"item.radioConfig\" [label]=\"item.label\"\r\n [ngModel]=\"tempFilters[item.key]\" (selectionChange)=\"onFilterChange(item.key, $event)\">\r\n </lib-radio>\r\n\r\n <!-- Toggle -->\r\n <lib-toggle *ngSwitchCase=\"'toggle'\" [config]=\"item.toggleConfig\" [label]=\"item.label\"\r\n [checked]=\"tempFilters[item.key]\" (toggleChange)=\"onFilterChange(item.key, $event)\">\r\n </lib-toggle>\r\n\r\n <!-- Datepicker -->\r\n <lib-datepicker *ngSwitchCase=\"'datepicker'\" [config]=\"item.datepickerConfig\" [label]=\"item.label\"\r\n [ngModel]=\"tempFilters[item.key]\" (dateChange)=\"onFilterChange(item.key, $event)\">\r\n </lib-datepicker>\r\n\r\n <!-- Search -->\r\n <lib-search *ngSwitchCase=\"'active-search'\" [config]=\"item.searchConfig\" [label]=\"item.label\"\r\n [ngModel]=\"tempFilters[item.key]\" (search)=\"onFilterChange(item.key, $event)\">\r\n </lib-search>\r\n\r\n <!-- Group / Accordion -->\r\n <div *ngSwitchCase=\"'group'\" class=\"cc-accordion-item\" [class.expanded]=\"item.expanded\">\r\n <button type=\"button\" class=\"cc-accordion-header\" (click)=\"item.expanded = !item.expanded\">\r\n <span class=\"cc-accordion-title\">{{ item.label }}</span>\r\n <span class=\"material-icons cc-accordion-icon\">{{ item.expanded ? 'expand_less' : 'expand_more'\r\n }}</span>\r\n </button>\r\n\r\n <div class=\"cc-accordion-body\" *ngIf=\"item.expanded\">\r\n <ng-container *ngFor=\"let child of item.children; trackBy: trackByFn\">\r\n <ng-container *ngTemplateOutlet=\"itemTemplate; context: { item: child }\"></ng-container>\r\n </ng-container>\r\n </div>\r\n </div>\r\n\r\n <!-- Custom Divider -->\r\n <div *ngSwitchCase=\"'divider'\" class=\"cc-filter-divider\"></div>\r\n\r\n </ng-container>\r\n </div>\r\n</ng-template>", styles: [".cc-filter-container{position:relative;display:inline-block;font-family:var(--cc-filter-font-family, \"Roboto\", sans-serif)}.cc-filter-container .cc-filter-trigger ::ng-deep button{display:inline-flex;align-items:center;justify-content:center;gap:8px;width:var(--cc-filter-btn-width, 103px);height:var(--cc-filter-btn-height, 44px);padding:0 16px;background-color:var(--cc-filter-btn-bg, #FCFCFB);border:var(--cc-filter-btn-border, 1px solid #E8EAED);border-radius:var(--cc-filter-btn-radius, 8px);color:var(--cc-filter-btn-text-color, #5F6368);font-size:14px;font-weight:500;transition:all .2s ease}.cc-filter-container .cc-filter-trigger ::ng-deep button mat-icon,.cc-filter-container .cc-filter-trigger ::ng-deep button .material-icons{color:#5f6368}.cc-filter-container .cc-filter-trigger ::ng-deep button:hover{background-color:var(--cc-filter-btn-hover-bg, #f1f3f4)}.cc-filter-container .cc-filter-trigger.active ::ng-deep button{background-color:var(--cc-filter-btn-active-bg, #e3f2fd);color:var(--cc-filter-btn-active-text, #1976d2);border-color:var(--cc-filter-btn-active-text, #1976d2)}.cc-filter-container .cc-filter-trigger.active ::ng-deep button mat-icon,.cc-filter-container .cc-filter-trigger.active ::ng-deep button .material-icons{color:var(--cc-filter-btn-active-text, #1976d2)}.cc-filter-container .cc-filter-trigger .cc-badge{background-color:var(--cc-filter-btn-badge-bg, #f44336);color:var(--cc-filter-btn-badge-text, #fff);font-size:10px;font-weight:700;padding:2px 6px;border-radius:10px;min-width:16px;text-align:center;margin-left:4px;line-height:1}.cc-filter-container .cc-filter-panel{position:absolute;top:calc(100% + 8px);right:0;z-index:1000;width:var(--cc-filter-panel-width, 320px);min-width:var(--cc-filter-panel-min-width, 480px)!important;padding:var(--cc-filter-panel-padding, 0);background-color:var(--cc-filter-panel-bg, #fff);border:var(--cc-filter-panel-border, 1px solid #e0e0e0);box-shadow:var(--cc-filter-panel-shadow, 0 4px 12px rgba(0, 0, 0, .15));border-radius:var(--cc-filter-panel-radius, 8px);display:flex;flex-direction:column;overflow:hidden}.cc-filter-container .cc-filter-panel.hidden{display:none}.cc-filter-container .cc-filter-panel .cc-panel-header{display:flex;align-items:center;justify-content:space-between;padding:0 1rem;height:var(--cc-filter-panel-header-height, 48px);border-bottom:1px solid #E0E0E0;background-color:var(--cc-filter-panel-header-bg, #fafafa)}.cc-filter-container .cc-tabs{display:flex;gap:1rem}.cc-filter-container .cc-tabs .cc-tab{cursor:pointer;padding:.5rem 0;font-weight:500;color:#5f6368;border-bottom:2px solid transparent;font-size:14px}.cc-filter-container .cc-tabs .cc-tab.active{color:var(--cc-filter-tab-active-text, #1976d2);border-bottom:var(--cc-filter-tab-border-bottom, 2px solid #1976d2)}.cc-filter-container .cc-icon-btn{background:none;border:none;cursor:pointer;color:#5f6368;padding:.25rem;border-radius:50%;display:flex;align-items:center;justify-content:center}.cc-filter-container .cc-icon-btn:hover{background-color:#0000000a}.cc-filter-container .cc-panel-content{padding:16px;max-height:400px;overflow-y:auto;display:flex;flex-direction:column;gap:var(--cc-filter-panel-gap, 1rem)}.cc-filter-container .cc-filter-section{margin-bottom:16px}.cc-filter-container .cc-filter-section .cc-section-title{font-size:13px;font-weight:600;margin-bottom:8px;color:var(--cc-filter-section-title, #333);text-transform:uppercase;letter-spacing:.5px}.cc-filter-container .cc-filter-section .cc-control-group{display:flex;flex-direction:column;gap:8px}.cc-filter-container .cc-filter-section .cc-control-group label{display:flex;align-items:center;gap:8px;font-size:14px;color:var(--cc-filter-option-text, #555);cursor:pointer}.cc-filter-container .cc-filter-section .cc-control-group label:hover{color:#000}.cc-filter-container .cc-accordion-item{border-bottom:1px solid #E0E0E0}.cc-filter-container .cc-accordion-item:last-child{border-bottom:none}.cc-filter-container .cc-accordion-item .cc-accordion-header{display:flex;align-items:center;justify-content:space-between;width:100%;padding:.75rem 0;background:none;border:none;cursor:pointer;text-align:left;outline:none}.cc-filter-container .cc-accordion-item .cc-accordion-header .cc-accordion-title{font-size:.875rem;font-weight:500;color:#202124}.cc-filter-container .cc-accordion-item .cc-accordion-header .cc-accordion-icon{color:#5f6368;transition:transform .2s}.cc-filter-container .cc-accordion-item .cc-accordion-body{padding:0 0 1rem;display:flex;flex-direction:column;gap:1rem;animation:slideDown .2s ease-out}.cc-filter-container .cc-filter-divider{height:1px;background-color:#e0e0e0;margin:.5rem 0}.cc-filter-container .cc-panel-footer{padding:12px 16px;background-color:var(--cc-filter-footer-bg, #fff);border-top:var(--cc-filter-footer-border-top, 1px solid #e0e0e0);display:flex;justify-content:flex-end;align-items:center;gap:10px}.cc-filter-container .cc-columns-actions{display:flex;gap:.5rem;margin-bottom:.5rem}.cc-filter-container .cc-columns-list{display:flex;flex-direction:column;gap:.5rem}\n"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: i1.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i1.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: ButtonComponent, selector: "lib-button", inputs: ["variant", "type", "disabled", "width", "height", "borderRadius", "fontSize", "fontWeight", "backgroundColor", "color", "border", "icon", "labels"] }, { kind: "component", type: InputComponent, selector: "lib-input", inputs: ["config", "labels", "type", "label", "placeholder", "disabled", "required", "readonly", "clearable", "maxLength", "minLength", "min", "max", "pattern", "errorMessage", "helperText", "rows", "prefixIcon", "suffixIcon", "value", "width", "height", "borderRadius", "fontSize", "gap", "fontFamily", "labelColor", "labelFontSize", "labelFontWeight", "backgroundColor", "borderColor", "borderWidth", "padding", "fontWeight", "color", "placeholderColor", "focusBorderColor", "errorColor", "disabledBackgroundColor", "disabledColor", "boxShadow"], outputs: ["valueChange", "inputBlur", "inputFocus"] }, { kind: "component", type: DropdownComponent, selector: "lib-dropdown", inputs: ["config", "labels", "options", "selectedValue", "placeholder", "label", "multiple", "searchable", "clearable", "disabled", "required", "errorMessage", "serverSearch", "searchDebounceMs", "lazyLoad", "loading", "loadingMore", "hasMore", "width", "height", "borderRadius", "fontSize", "gap", "fontFamily", "labelColor", "labelFontSize", "labelFontWeight", "backgroundColor", "borderColor", "borderWidth", "padding", "fontWeight", "color", "placeholderColor", "focusBorderColor", "errorColor", "disabledBackgroundColor", "disabledColor", "boxShadow"], outputs: ["selectionChange", "searchTermChange", "loadMore"] }, { kind: "component", type: CheckboxComponent, selector: "lib-checkbox", inputs: ["config", "labels", "label", "checked", "disabled", "required", "indeterminate", "options", "labelPosition", "color", "borderRadius", "value", "errorMessage", "width", "height", "fontSize", "fontWeight", "labelColor", "labelFontSize", "labelFontWeight", "gap", "fontFamily", "backgroundColor", "borderColor", "borderWidth", "padding", "placeholderColor", "focusBorderColor", "errorColor", "disabledBackgroundColor", "disabledColor", "boxShadow", "size", "checkedColor", "uncheckedColor", "groupLabelColor", "groupLabelFontSize", "groupLabelFontWeight"], outputs: ["checkedChange"] }, { kind: "component", type: RadioComponent, selector: "lib-radio", inputs: ["config", "label", "options", "disabled", "required", "labelPosition", "color", "layout", "labels", "gap", "labelColor", "checkedColor", "uncheckedColor", "fontSize", "fontWeight", "fontFamily", "groupLabelColor", "groupLabelFontSize", "groupLabelFontWeight", "disabledColor", "errorColor", "size", "borderRadius", "labelFontSize", "labelFontWeight"], outputs: ["selectionChange"] }, { kind: "component", type: ToggleComponent, selector: "lib-toggle", inputs: ["config", "labels", "label", "checked", "disabled", "required", "labelPosition", "color", "labelColor", "uncheckedColor", "checkedColor", "thumbColor", "checkedThumbColor", "fontSize", "fontWeight", "fontFamily", "toggleWidth", "toggleHeight", "gap", "sliderColor", "labelFontSize", "labelFontWeight", "disabledColor"], outputs: ["toggleChange"] }, { kind: "component", type: DatepickerComponent, selector: "lib-datepicker", inputs: ["config", "labels", "label", "placeholder", "disabled", "required", "minDate", "maxDate", "isRange", "startView", "value", "startDate", "endDate", "errorMessage", "width", "height", "borderRadius", "fontSize", "gap", "fontFamily", "labelColor", "labelFontSize", "labelFontWeight", "backgroundColor", "borderColor", "borderWidth", "padding", "fontWeight", "color", "placeholderColor", "focusBorderColor", "errorColor", "disabledBackgroundColor", "disabledColor", "boxShadow"], outputs: ["dateChange"] }, { kind: "component", type: SearchComponent, selector: "lib-search", inputs: ["config", "labels", "placeholder", "label", "disabled", "debounceMs", "clearable", "value", "width", "height", "borderRadius", "fontSize", "gap", "fontFamily", "labelColor", "labelFontSize", "labelFontWeight", "backgroundColor", "borderColor", "borderWidth", "border", "padding", "fontWeight", "color", "textColor", "iconColor", "placeholderColor", "focusBorderColor", "disabledBackgroundColor", "disabledColor", "boxShadow"], outputs: ["search", "clear"] }] });
|
|
13012
13339
|
}
|
|
13013
13340
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FilterComponent, decorators: [{
|
|
13014
13341
|
type: Component,
|
|
@@ -13498,6 +13825,7 @@ class SmartTableComponent {
|
|
|
13498
13825
|
ngOnInit() {
|
|
13499
13826
|
window.addEventListener('scroll', this.onScrollCapture, true);
|
|
13500
13827
|
if (this.config) {
|
|
13828
|
+
this.sortColumnsBySequence();
|
|
13501
13829
|
this.applyPaginationDefaults();
|
|
13502
13830
|
if (this.config.sortBy) {
|
|
13503
13831
|
this.activeSort.key = this.config.sortBy;
|
|
@@ -13528,8 +13856,9 @@ class SmartTableComponent {
|
|
|
13528
13856
|
if (changes['totalItemsCount'] && this.totalItemsCount !== undefined) {
|
|
13529
13857
|
this.totalItems = this.totalItemsCount;
|
|
13530
13858
|
}
|
|
13531
|
-
// Config changed
|
|
13859
|
+
// Config changed — re-apply column ordering whenever a new config object arrives
|
|
13532
13860
|
if (changes['config'] && !changes['config'].firstChange) {
|
|
13861
|
+
this.sortColumnsBySequence();
|
|
13533
13862
|
this.applyPaginationDefaults();
|
|
13534
13863
|
this.loadFilterOptions();
|
|
13535
13864
|
if (this.tableData === undefined) {
|
|
@@ -14260,6 +14589,24 @@ class SmartTableComponent {
|
|
|
14260
14589
|
get columnCount() {
|
|
14261
14590
|
return this.config.columns.length;
|
|
14262
14591
|
}
|
|
14592
|
+
/**
|
|
14593
|
+
* Orders `config.columns` by their `sequence` value (ascending). Columns without a
|
|
14594
|
+
* `sequence` are left in their original relative order, placed after any columns that
|
|
14595
|
+
* do have one — so configs that never set `sequence` are left untouched (stable sort).
|
|
14596
|
+
*/
|
|
14597
|
+
sortColumnsBySequence() {
|
|
14598
|
+
const columns = this.config?.columns;
|
|
14599
|
+
if (!columns || columns.length === 0)
|
|
14600
|
+
return;
|
|
14601
|
+
const hasSequence = columns.some(c => c.sequence !== undefined && c.sequence !== null);
|
|
14602
|
+
if (!hasSequence)
|
|
14603
|
+
return;
|
|
14604
|
+
this.config.columns = [...columns].sort((a, b) => {
|
|
14605
|
+
const aSeq = a.sequence ?? Number.MAX_SAFE_INTEGER;
|
|
14606
|
+
const bSeq = b.sequence ?? Number.MAX_SAFE_INTEGER;
|
|
14607
|
+
return aSeq - bSeq;
|
|
14608
|
+
});
|
|
14609
|
+
}
|
|
14263
14610
|
/**
|
|
14264
14611
|
* Filters out actions/action-items that are either explicitly disabled via
|
|
14265
14612
|
* `isEnabled: false` or hidden for the given row by their `visibleWhen` /
|