@sd-angular/core 19.0.3 → 19.0.5

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.
Files changed (76) hide show
  1. package/README.md +13 -8
  2. package/assets/{scss/README.md → STYLE-GUIDE.md} +3 -0
  3. package/components/button/src/button.component.d.ts +1 -2
  4. package/components/form-generic/src/components/form-builder/form-builder.component.d.ts +1 -2
  5. package/components/form-generic/src/components/form-render/form-render.component.d.ts +1 -2
  6. package/components/form-generic/src/components/sd-feel-expression/sd-feel-expression.component.d.ts +1 -2
  7. package/components/index.d.ts +2 -0
  8. package/components/org-chart/index.d.ts +3 -0
  9. package/components/org-chart/src/org-chart-item-def.directive.d.ts +9 -0
  10. package/components/org-chart/src/org-chart.component.d.ts +26 -0
  11. package/components/org-chart/src/org-chart.model.d.ts +32 -0
  12. package/components/query-bar/src/query-bar.component.d.ts +15 -2
  13. package/components/query-bar/src/query-bar.model.d.ts +22 -0
  14. package/components/query-builder/index.d.ts +2 -0
  15. package/components/query-builder/src/query-builder.component.d.ts +115 -22
  16. package/components/query-builder/src/query-builder.model.d.ts +166 -0
  17. package/components/query-builder/src/query-builder.serializer.d.ts +32 -0
  18. package/components/section/src/section.component.d.ts +5 -3
  19. package/components/side-drawer/src/side-drawer.component.d.ts +1 -2
  20. package/components/splitter/src/splitter.component.d.ts +8 -2
  21. package/components/splitter/src/splitter.models.d.ts +13 -0
  22. package/components/stepper/src/stepper.component.d.ts +1 -2
  23. package/components/tab/src/tab-group.component.d.ts +1 -2
  24. package/components/table/src/services/table-filter/table-filter.model.d.ts +2 -0
  25. package/components/table/src/table.component.d.ts +1 -2
  26. package/components/tree/index.d.ts +3 -0
  27. package/components/tree/src/tree-item-def.directive.d.ts +9 -0
  28. package/components/tree/src/tree.component.d.ts +102 -0
  29. package/components/tree/src/tree.model.d.ts +142 -0
  30. package/components/upload-file/src/upload-file.component.d.ts +2 -0
  31. package/fesm2022/sd-angular-core-components-button.mjs +2 -4
  32. package/fesm2022/sd-angular-core-components-button.mjs.map +1 -1
  33. package/fesm2022/sd-angular-core-components-form-generic.mjs +7 -11
  34. package/fesm2022/sd-angular-core-components-form-generic.mjs.map +1 -1
  35. package/fesm2022/sd-angular-core-components-modal-resizable.mjs +5 -5
  36. package/fesm2022/sd-angular-core-components-modal-resizable.mjs.map +1 -1
  37. package/fesm2022/sd-angular-core-components-org-chart.mjs +110 -0
  38. package/fesm2022/sd-angular-core-components-org-chart.mjs.map +1 -0
  39. package/fesm2022/sd-angular-core-components-query-bar.mjs +37 -8
  40. package/fesm2022/sd-angular-core-components-query-bar.mjs.map +1 -1
  41. package/fesm2022/sd-angular-core-components-query-builder.mjs +867 -57
  42. package/fesm2022/sd-angular-core-components-query-builder.mjs.map +1 -1
  43. package/fesm2022/sd-angular-core-components-section.mjs +8 -7
  44. package/fesm2022/sd-angular-core-components-section.mjs.map +1 -1
  45. package/fesm2022/sd-angular-core-components-side-drawer.mjs +2 -4
  46. package/fesm2022/sd-angular-core-components-side-drawer.mjs.map +1 -1
  47. package/fesm2022/sd-angular-core-components-splitter.mjs +23 -12
  48. package/fesm2022/sd-angular-core-components-splitter.mjs.map +1 -1
  49. package/fesm2022/sd-angular-core-components-stepper.mjs +2 -4
  50. package/fesm2022/sd-angular-core-components-stepper.mjs.map +1 -1
  51. package/fesm2022/sd-angular-core-components-tab.mjs +2 -4
  52. package/fesm2022/sd-angular-core-components-tab.mjs.map +1 -1
  53. package/fesm2022/sd-angular-core-components-table.mjs +8 -6
  54. package/fesm2022/sd-angular-core-components-table.mjs.map +1 -1
  55. package/fesm2022/sd-angular-core-components-tree.mjs +526 -0
  56. package/fesm2022/sd-angular-core-components-tree.mjs.map +1 -0
  57. package/fesm2022/sd-angular-core-components-upload-file.mjs +15 -4
  58. package/fesm2022/sd-angular-core-components-upload-file.mjs.map +1 -1
  59. package/fesm2022/sd-angular-core-components.mjs +2 -0
  60. package/fesm2022/sd-angular-core-components.mjs.map +1 -1
  61. package/fesm2022/sd-angular-core-forms-autocomplete.mjs +9 -4
  62. package/fesm2022/sd-angular-core-forms-autocomplete.mjs.map +1 -1
  63. package/fesm2022/sd-angular-core-forms-input-number.mjs +9 -3
  64. package/fesm2022/sd-angular-core-forms-input-number.mjs.map +1 -1
  65. package/fesm2022/sd-angular-core-forms-input.mjs +2 -2
  66. package/fesm2022/sd-angular-core-forms-input.mjs.map +1 -1
  67. package/fesm2022/sd-angular-core-forms-select.mjs +33 -3
  68. package/fesm2022/sd-angular-core-forms-select.mjs.map +1 -1
  69. package/fesm2022/sd-angular-core-services-notify.mjs +26 -8
  70. package/fesm2022/sd-angular-core-services-notify.mjs.map +1 -1
  71. package/forms/select/src/select.component.d.ts +9 -1
  72. package/package.json +81 -73
  73. package/sd-angular-core-19.0.5.tgz +0 -0
  74. package/services/notify/src/components/toast/toast.component.d.ts +12 -1
  75. package/services/notify/src/notify.model.d.ts +17 -0
  76. package/sd-angular-core-19.0.3.tgz +0 -0
@@ -1,6 +1,6 @@
1
1
  import { CommonModule } from '@angular/common';
2
2
  import * as i0 from '@angular/core';
3
- import { input, output, signal, computed, effect, ChangeDetectionStrategy, Component, booleanAttribute, model, viewChild, isSignal, inject, Injector, viewChildren, afterNextRender } from '@angular/core';
3
+ import { input, output, signal, computed, effect, ChangeDetectionStrategy, Component, booleanAttribute, model, viewChild, isSignal, inject, Injector, viewChildren, afterNextRender, untracked } from '@angular/core';
4
4
  import * as i1$2 from '@angular/forms';
5
5
  import { FormsModule } from '@angular/forms';
6
6
  import * as i1$1 from '@angular/material/icon';
