@sd-angular/core 19.0.0-beta.101 → 19.0.0-beta.103

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 (68) hide show
  1. package/components/operator/src/operator.component.d.ts +0 -4
  2. package/components/query-bar/src/actions-bar.component.d.ts +31 -0
  3. package/components/query-bar/src/build-chip.component.d.ts +67 -0
  4. package/components/query-bar/src/chip-popover.component.d.ts +73 -0
  5. package/components/query-bar/src/field-picker.component.d.ts +37 -0
  6. package/components/query-bar/src/inline-chip.component.d.ts +87 -0
  7. package/components/query-bar/src/popover-chip.component.d.ts +35 -0
  8. package/components/query-bar/src/query-bar.component.d.ts +46 -89
  9. package/components/query-bar/src/query-bar.model.d.ts +44 -29
  10. package/components/query-bar/src/saved-filters-menu.component.d.ts +39 -0
  11. package/components/view/src/view.component.d.ts +2 -1
  12. package/fesm2022/sd-angular-core-components-anchor.mjs +73 -47
  13. package/fesm2022/sd-angular-core-components-anchor.mjs.map +1 -1
  14. package/fesm2022/sd-angular-core-components-badge.mjs +2 -2
  15. package/fesm2022/sd-angular-core-components-badge.mjs.map +1 -1
  16. package/fesm2022/sd-angular-core-components-form-generic.mjs +10 -10
  17. package/fesm2022/sd-angular-core-components-form-generic.mjs.map +1 -1
  18. package/fesm2022/sd-angular-core-components-operator.mjs +3 -16
  19. package/fesm2022/sd-angular-core-components-operator.mjs.map +1 -1
  20. package/fesm2022/sd-angular-core-components-query-bar.mjs +871 -432
  21. package/fesm2022/sd-angular-core-components-query-bar.mjs.map +1 -1
  22. package/fesm2022/sd-angular-core-components-table.mjs +6 -6
  23. package/fesm2022/sd-angular-core-components-table.mjs.map +1 -1
  24. package/fesm2022/sd-angular-core-components-upload-file.mjs +14 -13
  25. package/fesm2022/sd-angular-core-components-upload-file.mjs.map +1 -1
  26. package/fesm2022/sd-angular-core-components-view.mjs +5 -2
  27. package/fesm2022/sd-angular-core-components-view.mjs.map +1 -1
  28. package/fesm2022/sd-angular-core-forms-autocomplete.mjs +3 -3
  29. package/fesm2022/sd-angular-core-forms-autocomplete.mjs.map +1 -1
  30. package/fesm2022/sd-angular-core-forms-checkbox.mjs +14 -2
  31. package/fesm2022/sd-angular-core-forms-checkbox.mjs.map +1 -1
  32. package/fesm2022/sd-angular-core-forms-chip-calendar.mjs +3 -3
  33. package/fesm2022/sd-angular-core-forms-chip-calendar.mjs.map +1 -1
  34. package/fesm2022/sd-angular-core-forms-chip.mjs +3 -3
  35. package/fesm2022/sd-angular-core-forms-chip.mjs.map +1 -1
  36. package/fesm2022/sd-angular-core-forms-date-range.mjs +41 -4
  37. package/fesm2022/sd-angular-core-forms-date-range.mjs.map +1 -1
  38. package/fesm2022/sd-angular-core-forms-date.mjs +4 -4
  39. package/fesm2022/sd-angular-core-forms-date.mjs.map +1 -1
  40. package/fesm2022/sd-angular-core-forms-datetime.mjs +4 -4
  41. package/fesm2022/sd-angular-core-forms-datetime.mjs.map +1 -1
  42. package/fesm2022/sd-angular-core-forms-input-number.mjs +3 -3
  43. package/fesm2022/sd-angular-core-forms-input-number.mjs.map +1 -1
  44. package/fesm2022/sd-angular-core-forms-input.mjs +3 -4
  45. package/fesm2022/sd-angular-core-forms-input.mjs.map +1 -1
  46. package/fesm2022/sd-angular-core-forms-radio.mjs +20 -3
  47. package/fesm2022/sd-angular-core-forms-radio.mjs.map +1 -1
  48. package/fesm2022/sd-angular-core-forms-select.mjs +14 -6
  49. package/fesm2022/sd-angular-core-forms-select.mjs.map +1 -1
  50. package/fesm2022/sd-angular-core-forms-switch.mjs +14 -2
  51. package/fesm2022/sd-angular-core-forms-switch.mjs.map +1 -1
  52. package/fesm2022/sd-angular-core-forms-textarea.mjs +3 -3
  53. package/fesm2022/sd-angular-core-forms-textarea.mjs.map +1 -1
  54. package/fesm2022/sd-angular-core-i18n.mjs +35 -0
  55. package/fesm2022/sd-angular-core-i18n.mjs.map +1 -1
  56. package/fesm2022/sd-angular-core-modules-layout.mjs +2 -2
  57. package/fesm2022/sd-angular-core-modules-layout.mjs.map +1 -1
  58. package/fesm2022/sd-angular-core-services-confirm.mjs +1 -1
  59. package/fesm2022/sd-angular-core-services-confirm.mjs.map +1 -1
  60. package/forms/checkbox/src/checkbox.component.d.ts +4 -2
  61. package/forms/date-range/src/date-range.component.d.ts +16 -2
  62. package/forms/input/src/input.component.d.ts +1 -2
  63. package/forms/radio/src/radio.component.d.ts +3 -1
  64. package/forms/switch/src/switch.component.d.ts +2 -1
  65. package/i18n/src/en.d.ts +5 -0
  66. package/package.json +75 -75
  67. package/sd-angular-core-19.0.0-beta.103.tgz +0 -0
  68. package/sd-angular-core-19.0.0-beta.101.tgz +0 -0
