@sdcorejs/angular 19.0.1 → 19.0.4

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 (125) hide show
  1. package/README.md +22 -4
  2. package/assets/scss/core/_inline-edit.scss +105 -0
  3. package/assets/scss/core/form.scss +15 -0
  4. package/components/autoid-inspector/src/models/autoid-element.model.d.ts +11 -0
  5. package/components/autoid-inspector/src/models/autoid-export-format.model.d.ts +19 -0
  6. package/components/autoid-inspector/src/services/autoid-export.service.d.ts +7 -1
  7. package/components/autoid-inspector/src/services/autoid-scanner.service.d.ts +15 -2
  8. package/components/button/src/button.component.d.ts +1 -2
  9. package/components/form-generic/src/components/form-builder/form-builder.component.d.ts +13 -15
  10. package/components/form-generic/src/components/form-render/form-render.component.d.ts +1 -2
  11. package/components/form-generic/src/components/sd-feel-expression/sd-feel-expression.component.d.ts +1 -2
  12. package/components/index.d.ts +1 -0
  13. package/components/modal-resizable/index.d.ts +1 -0
  14. package/components/modal-resizable/src/modal-resizable.component.d.ts +29 -0
  15. package/components/query-bar/src/components/inline-chip/inline-chip.component.d.ts +11 -22
  16. package/components/query-bar/src/components/inline-value-chip/inline-value-chip.component.d.ts +3 -7
  17. package/components/query-builder/index.d.ts +2 -0
  18. package/components/query-builder/src/query-builder.component.d.ts +98 -22
  19. package/components/query-builder/src/query-builder.model.d.ts +118 -0
  20. package/components/query-builder/src/query-builder.serializer.d.ts +32 -0
  21. package/components/section/src/section.component.d.ts +1 -2
  22. package/components/side-drawer/src/side-drawer.component.d.ts +1 -2
  23. package/components/stepper/src/stepper.component.d.ts +1 -2
  24. package/components/tab/src/tab-group.component.d.ts +1 -2
  25. package/components/table/src/components/config/config.component.d.ts +3 -1
  26. package/components/table/src/components/selector-action/selector-action.component.d.ts +3 -1
  27. package/components/table/src/models/table-option-tree.model.d.ts +96 -8
  28. package/components/table/src/services/tree/tree.util.d.ts +43 -2
  29. package/components/table/src/table.component.d.ts +1 -2
  30. package/components/upload-file/src/upload-file.component.d.ts +2 -0
  31. package/components/view/src/view.component.d.ts +33 -0
  32. package/fesm2022/sdcorejs-angular-components-autoid-inspector.mjs +97 -10
  33. package/fesm2022/sdcorejs-angular-components-autoid-inspector.mjs.map +1 -1
  34. package/fesm2022/sdcorejs-angular-components-avatar.mjs +2 -2
  35. package/fesm2022/sdcorejs-angular-components-avatar.mjs.map +1 -1
  36. package/fesm2022/sdcorejs-angular-components-button.mjs +3 -5
  37. package/fesm2022/sdcorejs-angular-components-button.mjs.map +1 -1
  38. package/fesm2022/sdcorejs-angular-components-form-generic.mjs +106 -197
  39. package/fesm2022/sdcorejs-angular-components-form-generic.mjs.map +1 -1
  40. package/fesm2022/sdcorejs-angular-components-modal-resizable.mjs +158 -0
  41. package/fesm2022/sdcorejs-angular-components-modal-resizable.mjs.map +1 -0
  42. package/fesm2022/sdcorejs-angular-components-operator.mjs +3 -1
  43. package/fesm2022/sdcorejs-angular-components-operator.mjs.map +1 -1
  44. package/fesm2022/sdcorejs-angular-components-preview.mjs +4 -4
  45. package/fesm2022/sdcorejs-angular-components-preview.mjs.map +1 -1
  46. package/fesm2022/sdcorejs-angular-components-query-bar.mjs +41 -87
  47. package/fesm2022/sdcorejs-angular-components-query-bar.mjs.map +1 -1
  48. package/fesm2022/sdcorejs-angular-components-query-builder.mjs +669 -57
  49. package/fesm2022/sdcorejs-angular-components-query-builder.mjs.map +1 -1
  50. package/fesm2022/sdcorejs-angular-components-section.mjs +2 -4
  51. package/fesm2022/sdcorejs-angular-components-section.mjs.map +1 -1
  52. package/fesm2022/sdcorejs-angular-components-side-drawer.mjs +3 -5
  53. package/fesm2022/sdcorejs-angular-components-side-drawer.mjs.map +1 -1
  54. package/fesm2022/sdcorejs-angular-components-stepper.mjs +2 -4
  55. package/fesm2022/sdcorejs-angular-components-stepper.mjs.map +1 -1
  56. package/fesm2022/sdcorejs-angular-components-tab.mjs +2 -4
  57. package/fesm2022/sdcorejs-angular-components-tab.mjs.map +1 -1
  58. package/fesm2022/sdcorejs-angular-components-table.mjs +235 -110
  59. package/fesm2022/sdcorejs-angular-components-table.mjs.map +1 -1
  60. package/fesm2022/sdcorejs-angular-components-upload-file.mjs +15 -4
  61. package/fesm2022/sdcorejs-angular-components-upload-file.mjs.map +1 -1
  62. package/fesm2022/sdcorejs-angular-components-view.mjs +43 -11
  63. package/fesm2022/sdcorejs-angular-components-view.mjs.map +1 -1
  64. package/fesm2022/sdcorejs-angular-components.mjs +1 -0
  65. package/fesm2022/sdcorejs-angular-components.mjs.map +1 -1
  66. package/fesm2022/sdcorejs-angular-forms-autocomplete.mjs +32 -7
  67. package/fesm2022/sdcorejs-angular-forms-autocomplete.mjs.map +1 -1
  68. package/fesm2022/sdcorejs-angular-forms-checkbox.mjs +9 -4
  69. package/fesm2022/sdcorejs-angular-forms-checkbox.mjs.map +1 -1
  70. package/fesm2022/sdcorejs-angular-forms-chip-calendar.mjs +10 -5
  71. package/fesm2022/sdcorejs-angular-forms-chip-calendar.mjs.map +1 -1
  72. package/fesm2022/sdcorejs-angular-forms-chip.mjs +10 -5
  73. package/fesm2022/sdcorejs-angular-forms-chip.mjs.map +1 -1
  74. package/fesm2022/sdcorejs-angular-forms-date-range.mjs +18 -9
  75. package/fesm2022/sdcorejs-angular-forms-date-range.mjs.map +1 -1
  76. package/fesm2022/sdcorejs-angular-forms-date.mjs +20 -8
  77. package/fesm2022/sdcorejs-angular-forms-date.mjs.map +1 -1
  78. package/fesm2022/sdcorejs-angular-forms-datetime.mjs +20 -8
  79. package/fesm2022/sdcorejs-angular-forms-datetime.mjs.map +1 -1
  80. package/fesm2022/sdcorejs-angular-forms-inline-text.mjs +167 -0
  81. package/fesm2022/sdcorejs-angular-forms-inline-text.mjs.map +1 -0
  82. package/fesm2022/sdcorejs-angular-forms-input-color.mjs +5 -3
  83. package/fesm2022/sdcorejs-angular-forms-input-color.mjs.map +1 -1
  84. package/fesm2022/sdcorejs-angular-forms-input-number.mjs +41 -8
  85. package/fesm2022/sdcorejs-angular-forms-input-number.mjs.map +1 -1
  86. package/fesm2022/sdcorejs-angular-forms-input.mjs +35 -9
  87. package/fesm2022/sdcorejs-angular-forms-input.mjs.map +1 -1
  88. package/fesm2022/sdcorejs-angular-forms-models.mjs +32 -2
  89. package/fesm2022/sdcorejs-angular-forms-models.mjs.map +1 -1
  90. package/fesm2022/sdcorejs-angular-forms-radio.mjs +9 -4
  91. package/fesm2022/sdcorejs-angular-forms-radio.mjs.map +1 -1
  92. package/fesm2022/sdcorejs-angular-forms-select.mjs +33 -9
  93. package/fesm2022/sdcorejs-angular-forms-select.mjs.map +1 -1
  94. package/fesm2022/sdcorejs-angular-forms-switch.mjs +9 -4
  95. package/fesm2022/sdcorejs-angular-forms-switch.mjs.map +1 -1
  96. package/fesm2022/sdcorejs-angular-forms-textarea.mjs +15 -5
  97. package/fesm2022/sdcorejs-angular-forms-textarea.mjs.map +1 -1
  98. package/fesm2022/sdcorejs-angular-i18n.mjs +20 -0
  99. package/fesm2022/sdcorejs-angular-i18n.mjs.map +1 -1
  100. package/fesm2022/sdcorejs-angular-services-confirm.mjs +1 -1
  101. package/fesm2022/sdcorejs-angular-services-confirm.mjs.map +1 -1
  102. package/fesm2022/sdcorejs-angular-services-notify.mjs +40 -9
  103. package/fesm2022/sdcorejs-angular-services-notify.mjs.map +1 -1
  104. package/forms/autocomplete/src/autocomplete.component.d.ts +16 -3
  105. package/forms/checkbox/src/checkbox.component.d.ts +5 -1
  106. package/forms/chip/src/chip.component.d.ts +5 -2
  107. package/forms/chip-calendar/src/chip-calendar.component.d.ts +5 -2
  108. package/forms/date/src/date.component.d.ts +14 -5
  109. package/forms/date-range/src/date-range.component.d.ts +12 -5
  110. package/forms/datetime/src/datetime.component.d.ts +14 -5
  111. package/forms/inline-text/index.d.ts +1 -0
  112. package/forms/inline-text/src/inline-text.component.d.ts +76 -0
  113. package/forms/input/src/input.component.d.ts +14 -2
  114. package/forms/input-color/src/input-color.component.d.ts +3 -1
  115. package/forms/input-number/src/input-number.component.d.ts +14 -2
  116. package/forms/models/index.d.ts +1 -0
  117. package/forms/models/src/sd-viewed.d.ts +38 -0
  118. package/forms/radio/src/radio.component.d.ts +5 -2
  119. package/forms/select/src/select.component.d.ts +23 -5
  120. package/forms/switch/src/switch.component.d.ts +5 -2
  121. package/forms/textarea/src/textarea.component.d.ts +9 -2
  122. package/i18n/src/en.d.ts +4 -0
  123. package/package.json +9 -1
  124. package/services/notify/src/components/toast/toast.component.d.ts +16 -1
  125. package/services/notify/src/notify.model.d.ts +17 -0