@@ -963,6 +963,8 @@ class SdQueryBar {
963
963
  // ---------------------------------------------------------------------------
964
964
  // Inputs — all accept null|undefined at boundary, transform to canonical shape
965
965
  // ---------------------------------------------------------------------------
966
+ /** Main option object. Prefer this API for new usage; individual inputs stay as a migration bridge. */
967
+ option = input(undefined);
966
968
  /** Prefix for auto-generated `data-autoid` on inner controls (chips, operator/value editors, buttons). */
967
969
  autoIdInput = input(undefined, {
968
970
  alias: 'autoId',
@@ -1038,9 +1040,34 @@ class SdQueryBar {
1038
1040
  // Derived state
1039
1041
  // ---------------------------------------------------------------------------
1040
1042
  /** Map of `field.key` → `SdQueryField` for fast lookup from filters[]. */
1043
+ resolvedAutoId = computed(() => this.option()?.autoId ?? this.autoIdInput() ?? undefined);
1044
+ resolvedFields = computed(() => this.option()?.fields ?? this.fields());
1045
+ resolvedMode = computed(() => this.option()?.mode ?? this.mode());
1046
+ resolvedDensity = computed(() => this.option()?.density ?? this.density());
1047
+ resolvedShowSearch = computed(() => this.option()?.showSearch ?? this.showSearch());
1048
+ resolvedShowSavedFilters = computed(() => this.option()?.showSavedFilters ?? this.showSavedFilters());
1049
+ resolvedSavedFiltersKey = computed(() => this.option()?.savedFiltersKey ?? this.savedFiltersKey());
1050
+ resolvedShowLogicToggle = computed(() => this.option()?.showLogicToggle ?? this.showLogicToggle());
1051
+ resolvedShowClearAll = computed(() => this.option()?.showClearAll ?? this.showClearAll());
1052
+ resolvedShowOperatorOnChip = computed(() => this.option()?.showOperatorOnChip ?? this.showOperatorOnChip());
1053
+ constructor() {
1054
+ effect(() => {
1055
+ const option = this.option();
1056
+ if (!option)
1057
+ return;
1058
+ untracked(() => {
1059
+ if (option.filters && this.filters() !== option.filters)
1060
+ this.filters.set(option.filters);
1061
+ if (option.logic && this.logic() !== option.logic)
1062
+ this.logic.set(option.logic);
1063
+ if (option.search !== undefined && this.search() !== option.search)
1064
+ this.search.set(option.search);
1065
+ });
1066
+ });
1067
+ }
1041
1068
  fieldByKey = computed(() => {
1042
1069
  const map = {};
1043
- for (const f of this.fields())
1070
+ for (const f of this.resolvedFields())
1044
1071
  map[f.key] = f;
1045
1072
  return map;
1046
1073
  });
@@ -1054,7 +1081,7 @@ class SdQueryBar {
1054
1081
  return set;
1055
1082
  });
1056
1083
  /** Render the global AND/OR connector text between chips when `logic === 'OR'`. */
1057
- showOrConnector = computed(() => this.showLogicToggle() && this.logic() === 'OR' && this.filters().length >= 2);
1084
+ showOrConnector = computed(() => this.resolvedShowLogicToggle() && this.logic() === 'OR' && this.filters().length >= 2);
1058
1085
  /** Search button is actionable only when there is something to apply. */
1059
1086
  canSearch = computed(() => this.filters().length > 0 || this.search().trim().length > 0);
1060
1087
  // ---------------------------------------------------------------------------
@@ -1127,7 +1154,7 @@ class SdQueryBar {
1127
1154
  return sdQueryAllowedOperators(field);
1128
1155
  }
1129
1156
  inlineAutoId(index, role) {
1130
- const base = this.autoIdInput() ?? 'qb';
1157
+ const base = this.resolvedAutoId() ?? 'qb';
1131
1158
  return `${base}-inline${index}-${role}`;
1132
1159
  }
1133
1160
  // ---------------------------------------------------------------------------
@@ -1288,7 +1315,9 @@ class SdQueryBar {
1288
1315
  // why: single deferred trigger — fire both the change notification and the reload
1289
1316
  // signal once, from here only (mutations no longer emit).
1290
1317
  const q = this.#buildQuery();
1318
+ this.option()?.onQueryChange?.(q);
1291
1319
  this.queryChange.emit(q);
1320
+ this.option()?.onApply?.(q);
1292
1321
  this.apply.emit(q);
1293
1322
  }
1294
1323
  // ---------------------------------------------------------------------------
@@ -1323,7 +1352,7 @@ class SdQueryBar {
1323
1352
  return {
1324
1353
  filters: this.filters(),
1325
1354
  logic: this.logic(),
1326
- ...(this.showSearch() ? { search: this.search() } : {}),
1355
+ ...(this.resolvedShowSearch() ? { search: this.search() } : {}),
1327
1356
  };
1328
1357
  }
1329
1358
  #displayOne(filter, raw) {
@@ -1356,7 +1385,7 @@ class SdQueryBar {
1356
1385
  return null;
1357
1386
  }
1358
1387
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SdQueryBar, deps: [], target: i0.ɵɵFactoryTarget.Component });
1359
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: SdQueryBar, isStandalone: true, selector: "sd-query-bar", inputs: { autoIdInput: { classPropertyName: "autoIdInput", publicName: "autoId", isSignal: true, isRequired: false, transformFunction: null }, fields: { classPropertyName: "fields", publicName: "fields", isSignal: true, isRequired: false, transformFunction: null }, filters: { classPropertyName: "filters", publicName: "filters", isSignal: true, isRequired: false, transformFunction: null }, logic: { classPropertyName: "logic", publicName: "logic", isSignal: true, isRequired: false, transformFunction: null }, search: { classPropertyName: "search", publicName: "search", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, density: { classPropertyName: "density", publicName: "density", isSignal: true, isRequired: false, transformFunction: null }, showSearch: { classPropertyName: "showSearch", publicName: "showSearch", isSignal: true, isRequired: false, transformFunction: null }, showSavedFilters: { classPropertyName: "showSavedFilters", publicName: "showSavedFilters", isSignal: true, isRequired: false, transformFunction: null }, savedFiltersKey: { classPropertyName: "savedFiltersKey", publicName: "savedFiltersKey", isSignal: true, isRequired: false, transformFunction: null }, showLogicToggle: { classPropertyName: "showLogicToggle", publicName: "showLogicToggle", isSignal: true, isRequired: false, transformFunction: null }, showClearAll: { classPropertyName: "showClearAll", publicName: "showClearAll", isSignal: true, isRequired: false, transformFunction: null }, showOperatorOnChip: { classPropertyName: "showOperatorOnChip", publicName: "showOperatorOnChip", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { filters: "filtersChange", logic: "logicChange", search: "searchChange", queryChange: "queryChange", apply: "apply" }, viewQueries: [{ propertyName: "popoverChips", predicate: SdQueryPopoverChip, descendants: true, isSignal: true }, { propertyName: "buildChip", first: true, predicate: SdQueryBuildChip, descendants: true, isSignal: true }, { propertyName: "chipPopover", first: true, predicate: SdQueryChipPopover, descendants: true, isSignal: true }], ngImport: i0, template: "<!--\n sd-query-bar \u2014 unified filter chip row (Jira/Linear/Notion style).\n Visual spec: refs/design_handoff_sd_query_bar/README.md\n TODO(next-iter): replace inline placeholders for field-picker + chip-popover\n with extracted sub-components driven by CDK overlay.\n-->\n@let _filters = filters();\n@let _fields = fields();\n@let _density = density();\n@let _showOr = showOrConnector();\n@let _used = usedFieldKeys();\n@let _editingIndex = editingIndex();\n@let _mode = mode();\n@let _showOpOnChip = showOperatorOnChip();\n\n<div\n class=\"c-query-bar\"\n [class.c-density-compact]=\"_density === 'compact'\"\n [class.c-density-comfortable]=\"_density === 'comfortable'\">\n\n <!-- Main region \u2014 search + filters + add-filter. Wraps internally; the right\n action toolbar stays anchored and does NOT flow with this. -->\n <div class=\"c-query-bar__main\">\n\n <!-- Free-text search (left, optional) -->\n @if (showSearch()) {\n <div class=\"c-search\">\n <mat-icon class=\"c-search-icon\" fontSet=\"material-icons-outlined\">search</mat-icon>\n <input\n class=\"c-search-input\"\n type=\"text\"\n [ngModel]=\"search()\"\n (ngModelChange)=\"setSearch($event)\"\n (keydown.enter)=\"triggerApply()\"\n placeholder=\"T\u00ECm ki\u1EBFm...\" />\n </div>\n <span class=\"c-divider\" aria-hidden=\"true\"></span>\n }\n\n <!-- Field switcher (used by chipPopover header) \u2014 declared first so chipPopover's\n nested ng-template can resolve the template ref. -->\n <!-- Field switcher used by chipPopover header \u2014 current field key comes from editingIndex. -->\n <sd-query-field-picker\n #switchPicker\n [fields]=\"_fields\"\n [currentKey]=\"_editingIndex !== null ? $any(_filters[_editingIndex!])?.field : undefined\"\n (pick)=\"_editingIndex !== null && changeFilterField(_editingIndex!, $event)\" />\n\n <!-- Chip popover \u2014 extracted into <sd-query-chip-popover>. Declared BEFORE chips\n so the popover-mode @for chips can bind their [menu] to `chipPopover.menu()`. -->\n <sd-query-chip-popover\n #chipPopover\n [field]=\"editingField() ?? undefined\"\n [filter]=\"_editingIndex !== null ? $any(_filters[_editingIndex!]) : undefined\"\n [chipIndex]=\"_editingIndex\"\n [autoIdBase]=\"autoIdInput() ?? 'qb'\"\n [switchPickerMenu]=\"switchPicker.menu()!\"\n (commit)=\"onChipPopoverCommit($event)\"\n (swapField)=\"_editingIndex !== null && changeFilterField(_editingIndex!, $event)\" />\n\n @if (_mode === 'inline') {\n <!-- ===== INLINE MODE (GitLab-style token builder) ===== -->\n\n <!-- Completed chips -->\n @for (filter of _filters; track $index; let i = $index) {\n @if (_showOr && i > 0) {\n <span class=\"c-or-connector\" aria-hidden=\"true\">OR</span>\n }\n @let _field = fieldByKey()[$any(filter).field];\n @if (_field) {\n @let _op = $any(filter.operator);\n @let _data = $any(filter).data;\n @if (_field.type === 'string' || _field.type === 'number') {\n <!-- Seamless chip \u2014 the pill is the input (string / number). -->\n <sd-query-inline-value-chip\n [field]=\"_field\"\n [operator]=\"_op\"\n [value]=\"_data\"\n [density]=\"_density\"\n [showOperator]=\"_showOpOnChip\"\n [autoId]=\"inlineAutoId(i, 'value')\"\n (valueChange)=\"updateFilter(i, { data: $event })\"\n (remove)=\"removeFilter(i)\" />\n } @else {\n <sd-query-inline-chip\n [field]=\"_field\"\n [filter]=\"filter\"\n [density]=\"_density\"\n [multiple]=\"multiple(_op)\"\n [showOperator]=\"_showOpOnChip\"\n [autoId]=\"inlineAutoId(i, 'value')\"\n [valueText]=\"chipValueText(filter)\"\n [isNoData]=\"isNoDataOperator(_op)\"\n (commit)=\"updateFilter(i, { data: $event })\"\n (commitRange)=\"setFilterRange(i, $event)\"\n (liveChange)=\"updateFilter(i, { data: $event })\"\n (remove)=\"removeFilter(i)\" />\n }\n }\n }\n\n <!-- Building chip (in-progress) \u2014 extracted into <sd-query-build-chip>. -->\n @if (building(); as _b) {\n <sd-query-build-chip\n [building]=\"_b\"\n [density]=\"_density\"\n [allowedOperators]=\"allowedOperatorsFor(_b.field)\"\n [multiple]=\"multiple($any(_b.operator))\"\n [showOperator]=\"_showOpOnChip\"\n (pickOperator)=\"pickBuildOperator($any($event))\"\n (commitValue)=\"commitBuildValue($event)\"\n (cancel)=\"cancelBuild()\"\n (seamlessCommit)=\"onBuildSeamlessCommit($event)\" />\n }\n\n <!-- Add filter -->\n <button\n type=\"button\"\n class=\"c-add-filter\"\n [matMenuTriggerFor]=\"addPicker.menu()\"\n [disabled]=\"_fields.length === 0 || _used.size >= _fields.length\"\n [matTooltip]=\"_fields.length === 0 ? 'Ch\u01B0a c\u1EA5u h\u00ECnh fields' : 'Th\u00EAm filter'\">\n <mat-icon fontSet=\"material-icons-outlined\">add</mat-icon>\n </button>\n } @else {\n <!-- ===== POPOVER MODE (default) \u2014 compact chips edited via mat-menu ===== -->\n @for (filter of _filters; track $index; let i = $index) {\n @if (_showOr && i > 0) {\n <span class=\"c-or-connector\" aria-hidden=\"true\">OR</span>\n }\n @let _field = fieldByKey()[$any(filter).field];\n @let _active = isFilterActive(filter);\n <!-- why: menu close commit is handled by chipPopover's (commit) \u2192\n onChipPopoverCommit; popover-chip only signals open + remove here. -->\n <sd-query-popover-chip\n [field]=\"_field\"\n [filter]=\"filter\"\n [active]=\"_active\"\n [showOperator]=\"_showOpOnChip\"\n [valueText]=\"chipValueText(filter)\"\n [menu]=\"chipPopover.menu()!\"\n (open)=\"openChipPopover(i)\"\n (remove)=\"removeFilter(i)\" />\n }\n\n <!-- Add filter trigger -->\n <button\n type=\"button\"\n class=\"c-add-filter\"\n [matMenuTriggerFor]=\"addPicker.menu()\"\n [disabled]=\"_fields.length === 0 || _used.size >= _fields.length\"\n [matTooltip]=\"_fields.length === 0 ? 'Ch\u01B0a c\u1EA5u h\u00ECnh fields' : 'Th\u00EAm filter'\">\n <mat-icon fontSet=\"material-icons-outlined\">add</mat-icon>\n </button>\n }\n\n </div><!-- /.c-query-bar__main -->\n\n <!-- Field picker \u2014 list available fields, fade ones already in use. -->\n <sd-query-field-picker\n #addPicker\n [fields]=\"_fields\"\n [usedKeys]=\"_used\"\n (pick)=\"_mode === 'inline' ? beginBuild($event) : addFilter($event)\" />\n\n <sd-query-actions-bar\n [showLogicToggle]=\"showLogicToggle()\"\n [(logic)]=\"logic\"\n [filtersCount]=\"_filters.length\"\n [showSavedFilters]=\"showSavedFilters()\"\n [savedFiltersKey]=\"savedFiltersKey()\"\n [query]=\"currentQuery()\"\n (applyFilter)=\"onApplyFilter($event)\"\n [showClearAll]=\"showClearAll()\"\n [canSearch]=\"canSearch()\"\n (clear)=\"clearAll()\"\n (search)=\"triggerApply()\" />\n</div>\n", styles: [":host{display:block;font-family:Roboto,system-ui,sans-serif}.c-query-bar{display:flex;align-items:flex-start;flex-wrap:nowrap;gap:8px;background:#fff;border:1px solid #e2e4e7;border-radius:8px;box-shadow:0 1px 2px #0f172a0a}.c-query-bar.c-density-compact{padding:8px}.c-query-bar.c-density-comfortable{padding:10px}.c-query-bar__main{flex:1 1 auto;min-width:0;display:flex;align-items:center;flex-wrap:wrap;gap:6px}.c-search{display:flex;align-items:center;gap:6px;min-width:220px;padding:0 10px;border:1px solid #d6d8db;border-radius:6px;background:#fff}.c-density-compact .c-search{height:28px}.c-density-comfortable .c-search{height:32px}.c-search .c-search-icon{font-size:16px;width:16px;height:16px;color:#7a7a7a}.c-search .c-search-input{flex:1;border:none;outline:none;background:transparent;font-size:13px;color:#212121}.c-search .c-search-input::placeholder{color:#7a7a7a}.c-search .c-search-kbd{font-family:Roboto Mono,monospace;font-size:10px;padding:1px 4px;border:1px solid #e2e4e7;border-radius:3px;color:#7a7a7a}.c-divider{width:1px;height:16px;background:#e2e4e7;margin:0 2px}.c-token{display:inline-flex;align-items:center;gap:4px;padding:0 0 0 12px;border:1px solid var(--sd-primary-light);border-radius:999px;background:var(--sd-primary-light);font-size:13px;color:#5f6368;white-space:nowrap;overflow:hidden}.c-density-compact .c-token{height:28px}.c-density-comfortable .c-token{height:32px}.c-token-icon{font-size:14px;width:14px;height:14px;line-height:14px;color:inherit}.c-token-field{font-weight:500;line-height:1}.c-token-op{display:inline-flex;align-items:center;color:inherit}.c-token-op ::ng-deep .c-op-trigger{padding:0;color:inherit}.c-token-op ::ng-deep .c-op-icon svg{width:14px;height:14px;display:block}.c-token-value-edit sd-select,.c-token-value-edit sd-date,.c-token-value-edit sd-datetime{display:inline-flex;align-items:center;line-height:1}.c-token ::ng-deep .mat-mdc-form-field{line-height:1}.c-token ::ng-deep .mat-mdc-text-field-wrapper,.c-token ::ng-deep .mat-mdc-form-field-flex{padding:0;min-height:0;background:transparent}.c-token ::ng-deep .mat-mdc-form-field-infix{padding:0;min-height:0;width:auto;border:0;display:inline-flex;align-items:center}.c-token ::ng-deep .mat-mdc-select-value,.c-token ::ng-deep .mat-mdc-input-element,.c-token ::ng-deep input{line-height:1;font-size:13px;padding:0;height:auto;color:inherit}.c-token ::ng-deep .mat-mdc-select-value{display:inline-flex;align-items:center;min-width:0;max-width:200px;overflow:hidden;text-overflow:ellipsis;color:var(--sd-primary);font-weight:500}.c-token ::ng-deep .sd-suffix-icon{display:none}.c-token-sep{color:#7a7a7a}.c-token-dash{color:#7a7a7a;padding:0 4px;line-height:1}.c-token-value{border:none;background:transparent;padding:0;font:inherit;font-weight:500;color:var(--sd-primary);cursor:pointer}.c-token-value:hover{text-decoration:underline}.c-token-value-edit{display:inline-flex;align-items:center;gap:4px;max-width:240px}.c-token-value-edit sd-input,.c-token-value-edit sd-input-number{display:inline-flex;max-width:140px}.c-token-value-edit sd-date-range{display:inline-flex;max-width:220px;min-width:0;flex:0 1 auto}.c-token-multi-head{display:inline-block;max-width:140px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:bottom}.c-token-remove{align-self:stretch;display:inline-flex;align-items:center;justify-content:center;border:none;border-left:1px solid rgba(0,0,0,.04);border-radius:0;background:transparent;cursor:pointer;color:inherit}.c-density-compact .c-token-remove{width:26px}.c-density-comfortable .c-token-remove{width:28px}.c-token-remove mat-icon{font-size:14px;width:14px;height:14px}.c-token-remove:hover{background:#0000000d}.c-add-filter{display:inline-flex;align-items:center;justify-content:center;padding:0;border-radius:999px;border:1px dashed #d6d8db;background:transparent;cursor:pointer;color:#5f6368;transition:border-color .12s ease,color .12s ease,background-color .12s ease}.c-density-compact .c-add-filter{width:28px;height:28px}.c-density-comfortable .c-add-filter{width:32px;height:32px}.c-add-filter mat-icon{font-size:18px;width:18px;height:18px}.c-add-filter:hover:not([disabled]){border-color:var(--sd-primary);color:var(--sd-primary)}.c-add-filter[disabled]{opacity:.5;cursor:not-allowed}.c-or-connector{font-family:Roboto Mono,monospace;font-size:10px;font-weight:700;letter-spacing:.6px;color:#7a7a7a;padding:0 2px}::ng-deep .mat-mdc-menu-panel.c-chip-popover{min-width:280px;max-width:320px}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-header{display:flex;align-items:center;gap:8px;padding:10px 12px;border-bottom:1px solid #e2e4e7;font-size:13px;font-weight:500;color:#212121}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-header mat-icon{font-size:16px;width:16px;height:16px;color:var(--sd-primary)}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-header .c-pop-header-operator{margin-left:auto}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-header-field{display:inline-flex;align-items:center;gap:4px;padding:2px 4px 2px 6px;margin-left:-4px;background:transparent;border:1px solid transparent;border-radius:4px;font:inherit;font-weight:500;color:#212121;cursor:pointer;transition:background-color .12s ease,border-color .12s ease}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-header-field mat-icon{font-size:14px!important;width:14px!important;height:14px!important;color:#7a7a7a!important}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-header-field:hover{background:#f5f6f7;border-color:#e2e4e7}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-body{padding:10px 12px;display:flex;flex-direction:column;gap:12px}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-input{width:100%;height:32px;padding:0 10px;border:1px solid #d6d8db;border-radius:6px;background:#fff;font-family:inherit;font-size:13px;color:#212121;outline:none}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-input:focus{border-color:var(--sd-primary)}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-between{display:grid;grid-template-columns:1fr 1fr;gap:8px}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-boolean{display:flex;gap:8px}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-boolean button{flex:1;height:32px;border:1px solid #d6d8db;border-radius:6px;background:#fff;font:inherit;font-size:13px;cursor:pointer}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-boolean button.c-pop-boolean-active{background:var(--sd-primary-light);border-color:var(--sd-primary);color:var(--sd-primary)}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-values{max-height:220px;overflow-y:auto;margin:0;padding:0;list-style:none}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-values li{display:flex;align-items:center;gap:8px;padding:6px 8px;border-radius:4px;font-size:13px;cursor:pointer;-webkit-user-select:none;user-select:none}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-values li:hover{background:#f5f6f7}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-values li.c-pop-value-selected{background:var(--sd-primary-light);color:var(--sd-primary)}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-values li input[type=checkbox],::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-values li input[type=radio]{accent-color:var(--sd-primary)}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-values-loading,::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-values-empty{padding:10px 8px;font-size:12px;color:#7a7a7a}.c-bool-toggle{display:inline-flex;align-items:center;gap:4px}.c-bool-toggle ::ng-deep .mdc-button,.c-bool-toggle ::ng-deep button[mat-button],.c-bool-toggle ::ng-deep button[mat-stroked-button],.c-bool-toggle ::ng-deep button[mat-flat-button]{border-radius:999px;min-width:0;padding:0 12px}\n", ".c-query-bar ::ng-deep .mat-mdc-form-field .mdc-notched-outline__leading,.c-query-bar ::ng-deep .mat-mdc-form-field .mdc-notched-outline__notch,.c-query-bar ::ng-deep .mat-mdc-form-field .mdc-notched-outline__trailing{border-color:#d6d8db!important;transition:border-color .12s ease}.c-query-bar ::ng-deep .mat-mdc-form-field .mdc-notched-outline__leading{border-radius:6px 0 0 6px!important}.c-query-bar ::ng-deep .mat-mdc-form-field .mdc-notched-outline__trailing{border-radius:0 6px 6px 0!important}.c-query-bar ::ng-deep .mat-mdc-form-field:hover:not(.mat-focused):not(.mat-form-field-disabled) .mdc-notched-outline__leading,.c-query-bar ::ng-deep .mat-mdc-form-field:hover:not(.mat-focused):not(.mat-form-field-disabled) .mdc-notched-outline__notch,.c-query-bar ::ng-deep .mat-mdc-form-field:hover:not(.mat-focused):not(.mat-form-field-disabled) .mdc-notched-outline__trailing{border-color:#b9bdc3!important}.c-query-bar ::ng-deep .mat-mdc-form-field.mat-focused .mdc-notched-outline__leading,.c-query-bar ::ng-deep .mat-mdc-form-field.mat-focused .mdc-notched-outline__notch,.c-query-bar ::ng-deep .mat-mdc-form-field.mat-focused .mdc-notched-outline__trailing{border-color:var(--sd-primary)!important;border-width:1px!important}.c-query-bar ::ng-deep .mat-mdc-form-field .mat-mdc-select-arrow,.c-query-bar ::ng-deep .mat-mdc-form-field .mat-mdc-form-field-icon-suffix .mat-icon{color:#5f6368}.c-query-bar ::ng-deep .mat-mdc-form-field.mat-focused .mat-mdc-select-arrow{color:var(--sd-primary)}::ng-deep .mat-mdc-menu-panel.c-chip-popover .mat-mdc-form-field .mdc-notched-outline__leading,::ng-deep .mat-mdc-menu-panel.c-chip-popover .mat-mdc-form-field .mdc-notched-outline__notch,::ng-deep .mat-mdc-menu-panel.c-chip-popover .mat-mdc-form-field .mdc-notched-outline__trailing,::ng-deep .mat-mdc-menu-panel.c-field-picker-menu .mat-mdc-form-field .mdc-notched-outline__leading,::ng-deep .mat-mdc-menu-panel.c-field-picker-menu .mat-mdc-form-field .mdc-notched-outline__notch,::ng-deep .mat-mdc-menu-panel.c-field-picker-menu .mat-mdc-form-field .mdc-notched-outline__trailing{border-color:#d6d8db!important;transition:border-color .12s ease}::ng-deep .mat-mdc-menu-panel.c-chip-popover .mat-mdc-form-field .mdc-notched-outline__leading,::ng-deep .mat-mdc-menu-panel.c-field-picker-menu .mat-mdc-form-field .mdc-notched-outline__leading{border-radius:6px 0 0 6px!important}::ng-deep .mat-mdc-menu-panel.c-chip-popover .mat-mdc-form-field .mdc-notched-outline__trailing,::ng-deep .mat-mdc-menu-panel.c-field-picker-menu .mat-mdc-form-field .mdc-notched-outline__trailing{border-radius:0 6px 6px 0!important}::ng-deep .mat-mdc-menu-panel.c-chip-popover .mat-mdc-form-field:hover:not(.mat-focused):not(.mat-form-field-disabled) .mdc-notched-outline__leading,::ng-deep .mat-mdc-menu-panel.c-chip-popover .mat-mdc-form-field:hover:not(.mat-focused):not(.mat-form-field-disabled) .mdc-notched-outline__notch,::ng-deep .mat-mdc-menu-panel.c-chip-popover .mat-mdc-form-field:hover:not(.mat-focused):not(.mat-form-field-disabled) .mdc-notched-outline__trailing,::ng-deep .mat-mdc-menu-panel.c-field-picker-menu .mat-mdc-form-field:hover:not(.mat-focused):not(.mat-form-field-disabled) .mdc-notched-outline__leading,::ng-deep .mat-mdc-menu-panel.c-field-picker-menu .mat-mdc-form-field:hover:not(.mat-focused):not(.mat-form-field-disabled) .mdc-notched-outline__notch,::ng-deep .mat-mdc-menu-panel.c-field-picker-menu .mat-mdc-form-field:hover:not(.mat-focused):not(.mat-form-field-disabled) .mdc-notched-outline__trailing{border-color:#b9bdc3!important}::ng-deep .mat-mdc-menu-panel.c-chip-popover .mat-mdc-form-field.mat-focused .mdc-notched-outline__leading,::ng-deep .mat-mdc-menu-panel.c-chip-popover .mat-mdc-form-field.mat-focused .mdc-notched-outline__notch,::ng-deep .mat-mdc-menu-panel.c-chip-popover .mat-mdc-form-field.mat-focused .mdc-notched-outline__trailing,::ng-deep .mat-mdc-menu-panel.c-field-picker-menu .mat-mdc-form-field.mat-focused .mdc-notched-outline__leading,::ng-deep .mat-mdc-menu-panel.c-field-picker-menu .mat-mdc-form-field.mat-focused .mdc-notched-outline__notch,::ng-deep .mat-mdc-menu-panel.c-field-picker-menu .mat-mdc-form-field.mat-focused .mdc-notched-outline__trailing{border-color:var(--sd-primary)!important;border-width:1px!important}::ng-deep .mat-mdc-menu-panel.c-chip-popover .mat-mdc-form-field .mat-mdc-select-arrow,::ng-deep .mat-mdc-menu-panel.c-chip-popover .mat-mdc-form-field .mat-mdc-form-field-icon-suffix .mat-icon,::ng-deep .mat-mdc-menu-panel.c-field-picker-menu .mat-mdc-form-field .mat-mdc-select-arrow,::ng-deep .mat-mdc-menu-panel.c-field-picker-menu .mat-mdc-form-field .mat-mdc-form-field-icon-suffix .mat-icon{color:#5f6368}::ng-deep .mat-mdc-menu-panel.c-chip-popover .mat-mdc-form-field.mat-focused .mat-mdc-select-arrow,::ng-deep .mat-mdc-menu-panel.c-field-picker-menu .mat-mdc-form-field.mat-focused .mat-mdc-select-arrow{color:var(--sd-primary)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { 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: "ngmodule", type: MatIconModule }, { kind: "component", type: i1$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "directive", type: i1.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i3.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: SdQueryActionsBar, selector: "sd-query-actions-bar", inputs: ["showLogicToggle", "logic", "filtersCount", "showSavedFilters", "savedFiltersKey", "query", "showClearAll", "canSearch"], outputs: ["logicChange", "applyFilter", "clear", "search"] }, { kind: "component", type: SdQueryBuildChip, selector: "sd-query-build-chip", inputs: ["building", "density", "allowedOperators", "multiple", "showOperator", "autoId"], outputs: ["pickOperator", "commitValue", "cancel", "seamlessCommit", "draftChange", "draftCommit"] }, { kind: "component", type: SdQueryChipPopover, selector: "sd-query-chip-popover", inputs: ["field", "filter", "chipIndex", "autoIdBase", "switchPickerMenu"], outputs: ["commit", "swapField"] }, { kind: "component", type: SdQueryFieldPicker, selector: "sd-query-field-picker", inputs: ["fields", "currentKey", "usedKeys"], outputs: ["pick"] }, { kind: "component", type: SdQueryInlineChip, selector: "sd-query-inline-chip", inputs: ["field", "filter", "density", "multiple", "showOperator", "autoId", "valueText", "isNoData"], outputs: ["commit", "commitRange", "liveChange", "remove"] }, { kind: "component", type: SdQueryInlineValueChip, selector: "sd-query-inline-value-chip", inputs: ["field", "operator", "value", "density", "showOperator", "autoId", "autofocus"], outputs: ["valueChange", "remove"] }, { kind: "component", type: SdQueryPopoverChip, selector: "sd-query-popover-chip", inputs: ["field", "filter", "active", "showOperator", "valueText", "menu"], outputs: ["open", "remove"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1388
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: SdQueryBar, isStandalone: true, selector: "sd-query-bar", inputs: { option: { classPropertyName: "option", publicName: "option", isSignal: true, isRequired: false, transformFunction: null }, autoIdInput: { classPropertyName: "autoIdInput", publicName: "autoId", isSignal: true, isRequired: false, transformFunction: null }, fields: { classPropertyName: "fields", publicName: "fields", isSignal: true, isRequired: false, transformFunction: null }, filters: { classPropertyName: "filters", publicName: "filters", isSignal: true, isRequired: false, transformFunction: null }, logic: { classPropertyName: "logic", publicName: "logic", isSignal: true, isRequired: false, transformFunction: null }, search: { classPropertyName: "search", publicName: "search", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, density: { classPropertyName: "density", publicName: "density", isSignal: true, isRequired: false, transformFunction: null }, showSearch: { classPropertyName: "showSearch", publicName: "showSearch", isSignal: true, isRequired: false, transformFunction: null }, showSavedFilters: { classPropertyName: "showSavedFilters", publicName: "showSavedFilters", isSignal: true, isRequired: false, transformFunction: null }, savedFiltersKey: { classPropertyName: "savedFiltersKey", publicName: "savedFiltersKey", isSignal: true, isRequired: false, transformFunction: null }, showLogicToggle: { classPropertyName: "showLogicToggle", publicName: "showLogicToggle", isSignal: true, isRequired: false, transformFunction: null }, showClearAll: { classPropertyName: "showClearAll", publicName: "showClearAll", isSignal: true, isRequired: false, transformFunction: null }, showOperatorOnChip: { classPropertyName: "showOperatorOnChip", publicName: "showOperatorOnChip", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { filters: "filtersChange", logic: "logicChange", search: "searchChange", queryChange: "queryChange", apply: "apply" }, viewQueries: [{ propertyName: "popoverChips", predicate: SdQueryPopoverChip, descendants: true, isSignal: true }, { propertyName: "buildChip", first: true, predicate: SdQueryBuildChip, descendants: true, isSignal: true }, { propertyName: "chipPopover", first: true, predicate: SdQueryChipPopover, descendants: true, isSignal: true }], ngImport: i0, template: "<!--\r\n sd-query-bar \u2014 unified filter chip row (Jira/Linear/Notion style).\r\n Visual spec: refs/design_handoff_sd_query_bar/README.md\r\n TODO(next-iter): replace inline placeholders for field-picker + chip-popover\r\n with extracted sub-components driven by CDK overlay.\r\n-->\r\n@let _filters = filters();\n@let _fields = resolvedFields();\n@let _density = resolvedDensity();\n@let _showOr = showOrConnector();\n@let _used = usedFieldKeys();\n@let _editingIndex = editingIndex();\n@let _mode = resolvedMode();\n@let _showOpOnChip = resolvedShowOperatorOnChip();\n\r\n<div\r\n class=\"c-query-bar\"\r\n [class.c-density-compact]=\"_density === 'compact'\"\r\n [class.c-density-comfortable]=\"_density === 'comfortable'\">\r\n\r\n <!-- Main region \u2014 search + filters + add-filter. Wraps internally; the right\r\n action toolbar stays anchored and does NOT flow with this. -->\r\n <div class=\"c-query-bar__main\">\r\n\r\n <!-- Free-text search (left, optional) -->\r\n @if (resolvedShowSearch()) {\n <div class=\"c-search\">\r\n <mat-icon class=\"c-search-icon\" fontSet=\"material-icons-outlined\">search</mat-icon>\r\n <input\r\n class=\"c-search-input\"\r\n type=\"text\"\r\n [ngModel]=\"search()\"\r\n (ngModelChange)=\"setSearch($event)\"\r\n (keydown.enter)=\"triggerApply()\"\r\n placeholder=\"T\u00ECm ki\u1EBFm...\" />\r\n </div>\r\n <span class=\"c-divider\" aria-hidden=\"true\"></span>\r\n }\r\n\r\n <!-- Chip popover \u2014 extracted into <sd-query-chip-popover>. Declared BEFORE chips\r\n so the popover-mode @for chips can bind their [menu] to `chipPopover.menu()`.\r\n why: m\u1EDF popover \u0111\u1EC3 EDIT ch\u1EC9 cho ch\u1EC9nh operator + value \u2014 KH\u00D4NG \u0111\u1ED5i field.\r\n B\u1ECF [switchPickerMenu] \u2192 header render nh\u00E3n field t\u0129nh (read-only). Mu\u1ED1n \u0111\u1ED5i\r\n field th\u00EC xo\u00E1 chip r\u1ED3i th\u00EAm l\u1EA1i. -->\r\n <sd-query-chip-popover\r\n #chipPopover\r\n [field]=\"editingField() ?? undefined\"\r\n [filter]=\"_editingIndex !== null ? $any(_filters[_editingIndex!]) : undefined\"\r\n [chipIndex]=\"_editingIndex\"\r\n [autoIdBase]=\"resolvedAutoId() ?? 'qb'\"\n (commit)=\"onChipPopoverCommit($event)\" />\r\n\r\n @if (_mode === 'inline') {\r\n <!-- ===== INLINE MODE (GitLab-style token builder) ===== -->\r\n\r\n <!-- Completed chips -->\r\n @for (filter of _filters; track $index; let i = $index) {\r\n @if (_showOr && i > 0) {\r\n <span class=\"c-or-connector\" aria-hidden=\"true\">OR</span>\r\n }\r\n @let _field = fieldByKey()[$any(filter).field];\r\n @if (_field) {\r\n @let _op = $any(filter.operator);\r\n @let _data = $any(filter).data;\r\n @if (_field.type === 'string' || _field.type === 'number') {\r\n <!-- Seamless chip \u2014 the pill is the input (string / number). -->\r\n <sd-query-inline-value-chip\r\n [field]=\"_field\"\r\n [operator]=\"_op\"\r\n [value]=\"_data\"\r\n [density]=\"_density\"\r\n [showOperator]=\"_showOpOnChip\"\r\n [autoId]=\"inlineAutoId(i, 'value')\"\r\n (valueChange)=\"updateFilter(i, { data: $event })\"\r\n (remove)=\"removeFilter(i)\" />\r\n } @else {\r\n <sd-query-inline-chip\r\n [field]=\"_field\"\r\n [filter]=\"filter\"\r\n [density]=\"_density\"\r\n [multiple]=\"multiple(_op)\"\r\n [showOperator]=\"_showOpOnChip\"\r\n [autoId]=\"inlineAutoId(i, 'value')\"\r\n [valueText]=\"chipValueText(filter)\"\r\n [isNoData]=\"isNoDataOperator(_op)\"\r\n (commit)=\"updateFilter(i, { data: $event })\"\r\n (commitRange)=\"setFilterRange(i, $event)\"\r\n (liveChange)=\"updateFilter(i, { data: $event })\"\r\n (remove)=\"removeFilter(i)\" />\r\n }\r\n }\r\n }\r\n\r\n <!-- Building chip (in-progress) \u2014 extracted into <sd-query-build-chip>. -->\r\n @if (building(); as _b) {\r\n <sd-query-build-chip\r\n [building]=\"_b\"\r\n [density]=\"_density\"\r\n [allowedOperators]=\"allowedOperatorsFor(_b.field)\"\r\n [multiple]=\"multiple($any(_b.operator))\"\r\n [showOperator]=\"_showOpOnChip\"\r\n (pickOperator)=\"pickBuildOperator($any($event))\"\r\n (commitValue)=\"commitBuildValue($event)\"\r\n (cancel)=\"cancelBuild()\"\r\n (seamlessCommit)=\"onBuildSeamlessCommit($event)\" />\r\n }\r\n\r\n <!-- Add filter -->\r\n <button\r\n type=\"button\"\r\n class=\"c-add-filter\"\r\n [matMenuTriggerFor]=\"addPicker.menu()\"\r\n [disabled]=\"_fields.length === 0 || _used.size >= _fields.length\"\r\n [matTooltip]=\"_fields.length === 0 ? 'Ch\u01B0a c\u1EA5u h\u00ECnh fields' : 'Th\u00EAm filter'\">\r\n <mat-icon fontSet=\"material-icons-outlined\">add</mat-icon>\r\n </button>\r\n } @else {\r\n <!-- ===== POPOVER MODE (default) \u2014 compact chips edited via mat-menu ===== -->\r\n @for (filter of _filters; track $index; let i = $index) {\r\n @if (_showOr && i > 0) {\r\n <span class=\"c-or-connector\" aria-hidden=\"true\">OR</span>\r\n }\r\n @let _field = fieldByKey()[$any(filter).field];\r\n @let _active = isFilterActive(filter);\r\n <!-- why: menu close commit is handled by chipPopover's (commit) \u2192\r\n onChipPopoverCommit; popover-chip only signals open + remove here. -->\r\n <sd-query-popover-chip\r\n [field]=\"_field\"\r\n [filter]=\"filter\"\r\n [active]=\"_active\"\r\n [showOperator]=\"_showOpOnChip\"\r\n [valueText]=\"chipValueText(filter)\"\r\n [menu]=\"chipPopover.menu()!\"\r\n (open)=\"openChipPopover(i)\"\r\n (remove)=\"removeFilter(i)\" />\r\n }\r\n\r\n <!-- Add filter trigger -->\r\n <button\r\n type=\"button\"\r\n class=\"c-add-filter\"\r\n [matMenuTriggerFor]=\"addPicker.menu()\"\r\n [disabled]=\"_fields.length === 0 || _used.size >= _fields.length\"\r\n [matTooltip]=\"_fields.length === 0 ? 'Ch\u01B0a c\u1EA5u h\u00ECnh fields' : 'Th\u00EAm filter'\">\r\n <mat-icon fontSet=\"material-icons-outlined\">add</mat-icon>\r\n </button>\r\n }\r\n\r\n </div><!-- /.c-query-bar__main -->\r\n\r\n <!-- Field picker \u2014 list available fields, fade ones already in use. -->\r\n <sd-query-field-picker\r\n #addPicker\r\n [fields]=\"_fields\"\r\n [usedKeys]=\"_used\"\r\n (pick)=\"_mode === 'inline' ? beginBuild($event) : addFilter($event)\" />\r\n\r\n <sd-query-actions-bar\r\n [showLogicToggle]=\"resolvedShowLogicToggle()\"\n [(logic)]=\"logic\"\r\n [filtersCount]=\"_filters.length\"\r\n [showSavedFilters]=\"resolvedShowSavedFilters()\"\n [savedFiltersKey]=\"resolvedSavedFiltersKey()\"\n [query]=\"currentQuery()\"\r\n (applyFilter)=\"onApplyFilter($event)\"\r\n [showClearAll]=\"resolvedShowClearAll()\"\n [canSearch]=\"canSearch()\"\r\n (clear)=\"clearAll()\"\r\n (search)=\"triggerApply()\" />\r\n</div>\r\n", styles: [":host{display:block;font-family:Roboto,system-ui,sans-serif}.c-query-bar{display:flex;align-items:flex-start;flex-wrap:nowrap;gap:8px;background:#fff;border:1px solid #e2e4e7;border-radius:8px;box-shadow:0 1px 2px #0f172a0a}.c-query-bar.c-density-compact{padding:8px}.c-query-bar.c-density-comfortable{padding:10px}.c-query-bar__main{flex:1 1 auto;min-width:0;display:flex;align-items:center;flex-wrap:wrap;gap:6px}.c-search{display:flex;align-items:center;gap:6px;min-width:220px;padding:0 10px;border:1px solid #d6d8db;border-radius:6px;background:#fff}.c-density-compact .c-search{height:28px}.c-density-comfortable .c-search{height:32px}.c-search .c-search-icon{font-size:16px;width:16px;height:16px;color:#7a7a7a}.c-search .c-search-input{flex:1;border:none;outline:none;background:transparent;font-size:13px;color:#212121}.c-search .c-search-input::placeholder{color:#7a7a7a}.c-search .c-search-kbd{font-family:Roboto Mono,monospace;font-size:10px;padding:1px 4px;border:1px solid #e2e4e7;border-radius:3px;color:#7a7a7a}.c-divider{width:1px;height:16px;background:#e2e4e7;margin:0 2px}.c-token{display:inline-flex;align-items:center;gap:4px;padding:0 0 0 12px;border:1px solid var(--sd-primary-light);border-radius:999px;background:var(--sd-primary-light);font-size:13px;color:#5f6368;white-space:nowrap;overflow:hidden}.c-density-compact .c-token{height:28px}.c-density-comfortable .c-token{height:32px}.c-token-icon{font-size:14px;width:14px;height:14px;line-height:14px;color:inherit}.c-token-field{font-weight:500;line-height:1}.c-token-op{display:inline-flex;align-items:center;color:inherit}.c-token-op ::ng-deep .c-op-trigger{padding:0;color:inherit}.c-token-op ::ng-deep .c-op-icon svg{width:14px;height:14px;display:block}.c-token-value-edit sd-select,.c-token-value-edit sd-date,.c-token-value-edit sd-datetime{display:inline-flex;align-items:center;line-height:1}.c-token ::ng-deep .mat-mdc-form-field{line-height:1}.c-token ::ng-deep .mat-mdc-text-field-wrapper,.c-token ::ng-deep .mat-mdc-form-field-flex{padding:0;min-height:0;background:transparent}.c-token ::ng-deep .mat-mdc-form-field-infix{padding:0;min-height:0;width:auto;border:0;display:inline-flex;align-items:center}.c-token ::ng-deep .mat-mdc-select-value,.c-token ::ng-deep .mat-mdc-input-element,.c-token ::ng-deep input{line-height:1;font-size:13px;padding:0;height:auto;color:inherit}.c-token ::ng-deep .mat-mdc-select-value{display:inline-flex;align-items:center;min-width:0;max-width:200px;overflow:hidden;text-overflow:ellipsis;color:var(--sd-primary);font-weight:500}.c-token ::ng-deep .sd-suffix-icon{display:none}.c-token-sep{color:#7a7a7a}.c-token-dash{color:#7a7a7a;padding:0 4px;line-height:1}.c-token-value{border:none;background:transparent;padding:0;font:inherit;font-weight:500;color:var(--sd-primary);cursor:pointer}.c-token-value:hover{text-decoration:underline}.c-token-value-edit{display:inline-flex;align-items:center;gap:4px;max-width:240px}.c-token-value-edit sd-input,.c-token-value-edit sd-input-number{display:inline-flex;max-width:140px}.c-token-value-edit sd-date-range{display:inline-flex;max-width:220px;min-width:0;flex:0 1 auto}.c-token-multi-head{display:inline-block;max-width:140px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:bottom}.c-token-remove{align-self:stretch;display:inline-flex;align-items:center;justify-content:center;border:none;border-left:1px solid rgba(0,0,0,.04);border-radius:0;background:transparent;cursor:pointer;color:inherit}.c-density-compact .c-token-remove{width:26px}.c-density-comfortable .c-token-remove{width:28px}.c-token-remove mat-icon{font-size:14px;width:14px;height:14px}.c-token-remove:hover{background:#0000000d}.c-add-filter{display:inline-flex;align-items:center;justify-content:center;padding:0;border-radius:999px;border:1px dashed #d6d8db;background:transparent;cursor:pointer;color:#5f6368;transition:border-color .12s ease,color .12s ease,background-color .12s ease}.c-density-compact .c-add-filter{width:28px;height:28px}.c-density-comfortable .c-add-filter{width:32px;height:32px}.c-add-filter mat-icon{font-size:18px;width:18px;height:18px}.c-add-filter:hover:not([disabled]){border-color:var(--sd-primary);color:var(--sd-primary)}.c-add-filter[disabled]{opacity:.5;cursor:not-allowed}.c-or-connector{font-family:Roboto Mono,monospace;font-size:10px;font-weight:700;letter-spacing:.6px;color:#7a7a7a;padding:0 2px}::ng-deep .mat-mdc-menu-panel.c-chip-popover{min-width:280px;max-width:320px}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-header{display:flex;align-items:center;gap:8px;padding:10px 12px;border-bottom:1px solid #e2e4e7;font-size:13px;font-weight:500;color:#212121}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-header mat-icon{font-size:16px;width:16px;height:16px;color:var(--sd-primary)}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-header .c-pop-header-operator{margin-left:auto}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-header-field{display:inline-flex;align-items:center;gap:4px;padding:2px 4px 2px 6px;margin-left:-4px;background:transparent;border:1px solid transparent;border-radius:4px;font:inherit;font-weight:500;color:#212121;cursor:pointer;transition:background-color .12s ease,border-color .12s ease}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-header-field mat-icon{font-size:14px!important;width:14px!important;height:14px!important;color:#7a7a7a!important}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-header-field:hover{background:#f5f6f7;border-color:#e2e4e7}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-body{padding:10px 12px;display:flex;flex-direction:column;gap:12px}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-input{width:100%;height:32px;padding:0 10px;border:1px solid #d6d8db;border-radius:6px;background:#fff;font-family:inherit;font-size:13px;color:#212121;outline:none}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-input:focus{border-color:var(--sd-primary)}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-between{display:grid;grid-template-columns:1fr 1fr;gap:8px}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-boolean{display:flex;gap:8px}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-boolean button{flex:1;height:32px;border:1px solid #d6d8db;border-radius:6px;background:#fff;font:inherit;font-size:13px;cursor:pointer}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-boolean button.c-pop-boolean-active{background:var(--sd-primary-light);border-color:var(--sd-primary);color:var(--sd-primary)}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-values{max-height:220px;overflow-y:auto;margin:0;padding:0;list-style:none}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-values li{display:flex;align-items:center;gap:8px;padding:6px 8px;border-radius:4px;font-size:13px;cursor:pointer;-webkit-user-select:none;user-select:none}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-values li:hover{background:#f5f6f7}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-values li.c-pop-value-selected{background:var(--sd-primary-light);color:var(--sd-primary)}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-values li input[type=checkbox],::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-values li input[type=radio]{accent-color:var(--sd-primary)}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-values-loading,::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-values-empty{padding:10px 8px;font-size:12px;color:#7a7a7a}.c-bool-toggle{display:inline-flex;align-items:center;gap:4px}.c-bool-toggle ::ng-deep .mdc-button,.c-bool-toggle ::ng-deep button[mat-button],.c-bool-toggle ::ng-deep button[mat-stroked-button],.c-bool-toggle ::ng-deep button[mat-flat-button]{border-radius:999px;min-width:0;padding:0 12px}\n", ".c-query-bar ::ng-deep .mat-mdc-form-field .mdc-notched-outline__leading,.c-query-bar ::ng-deep .mat-mdc-form-field .mdc-notched-outline__notch,.c-query-bar ::ng-deep .mat-mdc-form-field .mdc-notched-outline__trailing{border-color:#d6d8db!important;transition:border-color .12s ease}.c-query-bar ::ng-deep .mat-mdc-form-field .mdc-notched-outline__leading{border-radius:6px 0 0 6px!important}.c-query-bar ::ng-deep .mat-mdc-form-field .mdc-notched-outline__trailing{border-radius:0 6px 6px 0!important}.c-query-bar ::ng-deep .mat-mdc-form-field:hover:not(.mat-focused):not(.mat-form-field-disabled) .mdc-notched-outline__leading,.c-query-bar ::ng-deep .mat-mdc-form-field:hover:not(.mat-focused):not(.mat-form-field-disabled) .mdc-notched-outline__notch,.c-query-bar ::ng-deep .mat-mdc-form-field:hover:not(.mat-focused):not(.mat-form-field-disabled) .mdc-notched-outline__trailing{border-color:#b9bdc3!important}.c-query-bar ::ng-deep .mat-mdc-form-field.mat-focused .mdc-notched-outline__leading,.c-query-bar ::ng-deep .mat-mdc-form-field.mat-focused .mdc-notched-outline__notch,.c-query-bar ::ng-deep .mat-mdc-form-field.mat-focused .mdc-notched-outline__trailing{border-color:var(--sd-primary)!important;border-width:1px!important}.c-query-bar ::ng-deep .mat-mdc-form-field .mat-mdc-select-arrow,.c-query-bar ::ng-deep .mat-mdc-form-field .mat-mdc-form-field-icon-suffix .mat-icon{color:#5f6368}.c-query-bar ::ng-deep .mat-mdc-form-field.mat-focused .mat-mdc-select-arrow{color:var(--sd-primary)}::ng-deep .mat-mdc-menu-panel.c-chip-popover .mat-mdc-form-field .mdc-notched-outline__leading,::ng-deep .mat-mdc-menu-panel.c-chip-popover .mat-mdc-form-field .mdc-notched-outline__notch,::ng-deep .mat-mdc-menu-panel.c-chip-popover .mat-mdc-form-field .mdc-notched-outline__trailing,::ng-deep .mat-mdc-menu-panel.c-field-picker-menu .mat-mdc-form-field .mdc-notched-outline__leading,::ng-deep .mat-mdc-menu-panel.c-field-picker-menu .mat-mdc-form-field .mdc-notched-outline__notch,::ng-deep .mat-mdc-menu-panel.c-field-picker-menu .mat-mdc-form-field .mdc-notched-outline__trailing{border-color:#d6d8db!important;transition:border-color .12s ease}::ng-deep .mat-mdc-menu-panel.c-chip-popover .mat-mdc-form-field .mdc-notched-outline__leading,::ng-deep .mat-mdc-menu-panel.c-field-picker-menu .mat-mdc-form-field .mdc-notched-outline__leading{border-radius:6px 0 0 6px!important}::ng-deep .mat-mdc-menu-panel.c-chip-popover .mat-mdc-form-field .mdc-notched-outline__trailing,::ng-deep .mat-mdc-menu-panel.c-field-picker-menu .mat-mdc-form-field .mdc-notched-outline__trailing{border-radius:0 6px 6px 0!important}::ng-deep .mat-mdc-menu-panel.c-chip-popover .mat-mdc-form-field:hover:not(.mat-focused):not(.mat-form-field-disabled) .mdc-notched-outline__leading,::ng-deep .mat-mdc-menu-panel.c-chip-popover .mat-mdc-form-field:hover:not(.mat-focused):not(.mat-form-field-disabled) .mdc-notched-outline__notch,::ng-deep .mat-mdc-menu-panel.c-chip-popover .mat-mdc-form-field:hover:not(.mat-focused):not(.mat-form-field-disabled) .mdc-notched-outline__trailing,::ng-deep .mat-mdc-menu-panel.c-field-picker-menu .mat-mdc-form-field:hover:not(.mat-focused):not(.mat-form-field-disabled) .mdc-notched-outline__leading,::ng-deep .mat-mdc-menu-panel.c-field-picker-menu .mat-mdc-form-field:hover:not(.mat-focused):not(.mat-form-field-disabled) .mdc-notched-outline__notch,::ng-deep .mat-mdc-menu-panel.c-field-picker-menu .mat-mdc-form-field:hover:not(.mat-focused):not(.mat-form-field-disabled) .mdc-notched-outline__trailing{border-color:#b9bdc3!important}::ng-deep .mat-mdc-menu-panel.c-chip-popover .mat-mdc-form-field.mat-focused .mdc-notched-outline__leading,::ng-deep .mat-mdc-menu-panel.c-chip-popover .mat-mdc-form-field.mat-focused .mdc-notched-outline__notch,::ng-deep .mat-mdc-menu-panel.c-chip-popover .mat-mdc-form-field.mat-focused .mdc-notched-outline__trailing,::ng-deep .mat-mdc-menu-panel.c-field-picker-menu .mat-mdc-form-field.mat-focused .mdc-notched-outline__leading,::ng-deep .mat-mdc-menu-panel.c-field-picker-menu .mat-mdc-form-field.mat-focused .mdc-notched-outline__notch,::ng-deep .mat-mdc-menu-panel.c-field-picker-menu .mat-mdc-form-field.mat-focused .mdc-notched-outline__trailing{border-color:var(--sd-primary)!important;border-width:1px!important}::ng-deep .mat-mdc-menu-panel.c-chip-popover .mat-mdc-form-field .mat-mdc-select-arrow,::ng-deep .mat-mdc-menu-panel.c-chip-popover .mat-mdc-form-field .mat-mdc-form-field-icon-suffix .mat-icon,::ng-deep .mat-mdc-menu-panel.c-field-picker-menu .mat-mdc-form-field .mat-mdc-select-arrow,::ng-deep .mat-mdc-menu-panel.c-field-picker-menu .mat-mdc-form-field .mat-mdc-form-field-icon-suffix .mat-icon{color:#5f6368}::ng-deep .mat-mdc-menu-panel.c-chip-popover .mat-mdc-form-field.mat-focused .mat-mdc-select-arrow,::ng-deep .mat-mdc-menu-panel.c-field-picker-menu .mat-mdc-form-field.mat-focused .mat-mdc-select-arrow{color:var(--sd-primary)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { 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: "ngmodule", type: MatIconModule }, { kind: "component", type: i1$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "directive", type: i1.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i3.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: SdQueryActionsBar, selector: "sd-query-actions-bar", inputs: ["showLogicToggle", "logic", "filtersCount", "showSavedFilters", "savedFiltersKey", "query", "showClearAll", "canSearch"], outputs: ["logicChange", "applyFilter", "clear", "search"] }, { kind: "component", type: SdQueryBuildChip, selector: "sd-query-build-chip", inputs: ["building", "density", "allowedOperators", "multiple", "showOperator", "autoId"], outputs: ["pickOperator", "commitValue", "cancel", "seamlessCommit", "draftChange", "draftCommit"] }, { kind: "component", type: SdQueryChipPopover, selector: "sd-query-chip-popover", inputs: ["field", "filter", "chipIndex", "autoIdBase", "switchPickerMenu"], outputs: ["commit", "swapField"] }, { kind: "component", type: SdQueryFieldPicker, selector: "sd-query-field-picker", inputs: ["fields", "currentKey", "usedKeys"], outputs: ["pick"] }, { kind: "component", type: SdQueryInlineChip, selector: "sd-query-inline-chip", inputs: ["field", "filter", "density", "multiple", "showOperator", "autoId", "valueText", "isNoData"], outputs: ["commit", "commitRange", "liveChange", "remove"] }, { kind: "component", type: SdQueryInlineValueChip, selector: "sd-query-inline-value-chip", inputs: ["field", "operator", "value", "density", "showOperator", "autoId", "autofocus"], outputs: ["valueChange", "remove"] }, { kind: "component", type: SdQueryPopoverChip, selector: "sd-query-popover-chip", inputs: ["field", "filter", "active", "showOperator", "valueText", "menu"], outputs: ["open", "remove"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1360
1389
  }
1361
1390
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SdQueryBar, decorators: [{
1362
1391
  type: Component,
@@ -1373,8 +1402,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImpo
1373
1402
  SdQueryInlineChip,
1374
1403
  SdQueryInlineValueChip,
1375
1404
  SdQueryPopoverChip,
1376
- ], template: "<!--\n sd-query-bar \u2014 unified filter chip row (Jira/Linear/Notion style).\n Visual spec: refs/design_handoff_sd_query_bar/README.md\n TODO(next-iter): replace inline placeholders for field-picker + chip-popover\n with extracted sub-components driven by CDK overlay.\n-->\n@let _filters = filters();\n@let _fields = fields();\n@let _density = density();\n@let _showOr = showOrConnector();\n@let _used = usedFieldKeys();\n@let _editingIndex = editingIndex();\n@let _mode = mode();\n@let _showOpOnChip = showOperatorOnChip();\n\n<div\n class=\"c-query-bar\"\n [class.c-density-compact]=\"_density === 'compact'\"\n [class.c-density-comfortable]=\"_density === 'comfortable'\">\n\n <!-- Main region \u2014 search + filters + add-filter. Wraps internally; the right\n action toolbar stays anchored and does NOT flow with this. -->\n <div class=\"c-query-bar__main\">\n\n <!-- Free-text search (left, optional) -->\n @if (showSearch()) {\n <div class=\"c-search\">\n <mat-icon class=\"c-search-icon\" fontSet=\"material-icons-outlined\">search</mat-icon>\n <input\n class=\"c-search-input\"\n type=\"text\"\n [ngModel]=\"search()\"\n (ngModelChange)=\"setSearch($event)\"\n (keydown.enter)=\"triggerApply()\"\n placeholder=\"T\u00ECm ki\u1EBFm...\" />\n </div>\n <span class=\"c-divider\" aria-hidden=\"true\"></span>\n }\n\n <!-- Field switcher (used by chipPopover header) \u2014 declared first so chipPopover's\n nested ng-template can resolve the template ref. -->\n <!-- Field switcher used by chipPopover header \u2014 current field key comes from editingIndex. -->\n <sd-query-field-picker\n #switchPicker\n [fields]=\"_fields\"\n [currentKey]=\"_editingIndex !== null ? $any(_filters[_editingIndex!])?.field : undefined\"\n (pick)=\"_editingIndex !== null && changeFilterField(_editingIndex!, $event)\" />\n\n <!-- Chip popover \u2014 extracted into <sd-query-chip-popover>. Declared BEFORE chips\n so the popover-mode @for chips can bind their [menu] to `chipPopover.menu()`. -->\n <sd-query-chip-popover\n #chipPopover\n [field]=\"editingField() ?? undefined\"\n [filter]=\"_editingIndex !== null ? $any(_filters[_editingIndex!]) : undefined\"\n [chipIndex]=\"_editingIndex\"\n [autoIdBase]=\"autoIdInput() ?? 'qb'\"\n [switchPickerMenu]=\"switchPicker.menu()!\"\n (commit)=\"onChipPopoverCommit($event)\"\n (swapField)=\"_editingIndex !== null && changeFilterField(_editingIndex!, $event)\" />\n\n @if (_mode === 'inline') {\n <!-- ===== INLINE MODE (GitLab-style token builder) ===== -->\n\n <!-- Completed chips -->\n @for (filter of _filters; track $index; let i = $index) {\n @if (_showOr && i > 0) {\n <span class=\"c-or-connector\" aria-hidden=\"true\">OR</span>\n }\n @let _field = fieldByKey()[$any(filter).field];\n @if (_field) {\n @let _op = $any(filter.operator);\n @let _data = $any(filter).data;\n @if (_field.type === 'string' || _field.type === 'number') {\n <!-- Seamless chip \u2014 the pill is the input (string / number). -->\n <sd-query-inline-value-chip\n [field]=\"_field\"\n [operator]=\"_op\"\n [value]=\"_data\"\n [density]=\"_density\"\n [showOperator]=\"_showOpOnChip\"\n [autoId]=\"inlineAutoId(i, 'value')\"\n (valueChange)=\"updateFilter(i, { data: $event })\"\n (remove)=\"removeFilter(i)\" />\n } @else {\n <sd-query-inline-chip\n [field]=\"_field\"\n [filter]=\"filter\"\n [density]=\"_density\"\n [multiple]=\"multiple(_op)\"\n [showOperator]=\"_showOpOnChip\"\n [autoId]=\"inlineAutoId(i, 'value')\"\n [valueText]=\"chipValueText(filter)\"\n [isNoData]=\"isNoDataOperator(_op)\"\n (commit)=\"updateFilter(i, { data: $event })\"\n (commitRange)=\"setFilterRange(i, $event)\"\n (liveChange)=\"updateFilter(i, { data: $event })\"\n (remove)=\"removeFilter(i)\" />\n }\n }\n }\n\n <!-- Building chip (in-progress) \u2014 extracted into <sd-query-build-chip>. -->\n @if (building(); as _b) {\n <sd-query-build-chip\n [building]=\"_b\"\n [density]=\"_density\"\n [allowedOperators]=\"allowedOperatorsFor(_b.field)\"\n [multiple]=\"multiple($any(_b.operator))\"\n [showOperator]=\"_showOpOnChip\"\n (pickOperator)=\"pickBuildOperator($any($event))\"\n (commitValue)=\"commitBuildValue($event)\"\n (cancel)=\"cancelBuild()\"\n (seamlessCommit)=\"onBuildSeamlessCommit($event)\" />\n }\n\n <!-- Add filter -->\n <button\n type=\"button\"\n class=\"c-add-filter\"\n [matMenuTriggerFor]=\"addPicker.menu()\"\n [disabled]=\"_fields.length === 0 || _used.size >= _fields.length\"\n [matTooltip]=\"_fields.length === 0 ? 'Ch\u01B0a c\u1EA5u h\u00ECnh fields' : 'Th\u00EAm filter'\">\n <mat-icon fontSet=\"material-icons-outlined\">add</mat-icon>\n </button>\n } @else {\n <!-- ===== POPOVER MODE (default) \u2014 compact chips edited via mat-menu ===== -->\n @for (filter of _filters; track $index; let i = $index) {\n @if (_showOr && i > 0) {\n <span class=\"c-or-connector\" aria-hidden=\"true\">OR</span>\n }\n @let _field = fieldByKey()[$any(filter).field];\n @let _active = isFilterActive(filter);\n <!-- why: menu close commit is handled by chipPopover's (commit) \u2192\n onChipPopoverCommit; popover-chip only signals open + remove here. -->\n <sd-query-popover-chip\n [field]=\"_field\"\n [filter]=\"filter\"\n [active]=\"_active\"\n [showOperator]=\"_showOpOnChip\"\n [valueText]=\"chipValueText(filter)\"\n [menu]=\"chipPopover.menu()!\"\n (open)=\"openChipPopover(i)\"\n (remove)=\"removeFilter(i)\" />\n }\n\n <!-- Add filter trigger -->\n <button\n type=\"button\"\n class=\"c-add-filter\"\n [matMenuTriggerFor]=\"addPicker.menu()\"\n [disabled]=\"_fields.length === 0 || _used.size >= _fields.length\"\n [matTooltip]=\"_fields.length === 0 ? 'Ch\u01B0a c\u1EA5u h\u00ECnh fields' : 'Th\u00EAm filter'\">\n <mat-icon fontSet=\"material-icons-outlined\">add</mat-icon>\n </button>\n }\n\n </div><!-- /.c-query-bar__main -->\n\n <!-- Field picker \u2014 list available fields, fade ones already in use. -->\n <sd-query-field-picker\n #addPicker\n [fields]=\"_fields\"\n [usedKeys]=\"_used\"\n (pick)=\"_mode === 'inline' ? beginBuild($event) : addFilter($event)\" />\n\n <sd-query-actions-bar\n [showLogicToggle]=\"showLogicToggle()\"\n [(logic)]=\"logic\"\n [filtersCount]=\"_filters.length\"\n [showSavedFilters]=\"showSavedFilters()\"\n [savedFiltersKey]=\"savedFiltersKey()\"\n [query]=\"currentQuery()\"\n (applyFilter)=\"onApplyFilter($event)\"\n [showClearAll]=\"showClearAll()\"\n [canSearch]=\"canSearch()\"\n (clear)=\"clearAll()\"\n (search)=\"triggerApply()\" />\n</div>\n", styles: [":host{display:block;font-family:Roboto,system-ui,sans-serif}.c-query-bar{display:flex;align-items:flex-start;flex-wrap:nowrap;gap:8px;background:#fff;border:1px solid #e2e4e7;border-radius:8px;box-shadow:0 1px 2px #0f172a0a}.c-query-bar.c-density-compact{padding:8px}.c-query-bar.c-density-comfortable{padding:10px}.c-query-bar__main{flex:1 1 auto;min-width:0;display:flex;align-items:center;flex-wrap:wrap;gap:6px}.c-search{display:flex;align-items:center;gap:6px;min-width:220px;padding:0 10px;border:1px solid #d6d8db;border-radius:6px;background:#fff}.c-density-compact .c-search{height:28px}.c-density-comfortable .c-search{height:32px}.c-search .c-search-icon{font-size:16px;width:16px;height:16px;color:#7a7a7a}.c-search .c-search-input{flex:1;border:none;outline:none;background:transparent;font-size:13px;color:#212121}.c-search .c-search-input::placeholder{color:#7a7a7a}.c-search .c-search-kbd{font-family:Roboto Mono,monospace;font-size:10px;padding:1px 4px;border:1px solid #e2e4e7;border-radius:3px;color:#7a7a7a}.c-divider{width:1px;height:16px;background:#e2e4e7;margin:0 2px}.c-token{display:inline-flex;align-items:center;gap:4px;padding:0 0 0 12px;border:1px solid var(--sd-primary-light);border-radius:999px;background:var(--sd-primary-light);font-size:13px;color:#5f6368;white-space:nowrap;overflow:hidden}.c-density-compact .c-token{height:28px}.c-density-comfortable .c-token{height:32px}.c-token-icon{font-size:14px;width:14px;height:14px;line-height:14px;color:inherit}.c-token-field{font-weight:500;line-height:1}.c-token-op{display:inline-flex;align-items:center;color:inherit}.c-token-op ::ng-deep .c-op-trigger{padding:0;color:inherit}.c-token-op ::ng-deep .c-op-icon svg{width:14px;height:14px;display:block}.c-token-value-edit sd-select,.c-token-value-edit sd-date,.c-token-value-edit sd-datetime{display:inline-flex;align-items:center;line-height:1}.c-token ::ng-deep .mat-mdc-form-field{line-height:1}.c-token ::ng-deep .mat-mdc-text-field-wrapper,.c-token ::ng-deep .mat-mdc-form-field-flex{padding:0;min-height:0;background:transparent}.c-token ::ng-deep .mat-mdc-form-field-infix{padding:0;min-height:0;width:auto;border:0;display:inline-flex;align-items:center}.c-token ::ng-deep .mat-mdc-select-value,.c-token ::ng-deep .mat-mdc-input-element,.c-token ::ng-deep input{line-height:1;font-size:13px;padding:0;height:auto;color:inherit}.c-token ::ng-deep .mat-mdc-select-value{display:inline-flex;align-items:center;min-width:0;max-width:200px;overflow:hidden;text-overflow:ellipsis;color:var(--sd-primary);font-weight:500}.c-token ::ng-deep .sd-suffix-icon{display:none}.c-token-sep{color:#7a7a7a}.c-token-dash{color:#7a7a7a;padding:0 4px;line-height:1}.c-token-value{border:none;background:transparent;padding:0;font:inherit;font-weight:500;color:var(--sd-primary);cursor:pointer}.c-token-value:hover{text-decoration:underline}.c-token-value-edit{display:inline-flex;align-items:center;gap:4px;max-width:240px}.c-token-value-edit sd-input,.c-token-value-edit sd-input-number{display:inline-flex;max-width:140px}.c-token-value-edit sd-date-range{display:inline-flex;max-width:220px;min-width:0;flex:0 1 auto}.c-token-multi-head{display:inline-block;max-width:140px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:bottom}.c-token-remove{align-self:stretch;display:inline-flex;align-items:center;justify-content:center;border:none;border-left:1px solid rgba(0,0,0,.04);border-radius:0;background:transparent;cursor:pointer;color:inherit}.c-density-compact .c-token-remove{width:26px}.c-density-comfortable .c-token-remove{width:28px}.c-token-remove mat-icon{font-size:14px;width:14px;height:14px}.c-token-remove:hover{background:#0000000d}.c-add-filter{display:inline-flex;align-items:center;justify-content:center;padding:0;border-radius:999px;border:1px dashed #d6d8db;background:transparent;cursor:pointer;color:#5f6368;transition:border-color .12s ease,color .12s ease,background-color .12s ease}.c-density-compact .c-add-filter{width:28px;height:28px}.c-density-comfortable .c-add-filter{width:32px;height:32px}.c-add-filter mat-icon{font-size:18px;width:18px;height:18px}.c-add-filter:hover:not([disabled]){border-color:var(--sd-primary);color:var(--sd-primary)}.c-add-filter[disabled]{opacity:.5;cursor:not-allowed}.c-or-connector{font-family:Roboto Mono,monospace;font-size:10px;font-weight:700;letter-spacing:.6px;color:#7a7a7a;padding:0 2px}::ng-deep .mat-mdc-menu-panel.c-chip-popover{min-width:280px;max-width:320px}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-header{display:flex;align-items:center;gap:8px;padding:10px 12px;border-bottom:1px solid #e2e4e7;font-size:13px;font-weight:500;color:#212121}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-header mat-icon{font-size:16px;width:16px;height:16px;color:var(--sd-primary)}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-header .c-pop-header-operator{margin-left:auto}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-header-field{display:inline-flex;align-items:center;gap:4px;padding:2px 4px 2px 6px;margin-left:-4px;background:transparent;border:1px solid transparent;border-radius:4px;font:inherit;font-weight:500;color:#212121;cursor:pointer;transition:background-color .12s ease,border-color .12s ease}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-header-field mat-icon{font-size:14px!important;width:14px!important;height:14px!important;color:#7a7a7a!important}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-header-field:hover{background:#f5f6f7;border-color:#e2e4e7}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-body{padding:10px 12px;display:flex;flex-direction:column;gap:12px}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-input{width:100%;height:32px;padding:0 10px;border:1px solid #d6d8db;border-radius:6px;background:#fff;font-family:inherit;font-size:13px;color:#212121;outline:none}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-input:focus{border-color:var(--sd-primary)}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-between{display:grid;grid-template-columns:1fr 1fr;gap:8px}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-boolean{display:flex;gap:8px}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-boolean button{flex:1;height:32px;border:1px solid #d6d8db;border-radius:6px;background:#fff;font:inherit;font-size:13px;cursor:pointer}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-boolean button.c-pop-boolean-active{background:var(--sd-primary-light);border-color:var(--sd-primary);color:var(--sd-primary)}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-values{max-height:220px;overflow-y:auto;margin:0;padding:0;list-style:none}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-values li{display:flex;align-items:center;gap:8px;padding:6px 8px;border-radius:4px;font-size:13px;cursor:pointer;-webkit-user-select:none;user-select:none}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-values li:hover{background:#f5f6f7}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-values li.c-pop-value-selected{background:var(--sd-primary-light);color:var(--sd-primary)}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-values li input[type=checkbox],::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-values li input[type=radio]{accent-color:var(--sd-primary)}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-values-loading,::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-values-empty{padding:10px 8px;font-size:12px;color:#7a7a7a}.c-bool-toggle{display:inline-flex;align-items:center;gap:4px}.c-bool-toggle ::ng-deep .mdc-button,.c-bool-toggle ::ng-deep button[mat-button],.c-bool-toggle ::ng-deep button[mat-stroked-button],.c-bool-toggle ::ng-deep button[mat-flat-button]{border-radius:999px;min-width:0;padding:0 12px}\n", ".c-query-bar ::ng-deep .mat-mdc-form-field .mdc-notched-outline__leading,.c-query-bar ::ng-deep .mat-mdc-form-field .mdc-notched-outline__notch,.c-query-bar ::ng-deep .mat-mdc-form-field .mdc-notched-outline__trailing{border-color:#d6d8db!important;transition:border-color .12s ease}.c-query-bar ::ng-deep .mat-mdc-form-field .mdc-notched-outline__leading{border-radius:6px 0 0 6px!important}.c-query-bar ::ng-deep .mat-mdc-form-field .mdc-notched-outline__trailing{border-radius:0 6px 6px 0!important}.c-query-bar ::ng-deep .mat-mdc-form-field:hover:not(.mat-focused):not(.mat-form-field-disabled) .mdc-notched-outline__leading,.c-query-bar ::ng-deep .mat-mdc-form-field:hover:not(.mat-focused):not(.mat-form-field-disabled) .mdc-notched-outline__notch,.c-query-bar ::ng-deep .mat-mdc-form-field:hover:not(.mat-focused):not(.mat-form-field-disabled) .mdc-notched-outline__trailing{border-color:#b9bdc3!important}.c-query-bar ::ng-deep .mat-mdc-form-field.mat-focused .mdc-notched-outline__leading,.c-query-bar ::ng-deep .mat-mdc-form-field.mat-focused .mdc-notched-outline__notch,.c-query-bar ::ng-deep .mat-mdc-form-field.mat-focused .mdc-notched-outline__trailing{border-color:var(--sd-primary)!important;border-width:1px!important}.c-query-bar ::ng-deep .mat-mdc-form-field .mat-mdc-select-arrow,.c-query-bar ::ng-deep .mat-mdc-form-field .mat-mdc-form-field-icon-suffix .mat-icon{color:#5f6368}.c-query-bar ::ng-deep .mat-mdc-form-field.mat-focused .mat-mdc-select-arrow{color:var(--sd-primary)}::ng-deep .mat-mdc-menu-panel.c-chip-popover .mat-mdc-form-field .mdc-notched-outline__leading,::ng-deep .mat-mdc-menu-panel.c-chip-popover .mat-mdc-form-field .mdc-notched-outline__notch,::ng-deep .mat-mdc-menu-panel.c-chip-popover .mat-mdc-form-field .mdc-notched-outline__trailing,::ng-deep .mat-mdc-menu-panel.c-field-picker-menu .mat-mdc-form-field .mdc-notched-outline__leading,::ng-deep .mat-mdc-menu-panel.c-field-picker-menu .mat-mdc-form-field .mdc-notched-outline__notch,::ng-deep .mat-mdc-menu-panel.c-field-picker-menu .mat-mdc-form-field .mdc-notched-outline__trailing{border-color:#d6d8db!important;transition:border-color .12s ease}::ng-deep .mat-mdc-menu-panel.c-chip-popover .mat-mdc-form-field .mdc-notched-outline__leading,::ng-deep .mat-mdc-menu-panel.c-field-picker-menu .mat-mdc-form-field .mdc-notched-outline__leading{border-radius:6px 0 0 6px!important}::ng-deep .mat-mdc-menu-panel.c-chip-popover .mat-mdc-form-field .mdc-notched-outline__trailing,::ng-deep .mat-mdc-menu-panel.c-field-picker-menu .mat-mdc-form-field .mdc-notched-outline__trailing{border-radius:0 6px 6px 0!important}::ng-deep .mat-mdc-menu-panel.c-chip-popover .mat-mdc-form-field:hover:not(.mat-focused):not(.mat-form-field-disabled) .mdc-notched-outline__leading,::ng-deep .mat-mdc-menu-panel.c-chip-popover .mat-mdc-form-field:hover:not(.mat-focused):not(.mat-form-field-disabled) .mdc-notched-outline__notch,::ng-deep .mat-mdc-menu-panel.c-chip-popover .mat-mdc-form-field:hover:not(.mat-focused):not(.mat-form-field-disabled) .mdc-notched-outline__trailing,::ng-deep .mat-mdc-menu-panel.c-field-picker-menu .mat-mdc-form-field:hover:not(.mat-focused):not(.mat-form-field-disabled) .mdc-notched-outline__leading,::ng-deep .mat-mdc-menu-panel.c-field-picker-menu .mat-mdc-form-field:hover:not(.mat-focused):not(.mat-form-field-disabled) .mdc-notched-outline__notch,::ng-deep .mat-mdc-menu-panel.c-field-picker-menu .mat-mdc-form-field:hover:not(.mat-focused):not(.mat-form-field-disabled) .mdc-notched-outline__trailing{border-color:#b9bdc3!important}::ng-deep .mat-mdc-menu-panel.c-chip-popover .mat-mdc-form-field.mat-focused .mdc-notched-outline__leading,::ng-deep .mat-mdc-menu-panel.c-chip-popover .mat-mdc-form-field.mat-focused .mdc-notched-outline__notch,::ng-deep .mat-mdc-menu-panel.c-chip-popover .mat-mdc-form-field.mat-focused .mdc-notched-outline__trailing,::ng-deep .mat-mdc-menu-panel.c-field-picker-menu .mat-mdc-form-field.mat-focused .mdc-notched-outline__leading,::ng-deep .mat-mdc-menu-panel.c-field-picker-menu .mat-mdc-form-field.mat-focused .mdc-notched-outline__notch,::ng-deep .mat-mdc-menu-panel.c-field-picker-menu .mat-mdc-form-field.mat-focused .mdc-notched-outline__trailing{border-color:var(--sd-primary)!important;border-width:1px!important}::ng-deep .mat-mdc-menu-panel.c-chip-popover .mat-mdc-form-field .mat-mdc-select-arrow,::ng-deep .mat-mdc-menu-panel.c-chip-popover .mat-mdc-form-field .mat-mdc-form-field-icon-suffix .mat-icon,::ng-deep .mat-mdc-menu-panel.c-field-picker-menu .mat-mdc-form-field .mat-mdc-select-arrow,::ng-deep .mat-mdc-menu-panel.c-field-picker-menu .mat-mdc-form-field .mat-mdc-form-field-icon-suffix .mat-icon{color:#5f6368}::ng-deep .mat-mdc-menu-panel.c-chip-popover .mat-mdc-form-field.mat-focused .mat-mdc-select-arrow,::ng-deep .mat-mdc-menu-panel.c-field-picker-menu .mat-mdc-form-field.mat-focused .mat-mdc-select-arrow{color:var(--sd-primary)}\n"] }]
1377
- }] });
1405
+ ], template: "<!--\r\n sd-query-bar \u2014 unified filter chip row (Jira/Linear/Notion style).\r\n Visual spec: refs/design_handoff_sd_query_bar/README.md\r\n TODO(next-iter): replace inline placeholders for field-picker + chip-popover\r\n with extracted sub-components driven by CDK overlay.\r\n-->\r\n@let _filters = filters();\n@let _fields = resolvedFields();\n@let _density = resolvedDensity();\n@let _showOr = showOrConnector();\n@let _used = usedFieldKeys();\n@let _editingIndex = editingIndex();\n@let _mode = resolvedMode();\n@let _showOpOnChip = resolvedShowOperatorOnChip();\n\r\n<div\r\n class=\"c-query-bar\"\r\n [class.c-density-compact]=\"_density === 'compact'\"\r\n [class.c-density-comfortable]=\"_density === 'comfortable'\">\r\n\r\n <!-- Main region \u2014 search + filters + add-filter. Wraps internally; the right\r\n action toolbar stays anchored and does NOT flow with this. -->\r\n <div class=\"c-query-bar__main\">\r\n\r\n <!-- Free-text search (left, optional) -->\r\n @if (resolvedShowSearch()) {\n <div class=\"c-search\">\r\n <mat-icon class=\"c-search-icon\" fontSet=\"material-icons-outlined\">search</mat-icon>\r\n <input\r\n class=\"c-search-input\"\r\n type=\"text\"\r\n [ngModel]=\"search()\"\r\n (ngModelChange)=\"setSearch($event)\"\r\n (keydown.enter)=\"triggerApply()\"\r\n placeholder=\"T\u00ECm ki\u1EBFm...\" />\r\n </div>\r\n <span class=\"c-divider\" aria-hidden=\"true\"></span>\r\n }\r\n\r\n <!-- Chip popover \u2014 extracted into <sd-query-chip-popover>. Declared BEFORE chips\r\n so the popover-mode @for chips can bind their [menu] to `chipPopover.menu()`.\r\n why: m\u1EDF popover \u0111\u1EC3 EDIT ch\u1EC9 cho ch\u1EC9nh operator + value \u2014 KH\u00D4NG \u0111\u1ED5i field.\r\n B\u1ECF [switchPickerMenu] \u2192 header render nh\u00E3n field t\u0129nh (read-only). Mu\u1ED1n \u0111\u1ED5i\r\n field th\u00EC xo\u00E1 chip r\u1ED3i th\u00EAm l\u1EA1i. -->\r\n <sd-query-chip-popover\r\n #chipPopover\r\n [field]=\"editingField() ?? undefined\"\r\n [filter]=\"_editingIndex !== null ? $any(_filters[_editingIndex!]) : undefined\"\r\n [chipIndex]=\"_editingIndex\"\r\n [autoIdBase]=\"resolvedAutoId() ?? 'qb'\"\n (commit)=\"onChipPopoverCommit($event)\" />\r\n\r\n @if (_mode === 'inline') {\r\n <!-- ===== INLINE MODE (GitLab-style token builder) ===== -->\r\n\r\n <!-- Completed chips -->\r\n @for (filter of _filters; track $index; let i = $index) {\r\n @if (_showOr && i > 0) {\r\n <span class=\"c-or-connector\" aria-hidden=\"true\">OR</span>\r\n }\r\n @let _field = fieldByKey()[$any(filter).field];\r\n @if (_field) {\r\n @let _op = $any(filter.operator);\r\n @let _data = $any(filter).data;\r\n @if (_field.type === 'string' || _field.type === 'number') {\r\n <!-- Seamless chip \u2014 the pill is the input (string / number). -->\r\n <sd-query-inline-value-chip\r\n [field]=\"_field\"\r\n [operator]=\"_op\"\r\n [value]=\"_data\"\r\n [density]=\"_density\"\r\n [showOperator]=\"_showOpOnChip\"\r\n [autoId]=\"inlineAutoId(i, 'value')\"\r\n (valueChange)=\"updateFilter(i, { data: $event })\"\r\n (remove)=\"removeFilter(i)\" />\r\n } @else {\r\n <sd-query-inline-chip\r\n [field]=\"_field\"\r\n [filter]=\"filter\"\r\n [density]=\"_density\"\r\n [multiple]=\"multiple(_op)\"\r\n [showOperator]=\"_showOpOnChip\"\r\n [autoId]=\"inlineAutoId(i, 'value')\"\r\n [valueText]=\"chipValueText(filter)\"\r\n [isNoData]=\"isNoDataOperator(_op)\"\r\n (commit)=\"updateFilter(i, { data: $event })\"\r\n (commitRange)=\"setFilterRange(i, $event)\"\r\n (liveChange)=\"updateFilter(i, { data: $event })\"\r\n (remove)=\"removeFilter(i)\" />\r\n }\r\n }\r\n }\r\n\r\n <!-- Building chip (in-progress) \u2014 extracted into <sd-query-build-chip>. -->\r\n @if (building(); as _b) {\r\n <sd-query-build-chip\r\n [building]=\"_b\"\r\n [density]=\"_density\"\r\n [allowedOperators]=\"allowedOperatorsFor(_b.field)\"\r\n [multiple]=\"multiple($any(_b.operator))\"\r\n [showOperator]=\"_showOpOnChip\"\r\n (pickOperator)=\"pickBuildOperator($any($event))\"\r\n (commitValue)=\"commitBuildValue($event)\"\r\n (cancel)=\"cancelBuild()\"\r\n (seamlessCommit)=\"onBuildSeamlessCommit($event)\" />\r\n }\r\n\r\n <!-- Add filter -->\r\n <button\r\n type=\"button\"\r\n class=\"c-add-filter\"\r\n [matMenuTriggerFor]=\"addPicker.menu()\"\r\n [disabled]=\"_fields.length === 0 || _used.size >= _fields.length\"\r\n [matTooltip]=\"_fields.length === 0 ? 'Ch\u01B0a c\u1EA5u h\u00ECnh fields' : 'Th\u00EAm filter'\">\r\n <mat-icon fontSet=\"material-icons-outlined\">add</mat-icon>\r\n </button>\r\n } @else {\r\n <!-- ===== POPOVER MODE (default) \u2014 compact chips edited via mat-menu ===== -->\r\n @for (filter of _filters; track $index; let i = $index) {\r\n @if (_showOr && i > 0) {\r\n <span class=\"c-or-connector\" aria-hidden=\"true\">OR</span>\r\n }\r\n @let _field = fieldByKey()[$any(filter).field];\r\n @let _active = isFilterActive(filter);\r\n <!-- why: menu close commit is handled by chipPopover's (commit) \u2192\r\n onChipPopoverCommit; popover-chip only signals open + remove here. -->\r\n <sd-query-popover-chip\r\n [field]=\"_field\"\r\n [filter]=\"filter\"\r\n [active]=\"_active\"\r\n [showOperator]=\"_showOpOnChip\"\r\n [valueText]=\"chipValueText(filter)\"\r\n [menu]=\"chipPopover.menu()!\"\r\n (open)=\"openChipPopover(i)\"\r\n (remove)=\"removeFilter(i)\" />\r\n }\r\n\r\n <!-- Add filter trigger -->\r\n <button\r\n type=\"button\"\r\n class=\"c-add-filter\"\r\n [matMenuTriggerFor]=\"addPicker.menu()\"\r\n [disabled]=\"_fields.length === 0 || _used.size >= _fields.length\"\r\n [matTooltip]=\"_fields.length === 0 ? 'Ch\u01B0a c\u1EA5u h\u00ECnh fields' : 'Th\u00EAm filter'\">\r\n <mat-icon fontSet=\"material-icons-outlined\">add</mat-icon>\r\n </button>\r\n }\r\n\r\n </div><!-- /.c-query-bar__main -->\r\n\r\n <!-- Field picker \u2014 list available fields, fade ones already in use. -->\r\n <sd-query-field-picker\r\n #addPicker\r\n [fields]=\"_fields\"\r\n [usedKeys]=\"_used\"\r\n (pick)=\"_mode === 'inline' ? beginBuild($event) : addFilter($event)\" />\r\n\r\n <sd-query-actions-bar\r\n [showLogicToggle]=\"resolvedShowLogicToggle()\"\n [(logic)]=\"logic\"\r\n [filtersCount]=\"_filters.length\"\r\n [showSavedFilters]=\"resolvedShowSavedFilters()\"\n [savedFiltersKey]=\"resolvedSavedFiltersKey()\"\n [query]=\"currentQuery()\"\r\n (applyFilter)=\"onApplyFilter($event)\"\r\n [showClearAll]=\"resolvedShowClearAll()\"\n [canSearch]=\"canSearch()\"\r\n (clear)=\"clearAll()\"\r\n (search)=\"triggerApply()\" />\r\n</div>\r\n", styles: [":host{display:block;font-family:Roboto,system-ui,sans-serif}.c-query-bar{display:flex;align-items:flex-start;flex-wrap:nowrap;gap:8px;background:#fff;border:1px solid #e2e4e7;border-radius:8px;box-shadow:0 1px 2px #0f172a0a}.c-query-bar.c-density-compact{padding:8px}.c-query-bar.c-density-comfortable{padding:10px}.c-query-bar__main{flex:1 1 auto;min-width:0;display:flex;align-items:center;flex-wrap:wrap;gap:6px}.c-search{display:flex;align-items:center;gap:6px;min-width:220px;padding:0 10px;border:1px solid #d6d8db;border-radius:6px;background:#fff}.c-density-compact .c-search{height:28px}.c-density-comfortable .c-search{height:32px}.c-search .c-search-icon{font-size:16px;width:16px;height:16px;color:#7a7a7a}.c-search .c-search-input{flex:1;border:none;outline:none;background:transparent;font-size:13px;color:#212121}.c-search .c-search-input::placeholder{color:#7a7a7a}.c-search .c-search-kbd{font-family:Roboto Mono,monospace;font-size:10px;padding:1px 4px;border:1px solid #e2e4e7;border-radius:3px;color:#7a7a7a}.c-divider{width:1px;height:16px;background:#e2e4e7;margin:0 2px}.c-token{display:inline-flex;align-items:center;gap:4px;padding:0 0 0 12px;border:1px solid var(--sd-primary-light);border-radius:999px;background:var(--sd-primary-light);font-size:13px;color:#5f6368;white-space:nowrap;overflow:hidden}.c-density-compact .c-token{height:28px}.c-density-comfortable .c-token{height:32px}.c-token-icon{font-size:14px;width:14px;height:14px;line-height:14px;color:inherit}.c-token-field{font-weight:500;line-height:1}.c-token-op{display:inline-flex;align-items:center;color:inherit}.c-token-op ::ng-deep .c-op-trigger{padding:0;color:inherit}.c-token-op ::ng-deep .c-op-icon svg{width:14px;height:14px;display:block}.c-token-value-edit sd-select,.c-token-value-edit sd-date,.c-token-value-edit sd-datetime{display:inline-flex;align-items:center;line-height:1}.c-token ::ng-deep .mat-mdc-form-field{line-height:1}.c-token ::ng-deep .mat-mdc-text-field-wrapper,.c-token ::ng-deep .mat-mdc-form-field-flex{padding:0;min-height:0;background:transparent}.c-token ::ng-deep .mat-mdc-form-field-infix{padding:0;min-height:0;width:auto;border:0;display:inline-flex;align-items:center}.c-token ::ng-deep .mat-mdc-select-value,.c-token ::ng-deep .mat-mdc-input-element,.c-token ::ng-deep input{line-height:1;font-size:13px;padding:0;height:auto;color:inherit}.c-token ::ng-deep .mat-mdc-select-value{display:inline-flex;align-items:center;min-width:0;max-width:200px;overflow:hidden;text-overflow:ellipsis;color:var(--sd-primary);font-weight:500}.c-token ::ng-deep .sd-suffix-icon{display:none}.c-token-sep{color:#7a7a7a}.c-token-dash{color:#7a7a7a;padding:0 4px;line-height:1}.c-token-value{border:none;background:transparent;padding:0;font:inherit;font-weight:500;color:var(--sd-primary);cursor:pointer}.c-token-value:hover{text-decoration:underline}.c-token-value-edit{display:inline-flex;align-items:center;gap:4px;max-width:240px}.c-token-value-edit sd-input,.c-token-value-edit sd-input-number{display:inline-flex;max-width:140px}.c-token-value-edit sd-date-range{display:inline-flex;max-width:220px;min-width:0;flex:0 1 auto}.c-token-multi-head{display:inline-block;max-width:140px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:bottom}.c-token-remove{align-self:stretch;display:inline-flex;align-items:center;justify-content:center;border:none;border-left:1px solid rgba(0,0,0,.04);border-radius:0;background:transparent;cursor:pointer;color:inherit}.c-density-compact .c-token-remove{width:26px}.c-density-comfortable .c-token-remove{width:28px}.c-token-remove mat-icon{font-size:14px;width:14px;height:14px}.c-token-remove:hover{background:#0000000d}.c-add-filter{display:inline-flex;align-items:center;justify-content:center;padding:0;border-radius:999px;border:1px dashed #d6d8db;background:transparent;cursor:pointer;color:#5f6368;transition:border-color .12s ease,color .12s ease,background-color .12s ease}.c-density-compact .c-add-filter{width:28px;height:28px}.c-density-comfortable .c-add-filter{width:32px;height:32px}.c-add-filter mat-icon{font-size:18px;width:18px;height:18px}.c-add-filter:hover:not([disabled]){border-color:var(--sd-primary);color:var(--sd-primary)}.c-add-filter[disabled]{opacity:.5;cursor:not-allowed}.c-or-connector{font-family:Roboto Mono,monospace;font-size:10px;font-weight:700;letter-spacing:.6px;color:#7a7a7a;padding:0 2px}::ng-deep .mat-mdc-menu-panel.c-chip-popover{min-width:280px;max-width:320px}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-header{display:flex;align-items:center;gap:8px;padding:10px 12px;border-bottom:1px solid #e2e4e7;font-size:13px;font-weight:500;color:#212121}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-header mat-icon{font-size:16px;width:16px;height:16px;color:var(--sd-primary)}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-header .c-pop-header-operator{margin-left:auto}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-header-field{display:inline-flex;align-items:center;gap:4px;padding:2px 4px 2px 6px;margin-left:-4px;background:transparent;border:1px solid transparent;border-radius:4px;font:inherit;font-weight:500;color:#212121;cursor:pointer;transition:background-color .12s ease,border-color .12s ease}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-header-field mat-icon{font-size:14px!important;width:14px!important;height:14px!important;color:#7a7a7a!important}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-header-field:hover{background:#f5f6f7;border-color:#e2e4e7}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-body{padding:10px 12px;display:flex;flex-direction:column;gap:12px}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-input{width:100%;height:32px;padding:0 10px;border:1px solid #d6d8db;border-radius:6px;background:#fff;font-family:inherit;font-size:13px;color:#212121;outline:none}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-input:focus{border-color:var(--sd-primary)}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-between{display:grid;grid-template-columns:1fr 1fr;gap:8px}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-boolean{display:flex;gap:8px}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-boolean button{flex:1;height:32px;border:1px solid #d6d8db;border-radius:6px;background:#fff;font:inherit;font-size:13px;cursor:pointer}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-boolean button.c-pop-boolean-active{background:var(--sd-primary-light);border-color:var(--sd-primary);color:var(--sd-primary)}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-values{max-height:220px;overflow-y:auto;margin:0;padding:0;list-style:none}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-values li{display:flex;align-items:center;gap:8px;padding:6px 8px;border-radius:4px;font-size:13px;cursor:pointer;-webkit-user-select:none;user-select:none}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-values li:hover{background:#f5f6f7}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-values li.c-pop-value-selected{background:var(--sd-primary-light);color:var(--sd-primary)}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-values li input[type=checkbox],::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-values li input[type=radio]{accent-color:var(--sd-primary)}::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-values-loading,::ng-deep .mat-mdc-menu-panel.c-chip-popover .c-pop-values-empty{padding:10px 8px;font-size:12px;color:#7a7a7a}.c-bool-toggle{display:inline-flex;align-items:center;gap:4px}.c-bool-toggle ::ng-deep .mdc-button,.c-bool-toggle ::ng-deep button[mat-button],.c-bool-toggle ::ng-deep button[mat-stroked-button],.c-bool-toggle ::ng-deep button[mat-flat-button]{border-radius:999px;min-width:0;padding:0 12px}\n", ".c-query-bar ::ng-deep .mat-mdc-form-field .mdc-notched-outline__leading,.c-query-bar ::ng-deep .mat-mdc-form-field .mdc-notched-outline__notch,.c-query-bar ::ng-deep .mat-mdc-form-field .mdc-notched-outline__trailing{border-color:#d6d8db!important;transition:border-color .12s ease}.c-query-bar ::ng-deep .mat-mdc-form-field .mdc-notched-outline__leading{border-radius:6px 0 0 6px!important}.c-query-bar ::ng-deep .mat-mdc-form-field .mdc-notched-outline__trailing{border-radius:0 6px 6px 0!important}.c-query-bar ::ng-deep .mat-mdc-form-field:hover:not(.mat-focused):not(.mat-form-field-disabled) .mdc-notched-outline__leading,.c-query-bar ::ng-deep .mat-mdc-form-field:hover:not(.mat-focused):not(.mat-form-field-disabled) .mdc-notched-outline__notch,.c-query-bar ::ng-deep .mat-mdc-form-field:hover:not(.mat-focused):not(.mat-form-field-disabled) .mdc-notched-outline__trailing{border-color:#b9bdc3!important}.c-query-bar ::ng-deep .mat-mdc-form-field.mat-focused .mdc-notched-outline__leading,.c-query-bar ::ng-deep .mat-mdc-form-field.mat-focused .mdc-notched-outline__notch,.c-query-bar ::ng-deep .mat-mdc-form-field.mat-focused .mdc-notched-outline__trailing{border-color:var(--sd-primary)!important;border-width:1px!important}.c-query-bar ::ng-deep .mat-mdc-form-field .mat-mdc-select-arrow,.c-query-bar ::ng-deep .mat-mdc-form-field .mat-mdc-form-field-icon-suffix .mat-icon{color:#5f6368}.c-query-bar ::ng-deep .mat-mdc-form-field.mat-focused .mat-mdc-select-arrow{color:var(--sd-primary)}::ng-deep .mat-mdc-menu-panel.c-chip-popover .mat-mdc-form-field .mdc-notched-outline__leading,::ng-deep .mat-mdc-menu-panel.c-chip-popover .mat-mdc-form-field .mdc-notched-outline__notch,::ng-deep .mat-mdc-menu-panel.c-chip-popover .mat-mdc-form-field .mdc-notched-outline__trailing,::ng-deep .mat-mdc-menu-panel.c-field-picker-menu .mat-mdc-form-field .mdc-notched-outline__leading,::ng-deep .mat-mdc-menu-panel.c-field-picker-menu .mat-mdc-form-field .mdc-notched-outline__notch,::ng-deep .mat-mdc-menu-panel.c-field-picker-menu .mat-mdc-form-field .mdc-notched-outline__trailing{border-color:#d6d8db!important;transition:border-color .12s ease}::ng-deep .mat-mdc-menu-panel.c-chip-popover .mat-mdc-form-field .mdc-notched-outline__leading,::ng-deep .mat-mdc-menu-panel.c-field-picker-menu .mat-mdc-form-field .mdc-notched-outline__leading{border-radius:6px 0 0 6px!important}::ng-deep .mat-mdc-menu-panel.c-chip-popover .mat-mdc-form-field .mdc-notched-outline__trailing,::ng-deep .mat-mdc-menu-panel.c-field-picker-menu .mat-mdc-form-field .mdc-notched-outline__trailing{border-radius:0 6px 6px 0!important}::ng-deep .mat-mdc-menu-panel.c-chip-popover .mat-mdc-form-field:hover:not(.mat-focused):not(.mat-form-field-disabled) .mdc-notched-outline__leading,::ng-deep .mat-mdc-menu-panel.c-chip-popover .mat-mdc-form-field:hover:not(.mat-focused):not(.mat-form-field-disabled) .mdc-notched-outline__notch,::ng-deep .mat-mdc-menu-panel.c-chip-popover .mat-mdc-form-field:hover:not(.mat-focused):not(.mat-form-field-disabled) .mdc-notched-outline__trailing,::ng-deep .mat-mdc-menu-panel.c-field-picker-menu .mat-mdc-form-field:hover:not(.mat-focused):not(.mat-form-field-disabled) .mdc-notched-outline__leading,::ng-deep .mat-mdc-menu-panel.c-field-picker-menu .mat-mdc-form-field:hover:not(.mat-focused):not(.mat-form-field-disabled) .mdc-notched-outline__notch,::ng-deep .mat-mdc-menu-panel.c-field-picker-menu .mat-mdc-form-field:hover:not(.mat-focused):not(.mat-form-field-disabled) .mdc-notched-outline__trailing{border-color:#b9bdc3!important}::ng-deep .mat-mdc-menu-panel.c-chip-popover .mat-mdc-form-field.mat-focused .mdc-notched-outline__leading,::ng-deep .mat-mdc-menu-panel.c-chip-popover .mat-mdc-form-field.mat-focused .mdc-notched-outline__notch,::ng-deep .mat-mdc-menu-panel.c-chip-popover .mat-mdc-form-field.mat-focused .mdc-notched-outline__trailing,::ng-deep .mat-mdc-menu-panel.c-field-picker-menu .mat-mdc-form-field.mat-focused .mdc-notched-outline__leading,::ng-deep .mat-mdc-menu-panel.c-field-picker-menu .mat-mdc-form-field.mat-focused .mdc-notched-outline__notch,::ng-deep .mat-mdc-menu-panel.c-field-picker-menu .mat-mdc-form-field.mat-focused .mdc-notched-outline__trailing{border-color:var(--sd-primary)!important;border-width:1px!important}::ng-deep .mat-mdc-menu-panel.c-chip-popover .mat-mdc-form-field .mat-mdc-select-arrow,::ng-deep .mat-mdc-menu-panel.c-chip-popover .mat-mdc-form-field .mat-mdc-form-field-icon-suffix .mat-icon,::ng-deep .mat-mdc-menu-panel.c-field-picker-menu .mat-mdc-form-field .mat-mdc-select-arrow,::ng-deep .mat-mdc-menu-panel.c-field-picker-menu .mat-mdc-form-field .mat-mdc-form-field-icon-suffix .mat-icon{color:#5f6368}::ng-deep .mat-mdc-menu-panel.c-chip-popover .mat-mdc-form-field.mat-focused .mat-mdc-select-arrow,::ng-deep .mat-mdc-menu-panel.c-field-picker-menu .mat-mdc-form-field.mat-focused .mat-mdc-select-arrow{color:var(--sd-primary)}\n"] }]
1406
+ }], ctorParameters: () => [] });
1378
1407
 
1379
1408
  /**
1380
1409
  * Generated bundle index. Do not edit.