@@ -8,18 +8,9 @@ import { DomSanitizer } from '@angular/platform-browser';
8
8
  import { OPERATORS } from '@sdcorejs/utils/constants';
9
9
  import { I18nService } from '@sd-angular/core/i18n';
10
10
 
11
- var _a;
12
11
  class SdOperator {
13
12
  // Inner SVG markup (hình phễu) dùng khi chưa chọn operator.
14
13
  static FALLBACK_ICON = '<path d="M4 5h16l-6.5 7.5V19l-3 2v-8.5z"/>';
15
- // why: vài operator hợp lệ chưa có trong bảng OPERATORS dùng chung (vd BETWEEN). Bổ sung
16
- // cục bộ icon (inner SVG) + nhãn đã dịch để không rơi về phễu và hiện được trong menu.
17
- static SUPPLEMENT = {
18
- BETWEEN: {
19
- icon: '<line x1="5" y1="7" x2="5" y2="17"/><line x1="19" y1="7" x2="19" y2="17"/><line x1="5" y1="12" x2="19" y2="12"/>',
20
- display: 'Trong khoảng',
21
- },
22
- };
23
14
  #i18n = inject(I18nService);
24
15
  #sanitizer = inject(DomSanitizer);
25
16
  /** Operator hiện tại — binding hai chiều [(model)]. */
@@ -43,19 +34,16 @@ class SdOperator {
43
34
  });
44
35
  /** Icon SVG ở trigger — fallback phễu khi model chưa set / không tìm thấy. */
45
36
  currentIcon = computed(() => {
46
- return this.#svg(this.#resolve(this.model())?.icon ?? _a.FALLBACK_ICON);
37
+ return this.#svg(this.#resolve(this.model())?.icon ?? SdOperator.FALLBACK_ICON);
47
38
  });
48
39
  /** Tooltip = i18n label của operator hiện tại ('' khi chưa chọn). */