package/README.md CHANGED
@@ -380,6 +380,25 @@ option: SdTableOption<Product> = {
380
380
  <sd-table #sdTable [option]="option" />
381
381
  ```
382
382
 
383
+ **Tree rows / Dòng cây:**
384
+
385
+ `tree` là discriminated union theo `loadType`. Icon expand (`chevron_right` / `expand_more`) nằm ở **cột đầu** — cột STT khi bật `index`, ngược lại cột data đầu tiên — thụt lề theo cấp.
386
+
387
+ ```typescript
388
+ // loadType: 'static' — children embedded sẵn trong mỗi row
389
+ tree: { loadType: 'static', childrenKey: 'children', defaultExpanded: 1 }
390
+
391
+ // loadType: 'lazy' — nạp con khi bung (Promise); hasChildren gate icon expand
392
+ tree: {
393
+ loadType: 'lazy',
394
+ hasChildren: (row) => row.type === 'Folder', // chỉ Folder mới có icon expand
395
+ onExpandChildren: (row) => api.getChildren(row.id), // () => Promise<T[]>
396
+ }
397
+ ```
398
+
399
+ - **Child-level search** (`type: 'local'` + `loadType: 'static'`): lọc inline tìm cả **cấp con** — giữ nhánh cha của node khớp, ẩn sibling không khớp, tự bung tới node khớp. Clear filter khôi phục cây.
400
+ - **Lazy loading**: spinner hiện trong ô chevron khi `onExpandChildren` đang chạy; `hasChildren` quyết định dòng nào hiện icon (không truyền = mọi node đều hiện).
401
+
383
402
  ---
384
403
 
385
404
  ### SdAvatar
@@ -703,11 +722,10 @@ ng-packagr -p ng-package.json --watch
703
722
 
704
723
  ### Versioning
705
724
 
706
- Thư viện tuân theo [Semantic Versioning](https://semver.org):
725
+ Scheme: `<angular-major>.0.<release>`. Major digit **khoá theo Angular line** (19.x = Angular 19, 20.x = Angular 20, 21.x = Angular 21) — **KHÔNG** dùng để báo breaking. Mỗi release publish đồng thời 3 major cùng nội dung feature, chỉ khác Angular shim.
707
726
 
708
- - `MAJOR` Breaking changes (thay đổi API không tương thích)
709
- - `MINOR` Tính năng mới (tương thích ngược)
710
- - `PATCH` — Bug fixes
727
+ - Luôn pin theo Angular line của bạn: `npm i @sdcorejs/angular@^19` (hoặc `@^20` / `@^21`).
728
+ - Breaking change được ghi ở `CHANGELOG.md`, mục **Changed (BREAKING for consumers)**, kèm migration.
711
729
 
712
730
  ---
713
731
 
@@ -0,0 +1,105 @@
1
+ // Shared `viewed='inline'` styles for sd-form-controls.
2
+ // why: 1 nguồn cho text-face + editor ẩn (panel control) và input borderless, tránh lặp ~40 dòng/control.
3
+ // Bare-flatten (mat-* internals) KHÔNG nằm ở đây — khác nhau theo control, giữ trong scss riêng.
4
+
5
+ // Clear-× — hover-gated, đặt cuối "mặt". Include BÊN TRONG rule của phần tử hover (face/input).
6
+ @mixin _inline-clear {
7
+ .sd-inline-clear {
8
+ display: none;
9
+ align-items: center;
10
+ margin-left: 4px;
11
+ padding: 0;
12
+ border: 0;
13
+ background: transparent;
14
+ cursor: pointer;
15
+ line-height: 0;
16
+ color: var(--sd-text-secondary, #6b7280);
17
+ transition: color 0.15s ease;
18
+
19
+ mat-icon {
20
+ font-size: 16px;
21
+ width: 16px;
22
+ height: 16px;
23
+ }
24
+
25
+ &:hover {
26
+ color: var(--sd-error, #b32626);
27
+ }
28
+ }
29
+
30
+ &:hover .sd-inline-clear {
31
+ display: inline-flex;
32
+ }
33
+ }
34
+
35
+ // Panel-based controls (select / date / datetime / date-range / autocomplete):
36
+ // `<sd-view>` text là "mặt" + trigger; editor render ẩn (overlay) chỉ để neo + mở panel.
37
+ @mixin sd-inline-panel {
38
+ // Neo cho .sd-inline-editor (absolute). Bare flatten + display nằm ở :host(.sd-bare) riêng của control.
39
+ :host(.sd-bare) {
40
+ position: relative;
41
+ }
42
+
43
+ .sd-inline-view {
44
+ cursor: pointer;
45
+ display: inline-flex;
46
+ align-items: center;
47
+ width: 100%;
48
+ // why: nền nhẹ + đậm hơn khi hover → tín hiệu "viewed có thể bấm để sửa".
49
+ padding: 1px 6px;
50
+ border-radius: 4px;
51
+ background-color: rgba(0, 0, 0, 0.04);
52
+ transition: background-color 0.15s ease;
53
+
54
+ &:hover {
55
+ background-color: rgba(0, 0, 0, 0.08);
56
+ }
57
+
58
+ @include _inline-clear;
59
+ }
60
+
61
+ // why: editor vô hình phủ lên face. Tắt pointer-events CẢ cây con (mat-* tự bật lại ở trigger)
62
+ // để hover/click rơi xuống .sd-inline-view ở mọi chỗ. Panel mở qua enterInlineEdit() → open().
63
+ .sd-inline-editor {
64
+ position: absolute;
65
+ inset: 0;
66
+ opacity: 0;
67
+ pointer-events: none;
68
+
69
+ ::ng-deep * {
70
+ pointer-events: none !important;
71
+ }
72
+ }
73
+ }
74
+
75
+ // NOTE: the former `sd-inline-input` mixin (mat-form-field flatten for the input/input-number
76
+ // inline variant) was removed when those controls moved to the <sd-inline-text> primitive
77
+ // (forms/inline-text), which owns its own borderless styling. The panel mixin above stays.
78
+
79
+ // Multiline input (textarea): no panel, no single-line `<sd-inline-text>` — flatten the
80
+ // mat-form-field so the `<textarea>` reads like text, transparent with a hover/focus affordance.
81
+ @mixin sd-inline-textarea {
82
+ .sd-inline-textarea {
83
+ cursor: text;
84
+ border-radius: 4px;
85
+ background-color: rgba(0, 0, 0, 0.04);
86
+ transition: background-color 0.15s ease;
87
+
88
+ &:hover {
89
+ background-color: rgba(0, 0, 0, 0.08);
90
+ }
91
+
92
+ &:focus-within {
93
+ background-color: rgba(0, 0, 0, 0.06);
94
+ box-shadow: inset 0 0 0 1px var(--sd-primary, #1f6feb);
95
+ }
96
+
97
+ ::ng-deep {
98
+ .mat-mdc-text-field-wrapper { padding: 0 6px; background: transparent; }
99
+ .mat-mdc-form-field-flex { padding: 0; }
100
+ .mdc-notched-outline { display: none; }
101
+ .mat-mdc-form-field-subscript-wrapper { display: none; }
102
+ .mat-mdc-form-field-infix { padding: 4px 0; min-height: 0; border: 0; }
103
+ }
104
+ }
105
+ }
@@ -296,6 +296,21 @@ mat-checkbox {
296
296
  }
297
297
  }
298
298
 
299
+ // why: selector radio của <sd-table> (.c-selection, single mode) hiện một dấu chấm tối thừa
300
+ // nằm cạnh vòng radio. Nguồn gốc THẬT là state-layer padding của Material trên `.mdc-radio`
301
+ // (`padding: calc((var(--mdc-radio-state-layer-size) - 20px) / 2)`): trong cột selector, .c-selection
302
+ // bị scale(0.85) (xem table.component.scss) còn `.mdc-radio` có `will-change: transform` nên lên
303
+ // compositing layer riêng → phần `.mdc-radio__inner-circle` (transform: scale(0), border 10px màu
304
+ // tối) bị render rớt lại ~1px artifact trong dải padding đó, đọc thành "dấu chấm". Bỏ state-layer
305
+ // padding cho radio selector compact là khử sạch (vòng 20px + scale 0.85 vẫn căn giữa). Scope theo
306
+ // `.c-selection` nên KHÔNG ảnh hưởng radio ở nơi khác (giữ nguyên vùng hover/state-layer của chúng).
307
+ //
308
+ // LƯU Ý: cách trước (`label.mdc-label:empty { display:none }`) KHÔNG khử được dot — nó chỉ TÁCH dot
309
+ // thành 2 dấu chấm (label rỗng vốn đang phủ chồng lên artifact). Đã thay bằng fix dưới đây.
310
+ .c-selection.mat-mdc-radio-button .mdc-radio {
311
+ padding: 0;
312
+ }
313
+
299
314
  // Placeholder mặc định 1rem (16px), mong muốn nên là 14px
300
315
  .mat-mdc-floating-label {
301
316
  font-size: 14px !important;
@@ -17,6 +17,9 @@ export interface SdAutoidElementState {
17
17
  minlength?: string;
18
18
  pattern?: string;
19
19
  errorMessage?: string;
20
+ type?: string;
21
+ title?: string;
22
+ message?: string;
20
23
  }
21
24
  export interface SdAutoidElement {
22
25
  stt: number;
@@ -39,6 +42,14 @@ export interface SdAutoidElement {
39
42
  * Used by the UI to group table-scoped elements into a separate section.
40
43
  */
41
44
  tableScope?: string;
45
+ /**
46
+ * `true` when the element matched a required selector (sd-button, sd-input, …) but
47
+ * had NO `data-autoid` — the scanner still emits it with `autoid: ''` and a positional
48
+ * `xpath` fallback so the export stays usable. The dev should backfill an autoid.
49
+ */
50
+ missingAutoid?: boolean;
51
+ /** Human-readable warning attached to a fallback element (only set when `missingAutoid`). */
52
+ warning?: string;
42
53
  }
43
54
  export interface SdAutoidMissing {
44
55
  tag: string;
@@ -1,6 +1,25 @@
1
1
  export type SdAutoidExportFormat = 'csv' | 'json' | 'md-pom' | 'md-table';
2
2
  export interface SdAutoidExportMeta {
3
+ /** `location.pathname + location.search` — kept for back-compat with MD exports. */
3
4
  pageUrl: string;
4
5
  pageTitle: string;
5
6
  timestamp: string;
7
+ /** Full `location.href`. */
8
+ url: string;
9
+ /** `location.pathname` only. */
10
+ pathname: string;
11
+ /** Raw `location.search` (incl. leading `?`), or `''`. */
12
+ search: string;
13
+ /** Parsed query string → key/value map (last value wins on repeats). */
14
+ queryParams: Record<string, string>;
15
+ /**
16
+ * Angular route path params (`:id`, …) merged across the activated-route tree.
17
+ * Only present when an Angular `Router` is available at scan time; omitted otherwise.
18
+ */
19
+ params?: Record<string, string>;
20
+ }
21
+ /** JSON export envelope: page meta + the scanned elements. */
22
+ export interface SdAutoidExportJson {
23
+ meta: SdAutoidExportMeta;
24
+ elements: import('./autoid-element.model').SdAutoidElement[];
6
25
  }
@@ -2,7 +2,13 @@ import { SdAutoidElement } from '../models/autoid-element.model';
2
2
  import { SdAutoidExportMeta } from '../models/autoid-export-format.model';
3
3
  import * as i0 from "@angular/core";
4
4
  export declare class SdAutoidExportService {
5
- toJson(elements: SdAutoidElement[]): string;
5
+ /**
6
+ * Có `meta` → bọc `{ meta, elements }` (kèm url/queryParams) để consumer biết trang/route.
7
+ * Không `meta` → giữ mảng thuần (back-compat cho caller cũ chỉ cần elements).
8
+ */
9
+ toJson(elements: SdAutoidElement[], meta?: SdAutoidExportMeta): string;
10
+ /** Parse a `location.search` string into a flat key/value map (last value wins). */
11
+ parseQueryParams(search: string): Record<string, string>;
6
12
  toCsv(elements: SdAutoidElement[]): string;
7
13
  /** POM TypeScript skeleton — copy ngay vào file Playwright/Cypress. */
8
14
  toMarkdownPom(elements: SdAutoidElement[], meta: SdAutoidExportMeta): string;
@@ -1,8 +1,21 @@
1
1
  import { SdAutoidElement } from '../models/autoid-element.model';
2
2
  import * as i0 from "@angular/core";
3
3
  export declare class SdAutoidScannerService {
4
- /** Quét toàn bộ element có [data-autoid] trong root, gắn thông tin name/tag/value/xpath. */
5
- scan(root?: HTMLElement): SdAutoidElement[];
4
+ /**
5
+ * Quét element có [data-autoid] trong root, gắn name/tag/value/xpath.
6
+ * Khi truyền `requireSelectors` (vd các sd-* form/button), những node khớp selector
7
+ * mà KHÔNG có data-autoid (self lẫn con) sẽ được thêm vào dưới dạng phần tử fallback
8
+ * (`autoid: ''`, xpath theo vị trí thẻ + cờ `missingAutoid` + warning) — để JSON xuất ra
9
+ * vẫn dùng được và dev biết chỗ cần bổ sung autoid.
10
+ */
11
+ scan(root?: HTMLElement, requireSelectors?: ReadonlyArray<string>): SdAutoidElement[];
12
+ /**
13
+ * Tìm các node khớp `requireSelectors` nhưng thiếu data-autoid (self + mọi descendant),
14
+ * thêm vào `result` dưới dạng phần tử fallback. Trả về `stt` kế tiếp.
15
+ */
16
+ private appendMissing;
17
+ /** XPath theo vị trí thẻ trong document, vd `(//sd-button)[2]`, khi không có autoid. */
18
+ private fallbackXpath;
6
19
  /** Group element theo autoid để consumer lấy duplicate map. */
7
20
  groupByAutoid(elements: SdAutoidElement[]): Record<string, SdAutoidElement[]>;
8
21
  /**
@@ -1,12 +1,11 @@
1
1
  import { OnDestroy, OnInit } from '@angular/core';
2
- import { SdBaseSecureComponent } from '@sdcorejs/angular/components/base';
3
2
  import { Color } from '@sdcorejs/utils/models';
4
3
  import { MaterialIconFontSet } from '@sdcorejs/angular/utilities/models';
5
4
  import * as i0 from "@angular/core";
6
5
  export type SdButtonType = 'fill' | 'light' | 'outline' | 'link';
7
6
  export type SdButtonSize = 'sm' | 'md' | 'lg';
8
7
  export type SdButtonHtmlType = 'button' | 'submit' | 'reset';
9
- export declare class SdButton extends SdBaseSecureComponent implements OnInit, OnDestroy {
8
+ export declare class SdButton implements OnInit, OnDestroy {
10
9
  #private;
11
10
  private el;
12
11
  autoIdInput: import("@angular/core").InputSignal<string | null | undefined>;
@@ -1,6 +1,5 @@
1
1
  import { CdkDragDrop, CdkDragMove } from '@angular/cdk/drag-drop';
2
2
  import { FormGroup } from '@angular/forms';
3
- import { SdBaseSecureComponent } from '@sdcorejs/angular/components/base';
4
3
  import { SdModal } from '@sdcorejs/angular/components/modal';
5
4
  import { FormBuilderComponent, FormBuilderComponentGroup, SdFormGenericComponent, SdFormGenericGroup, SdFormGenericVariable } from '../../models';
6
5
  import { SdFormGenericValidation } from '../../models/form-generic-validation.model';
@@ -12,7 +11,7 @@ interface DragDropRowItem {
12
11
  items: (SdFormGenericComponent | SdFormGenericGroup)[];
13
12
  rowIndex?: number;
14
13
  }
15
- export declare class SdFormBuilder extends SdBaseSecureComponent {
14
+ export declare class SdFormBuilder {
16
15
  #private;
17
16
  readonly popupViewJSON: import("@angular/core").Signal<SdModal | undefined>;
18
17
  readonly popupConfigureVariables: import("@angular/core").Signal<SdModal | undefined>;
@@ -39,6 +38,9 @@ export declare class SdFormBuilder extends SdBaseSecureComponent {
39
38
  clonedVariables: SdFormGenericVariable[];
40
39
  readonly selectedComponent: import("@angular/core").WritableSignal<SdFormGenericComponent | SdFormGenericGroup | undefined>;
41
40
  readonly isPreview: import("@angular/core").WritableSignal<boolean>;
41
+ readonly editingGroupId: import("@angular/core").WritableSignal<string | undefined>;
42
+ /** Group đang được Detail (tìm ở TOP-LEVEL theo id), undefined = đang ở canvas chính. */
43
+ readonly editingGroup: import("@angular/core").Signal<SdFormGenericGroup | undefined>;
42
44
  /** Signal toàn cục: TRUE khi BẤT KỲ cdkDrag nào đang active (palette, canvas, group, resize).
43
45
  * Trigger class `.fb-shell--dragging` để ẩn hover/actions/resize toàn diện, không phụ thuộc :has(). */
44
46
  readonly isAnyDragging: import("@angular/core").WritableSignal<boolean>;
@@ -70,15 +72,17 @@ export declare class SdFormBuilder extends SdBaseSecureComponent {
70
72
  };
71
73
  /** Segmented Design/Preview toggle (replaces play_circle/stop_circle). */
72
74
  setMode: (preview: boolean) => void;
73
- /** Nested drop handler when dragging a palette item or canvas item INTO a group body. */
74
- dropInGroup: (event: CdkDragDrop<any[]>, group: SdFormGenericGroup) => void;
75
- /** Quick-add break sau row chỉ định.
76
- * Tính component index cuối cùng của row đó trong this.components, splice break vào sau.
77
- * Không qua palette chỉ utility action bám theo row trên canvas.
75
+ /** Mở canvas thiết kế riêng cho 1 group (chỉ children của nó). Snapshot để Cancel revert. */
76
+ enterGroupEdit: (group: SdFormGenericGroup) => void;
77
+ /** OK: giữ thay đổi children, quay về canvas chính. */
78
+ confirmGroupEdit: () => void;
79
+ /** Cancel: revert children về snapshot lúc vào Detail, rồi quay về canvas chính. */
80
+ cancelGroupEdit: () => void;
81
+ /** Quick-add break sau row chỉ định (theo scope hiện tại — top-level hoặc group).
82
+ * Tính component index cuối cùng của row đó trong scope, splice break vào sau.
78
83
  */
79
84
  insertBreakAfter: (row: DragDropRowItem) => void;
80
- /** Remove a child component from a group's nested list. */
81
- removeFromGroup: (group: SdFormGenericGroup, id: string) => void;
85
+ /** Xoá component theo scope hiện tại (top-level hoặc children của group đang Detail). */
82
86
  removeComponent: (id: string) => void;
83
87
  selectComponent: (item?: SdFormGenericComponent | SdFormGenericGroup) => void;
84
88
  onClickedOutside: (e: any) => void;
@@ -92,12 +96,6 @@ export declare class SdFormBuilder extends SdBaseSecureComponent {
92
96
  noReturnPredicate: () => boolean;
93
97
  changeSizeControl: (event: CdkDragMove<SdFormGenericComponent | SdFormGenericGroup>, item: SdFormGenericComponent | SdFormGenericGroup, items: (SdFormGenericComponent | SdFormGenericGroup)[], currentIndex: number) => Promise<void>;
94
98
  dragEndChangeSizeControl: (event: any) => void;
95
- /** Resize a child item INSIDE a group.
96
- * Math: lấy bounding của chính item, tính (mouse.x - item.left) / colWidth = newCols.
97
- * Cách này đúng cho cả flex-wrap (item ở wrap row 2+) vì dùng item-relative,
98
- * không phải sum-of-all-preceding-cols (sai khi item wrap xuống row mới).
99
- */
100
- changeSizeChildInGroup: (event: CdkDragMove<SdFormGenericComponent>, child: SdFormGenericComponent, group: SdFormGenericGroup) => void;
101
99
  onChangeViewed: (component: SdFormGenericComponent) => void;
102
100
  onChangeHidden: (component: SdFormGenericComponent | SdFormGenericGroup) => void;
103
101
  onDuplicate: (component: SdFormGenericComponent | SdFormGenericGroup) => void;
@@ -1,13 +1,12 @@
1
1
  import { AfterViewInit, ChangeDetectorRef, OnDestroy, QueryList } from '@angular/core';
2
2
  import { FormGroup } from '@angular/forms';
3
- import { SdBaseSecureComponent } from '@sdcorejs/angular/components/base';
4
3
  import { Subject } from 'rxjs';
5
4
  import { ISdFormGenericConfiguration } from '../../configurations';
6
5
  import { SdFormRenderConfiguration } from '../../models';
7
6
  import { SdFormGenericValidation } from '../../models/form-generic-validation.model';
8
7
  import { LibItemComponent } from './components';
9
8
  import * as i0 from "@angular/core";
10
- export declare class SdFormRender extends SdBaseSecureComponent implements OnDestroy, AfterViewInit {
9
+ export declare class SdFormRender implements OnDestroy, AfterViewInit {
11
10
  #private;
12
11
  private ref;
13
12
  private formGenericConfiguration;
@@ -1,12 +1,11 @@
1
1
  import { ChangeDetectorRef, EventEmitter } from '@angular/core';
2
2
  import { FormGroup } from '@angular/forms';
3
- import { SdBaseSecureComponent } from '@sdcorejs/angular/components/base';
4
3
  import { SdModal } from '@sdcorejs/angular/components/modal';
5
4
  import { Attribute, SdFormGenericComponent, SdFormGenericExpression, SdFormGenericGroup } from '../../models';
6
5
  import { ExpressionFeelPipe } from '../../pipes';
7
6
  import { FormGenericService } from '../../services';
8
7
  import * as i0 from "@angular/core";
9
- export declare class SdFeelExpression extends SdBaseSecureComponent {
8
+ export declare class SdFeelExpression {
10
9
  #private;
11
10
  private ref;
12
11
  private expressionFeelPipe;
@@ -3,6 +3,7 @@ export * from '@sdcorejs/angular/components/button';
3
3
  export * from '@sdcorejs/angular/components/badge';
4
4
  export * from '@sdcorejs/angular/components/tab-router';
5
5
  export * from '@sdcorejs/angular/components/side-drawer';
6
+ export * from '@sdcorejs/angular/components/modal-resizable';
6
7
  export * from '@sdcorejs/angular/components/modal';
7
8
  export * from '@sdcorejs/angular/components/table';
8
9
  export * from '@sdcorejs/angular/components/quick-action';
@@ -0,0 +1 @@
1
+ export * from './src/modal-resizable.component';
@@ -0,0 +1,29 @@
1
+ import { CdkPortal } from '@angular/cdk/portal';
2
+ import * as i0 from "@angular/core";
3
+ export declare class SdModalResizable {
4
+ #private;
5
+ readonly id: string;
6
+ readonly portal: import("@angular/core").Signal<CdkPortal>;
7
+ readonly editable: import("@angular/core").InputSignalWithTransform<boolean, boolean | "">;
8
+ readonly width: import("@angular/core").InputSignal<string>;
9
+ readonly editingChanged: import("@angular/core").OutputEmitterRef<boolean>;
10
+ readonly isEditing: import("@angular/core").WritableSignal<boolean>;
11
+ readonly isOpened: import("@angular/core").WritableSignal<boolean>;
12
+ readonly isHover: import("@angular/core").WritableSignal<boolean>;
13
+ readonly isLoading: import("@angular/core").WritableSignal<boolean>;
14
+ readonly isMinimum: import("@angular/core").WritableSignal<boolean>;
15
+ readonly isMaximum: import("@angular/core").WritableSignal<boolean>;
16
+ constructor();
17
+ open: () => void;
18
+ close: () => void;
19
+ minimize: () => void;
20
+ maximize: () => void;
21
+ toggleMaximum: () => void;
22
+ startLoading: () => void;
23
+ stopLoading: () => void;
24
+ toggleEditable(): void;
25
+ onFocus: () => void;
26
+ onBlur: () => void;
27
+ static ɵfac: i0.ɵɵFactoryDeclaration<SdModalResizable, never>;
28
+ static ɵcmp: i0.ɵɵComponentDeclaration<SdModalResizable, "sd-modal-resizable", never, { "editable": { "alias": "editable"; "required": false; "isSignal": true; }; "width": { "alias": "width"; "required": false; "isSignal": true; }; }, { "editingChanged": "editingChanged"; }, never, ["[sdTitle]", "[sdBody]", "[sdFooter]"], true, never>;
29
+ }
@@ -12,6 +12,11 @@ type Density = 'compact' | 'comfortable';
12
12
  * Covers types: boolean, date, datetime, values, lazy-values, plus a fallback else
13
13
  * branch. BETWEEN (date / datetime) uses a single `<sd-date-range>` (datetime
14
14
  * downgrades to date precision).
15
+ *
16
+ * why: `values` / `lazy-values` đã chuyển sang `<sd-select [viewed]="'inline'">` — sd-select
17
+ * tự quản click→edit + focusout→thoát + bare editor, nên các nhánh đó KHÔNG dùng
18
+ * `enterEdit` / `onFocusOut` / `#editing` nữa. Các nhánh còn lại (boolean / date / datetime /
19
+ * BETWEEN) vẫn dùng lifecycle thủ công cho tới khi control tương ứng có inline mode (rollout).
15
20
  */
16
21
  export declare class SdQueryInlineChip {
17
22
  #private;
@@ -43,41 +48,25 @@ export declare class SdQueryInlineChip {
43
48
  /** × removal. */
44
49
  readonly remove: import("@angular/core").OutputEmitterRef<void>;
45
50
  readonly editing: import("@angular/core").Signal<boolean>;
46
- /** Active picker reference — auto-opened right after entering edit. */
47
- private readonly chipPicker;
48
51
  readonly iconName: import("@angular/core").Signal<string>;
49
52
  /** Operator code — convenience accessor for template. */
50
53
  readonly operator: import("@angular/core").Signal<Operator>;
51
54
  /** Data payload — convenience accessor for template. */
52
55
  readonly data: import("@angular/core").Signal<unknown>;
53
- /** Enter edit mode + auto-open the picker on next render. */
56
+ /** Enter edit mode (BOOLEAN branch — shows the toggle buttons; exits on toggle commit). */
54
57
  enterEdit(): void;
55
58
  /**
56
- * Exit edit only when focus actually leaves the wrapper subtree.
57
- * why: focusout fires for every internal blur only exit when relatedTarget
58
- * is OUTSIDE the wrapper AND không thuộc cdk-overlay (mat-select panel, mat-calendar,
59
- * datetime overlay đều render trong document.body). Tick option trong panel multi-
60
- * select sẽ chuyển focus sang `<mat-option>` (nằm trong cdk-overlay-container) →
61
- * nếu exit ngay sẽ flip viewed → kill panel sớm. Chỉ exit khi panel đã close
62
- * (relatedTarget không nằm trong overlay). markForCheck vì overlay focusout
63
- * không kéo theo CD cho OnPush parent.
59
+ * Single-value commit (sd-date, sd-datetime, single sd-select).
60
+ * why: date/datetime/values render via `viewed='inline'` (self-managed)the chip only
61
+ * forwards the value; it no longer toggles `#editing` (that's boolean-only now).
64
62
  */
65
- onFocusOut(ev: FocusEvent): void;
66
- /** Test-only shim — direct call avoids dispatching real FocusEvent in JSDOM. */
67
- onFocusOutForTest(ev: FocusEvent): void;
68
- /** Single-value commit (sd-date, sd-datetime, single sd-select). */
69
63
  emitSingleCommit(v: unknown): void;
70
- /**
71
- * BETWEEN commit — sd-date-range emits {from, to}.
72
- * why: nếu cả from + to đều có giá trị → coi như range đã chọn xong → exit edit
73
- * ngay tại commit (đồng bộ với model.set của parent), không chờ focusout. Tránh
74
- * race "focusout firing trước sdChange" làm viewed text render với model cũ.
75
- */
64
+ /** BETWEEN commit — sd-date-range (viewed='inline') emits `{from, to}`; chip just forwards it. */
76
65
  emitRangeCommit(ev: {
77
66
  from: unknown;
78
67
  to: unknown;
79
68
  } | null): void;
80
- /** Multi-select live emit — does NOT exit edit (focusout handles exit). */
69
+ /** Multi-select live emit (sd-select inline). */
81
70
  emitLive(v: unknown): void;
82
71
  /** Boolean toggle commit — exits edit. */
83
72
  emitBoolean(v: boolean): void;
@@ -49,12 +49,6 @@ export declare class SdQueryInlineValueChip {
49
49
  readonly hasValue: import("@angular/core").Signal<boolean>;
50
50
  readonly state: import("@angular/core").Signal<ChipState>;
51
51
  constructor();
52
- /**
53
- * Width in chars — hugs the current value; falls back to the placeholder width only when
54
- * empty. why: using placeholder.length unconditionally left a long trailing gap before the
55
- * × for short values (e.g. a 1-digit number under the 'giá trị' placeholder).
56
- */
57
- sizeFor(text: string, placeholder: string): number;
58
52
  /** Click anywhere in the pill (except × or an input) focuses the first input. */
59
53
  focusFromShell(ev: Event): void;
60
54
  onFocus(): void;
@@ -63,7 +57,9 @@ export declare class SdQueryInlineValueChip {
63
57
  /** Commit a BETWEEN range — both ends parsed, emitted as `{ from, to }`. */
64
58
  commitRange(): void;
65
59
  /** Esc — revert drafts to the committed value and blur without emitting. */
66
- revertAndBlur(input: HTMLInputElement): void;
60
+ revertAndBlur(ref?: {
61
+ blur: () => void;
62
+ }): void;
67
63
  onRemove(ev: Event): void;
68
64
  static ɵfac: i0.ɵɵFactoryDeclaration<SdQueryInlineValueChip, never>;
69
65
  static ɵcmp: i0.ɵɵComponentDeclaration<SdQueryInlineValueChip, "sd-query-inline-value-chip", never, { "field": { "alias": "field"; "required": true; "isSignal": true; }; "operator": { "alias": "operator"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; "density": { "alias": "density"; "required": false; "isSignal": true; }; "showOperator": { "alias": "showOperator"; "required": false; "isSignal": true; }; "autoId": { "alias": "autoId"; "required": false; "isSignal": true; }; "autofocus": { "alias": "autofocus"; "required": false; "isSignal": true; }; }, { "valueChange": "valueChange"; "remove": "remove"; }, never, never, true, never>;
@@ -1 +1,3 @@
1
1
  export * from './src/query-builder.component';
2
+ export * from './src/query-builder.model';
3
+ export * from './src/query-builder.serializer';
@@ -1,26 +1,102 @@
1
- import { EventEmitter } from '@angular/core';
1
+ import { Filter, Operator } from '@sdcorejs/utils/models';
2
+ import { isQbGroup, QbDateMode, QbGroup, QbRule, QbToken, SdQueryBuilderField, SdQueryBuilderFieldOption } from './query-builder.model';
2
3
  import * as i0 from "@angular/core";
3
- export interface QueryRule {
4
- field: string;
5
- operator: string;
6
- value: any;
7
- }
8
- export interface QueryGroup {
9
- condition: 'AND' | 'OR';
10
- rules: (QueryRule | QueryGroup)[];
11
- isOpen?: boolean;
12
- }
4
+ /**
5
+ * Visual filter / rule builder. Compose nested AND / OR groups of
6
+ * `field operator value` conditions; emits the canonical `Filter` (root is a
7
+ * `FilterAndOr` tree) via `[(value)]`, plus a flat `[(filters)]` mirror of the
8
+ * root group's direct children. `mode="view"` renders a read-only SQL-ish raw
9
+ * string with highlighted operators + values.
10
+ */
13
11
  export declare class SdQueryBuilder {
14
- group: QueryGroup;
15
- groupChange: EventEmitter<QueryGroup>;
16
- isGroup(item: any): item is QueryGroup;
17
- toggleCondition(group: QueryGroup, condition: 'AND' | 'OR'): void;
18
- toggleDropdown(group: QueryGroup, event: Event): void;
19
- closeAll(): void;
20
- closeAllDropdowns(group: QueryGroup): void;
21
- addRule(group: QueryGroup): void;
22
- addGroup(group: QueryGroup): void;
23
- removeItem(parentGroup: QueryGroup, index: number): void;
12
+ #private;
13
+ /** Filterable fields — each declares a `type` that drives the operator set + value editor. */
14
+ readonly fields: import("@angular/core").InputSignal<SdQueryBuilderField[]>;
15
+ /** `'edit'` (default) = interactive tree · `'view'` = read-only raw-query string. */
16
+ readonly mode: import("@angular/core").InputSignal<"edit" | "view">;
17
+ /** Disable all editing controls. */
18
+ readonly disabled: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
19
+ /** Prefix for `data-autoid` on inner controls (E2E selectors). */
20
+ readonly autoId: import("@angular/core").InputSignal<string | undefined>;
21
+ /** Canonical output — the root `FilterAndOr` tree, or `null` when empty. `[(value)]`. */
22
+ readonly value: import("@angular/core").ModelSignal<Filter | null>;
23
+ /** Convenience mirror — the root group's direct children. `[(filters)]`. */
24
+ readonly filters: import("@angular/core").ModelSignal<Filter[]>;
25
+ /** Root group's logical connector. `[(rootLogic)]`. */
26
+ readonly rootLogic: import("@angular/core").ModelSignal<"AND" | "OR">;
27
+ readonly tree: import("@angular/core").Signal<QbGroup>;
28
+ /** `field.key` → field, for fast lookup from a rule. */
29
+ readonly fieldByKey: import("@angular/core").Signal<Record<string, SdQueryBuilderField>>;
30
+ /** Stable option list for the date-mode select. */
31
+ readonly dateModes: readonly {
32
+ value: QbDateMode;
33
+ display: string;
34
+ }[];
35
+ /** Stable combined unit×direction option list for the relative select. */
36
+ readonly relativeUnitOptions: readonly {
37
+ value: string;
38
+ display: string;
39
+ }[];
40
+ /** View-mode token stream — recomputed from the emitted value. */
41
+ readonly tokens: import("@angular/core").Signal<QbToken[]>;
42
+ readonly isView: import("@angular/core").Signal<boolean>;
43
+ /** Expose the type-guard to the template. */
44
+ readonly isGroup: typeof isQbGroup;
45
+ constructor();
46
+ /** Switch a group's AND/OR connector and re-emit. No-op when disabled or unchanged. */
47
+ setGroupLogic(group: QbGroup, logic: 'AND' | 'OR'): void;
48
+ /** Open this group's "+" menu (closing any other open one). UI-only — does not emit. */
49
+ toggleDropdown(group: QbGroup, event: Event): void;
50
+ closeAllDropdowns(): void;
51
+ /** Append a blank rule to `group`. */
52
+ addRule(group: QbGroup): void;
53
+ /** Append a nested sub-group (seeded with one blank rule) to `group`. */
54
+ addGroup(group: QbGroup): void;
55
+ /** Remove the child at `index` from `parent` (a rule or a whole sub-group). */
56
+ removeNode(parent: QbGroup, index: number): void;
57
+ /**
58
+ * Point `rule` at a new field. Resets operator to the field's default and the value
59
+ * to that operator's empty shape — the old operator/value rarely fit the new type.
60
+ *
61
+ * @param rule - the rule being edited.
62
+ * @param key - the chosen field key (from the field picker). Swap-only: a null / undefined
63
+ * key is a no-op — the field can be changed but never cleared (issue #2).
64
+ */
65
+ setField(rule: QbRule, key: any): void;
66
+ /** Change `rule`'s operator and reshape its value to fit the new operator (array / range / none). */
67
+ setOperator(rule: QbRule, op: Operator | undefined): void;
68
+ /** Set a single-value rule's value (coercing numeric fields to `number`). */
69
+ setScalar(rule: QbRule, raw: any): void;
70
+ /** Set the lower bound of a BETWEEN rule's `{ from, to }` value. */
71
+ setBetweenFrom(rule: QbRule, raw: any): void;
72
+ /** Set the upper bound of a BETWEEN rule's `{ from, to }` value. */
73
+ setBetweenTo(rule: QbRule, raw: any): void;
74
+ /** The field metadata for a rule's current `field` key (or undefined if unset). */
75
+ fieldOf(rule: QbRule): SdQueryBuilderField | undefined;
76
+ /** Operators allowed for a rule, derived from its field's type / override. */
77
+ allowedOperators(rule: QbRule): Operator[];
78
+ /** Whether to render the operator picker — hidden when only one operator is allowed. */
79
+ showOperatorSelector(rule: QbRule): boolean;
80
+ /** True for NULL / NOT_NULL — the template then renders no value editor. */
81
+ isNoData(op: Operator | undefined): boolean;
82
+ /** True for IN / NOT_IN — the template then renders a multi-select value editor. */
83
+ isMulti(op: Operator | undefined): boolean;
84
+ /** `[true/false]` option list for a boolean field's value select (stable reference). */
85
+ booleanItems(field: SdQueryBuilderField): SdQueryBuilderFieldOption[];
86
+ /** Current date-value mode of a rule, derived from its value (no separate state). */
87
+ dateMode(rule: QbRule): QbDateMode;
88
+ /** Switch a date/datetime rule's value mode, reseeding the value for the new mode. */
89
+ setDateMode(rule: QbRule, mode: QbDateMode): void;
90
+ /** Read the offset amount of a relative rule (default 1). */
91
+ relativeAmount(rule: QbRule): number;
92
+ /** Set the offset amount (clamped to an integer >= 1). */
93
+ setRelativeAmount(rule: QbRule, raw: any): void;
94
+ /** Read the `'unit:direction'` token of a relative rule (default `'day:previous'`). */
95
+ relativeUnitDirValue(rule: QbRule): string;
96
+ /** Set the offset unit + direction from a `'unit:direction'` token. */
97
+ setRelativeUnitDir(rule: QbRule, token: string): void;
98
+ /** Build a `data-autoid` for an inner control under this builder's `autoId` prefix. */
99
+ autoIdFor(suffix: string): string;
24
100
  static ɵfac: i0.ɵɵFactoryDeclaration<SdQueryBuilder, never>;
25
- static ɵcmp: i0.ɵɵComponentDeclaration<SdQueryBuilder, "sd-query-builder", never, { "group": { "alias": "group"; "required": false; }; }, { "groupChange": "groupChange"; }, never, never, true, never>;
101
+ static ɵcmp: i0.ɵɵComponentDeclaration<SdQueryBuilder, "sd-query-builder", never, { "fields": { "alias": "fields"; "required": false; "isSignal": true; }; "mode": { "alias": "mode"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "autoId": { "alias": "autoId"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; "filters": { "alias": "filters"; "required": false; "isSignal": true; }; "rootLogic": { "alias": "rootLogic"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "filters": "filtersChange"; "rootLogic": "rootLogicChange"; }, never, never, true, never>;
26
102
  }