@sdcorejs/angular 20.0.1 → 20.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 (142) 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/index.d.ts +53 -4
  5. package/components/button/index.d.ts +1 -2
  6. package/components/form-generic/index.d.ts +15 -17
  7. package/components/index.d.ts +1 -0
  8. package/components/modal-resizable/index.d.ts +32 -0
  9. package/components/query-builder/index.d.ts +247 -23
  10. package/components/section/index.d.ts +1 -2
  11. package/components/side-drawer/index.d.ts +1 -2
  12. package/components/stepper/index.d.ts +1 -2
  13. package/components/tab/index.d.ts +1 -2
  14. package/components/table/index.d.ts +100 -12
  15. package/components/upload-file/index.d.ts +2 -0
  16. package/components/view/index.d.ts +33 -0
  17. package/fesm2022/sdcorejs-angular-components-anchor.mjs +9 -9
  18. package/fesm2022/sdcorejs-angular-components-autoid-inspector.mjs +111 -24
  19. package/fesm2022/sdcorejs-angular-components-autoid-inspector.mjs.map +1 -1
  20. package/fesm2022/sdcorejs-angular-components-avatar.mjs +4 -4
  21. package/fesm2022/sdcorejs-angular-components-avatar.mjs.map +1 -1
  22. package/fesm2022/sdcorejs-angular-components-badge.mjs +3 -3
  23. package/fesm2022/sdcorejs-angular-components-base.mjs +3 -3
  24. package/fesm2022/sdcorejs-angular-components-button.mjs +5 -7
  25. package/fesm2022/sdcorejs-angular-components-button.mjs.map +1 -1
  26. package/fesm2022/sdcorejs-angular-components-chart.mjs +12 -12
  27. package/fesm2022/sdcorejs-angular-components-ckeditor-styles.mjs +3 -3
  28. package/fesm2022/sdcorejs-angular-components-code-editor.mjs +3 -3
  29. package/fesm2022/sdcorejs-angular-components-document-builder.mjs +6 -6
  30. package/fesm2022/sdcorejs-angular-components-editor.mjs +3 -3
  31. package/fesm2022/sdcorejs-angular-components-form-generic.mjs +291 -382
  32. package/fesm2022/sdcorejs-angular-components-form-generic.mjs.map +1 -1
  33. package/fesm2022/sdcorejs-angular-components-history.mjs +7 -7
  34. package/fesm2022/sdcorejs-angular-components-import-excel.mjs +10 -10
  35. package/fesm2022/sdcorejs-angular-components-inform.mjs +6 -6
  36. package/fesm2022/sdcorejs-angular-components-mini-editor.mjs +3 -3
  37. package/fesm2022/sdcorejs-angular-components-modal-resizable.mjs +158 -0
  38. package/fesm2022/sdcorejs-angular-components-modal-resizable.mjs.map +1 -0
  39. package/fesm2022/sdcorejs-angular-components-modal.mjs +3 -3
  40. package/fesm2022/sdcorejs-angular-components-operator.mjs +6 -4
  41. package/fesm2022/sdcorejs-angular-components-operator.mjs.map +1 -1
  42. package/fesm2022/sdcorejs-angular-components-preview.mjs +8 -8
  43. package/fesm2022/sdcorejs-angular-components-preview.mjs.map +1 -1
  44. package/fesm2022/sdcorejs-angular-components-query-bar.mjs +60 -106
  45. package/fesm2022/sdcorejs-angular-components-query-bar.mjs.map +1 -1
  46. package/fesm2022/sdcorejs-angular-components-query-builder.mjs +671 -59
  47. package/fesm2022/sdcorejs-angular-components-query-builder.mjs.map +1 -1
  48. package/fesm2022/sdcorejs-angular-components-quick-action.mjs +3 -3
  49. package/fesm2022/sdcorejs-angular-components-section.mjs +7 -9
  50. package/fesm2022/sdcorejs-angular-components-section.mjs.map +1 -1
  51. package/fesm2022/sdcorejs-angular-components-side-drawer.mjs +5 -7
  52. package/fesm2022/sdcorejs-angular-components-side-drawer.mjs.map +1 -1
  53. package/fesm2022/sdcorejs-angular-components-splitter.mjs +12 -12
  54. package/fesm2022/sdcorejs-angular-components-stepper.mjs +7 -9
  55. package/fesm2022/sdcorejs-angular-components-stepper.mjs.map +1 -1
  56. package/fesm2022/sdcorejs-angular-components-tab-router.mjs +18 -18
  57. package/fesm2022/sdcorejs-angular-components-tab.mjs +7 -9
  58. package/fesm2022/sdcorejs-angular-components-tab.mjs.map +1 -1
  59. package/fesm2022/sdcorejs-angular-components-table.mjs +336 -211
  60. package/fesm2022/sdcorejs-angular-components-table.mjs.map +1 -1
  61. package/fesm2022/sdcorejs-angular-components-upload-file.mjs +29 -18
  62. package/fesm2022/sdcorejs-angular-components-upload-file.mjs.map +1 -1
  63. package/fesm2022/sdcorejs-angular-components-view.mjs +45 -13
  64. package/fesm2022/sdcorejs-angular-components-view.mjs.map +1 -1
  65. package/fesm2022/sdcorejs-angular-components.mjs +1 -0
  66. package/fesm2022/sdcorejs-angular-components.mjs.map +1 -1
  67. package/fesm2022/sdcorejs-angular-directives.mjs +21 -21
  68. package/fesm2022/sdcorejs-angular-forms-autocomplete.mjs +35 -10
  69. package/fesm2022/sdcorejs-angular-forms-autocomplete.mjs.map +1 -1
  70. package/fesm2022/sdcorejs-angular-forms-checkbox.mjs +11 -6
  71. package/fesm2022/sdcorejs-angular-forms-checkbox.mjs.map +1 -1
  72. package/fesm2022/sdcorejs-angular-forms-chip-calendar.mjs +15 -10
  73. package/fesm2022/sdcorejs-angular-forms-chip-calendar.mjs.map +1 -1
  74. package/fesm2022/sdcorejs-angular-forms-chip.mjs +15 -10
  75. package/fesm2022/sdcorejs-angular-forms-chip.mjs.map +1 -1
  76. package/fesm2022/sdcorejs-angular-forms-date-range.mjs +21 -12
  77. package/fesm2022/sdcorejs-angular-forms-date-range.mjs.map +1 -1
  78. package/fesm2022/sdcorejs-angular-forms-date.mjs +29 -17
  79. package/fesm2022/sdcorejs-angular-forms-date.mjs.map +1 -1
  80. package/fesm2022/sdcorejs-angular-forms-datetime.mjs +34 -22
  81. package/fesm2022/sdcorejs-angular-forms-datetime.mjs.map +1 -1
  82. package/fesm2022/sdcorejs-angular-forms-directives.mjs +12 -12
  83. package/fesm2022/sdcorejs-angular-forms-inline-text.mjs +167 -0
  84. package/fesm2022/sdcorejs-angular-forms-inline-text.mjs.map +1 -0
  85. package/fesm2022/sdcorejs-angular-forms-input-color.mjs +7 -5
  86. package/fesm2022/sdcorejs-angular-forms-input-color.mjs.map +1 -1
  87. package/fesm2022/sdcorejs-angular-forms-input-number.mjs +44 -11
  88. package/fesm2022/sdcorejs-angular-forms-input-number.mjs.map +1 -1
  89. package/fesm2022/sdcorejs-angular-forms-input.mjs +38 -12
  90. package/fesm2022/sdcorejs-angular-forms-input.mjs.map +1 -1
  91. package/fesm2022/sdcorejs-angular-forms-label.mjs +3 -3
  92. package/fesm2022/sdcorejs-angular-forms-models.mjs +32 -2
  93. package/fesm2022/sdcorejs-angular-forms-models.mjs.map +1 -1
  94. package/fesm2022/sdcorejs-angular-forms-radio.mjs +11 -6
  95. package/fesm2022/sdcorejs-angular-forms-radio.mjs.map +1 -1
  96. package/fesm2022/sdcorejs-angular-forms-select.mjs +36 -12
  97. package/fesm2022/sdcorejs-angular-forms-select.mjs.map +1 -1
  98. package/fesm2022/sdcorejs-angular-forms-switch.mjs +11 -6
  99. package/fesm2022/sdcorejs-angular-forms-switch.mjs.map +1 -1
  100. package/fesm2022/sdcorejs-angular-forms-textarea.mjs +17 -7
  101. package/fesm2022/sdcorejs-angular-forms-textarea.mjs.map +1 -1
  102. package/fesm2022/sdcorejs-angular-forms.mjs +4 -4
  103. package/fesm2022/sdcorejs-angular-handlers.mjs +3 -3
  104. package/fesm2022/sdcorejs-angular-i18n.mjs +26 -6
  105. package/fesm2022/sdcorejs-angular-i18n.mjs.map +1 -1
  106. package/fesm2022/sdcorejs-angular-interceptors.mjs +6 -6
  107. package/fesm2022/sdcorejs-angular-modules-auth.mjs +9 -9
  108. package/fesm2022/sdcorejs-angular-modules-authom.mjs +7 -7
  109. package/fesm2022/sdcorejs-angular-modules-keycloak.mjs +7 -7
  110. package/fesm2022/sdcorejs-angular-modules-layout.mjs +73 -73
  111. package/fesm2022/sdcorejs-angular-modules-permission.mjs +9 -9
  112. package/fesm2022/sdcorejs-angular-pipes.mjs +14 -14
  113. package/fesm2022/sdcorejs-angular-services-api.mjs +10 -10
  114. package/fesm2022/sdcorejs-angular-services-cache.mjs +3 -3
  115. package/fesm2022/sdcorejs-angular-services-confirm.mjs +6 -6
  116. package/fesm2022/sdcorejs-angular-services-confirm.mjs.map +1 -1
  117. package/fesm2022/sdcorejs-angular-services-docx.mjs +3 -3
  118. package/fesm2022/sdcorejs-angular-services-excel.mjs +3 -3
  119. package/fesm2022/sdcorejs-angular-services-license.mjs +3 -3
  120. package/fesm2022/sdcorejs-angular-services-loading.mjs +3 -3
  121. package/fesm2022/sdcorejs-angular-services-notify.mjs +47 -16
  122. package/fesm2022/sdcorejs-angular-services-notify.mjs.map +1 -1
  123. package/fesm2022/sdcorejs-angular-services-storage.mjs +3 -3
  124. package/forms/autocomplete/index.d.ts +16 -3
  125. package/forms/checkbox/index.d.ts +5 -1
  126. package/forms/chip/index.d.ts +5 -2
  127. package/forms/chip-calendar/index.d.ts +5 -2
  128. package/forms/date/index.d.ts +14 -5
  129. package/forms/date-range/index.d.ts +12 -5
  130. package/forms/datetime/index.d.ts +14 -5
  131. package/forms/inline-text/index.d.ts +80 -0
  132. package/forms/input/index.d.ts +14 -2
  133. package/forms/input-color/index.d.ts +3 -1
  134. package/forms/input-number/index.d.ts +14 -2
  135. package/forms/models/index.d.ts +40 -2
  136. package/forms/radio/index.d.ts +5 -2
  137. package/forms/select/index.d.ts +23 -5
  138. package/forms/switch/index.d.ts +5 -2
  139. package/forms/textarea/index.d.ts +9 -2
  140. package/i18n/index.d.ts +4 -0
  141. package/package.json +9 -1
  142. package/services/notify/index.d.ts +17 -0