49
40
  currentLabel = computed(() => this.#resolve(this.model())?.display ?? '');
50
- // Resolve một operator → { inner-svg, nhãn đã dịch }: OPERATORS trước, rồi SUPPLEMENT cục bộ.
41
+ // Resolve một operator → { inner-svg, nhãn đã dịch } từ bảng OPERATORS dùng chung.
51
42
  #resolve(value) {
52
43
  if (value == null)
53
44
  return undefined;
54
45
  const entry = OPERATORS.find((o) => o.value === value);
55
- if (entry)
56
- return { icon: entry.icon, display: this.#i18n.t(entry.display) };
57
- const sup = _a.SUPPLEMENT[value];
58
- return sup ? { icon: sup.icon, display: sup.display } : undefined;
46
+ return entry ? { icon: entry.icon, display: this.#i18n.t(entry.display) } : undefined;
59
47
  }
60
48
  // why: OPERATORS.icon là inner SVG (path/line/rect). Bọc <svg> + bypass sanitizer
61
49
  // (nguồn là hằng số nội bộ, không phải input người dùng) để Angular không strip svg con.
@@ -74,7 +62,6 @@ class SdOperator {
74
62
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SdOperator, deps: [], target: i0.ɵɵFactoryTarget.Component });
75
63
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: SdOperator, isStandalone: true, selector: "sd-operator", inputs: { model: { classPropertyName: "model", publicName: "model", isSignal: true, isRequired: false, transformFunction: null }, operators: { classPropertyName: "operators", publicName: "operators", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, autoId: { classPropertyName: "autoId", publicName: "autoId", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { model: "modelChange" }, viewQueries: [{ propertyName: "trigger", first: true, predicate: MatMenuTrigger, descendants: true, isSignal: true }], ngImport: i0, template: "@let _current = model();\r\n\r\n<button\r\n type=\"button\"\r\n class=\"c-op-trigger\"\r\n [disabled]=\"disabled()\"\r\n [matMenuTriggerFor]=\"menu\"\r\n [matTooltip]=\"currentLabel()\"\r\n matTooltipPosition=\"above\"\r\n [attr.data-autoId]=\"autoId() ?? null\">\r\n <span class=\"c-op-icon\" [innerHTML]=\"currentIcon()\"></span>\r\n</button>\r\n\r\n<mat-menu #menu=\"matMenu\" class=\"c-op-menu\">\r\n @for (item of items(); track item.value) {\r\n <button\r\n type=\"button\"\r\n mat-menu-item\r\n class=\"c-op-row\"\r\n [class.c-op-active]=\"item.value === _current\"\r\n (click)=\"select(item.value)\">\r\n <span class=\"c-op-icon\" [innerHTML]=\"item.icon\"></span>\r\n <span class=\"c-op-label\">{{ item.display }}</span>\r\n <span class=\"c-op-code\">{{ item.value }}</span>\r\n </button>\r\n }\r\n</mat-menu>\r\n", styles: [".c-op-trigger{display:inline-flex;align-items:center;justify-content:center;padding:4px;border:none;background:transparent;color:var(--sd-primary, #0f766e);cursor:pointer;border-radius:4px}.c-op-trigger:hover:not([disabled]){background:#0000000a}.c-op-trigger[disabled]{color:#00000042;cursor:default}.c-op-icon{display:inline-flex;align-items:center}.c-op-icon svg{display:block}::ng-deep .c-op-menu .mat-mdc-menu-item-text{display:flex;align-items:center;gap:8px;width:100%}::ng-deep .c-op-menu .c-op-icon{display:inline-flex;align-items:center;flex:0 0 auto}::ng-deep .c-op-menu .c-op-icon svg{display:block}::ng-deep .c-op-menu .c-op-label{flex:1 1 auto}::ng-deep .c-op-menu .c-op-code{margin-left:auto;padding-left:16px;color:var(--sd-text-muted, #7a7a7a);font-size:11px;font-family:monospace}::ng-deep .c-op-menu .c-op-row.c-op-active{background:var(--sd-primary-light, rgba(15, 118, 110, .08))}\n"], dependencies: [{ kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i1.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i1.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { 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: i2.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
76
64
  }
77
- _a = SdOperator;
78
65
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SdOperator, decorators: [{
79
66
  type: Component,
80
67
  args: [{ selector: 'sd-operator', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [MatMenuModule, MatTooltipModule], template: "@let _current = model();\r\n\r\n<button\r\n type=\"button\"\r\n class=\"c-op-trigger\"\r\n [disabled]=\"disabled()\"\r\n [matMenuTriggerFor]=\"menu\"\r\n [matTooltip]=\"currentLabel()\"\r\n matTooltipPosition=\"above\"\r\n [attr.data-autoId]=\"autoId() ?? null\">\r\n <span class=\"c-op-icon\" [innerHTML]=\"currentIcon()\"></span>\r\n</button>\r\n\r\n<mat-menu #menu=\"matMenu\" class=\"c-op-menu\">\r\n @for (item of items(); track item.value) {\r\n <button\r\n type=\"button\"\r\n mat-menu-item\r\n class=\"c-op-row\"\r\n [class.c-op-active]=\"item.value === _current\"\r\n (click)=\"select(item.value)\">\r\n <span class=\"c-op-icon\" [innerHTML]=\"item.icon\"></span>\r\n <span class=\"c-op-label\">{{ item.display }}</span>\r\n <span class=\"c-op-code\">{{ item.value }}</span>\r\n </button>\r\n }\r\n</mat-menu>\r\n", styles: [".c-op-trigger{display:inline-flex;align-items:center;justify-content:center;padding:4px;border:none;background:transparent;color:var(--sd-primary, #0f766e);cursor:pointer;border-radius:4px}.c-op-trigger:hover:not([disabled]){background:#0000000a}.c-op-trigger[disabled]{color:#00000042;cursor:default}.c-op-icon{display:inline-flex;align-items:center}.c-op-icon svg{display:block}::ng-deep .c-op-menu .mat-mdc-menu-item-text{display:flex;align-items:center;gap:8px;width:100%}::ng-deep .c-op-menu .c-op-icon{display:inline-flex;align-items:center;flex:0 0 auto}::ng-deep .c-op-menu .c-op-icon svg{display:block}::ng-deep .c-op-menu .c-op-label{flex:1 1 auto}::ng-deep .c-op-menu .c-op-code{margin-left:auto;padding-left:16px;color:var(--sd-text-muted, #7a7a7a);font-size:11px;font-family:monospace}::ng-deep .c-op-menu .c-op-row.c-op-active{background:var(--sd-primary-light, rgba(15, 118, 110, .08))}\n"] }]
@@ -1 +1 @@
1
- {"version":3,"file":"sd-angular-core-components-operator.mjs","sources":["../../../projects/sd-angular/components/operator/src/operator.component.ts","../../../projects/sd-angular/components/operator/src/operator.component.html","../../../projects/sd-angular/components/operator/sd-angular-core-components-operator.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, booleanAttribute, computed, inject, input, model, viewChild } from '@angular/core';\r\nimport { MatMenuModule, MatMenuTrigger } from '@angular/material/menu';\r\nimport { MatTooltipModule } from '@angular/material/tooltip';\r\nimport { DomSanitizer, SafeHtml } from '@angular/platform-browser';\r\nimport { OPERATORS } from '@sdcorejs/utils/constants';\r\nimport { Operator } from '@sdcorejs/utils/models';\r\nimport { I18nService } from '@sd-angular/core/i18n';\r\n\r\ninterface OperatorItem {\r\n value: Operator;\r\n icon: SafeHtml;\r\n display: string;\r\n}\r\n\r\n@Component({\r\n selector: 'sd-operator',\r\n templateUrl: './operator.component.html',\r\n styleUrls: ['./operator.component.scss'],\r\n standalone: true,\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n imports: [MatMenuModule, MatTooltipModule],\r\n})\r\nexport class SdOperator {\r\n // Inner SVG markup (hình phễu) dùng khi chưa chọn operator.\r\n static readonly FALLBACK_ICON = '<path d=\"M4 5h16l-6.5 7.5V19l-3 2v-8.5z\"/>';\r\n\r\n // why: vài operator hợp lệ chưa có trong bảng OPERATORS dùng chung (vd BETWEEN). Bổ sung\r\n // cục bộ icon (inner SVG) + nhãn đã dịch để không rơi về phễu và hiện được trong menu.\r\n static readonly SUPPLEMENT: Partial<Record<Operator, { icon: string; display: string }>> = {\r\n BETWEEN: {\r\n icon: '<line x1=\"5\" y1=\"7\" x2=\"5\" y2=\"17\"/><line x1=\"19\" y1=\"7\" x2=\"19\" y2=\"17\"/><line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\"/>',\r\n display: 'Trong khoảng',\r\n },\r\n };\r\n\r\n readonly #i18n = inject(I18nService);\r\n readonly #sanitizer = inject(DomSanitizer);\r\n\r\n /** Operator hiện tại — binding hai chiều [(model)]. */\r\n model = model<Operator | undefined>();\r\n\r\n /** Danh sách operator cho phép, giữ nguyên thứ tự truyền vào. */\r\n operators = input<Operator[]>([]);\r\n\r\n /** Vô hiệu hóa trigger (không mở được menu). */\r\n disabled = input(false, { transform: booleanAttribute });\r\n\r\n /** data-autoId cho e2e selector. */\r\n autoId = input<string>();\r\n\r\n /** Allowed operators map sang { value, icon, display } theo thứ tự input. */\r\n readonly items = computed<OperatorItem[]>(() => {\r\n const out: OperatorItem[] = [];\r\n for (const value of this.operators()) {\r\n const r = this.#resolve(value);\r\n if (!r) continue;\r\n out.push({ value, icon: this.#svg(r.icon), display: r.display });\r\n }\r\n return out;\r\n });\r\n\r\n /** Icon SVG ở trigger — fallback phễu khi model chưa set / không tìm thấy. */\r\n readonly currentIcon = computed<SafeHtml>(() => {\r\n return this.#svg(this.#resolve(this.model())?.icon ?? SdOperator.FALLBACK_ICON);\r\n });\r\n\r\n /** Tooltip = i18n label của operator hiện tại ('' khi chưa chọn). */\r\n readonly currentLabel = computed<string>(() => this.#resolve(this.model())?.display ?? '');\r\n\r\n // Resolve một operator → { inner-svg, nhãn đã dịch }: OPERATORS trước, rồi SUPPLEMENT cục bộ.\r\n #resolve(value: Operator | undefined): { icon: string; display: string } | undefined {\r\n if (value == null) return undefined;\r\n const entry = OPERATORS.find((o) => o.value === value);\r\n if (entry) return { icon: entry.icon, display: this.#i18n.t(entry.display) };\r\n const sup = SdOperator.SUPPLEMENT[value];\r\n return sup ? { icon: sup.icon, display: sup.display } : undefined;\r\n }\r\n\r\n // why: OPERATORS.icon là inner SVG (path/line/rect). Bọc <svg> + bypass sanitizer\r\n // (nguồn là hằng số nội bộ, không phải input người dùng) để Angular không strip svg con.\r\n #svg(inner: string): SafeHtml {\r\n return this.#sanitizer.bypassSecurityTrustHtml(\r\n `<svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">${inner}</svg>`,\r\n );\r\n }\r\n\r\n private readonly trigger = viewChild(MatMenuTrigger);\r\n\r\n /** Open the operator menu programmatically (used by the query-bar build flow). */\r\n open(): void {\r\n this.trigger()?.openMenu();\r\n }\r\n\r\n /** Chọn operator từ menu. */\r\n select(value: Operator): void {\r\n this.model.set(value);\r\n }\r\n}\r\n","@let _current = model();\r\n\r\n<button\r\n type=\"button\"\r\n class=\"c-op-trigger\"\r\n [disabled]=\"disabled()\"\r\n [matMenuTriggerFor]=\"menu\"\r\n [matTooltip]=\"currentLabel()\"\r\n matTooltipPosition=\"above\"\r\n [attr.data-autoId]=\"autoId() ?? null\">\r\n <span class=\"c-op-icon\" [innerHTML]=\"currentIcon()\"></span>\r\n</button>\r\n\r\n<mat-menu #menu=\"matMenu\" class=\"c-op-menu\">\r\n @for (item of items(); track item.value) {\r\n <button\r\n type=\"button\"\r\n mat-menu-item\r\n class=\"c-op-row\"\r\n [class.c-op-active]=\"item.value === _current\"\r\n (click)=\"select(item.value)\">\r\n <span class=\"c-op-icon\" [innerHTML]=\"item.icon\"></span>\r\n <span class=\"c-op-label\">{{ item.display }}</span>\r\n <span class=\"c-op-code\">{{ item.value }}</span>\r\n </button>\r\n }\r\n</mat-menu>\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sd-angular-core-components-operator.mjs","sources":["../../../projects/sd-angular/components/operator/src/operator.component.ts","../../../projects/sd-angular/components/operator/src/operator.component.html","../../../projects/sd-angular/components/operator/sd-angular-core-components-operator.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, booleanAttribute, computed, inject, input, model, viewChild } from '@angular/core';\r\nimport { MatMenuModule, MatMenuTrigger } from '@angular/material/menu';\r\nimport { MatTooltipModule } from '@angular/material/tooltip';\r\nimport { DomSanitizer, SafeHtml } from '@angular/platform-browser';\r\nimport { OPERATORS } from '@sdcorejs/utils/constants';\r\nimport { Operator } from '@sdcorejs/utils/models';\r\nimport { I18nService } from '@sd-angular/core/i18n';\r\n\r\ninterface OperatorItem {\r\n value: Operator;\r\n icon: SafeHtml;\r\n display: string;\r\n}\r\n\r\n@Component({\r\n selector: 'sd-operator',\r\n templateUrl: './operator.component.html',\r\n styleUrls: ['./operator.component.scss'],\r\n standalone: true,\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n imports: [MatMenuModule, MatTooltipModule],\r\n})\r\nexport class SdOperator {\r\n // Inner SVG markup (hình phễu) dùng khi chưa chọn operator.\r\n static readonly FALLBACK_ICON = '<path d=\"M4 5h16l-6.5 7.5V19l-3 2v-8.5z\"/>';\r\n\r\n readonly #i18n = inject(I18nService);\r\n readonly #sanitizer = inject(DomSanitizer);\r\n\r\n /** Operator hiện tại — binding hai chiều [(model)]. */\r\n model = model<Operator | undefined>();\r\n\r\n /** Danh sách operator cho phép, giữ nguyên thứ tự truyền vào. */\r\n operators = input<Operator[]>([]);\r\n\r\n /** Vô hiệu hóa trigger (không mở được menu). */\r\n disabled = input(false, { transform: booleanAttribute });\r\n\r\n /** data-autoId cho e2e selector. */\r\n autoId = input<string>();\r\n\r\n /** Allowed operators map sang { value, icon, display } theo thứ tự input. */\r\n readonly items = computed<OperatorItem[]>(() => {\r\n const out: OperatorItem[] = [];\r\n for (const value of this.operators()) {\r\n const r = this.#resolve(value);\r\n if (!r) continue;\r\n out.push({ value, icon: this.#svg(r.icon), display: r.display });\r\n }\r\n return out;\r\n });\r\n\r\n /** Icon SVG ở trigger — fallback phễu khi model chưa set / không tìm thấy. */\r\n readonly currentIcon = computed<SafeHtml>(() => {\r\n return this.#svg(this.#resolve(this.model())?.icon ?? SdOperator.FALLBACK_ICON);\r\n });\r\n\r\n /** Tooltip = i18n label của operator hiện tại ('' khi chưa chọn). */\r\n readonly currentLabel = computed<string>(() => this.#resolve(this.model())?.display ?? '');\r\n\r\n // Resolve một operator → { inner-svg, nhãn đã dịch } từ bảng OPERATORS dùng chung.\r\n #resolve(value: Operator | undefined): { icon: string; display: string } | undefined {\r\n if (value == null) return undefined;\r\n const entry = OPERATORS.find((o) => o.value === value);\r\n return entry ? { icon: entry.icon, display: this.#i18n.t(entry.display) } : undefined;\r\n }\r\n\r\n // why: OPERATORS.icon là inner SVG (path/line/rect). Bọc <svg> + bypass sanitizer\r\n // (nguồn là hằng số nội bộ, không phải input người dùng) để Angular không strip svg con.\r\n #svg(inner: string): SafeHtml {\r\n return this.#sanitizer.bypassSecurityTrustHtml(\r\n `<svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">${inner}</svg>`,\r\n );\r\n }\r\n\r\n private readonly trigger = viewChild(MatMenuTrigger);\r\n\r\n /** Open the operator menu programmatically (used by the query-bar build flow). */\r\n open(): void {\r\n this.trigger()?.openMenu();\r\n }\r\n\r\n /** Chọn operator từ menu. */\r\n select(value: Operator): void {\r\n this.model.set(value);\r\n }\r\n}\r\n","@let _current = model();\r\n\r\n<button\r\n type=\"button\"\r\n class=\"c-op-trigger\"\r\n [disabled]=\"disabled()\"\r\n [matMenuTriggerFor]=\"menu\"\r\n [matTooltip]=\"currentLabel()\"\r\n matTooltipPosition=\"above\"\r\n [attr.data-autoId]=\"autoId() ?? null\">\r\n <span class=\"c-op-icon\" [innerHTML]=\"currentIcon()\"></span>\r\n</button>\r\n\r\n<mat-menu #menu=\"matMenu\" class=\"c-op-menu\">\r\n @for (item of items(); track item.value) {\r\n <button\r\n type=\"button\"\r\n mat-menu-item\r\n class=\"c-op-row\"\r\n [class.c-op-active]=\"item.value === _current\"\r\n (click)=\"select(item.value)\">\r\n <span class=\"c-op-icon\" [innerHTML]=\"item.icon\"></span>\r\n <span class=\"c-op-label\">{{ item.display }}</span>\r\n <span class=\"c-op-code\">{{ item.value }}</span>\r\n </button>\r\n }\r\n</mat-menu>\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}