@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
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;
@@ -20,6 +20,9 @@ interface SdAutoidElementState {
20
20
  minlength?: string;
21
21
  pattern?: string;
22
22
  errorMessage?: string;
23
+ type?: string;
24
+ title?: string;
25
+ message?: string;
23
26
  }
24
27
  interface SdAutoidElement {
25
28
  stt: number;
@@ -42,6 +45,14 @@ interface SdAutoidElement {
42
45
  * Used by the UI to group table-scoped elements into a separate section.
43
46
  */
44
47
  tableScope?: string;
48
+ /**
49
+ * `true` when the element matched a required selector (sd-button, sd-input, …) but
50
+ * had NO `data-autoid` — the scanner still emits it with `autoid: ''` and a positional
51
+ * `xpath` fallback so the export stays usable. The dev should backfill an autoid.
52
+ */
53
+ missingAutoid?: boolean;
54
+ /** Human-readable warning attached to a fallback element (only set when `missingAutoid`). */
55
+ warning?: string;
45
56
  }
46
57
  interface SdAutoidMissing {
47
58
  tag: string;
@@ -119,14 +130,46 @@ declare class SdAutoidInspector implements OnDestroy {
119
130
 
120
131
  type SdAutoidExportFormat = 'csv' | 'json' | 'md-pom' | 'md-table';
121
132
  interface SdAutoidExportMeta {
133
+ /** `location.pathname + location.search` — kept for back-compat with MD exports. */
122
134
  pageUrl: string;
123
135
  pageTitle: string;
124
136
  timestamp: string;
137
+ /** Full `location.href`. */
138
+ url: string;
139
+ /** `location.pathname` only. */
140
+ pathname: string;
141
+ /** Raw `location.search` (incl. leading `?`), or `''`. */
142
+ search: string;
143
+ /** Parsed query string → key/value map (last value wins on repeats). */
144
+ queryParams: Record<string, string>;
145
+ /**
146
+ * Angular route path params (`:id`, …) merged across the activated-route tree.
147
+ * Only present when an Angular `Router` is available at scan time; omitted otherwise.
148
+ */
149
+ params?: Record<string, string>;
150
+ }
151
+ /** JSON export envelope: page meta + the scanned elements. */
152
+ interface SdAutoidExportJson {
153
+ meta: SdAutoidExportMeta;
154
+ elements: SdAutoidElement[];
125
155
  }
126
156
 
127
157
  declare class SdAutoidScannerService {
128
- /** Quét toàn bộ element có [data-autoid] trong root, gắn thông tin name/tag/value/xpath. */
129
- scan(root?: HTMLElement): SdAutoidElement[];
158
+ /**
159
+ * Quét element có [data-autoid] trong root, gắn name/tag/value/xpath.
160
+ * Khi truyền `requireSelectors` (vd các sd-* form/button), những node khớp selector
161
+ * mà KHÔNG có data-autoid (self lẫn con) sẽ được thêm vào dưới dạng phần tử fallback
162
+ * (`autoid: ''`, xpath theo vị trí thẻ + cờ `missingAutoid` + warning) — để JSON xuất ra
163
+ * vẫn dùng được và dev biết chỗ cần bổ sung autoid.
164
+ */
165
+ scan(root?: HTMLElement, requireSelectors?: ReadonlyArray<string>): SdAutoidElement[];
166
+ /**
167
+ * Tìm các node khớp `requireSelectors` nhưng thiếu data-autoid (self + mọi descendant),
168
+ * thêm vào `result` dưới dạng phần tử fallback. Trả về `stt` kế tiếp.
169
+ */
170
+ private appendMissing;
171
+ /** XPath theo vị trí thẻ trong document, vd `(//sd-button)[2]`, khi không có autoid. */
172
+ private fallbackXpath;
130
173
  /** Group element theo autoid để consumer lấy duplicate map. */
131
174
  groupByAutoid(elements: SdAutoidElement[]): Record<string, SdAutoidElement[]>;
132
175
  /**
@@ -177,7 +220,13 @@ declare class SdAutoidHighlightService {
177
220
  }
178
221
 
179
222
  declare class SdAutoidExportService {
180
- toJson(elements: SdAutoidElement[]): string;
223
+ /**
224
+ * Có `meta` → bọc `{ meta, elements }` (kèm url/queryParams) để consumer biết trang/route.
225
+ * Không `meta` → giữ mảng thuần (back-compat cho caller cũ chỉ cần elements).
226
+ */
227
+ toJson(elements: SdAutoidElement[], meta?: SdAutoidExportMeta): string;
228
+ /** Parse a `location.search` string into a flat key/value map (last value wins). */
229
+ parseQueryParams(search: string): Record<string, string>;
181
230
  toCsv(elements: SdAutoidElement[]): string;
182
231
  /** POM TypeScript skeleton — copy ngay vào file Playwright/Cypress. */
183
232
  toMarkdownPom(elements: SdAutoidElement[], meta: SdAutoidExportMeta): string;
@@ -196,4 +245,4 @@ declare class SdAutoidExportService {
196
245
  }
197
246
 
198
247
  export { SD_AUTOID_DEFAULT_REQUIRE_SELECTORS, SdAutoidAuditService, SdAutoidExportService, SdAutoidHighlightService, SdAutoidInspector, SdAutoidScannerService };
199
- export type { SdAutoidAuditResult, SdAutoidElement, SdAutoidElementState, SdAutoidExportFormat, SdAutoidExportMeta, SdAutoidInspectorConfig, SdAutoidMissing };
248
+ export type { SdAutoidAuditResult, SdAutoidElement, SdAutoidElementState, SdAutoidExportFormat, SdAutoidExportJson, SdAutoidExportMeta, SdAutoidInspectorConfig, SdAutoidMissing };
@@ -1,13 +1,12 @@
1
1
  import * as _angular_core from '@angular/core';
2
2
  import { OnInit, OnDestroy } from '@angular/core';
3
- import { SdBaseSecureComponent } from '@sdcorejs/angular/components/base';
4
3
  import { Color } from '@sdcorejs/utils/models';
5
4
  import { MaterialIconFontSet } from '@sdcorejs/angular/utilities/models';
6
5
 
7
6
  type SdButtonType = 'fill' | 'light' | 'outline' | 'link';
8
7
  type SdButtonSize = 'sm' | 'md' | 'lg';
9
8
  type SdButtonHtmlType = 'button' | 'submit' | 'reset';
10
- declare class SdButton extends SdBaseSecureComponent implements OnInit, OnDestroy {
9
+ declare class SdButton implements OnInit, OnDestroy {
11
10
  #private;
12
11
  private el;
13
12
  autoIdInput: _angular_core.InputSignal<string | null | undefined>;
@@ -7,7 +7,6 @@ import { Operator as Operator$1, ValidationPatternType, Color } from '@sdcorejs/
7
7
  import { SdUnwrapSignal } from '@sdcorejs/angular/utilities/models';
8
8
  import { CdkDragMove, CdkDragDrop } from '@angular/cdk/drag-drop';
9
9
  import { FormGroup } from '@angular/forms';
10
- import { SdBaseSecureComponent } from '@sdcorejs/angular/components/base';
11
10
  import { SdModal } from '@sdcorejs/angular/components/modal';
12
11
  import { Subject } from 'rxjs';
13
12
  import { SdSideDrawer } from '@sdcorejs/angular/components/side-drawer';
@@ -690,7 +689,7 @@ declare class LibItemComponent {
690
689
  static ɵcmp: i0.ɵɵComponentDeclaration<LibItemComponent, "lib-item", never, { "setVariables": { "alias": "setVariables"; "required": true; }; "form": { "alias": "form"; "required": false; }; "_entity": { "alias": "entity"; "required": true; }; "_component": { "alias": "component"; "required": true; }; "_disabled": { "alias": "disabled"; "required": false; }; "_required": { "alias": "required"; "required": false; }; "_viewed": { "alias": "viewed"; "required": false; }; "_validator": { "alias": "validator"; "required": false; }; }, {}, never, never, true, never>;
691
690
  }
692
691
 
693
- declare class SdFormRender extends SdBaseSecureComponent implements OnDestroy, AfterViewInit {
692
+ declare class SdFormRender implements OnDestroy, AfterViewInit {
694
693
  #private;
695
694
  private ref;
696
695
  private formGenericConfiguration;
@@ -749,7 +748,7 @@ interface DragDropRowItem {
749
748
  items: (SdFormGenericComponent | SdFormGenericGroup)[];
750
749
  rowIndex?: number;
751
750
  }
752
- declare class SdFormBuilder extends SdBaseSecureComponent {
751
+ declare class SdFormBuilder {
753
752
  #private;
754
753
  readonly popupViewJSON: i0.Signal<SdModal | undefined>;
755
754
  readonly popupConfigureVariables: i0.Signal<SdModal | undefined>;
@@ -776,6 +775,9 @@ declare class SdFormBuilder extends SdBaseSecureComponent {
776
775
  clonedVariables: SdFormGenericVariable[];
777
776
  readonly selectedComponent: i0.WritableSignal<SdFormGenericComponent | SdFormGenericGroup | undefined>;
778
777
  readonly isPreview: i0.WritableSignal<boolean>;
778
+ readonly editingGroupId: i0.WritableSignal<string | undefined>;
779
+ /** Group đang được Detail (tìm ở TOP-LEVEL theo id), undefined = đang ở canvas chính. */
780
+ readonly editingGroup: i0.Signal<SdFormGenericGroup | undefined>;
779
781
  /** Signal toàn cục: TRUE khi BẤT KỲ cdkDrag nào đang active (palette, canvas, group, resize).
780
782
  * Trigger class `.fb-shell--dragging` để ẩn hover/actions/resize toàn diện, không phụ thuộc :has(). */
781
783
  readonly isAnyDragging: i0.WritableSignal<boolean>;
@@ -807,15 +809,17 @@ declare class SdFormBuilder extends SdBaseSecureComponent {
807
809
  };
808
810
  /** Segmented Design/Preview toggle (replaces play_circle/stop_circle). */
809
811
  setMode: (preview: boolean) => void;
810
- /** Nested drop handler when dragging a palette item or canvas item INTO a group body. */
811
- dropInGroup: (event: CdkDragDrop<any[]>, group: SdFormGenericGroup) => void;
812
- /** Quick-add break sau row chỉ định.
813
- * Tính component index cuối cùng của row đó trong this.components, splice break vào sau.
814
- * Không qua palette chỉ utility action bám theo row trên canvas.
812
+ /** Mở canvas thiết kế riêng cho 1 group (chỉ children của nó). Snapshot để Cancel revert. */
813
+ enterGroupEdit: (group: SdFormGenericGroup) => void;
814
+ /** OK: giữ thay đổi children, quay về canvas chính. */
815
+ confirmGroupEdit: () => void;
816
+ /** Cancel: revert children về snapshot lúc vào Detail, rồi quay về canvas chính. */
817
+ cancelGroupEdit: () => void;
818
+ /** Quick-add break sau row chỉ định (theo scope hiện tại — top-level hoặc group).
819
+ * Tính component index cuối cùng của row đó trong scope, splice break vào sau.
815
820
  */
816
821
  insertBreakAfter: (row: DragDropRowItem) => void;
817
- /** Remove a child component from a group's nested list. */
818
- removeFromGroup: (group: SdFormGenericGroup, id: string) => void;
822
+ /** Xoá component theo scope hiện tại (top-level hoặc children của group đang Detail). */
819
823
  removeComponent: (id: string) => void;
820
824
  selectComponent: (item?: SdFormGenericComponent | SdFormGenericGroup) => void;
821
825
  onClickedOutside: (e: any) => void;
@@ -829,12 +833,6 @@ declare class SdFormBuilder extends SdBaseSecureComponent {
829
833
  noReturnPredicate: () => boolean;
830
834
  changeSizeControl: (event: CdkDragMove<SdFormGenericComponent | SdFormGenericGroup>, item: SdFormGenericComponent | SdFormGenericGroup, items: (SdFormGenericComponent | SdFormGenericGroup)[], currentIndex: number) => Promise<void>;
831
835
  dragEndChangeSizeControl: (event: any) => void;
832
- /** Resize a child item INSIDE a group.
833
- * Math: lấy bounding của chính item, tính (mouse.x - item.left) / colWidth = newCols.
834
- * Cách này đúng cho cả flex-wrap (item ở wrap row 2+) vì dùng item-relative,
835
- * không phải sum-of-all-preceding-cols (sai khi item wrap xuống row mới).
836
- */
837
- changeSizeChildInGroup: (event: CdkDragMove<SdFormGenericComponent>, child: SdFormGenericComponent, group: SdFormGenericGroup) => void;
838
836
  onChangeViewed: (component: SdFormGenericComponent) => void;
839
837
  onChangeHidden: (component: SdFormGenericComponent | SdFormGenericGroup) => void;
840
838
  onDuplicate: (component: SdFormGenericComponent | SdFormGenericGroup) => void;
@@ -855,7 +853,7 @@ declare class SdFormBuilder extends SdBaseSecureComponent {
855
853
  static ɵcmp: i0.ɵɵComponentDeclaration<SdFormBuilder, "sd-form-builder", never, { "formGeneric": { "alias": "formGeneric"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
856
854
  }
857
855
 
858
- declare class SdFeelExpression extends SdBaseSecureComponent {
856
+ declare class SdFeelExpression {
859
857
  #private;
860
858
  private ref;
861
859
  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,32 @@
1
+ import * as _angular_core from '@angular/core';
2
+ import { CdkPortal } from '@angular/cdk/portal';
3
+
4
+ declare class SdModalResizable {
5
+ #private;
6
+ readonly id: string;
7
+ readonly portal: _angular_core.Signal<CdkPortal>;
8
+ readonly editable: _angular_core.InputSignalWithTransform<boolean, boolean | "">;
9
+ readonly width: _angular_core.InputSignal<string>;
10
+ readonly editingChanged: _angular_core.OutputEmitterRef<boolean>;
11
+ readonly isEditing: _angular_core.WritableSignal<boolean>;
12
+ readonly isOpened: _angular_core.WritableSignal<boolean>;
13
+ readonly isHover: _angular_core.WritableSignal<boolean>;
14
+ readonly isLoading: _angular_core.WritableSignal<boolean>;
15
+ readonly isMinimum: _angular_core.WritableSignal<boolean>;
16
+ readonly isMaximum: _angular_core.WritableSignal<boolean>;
17
+ constructor();
18
+ open: () => void;
19
+ close: () => void;
20
+ minimize: () => void;
21
+ maximize: () => void;
22
+ toggleMaximum: () => void;
23
+ startLoading: () => void;
24
+ stopLoading: () => void;
25
+ toggleEditable(): void;
26
+ onFocus: () => void;
27
+ onBlur: () => void;
28
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<SdModalResizable, never>;
29
+ static ɵcmp: _angular_core.ɵɵ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>;
30
+ }
31
+
32
+ export { SdModalResizable };