@@ -1,30 +1,254 @@
1
- import * as i0 from '@angular/core';
2
- import { EventEmitter } from '@angular/core';
1
+ import * as _angular_core from '@angular/core';
2
+ import { Operator, Filter } from '@sdcorejs/utils/models';
3
3
 
4
- interface QueryRule {
5
- field: string;
6
- operator: string;
4
+ /** Field kinds the builder understands. Drives the operator set + value editor. */
5
+ type SdQueryBuilderFieldType = 'string' | 'number' | 'boolean' | 'date' | 'datetime' | 'values';
6
+ /** One option for a `values`-type field (enum / lookup). */
7
+ interface SdQueryBuilderFieldOption {
8
+ /** Stored value (sent inside the `Filter`). */
7
9
  value: any;
10
+ /** Human-readable label shown in the select + view-mode string. */
11
+ display: string;
8
12
  }
9
- interface QueryGroup {
10
- condition: 'AND' | 'OR';
11
- rules: (QueryRule | QueryGroup)[];
12
- isOpen?: boolean;
13
+ /**
14
+ * One filterable field. `key` matches `Filter.field` (dot-notation allowed);
15
+ * `label` is what the view-mode raw string renders (field token = label).
16
+ */
17
+ interface SdQueryBuilderField {
18
+ /** Dot-notation field path — written to `Filter.field`. */
19
+ key: string;
20
+ /** Human label — shown in the field picker AND as the view-mode field token. */
21
+ label: string;
22
+ /** Field type — picks the default operator set + value editor control. */
23
+ type: SdQueryBuilderFieldType;
24
+ /** Override the allowed operator set (otherwise `QB_OPERATORS_BY_TYPE[type]`). */
25
+ operators?: Operator[];
26
+ /** Override the starting operator (otherwise `QB_DEFAULT_OPERATOR_BY_TYPE[type]`). */
27
+ defaultOperator?: Operator;
28
+ /** Options for `type: 'values'` — the select list + display-label lookup. */
29
+ values?: SdQueryBuilderFieldOption[];
30
+ /** Label for the `true` branch of a boolean field (default `'Có'`). */
31
+ trueLabel?: string;
32
+ /** Label for the `false` branch of a boolean field (default `'Không'`). */
33
+ falseLabel?: string;
34
+ /** Lower bound for number / date value editors. */
35
+ min?: number | string;
36
+ /** Upper bound for number / date value editors. */
37
+ max?: number | string;
13
38
  }
39
+ type QbNode = QbGroup | QbRule;
40
+ /** A logical group of nodes joined by AND / OR. Maps to `FilterAndOr`. */
41
+ interface QbGroup {
42
+ id: string;
43
+ kind: 'group';
44
+ logic: 'AND' | 'OR';
45
+ children: QbNode[];
46
+ /** UI-only: whether this group's "+" dropdown is open. */
47
+ open?: boolean;
48
+ }
49
+ /** A single `field operator value` condition. Maps to a leaf `Filter`. */
50
+ interface QbRule {
51
+ id: string;
52
+ kind: 'rule';
53
+ field?: string;
54
+ operator?: Operator;
55
+ /** Single value, `{ from, to }` for BETWEEN, or an array for IN / NOT_IN. */
56
+ value?: any;
57
+ }
58
+ /** Type guard — narrows a `QbNode` to a `QbGroup`. */
59
+ declare function isQbGroup(node: QbNode): node is QbGroup;
60
+ type QbTokenKind = 'field' | 'op' | 'value' | 'logic' | 'paren' | 'plain';
61
+ /** One piece of the rendered raw query string, tagged for highlight styling. */
62
+ interface QbToken {
63
+ text: string;
64
+ kind: QbTokenKind;
65
+ }
66
+ /** Allowed operators per field type — used when `field.operators` is not set. */
67
+ declare const QB_OPERATORS_BY_TYPE: Record<SdQueryBuilderFieldType, Operator[]>;
68
+ /** Default operator when a rule is first created for a field. */
69
+ declare const QB_DEFAULT_OPERATOR_BY_TYPE: Record<SdQueryBuilderFieldType, Operator>;
70
+ /** Operators with no value payload — the value editor is hidden for these. */
71
+ declare const QB_NO_DATA_OPERATORS: Operator[];
72
+ /** Operators whose value is an array — the value editor offers multi-select. */
73
+ declare const QB_MULTI_OPERATORS: Operator[];
74
+ /** Operators allowed for `field` — explicit override wins, else the per-type set. */
75
+ declare function qbAllowedOperators(field: SdQueryBuilderField | undefined): Operator[];
76
+ /** Starting operator for a new rule on `field` — falls back to the per-type default. */
77
+ declare function qbDefaultOperator(field: SdQueryBuilderField | undefined): Operator | undefined;
78
+ /** True when `op` is NULL / NOT_NULL (no value editor). */
79
+ declare function qbIsNoDataOperator(op: Operator | undefined): boolean;
80
+ /** True when `op` is IN / NOT_IN (array value). */
81
+ declare function qbIsMultiOperator(op: Operator | undefined): boolean;
82
+ /** Next stable node id with the given prefix. */
83
+ declare function qbId(prefix?: string): string;
84
+ /** Build a fresh rule node (optionally pre-filled). */
85
+ declare function qbNewRule(field?: string, operator?: Operator, value?: any): QbRule;
86
+ /** Build a fresh group node. */
87
+ declare function qbNewGroup(logic?: 'AND' | 'OR', children?: QbNode[]): QbGroup;
88
+ /** Offset unit for a relative date. */
89
+ type SdQbRelativeUnit = 'day' | 'week' | 'month';
90
+ /** Offset direction for a relative date. */
91
+ type SdQbRelativeDirection = 'previous' | 'next';
92
+ /** A relative (resolved-at-query-time) date value stored in `Filter.data`. */
93
+ interface SdQbRelativeDate {
94
+ /** `'now'` = current moment / today · `'offset'` = now ± amount × unit. */
95
+ rel: 'now' | 'offset';
96
+ /** Offset unit — only for `rel: 'offset'`. */
97
+ unit?: SdQbRelativeUnit;
98
+ /** Offset magnitude (>= 1) — only for `rel: 'offset'`. */
99
+ amount?: number;
100
+ /** Offset direction — only for `rel: 'offset'`. */
101
+ direction?: SdQbRelativeDirection;
102
+ }
103
+ /** Date value editor mode for a date/datetime rule (derived from the rule value). */
104
+ type QbDateMode = 'absolute' | 'now' | 'relative';
105
+ /** Type guard — narrows an arbitrary value to a relative-date spec. */
106
+ declare function qbIsRelativeDate(v: any): v is SdQbRelativeDate;
107
+ /** Starting relative value when a rule first switches to "relative" mode. */
108
+ declare function qbDefaultRelative(): SdQbRelativeDate;
109
+ /** Stable option list for the date-mode select (module ref — never reallocated). */
110
+ declare const QB_DATE_MODES: ReadonlyArray<{
111
+ value: QbDateMode;
112
+ display: string;
113
+ }>;
114
+ /** Stable combined direction×unit option list (token `'unit:direction'`). */
115
+ declare const QB_RELATIVE_UNIT_OPTIONS: ReadonlyArray<{
116
+ value: string;
117
+ display: string;
118
+ }>;
119
+ /** Shared empty option array — stable ref for fallbacks (avoids per-call allocation). */
120
+ declare const QB_EMPTY_OPTIONS: SdQueryBuilderFieldOption[];
121
+
122
+ /**
123
+ * Visual filter / rule builder. Compose nested AND / OR groups of
124
+ * `field operator value` conditions; emits the canonical `Filter` (root is a
125
+ * `FilterAndOr` tree) via `[(value)]`, plus a flat `[(filters)]` mirror of the
126
+ * root group's direct children. `mode="view"` renders a read-only SQL-ish raw
127
+ * string with highlighted operators + values.
128
+ */
14
129
  declare class SdQueryBuilder {
15
- group: QueryGroup;
16
- groupChange: EventEmitter<QueryGroup>;
17
- isGroup(item: any): item is QueryGroup;
18
- toggleCondition(group: QueryGroup, condition: 'AND' | 'OR'): void;
19
- toggleDropdown(group: QueryGroup, event: Event): void;
20
- closeAll(): void;
21
- closeAllDropdowns(group: QueryGroup): void;
22
- addRule(group: QueryGroup): void;
23
- addGroup(group: QueryGroup): void;
24
- removeItem(parentGroup: QueryGroup, index: number): void;
25
- static ɵfac: i0.ɵɵFactoryDeclaration<SdQueryBuilder, never>;
26
- static ɵcmp: i0.ɵɵComponentDeclaration<SdQueryBuilder, "sd-query-builder", never, { "group": { "alias": "group"; "required": false; }; }, { "groupChange": "groupChange"; }, never, never, true, never>;
130
+ #private;
131
+ /** Filterable fields — each declares a `type` that drives the operator set + value editor. */
132
+ readonly fields: _angular_core.InputSignal<SdQueryBuilderField[]>;
133
+ /** `'edit'` (default) = interactive tree · `'view'` = read-only raw-query string. */
134
+ readonly mode: _angular_core.InputSignal<"edit" | "view">;
135
+ /** Disable all editing controls. */
136
+ readonly disabled: _angular_core.InputSignalWithTransform<boolean, unknown>;
137
+ /** Prefix for `data-autoid` on inner controls (E2E selectors). */
138
+ readonly autoId: _angular_core.InputSignal<string | undefined>;
139
+ /** Canonical output — the root `FilterAndOr` tree, or `null` when empty. `[(value)]`. */
140
+ readonly value: _angular_core.ModelSignal<Filter | null>;
141
+ /** Convenience mirror the root group's direct children. `[(filters)]`. */
142
+ readonly filters: _angular_core.ModelSignal<Filter[]>;
143
+ /** Root group's logical connector. `[(rootLogic)]`. */
144
+ readonly rootLogic: _angular_core.ModelSignal<"AND" | "OR">;
145
+ readonly tree: _angular_core.Signal<QbGroup>;
146
+ /** `field.key` → field, for fast lookup from a rule. */
147
+ readonly fieldByKey: _angular_core.Signal<Record<string, SdQueryBuilderField>>;
148
+ /** Stable option list for the date-mode select. */
149
+ readonly dateModes: readonly {
150
+ value: QbDateMode;
151
+ display: string;
152
+ }[];
153
+ /** Stable combined unit×direction option list for the relative select. */
154
+ readonly relativeUnitOptions: readonly {
155
+ value: string;
156
+ display: string;
157
+ }[];
158
+ /** View-mode token stream — recomputed from the emitted value. */
159
+ readonly tokens: _angular_core.Signal<QbToken[]>;
160
+ readonly isView: _angular_core.Signal<boolean>;
161
+ /** Expose the type-guard to the template. */
162
+ readonly isGroup: typeof isQbGroup;
163
+ constructor();
164
+ /** Switch a group's AND/OR connector and re-emit. No-op when disabled or unchanged. */
165
+ setGroupLogic(group: QbGroup, logic: 'AND' | 'OR'): void;
166
+ /** Open this group's "+" menu (closing any other open one). UI-only — does not emit. */
167
+ toggleDropdown(group: QbGroup, event: Event): void;
168
+ closeAllDropdowns(): void;
169
+ /** Append a blank rule to `group`. */
170
+ addRule(group: QbGroup): void;
171
+ /** Append a nested sub-group (seeded with one blank rule) to `group`. */
172
+ addGroup(group: QbGroup): void;
173
+ /** Remove the child at `index` from `parent` (a rule or a whole sub-group). */
174
+ removeNode(parent: QbGroup, index: number): void;
175
+ /**
176
+ * Point `rule` at a new field. Resets operator to the field's default and the value
177
+ * to that operator's empty shape — the old operator/value rarely fit the new type.
178
+ *
179
+ * @param rule - the rule being edited.
180
+ * @param key - the chosen field key (from the field picker). Swap-only: a null / undefined
181
+ * key is a no-op — the field can be changed but never cleared (issue #2).
182
+ */
183
+ setField(rule: QbRule, key: any): void;
184
+ /** Change `rule`'s operator and reshape its value to fit the new operator (array / range / none). */
185
+ setOperator(rule: QbRule, op: Operator | undefined): void;
186
+ /** Set a single-value rule's value (coercing numeric fields to `number`). */
187
+ setScalar(rule: QbRule, raw: any): void;
188
+ /** Set the lower bound of a BETWEEN rule's `{ from, to }` value. */
189
+ setBetweenFrom(rule: QbRule, raw: any): void;
190
+ /** Set the upper bound of a BETWEEN rule's `{ from, to }` value. */
191
+ setBetweenTo(rule: QbRule, raw: any): void;
192
+ /** The field metadata for a rule's current `field` key (or undefined if unset). */
193
+ fieldOf(rule: QbRule): SdQueryBuilderField | undefined;
194
+ /** Operators allowed for a rule, derived from its field's type / override. */
195
+ allowedOperators(rule: QbRule): Operator[];
196
+ /** Whether to render the operator picker — hidden when only one operator is allowed. */
197
+ showOperatorSelector(rule: QbRule): boolean;
198
+ /** True for NULL / NOT_NULL — the template then renders no value editor. */
199
+ isNoData(op: Operator | undefined): boolean;
200
+ /** True for IN / NOT_IN — the template then renders a multi-select value editor. */
201
+ isMulti(op: Operator | undefined): boolean;
202
+ /** `[true/false]` option list for a boolean field's value select (stable reference). */
203
+ booleanItems(field: SdQueryBuilderField): SdQueryBuilderFieldOption[];
204
+ /** Current date-value mode of a rule, derived from its value (no separate state). */
205
+ dateMode(rule: QbRule): QbDateMode;
206
+ /** Switch a date/datetime rule's value mode, reseeding the value for the new mode. */
207
+ setDateMode(rule: QbRule, mode: QbDateMode): void;
208
+ /** Read the offset amount of a relative rule (default 1). */
209
+ relativeAmount(rule: QbRule): number;
210
+ /** Set the offset amount (clamped to an integer >= 1). */
211
+ setRelativeAmount(rule: QbRule, raw: any): void;
212
+ /** Read the `'unit:direction'` token of a relative rule (default `'day:previous'`). */
213
+ relativeUnitDirValue(rule: QbRule): string;
214
+ /** Set the offset unit + direction from a `'unit:direction'` token. */
215
+ setRelativeUnitDir(rule: QbRule, token: string): void;
216
+ /** Build a `data-autoid` for an inner control under this builder's `autoId` prefix. */
217
+ autoIdFor(suffix: string): string;
218
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<SdQueryBuilder, never>;
219
+ static ɵcmp: _angular_core.ɵɵ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>;
27
220
  }
28
221
 
29
- export { SdQueryBuilder };
30
- export type { QueryGroup, QueryRule };
222
+ /**
223
+ * Map the internal builder tree to the public `Filter` (the root is always a
224
+ * `FilterAndOr`). Rules missing field / operator / value — and empty nested
225
+ * groups — are dropped so the result is always a valid `Filter`.
226
+ *
227
+ * @param group - the editable tree's root group.
228
+ * @returns the canonical nested `Filter`, or `null` when no complete rule survives.
229
+ */
230
+ declare function treeToFilter(group: QbGroup): Filter | null;
231
+ /**
232
+ * Inverse of {@link treeToFilter} — rebuild the editable tree from a `Filter` so a
233
+ * consumer can seed `[value]`. A non-group (bare) filter is wrapped in an AND root;
234
+ * `null` yields an empty AND root.
235
+ *
236
+ * @param filter - a `Filter` (group or leaf), or `null` / `undefined` for an empty tree.
237
+ * @returns a fresh root `QbGroup` mirroring the filter's structure.
238
+ */
239
+ declare function filterToTree(filter: Filter | null | undefined): QbGroup;
240
+ /**
241
+ * Render a `Filter` to a SQL-ish token stream for view mode. Field tokens use the
242
+ * matching field's `label`; operators map to SQL syntax (`= != like between is null …`);
243
+ * `and` / `or` are lowercase; nested multi-child groups are wrapped in parentheses.
244
+ * Returns a token stream (not a string) so the template can wrap each piece in a
245
+ * highlight `<span>` keyed by `QbToken.kind`.
246
+ *
247
+ * @param filter - the `Filter` to render, or `null` / `undefined`.
248
+ * @param fields - field metadata, used to resolve each field key to its display label + value formatting.
249
+ * @returns the ordered tokens, or `[]` when `filter` is empty.
250
+ */
251
+ declare function filterToTokens(filter: Filter | null | undefined, fields: SdQueryBuilderField[]): QbToken[];
252
+
253
+ export { QB_DATE_MODES, QB_DEFAULT_OPERATOR_BY_TYPE, QB_EMPTY_OPTIONS, QB_MULTI_OPERATORS, QB_NO_DATA_OPERATORS, QB_OPERATORS_BY_TYPE, QB_RELATIVE_UNIT_OPTIONS, SdQueryBuilder, filterToTokens, filterToTree, isQbGroup, qbAllowedOperators, qbDefaultOperator, qbDefaultRelative, qbId, qbIsMultiOperator, qbIsNoDataOperator, qbIsRelativeDate, qbNewGroup, qbNewRule, treeToFilter };
254
+ export type { QbDateMode, QbGroup, QbNode, QbRule, QbToken, QbTokenKind, SdQbRelativeDate, SdQbRelativeDirection, SdQbRelativeUnit, SdQueryBuilderField, SdQueryBuilderFieldOption, SdQueryBuilderFieldType };
@@ -1,8 +1,7 @@
1
1
  import * as _angular_core from '@angular/core';
2
- import { SdBaseSecureComponent } from '@sdcorejs/angular/components/base';
3
2
  import { Color } from '@sdcorejs/utils/models';
4
3
 
5
- declare class SdSection extends SdBaseSecureComponent {
4
+ declare class SdSection {
6
5
  #private;
7
6
  title: _angular_core.InputSignal<string | null | undefined>;
8
7
  subTitle: _angular_core.InputSignal<string | null | undefined>;
@@ -1,9 +1,8 @@
1
1
  import * as _angular_core from '@angular/core';
2
2
  import { CdkPortal } from '@angular/cdk/portal';
3
- import { SdBaseSecureComponent } from '@sdcorejs/angular/components/base';
4
3
  import { Observable } from 'rxjs';
5
4
 
6
- declare class SdSideDrawer extends SdBaseSecureComponent {
5
+ declare class SdSideDrawer {
7
6
  #private;
8
7
  id: string;
9
8
  portal: _angular_core.Signal<CdkPortal>;
@@ -3,7 +3,6 @@ import { TemplateRef } from '@angular/core';
3
3
  import { AbstractControl } from '@angular/forms';
4
4
  import { StepperSelectionEvent } from '@angular/cdk/stepper';
5
5
  import { MatStepper } from '@angular/material/stepper';
6
- import { SdBaseSecureComponent } from '@sdcorejs/angular/components/base';
7
6
  import { Color } from '@sdcorejs/utils/models';
8
7
 
9
8
  type SdStepState = 'pending' | 'active' | 'completed' | 'error' | string;
@@ -21,7 +20,7 @@ declare class SdStep {
21
20
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<SdStep, "sd-step", never, { "label": { "alias": "label"; "required": true; "isSignal": true; }; "icon": { "alias": "icon"; "required": false; "isSignal": true; }; "optional": { "alias": "optional"; "required": false; "isSignal": true; }; "editable": { "alias": "editable"; "required": false; "isSignal": true; }; "stepControl": { "alias": "stepControl"; "required": false; "isSignal": true; }; "state": { "alias": "state"; "required": false; "isSignal": true; }; "errorMessage": { "alias": "errorMessage"; "required": false; "isSignal": true; }; }, { "selectChange": "selectChange"; }, never, ["*"], true, never>;
22
21
  }
23
22
 
24
- declare class SdStepper extends SdBaseSecureComponent {
23
+ declare class SdStepper {
25
24
  steps: _angular_core.Signal<readonly SdStep[]>;
26
25
  selectedIndex: _angular_core.ModelSignal<number>;
27
26
  linear: _angular_core.InputSignalWithTransform<boolean, unknown>;
@@ -1,7 +1,6 @@
1
1
  import * as _angular_core from '@angular/core';
2
2
  import { TemplateRef } from '@angular/core';
3
3
  import { MatTabGroup } from '@angular/material/tabs';
4
- import { SdBaseSecureComponent } from '@sdcorejs/angular/components/base';
5
4
  import { Color } from '@sdcorejs/utils/models';
6
5
 
7
6
  declare class SdTab {
@@ -20,7 +19,7 @@ interface SdTabClosedEvent {
20
19
  index: number;
21
20
  tab: SdTab;
22
21
  }
23
- declare class SdTabGroup extends SdBaseSecureComponent {
22
+ declare class SdTabGroup {
24
23
  tabs: _angular_core.Signal<readonly SdTab[]>;
25
24
  selectedIndex: _angular_core.ModelSignal<number>;
26
25
  variant: _angular_core.InputSignal<"line" | "pills" | "segmented">;
@@ -11,7 +11,6 @@ import { SdExcelColumn, SdLoadingService, SdExcelService, SdNotifyService, SdCon
11
11
  import { Observable } from 'rxjs';
12
12
  import { SdButton } from '@sdcorejs/angular/components/button';
13
13
  import { CdkDrag, CdkDropList, CdkDragDrop } from '@angular/cdk/drag-drop';
14
- import { SdBaseSecureComponent } from '@sdcorejs/angular/components/base';
15
14
  import { SdQuickAction } from '@sdcorejs/angular/components/quick-action';
16
15
  import { SdScrollDirective } from '@sdcorejs/angular/directives';
17
16
  import { FormGroup } from '@angular/forms';
@@ -710,16 +709,103 @@ interface SdTableOptionStyle<T = any> {
710
709
  rowCss?: (rowData: T, index?: number, ctx?: SdTableRowCssContext) => Record<string, string>;
711
710
  }
712
711
 
713
- interface SdTableOptionTree<T = any> {
714
- /** Key trên object row chứa mảng children. Mặc định: 'children' */
715
- childrenKey?: string;
716
- /** Giới hạn độ sâu cây. undefined = không giới hạn. */
712
+ /**
713
+ * Cấu hình tree-rows cho `<sd-table>` render dòng con inline dưới dòng cha
714
+ * kèm expand/collapse.
715
+ *
716
+ * Đây là discriminated union theo `loadType`:
717
+ * - `'static'` ({@link TableOptionTreeStatic}) — children đã nằm sẵn trong data
718
+ * (embedded array tại `childrenKey`). Không gọi API khi bung.
719
+ * - `'lazy'` ({@link TableOptionTreeLazy}) — children nạp theo yêu cầu qua
720
+ * `onExpandChildren` khi người dùng bung dòng lần đầu.
721
+ *
722
+ * `loadType` là discriminant: TypeScript dựa vào nó để narrow union (vd chỉ
723
+ * `static` mới có `childrenKey`/`defaultExpanded`, chỉ `lazy` mới có
724
+ * `onExpandChildren`). Dùng type-guard `isLazyTree()` trong `tree.util.ts` để
725
+ * narrow an toàn thay vì truy cập field trực tiếp trên union.
726
+ *
727
+ * @example Static (children embedded)
728
+ * ```ts
729
+ * tree: { loadType: 'static', childrenKey: 'children', defaultExpanded: 1 }
730
+ * ```
731
+ * @example Lazy (nạp theo yêu cầu)
732
+ * ```ts
733
+ * tree: { loadType: 'lazy', onExpandChildren: row => api.getChildren(row.id) }
734
+ * ```
735
+ */
736
+ type SdTableOptionTree<T = any> = TableOptionTreeStatic<T> | TableOptionTreeLazy<T>;
737
+ /**
738
+ * Tree với dữ liệu children **embedded** sẵn trong mỗi row.
739
+ *
740
+ * Table đọc mảng con tại `childrenKey` ngay trên object data; không có lời gọi
741
+ * bất đồng bộ nào khi bung dòng. Đây cũng là chế độ hỗ trợ **search ở cấp con**
742
+ * cho table `type: 'local'` (xem `tree.util.ts#subtreeMatches` /
743
+ * `filterMatchingChildren`): khi lọc, một nhánh được giữ lại nếu chính nó hoặc
744
+ * bất kỳ hậu duệ nào khớp từ khoá, và nhánh khớp sẽ tự bung.
745
+ */
746
+ interface TableOptionTreeStatic<T = any> {
747
+ /** Chế độ nạp children: dữ liệu đã embedded sẵn trong row. */
748
+ loadType: 'static';
749
+ /**
750
+ * Key trên object row chứa mảng children.
751
+ * Mặc định: `'children'`.
752
+ */
753
+ childrenKey?: NestedKeyOf<T> | 'children';
754
+ /**
755
+ * Giới hạn độ sâu cây (level gốc = 0).
756
+ * `undefined` = không giới hạn.
757
+ */
717
758
  maxDepth?: number;
718
- /** false | true | number (mở tới cấp N) */
759
+ /**
760
+ * Trạng thái bung mặc định khi load:
761
+ * - `false` — thu gọn hết (mặc định)
762
+ * - `true` — bung toàn bộ
763
+ * - `number N` — bung tới cấp `N` (row có `level < N` được bung)
764
+ */
719
765
  defaultExpanded?: boolean | number;
720
- /** Lazy load khi row chưa có children embedded */
721
- onExpandChildren?: (rowData: T) => Promise<T[]> | T[];
722
- /** Pixel indent mỗi cấp. Mặc định: 20 */
766
+ /**
767
+ * Số pixel thụt lề (indent) cho mỗi cấp sâu.
768
+ * Mặc định: `20`.
769
+ */
770
+ indentSize?: number;
771
+ }
772
+ /**
773
+ * Tree với children **nạp lười (lazy)** theo yêu cầu.
774
+ *
775
+ * Khi người dùng bung một dòng lần đầu mà dòng đó chưa có children embedded,
776
+ * table gọi `onExpandChildren(row)` để nạp; kết quả được cache lại trên row
777
+ * (ghi vào key `'children'`) nên các lần bung sau không gọi lại.
778
+ *
779
+ * Lazy tree **không hỗ trợ** `childrenKey` tuỳ biến (luôn dùng `'children'` làm
780
+ * nơi lưu kết quả) và **không hỗ trợ** `defaultExpanded` (không thể bung mặc
781
+ * định nhánh chưa nạp).
782
+ */
783
+ interface TableOptionTreeLazy<T = any> {
784
+ /** Chế độ nạp children: nạp lười theo yêu cầu khi bung. */
785
+ loadType: 'lazy';
786
+ /**
787
+ * Giới hạn độ sâu cây (level gốc = 0).
788
+ * `undefined` = không giới hạn.
789
+ */
790
+ maxDepth?: number;
791
+ /**
792
+ * Hàm nạp children khi bung dòng chưa có children embedded.
793
+ * Trả về `Promise<T[]>`; kết quả được ghi vào key `'children'` của row data
794
+ * và cache cho các lần bung sau.
795
+ */
796
+ onExpandChildren: (rowData: T) => Promise<T[]>;
797
+ /**
798
+ * Xác định một row có con hay không — để quyết định có hiển thị icon expand.
799
+ * - Không truyền: MỌI lazy node đều hiện icon expand (không biết trước được).
800
+ * - Truyền: chỉ hiện icon khi trả `true`; trả `false` ⇒ row là lá (ẩn icon,
801
+ * không gọi `onExpandChildren`).
802
+ * Lưu ý: nếu row đã có children embedded sẵn thì luôn coi là có con (bỏ qua hàm này).
803
+ */
804
+ hasChildren?: (rowData: T) => boolean;
805
+ /**
806
+ * Số pixel thụt lề (indent) cho mỗi cấp sâu.
807
+ * Mặc định: `20`.
808
+ */
723
809
  indentSize?: number;
724
810
  }
725
811
 
@@ -954,8 +1040,10 @@ declare class MobileFilterComponent {
954
1040
 
955
1041
  declare class ConfigComponent {
956
1042
  #private;
1043
+ autoIdInput: _angular_core.InputSignal<string | null | undefined>;
957
1044
  tableOption: _angular_core.InputSignal<SdTableOption | undefined>;
958
1045
  changes: _angular_core.OutputEmitterRef<ConfiguredTableResult>;
1046
+ autoId: _angular_core.Signal<string>;
959
1047
  modal: _angular_core.Signal<SdModal | undefined>;
960
1048
  table: _angular_core.Signal<MatTable<SdTableColumn>>;
961
1049
  configuration: _angular_core.WritableSignal<ConfiguredTable | undefined>;
@@ -969,7 +1057,7 @@ declare class ConfigComponent {
969
1057
  handleMouseDown(): void;
970
1058
  handleMouseUp(): void;
971
1059
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<ConfigComponent, never>;
972
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<ConfigComponent, "config", never, { "tableOption": { "alias": "tableOption"; "required": false; "isSignal": true; }; }, { "changes": "changes"; }, never, never, true, never>;
1060
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<ConfigComponent, "config", never, { "autoIdInput": { "alias": "autoId"; "required": false; "isSignal": true; }; "tableOption": { "alias": "tableOption"; "required": false; "isSignal": true; }; }, { "changes": "changes"; }, never, never, true, never>;
973
1061
  }
974
1062
 
975
1063
  declare class SdPopupExport {
@@ -1056,7 +1144,7 @@ declare class MatPaginatorIntlCro extends MatPaginatorIntl {
1056
1144
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<MatPaginatorIntlCro, never>;
1057
1145
  static ɵprov: _angular_core.ɵɵInjectableDeclaration<MatPaginatorIntlCro>;
1058
1146
  }
1059
- declare class SdTable<T = unknown> extends SdBaseSecureComponent implements OnInit, AfterViewInit, OnDestroy {
1147
+ declare class SdTable<T = unknown> implements OnInit, AfterViewInit, OnDestroy {
1060
1148
  #private;
1061
1149
  autoIdInput: _angular_core.InputSignal<string | null | undefined>;
1062
1150
  autoId: _angular_core.Signal<string | undefined>;
@@ -1158,4 +1246,4 @@ declare class SdTable<T = unknown> extends SdBaseSecureComponent implements OnIn
1158
1246
  }
1159
1247
 
1160
1248
  export { MatPaginatorIntlCro, SD_TABLE_CONFIGURATION, SdConvertToPagingReq, SdMaterialFooterDefDirective, SdTable, SdTableCellDefDirective, SdTableExpandDefDirective, SdTableFilterDefDirective, SdTableGroupDefDirective, SdTableTitleDefDirective };
1161
- export type { ISdTableConfiguration, SdTableColumn, SdTableColumnChildren, SdTableColumnLazyValues, SdTableColumnNormal, SdTableColumnTransformFunc, SdTableColumnValues, SdTableCommand, SdTableCommandChildren, SdTableCommandNormal, SdTableCommandOption, SdTableDisplay, SdTableExternalFilter, SdTableFilterRequest, SdTableGroupDefContext, SdTableItem, SdTableMeta, SdTableOption, SdTableOptionFilter, SdTableOptionTree, SdTableQuickFilter, TableFilterConfiguration, TableFilterRegister, TableFilterValue };
1249
+ export type { ISdTableConfiguration, SdTableColumn, SdTableColumnChildren, SdTableColumnLazyValues, SdTableColumnNormal, SdTableColumnTransformFunc, SdTableColumnValues, SdTableCommand, SdTableCommandChildren, SdTableCommandNormal, SdTableCommandOption, SdTableDisplay, SdTableExternalFilter, SdTableFilterRequest, SdTableGroupDefContext, SdTableItem, SdTableMeta, SdTableOption, SdTableOptionFilter, SdTableOptionTree, SdTableQuickFilter, TableFilterConfiguration, TableFilterRegister, TableFilterValue, TableOptionTreeLazy, TableOptionTreeStatic };
@@ -92,6 +92,8 @@ declare class SdUploadFile<TArgs = any> {
92
92
  #private;
93
93
  readonly id: string;
94
94
  readonly formControl: SdFormControl;
95
+ /** Hiển thị message "vui lòng upload": không disabled + đã touched + còn lỗi required. */
96
+ readonly showRequiredError: _angular_core.Signal<boolean>;
95
97
  readonly previewFiles: _angular_core.WritableSignal<PreviewFile[]>;
96
98
  readonly selectedFile: _angular_core.WritableSignal<PreviewFile | null | undefined>;
97
99
  readonly previewFileComponent: _angular_core.Signal<PreviewComponent | undefined>;
@@ -1,17 +1,50 @@
1
1
  import * as _angular_core from '@angular/core';
2
2
  import { TemplateRef } from '@angular/core';
3
3
 
4
+ /**
5
+ * `<sd-view>` — pure read-only display of a value (text, hyperlink, or a custom template).
6
+ *
7
+ * Presentational proxy with no state of its own: the parent form control (`<sd-select>`,
8
+ * `<sd-input>`, …) computes the display string + resolved selection and passes them in;
9
+ * `<sd-view>` only decides WHICH template renders. It is the single rendering path for every
10
+ * "viewed" state across the form controls (DETAIL `viewed=true` and the `viewed='inline'`
11
+ * text face), so a custom `valueTemplate` (e.g. `sdViewDef` / `#sdValue`) looks identical in
12
+ * both. OnPush — re-renders only when an input signal changes.
13
+ */
4
14
  declare class SdView {
15
+ /** Optional label rendered above the value (omitted when a parent supplies its own label). */
5
16
  label: _angular_core.InputSignal<string | null | undefined>;
17
+ /** Raw selected value — NOT rendered directly; only exposed in the `valueTemplate` context as `value`. */
6
18
  value: _angular_core.InputSignal<any>;
19
+ /**
20
+ * Display string — what shows when no custom value template is bound.
21
+ * why: `input.required()` forces the parent to bind `[display]` (compile error otherwise),
22
+ * so the component never has to guess a fallback string from `value`.
23
+ */
7
24
  display: _angular_core.InputSignal<string | null | undefined>;
25
+ /** When set, the value renders as a link (`<a [sdHref]>`) instead of plain text. */
8
26
  hyperlink: _angular_core.InputSignal<string | null | undefined>;
27
+ /** Label template handed down by a parent control (wins over `label` + `#sdLabel`). */
9
28
  labelTemplate: _angular_core.InputSignal<TemplateRef<any> | undefined>;
29
+ /** Value template handed down by a parent control (wins over `display` + `#sdValue`). */
10
30
  valueTemplate: _angular_core.InputSignal<TemplateRef<any> | undefined>;
31
+ /**
32
+ * Resolved selected-item objects passed by the parent (e.g. `<sd-select>`).
33
+ * why: the parent owns option/lazy resolution — `<sd-view>` is a proxy and must NOT rebuild
34
+ * the list. Exposed in the value-template context so a "head +N" template can read `displayField`.
35
+ */
11
36
  selectedItems: _angular_core.InputSignal<any[] | undefined>;
37
+ /** `#sdLabel` template projected directly into `<sd-view>` (fallback when no `[labelTemplate]`). */
12
38
  contentLabelTemplate: _angular_core.Signal<TemplateRef<any> | undefined>;
39
+ /** `#sdValue` template projected directly into `<sd-view>` (fallback when no `[valueTemplate]`). */
13
40
  contentValueTemplate: _angular_core.Signal<TemplateRef<any> | undefined>;
41
+ /**
42
+ * Effective label template: input from parent wins, else the projected `#sdLabel`.
43
+ * why: `computed` caches the choice so the template's `@if (activeLabelTemplate())` doesn't
44
+ * re-evaluate two content-child reads on every change-detection pass.
45
+ */
14
46
  activeLabelTemplate: _angular_core.Signal<TemplateRef<any> | undefined>;
47
+ /** Effective value template: input from parent wins, else the projected `#sdValue`. Cached for the same reason. */
15
48
  activeValueTemplate: _angular_core.Signal<TemplateRef<any> | undefined>;
16
49
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<SdView, never>;
17
50
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<SdView, "sd-view", never, { "label": { "alias": "label"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; "display": { "alias": "display"; "required": true; "isSignal": true; }; "hyperlink": { "alias": "hyperlink"; "required": false; "isSignal": true; }; "labelTemplate": { "alias": "labelTemplate"; "required": false; "isSignal": true; }; "valueTemplate": { "alias": "valueTemplate"; "required": false; "isSignal": true; }; "selectedItems": { "alias": "selectedItems"; "required": false; "isSignal": true; }; }, {}, ["contentLabelTemplate", "contentValueTemplate"], never, true, never>;