@sd-angular/core 19.0.0-beta.6 → 19.0.0-beta.60

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 (219) hide show
  1. package/README.md +686 -33
  2. package/assets/scss/ckeditor5.scss +60 -2
  3. package/assets/scss/core/bootstrap.scss +17 -0
  4. package/assets/scss/core/form.scss +4 -1
  5. package/assets/scss/core/grid.scss +40 -0
  6. package/assets/scss/sd-core.scss +1 -0
  7. package/components/avatar/index.d.ts +1 -0
  8. package/components/avatar/src/avatar.component.d.ts +19 -0
  9. package/components/badge/src/badge.component.d.ts +77 -19
  10. package/components/button/src/button.component.d.ts +30 -28
  11. package/components/code-editor/index.d.ts +1 -0
  12. package/components/code-editor/src/code-editor.component.d.ts +25 -0
  13. package/components/document-builder/index.d.ts +1 -0
  14. package/components/document-builder/src/document-builder.component.d.ts +12 -41
  15. package/components/document-builder/src/document-builder.model.d.ts +14 -11
  16. package/components/document-builder/src/plugins/block-space/block-space.plugin.d.ts +9 -0
  17. package/components/document-builder/src/plugins/ck-comment/ck-comment.plugin.d.ts +44 -0
  18. package/components/document-builder/src/plugins/ck-comment/ck-comment.plugin.model.d.ts +57 -0
  19. package/components/document-builder/src/plugins/heading/heading.plugin.d.ts +1 -0
  20. package/components/document-builder/src/plugins/highlight-range/highlight-range.plugin.d.ts +4 -0
  21. package/components/document-builder/src/plugins/image-custom/image-custom.plugin.d.ts +31 -0
  22. package/components/document-builder/src/plugins/index.d.ts +7 -2
  23. package/components/document-builder/src/plugins/page-orientation/page-orientation.plugin.d.ts +2 -2
  24. package/components/document-builder/src/plugins/paste-handler/filters/bookmark.d.ts +14 -0
  25. package/components/document-builder/src/plugins/paste-handler/filters/br.d.ts +15 -0
  26. package/components/document-builder/src/plugins/paste-handler/filters/image.d.ts +25 -0
  27. package/components/document-builder/src/plugins/paste-handler/filters/list.d.ts +29 -0
  28. package/components/document-builder/src/plugins/paste-handler/filters/parse.d.ts +35 -0
  29. package/components/document-builder/src/plugins/paste-handler/filters/removeboldwrapper.d.ts +15 -0
  30. package/components/document-builder/src/plugins/paste-handler/filters/removegooglesheetstag.d.ts +15 -0
  31. package/components/document-builder/src/plugins/paste-handler/filters/removeinvalidtablewidth.d.ts +15 -0
  32. package/components/document-builder/src/plugins/paste-handler/filters/removemsattributes.d.ts +15 -0
  33. package/components/document-builder/src/plugins/paste-handler/filters/removestyleblock.d.ts +15 -0
  34. package/components/document-builder/src/plugins/paste-handler/filters/removexmlns.d.ts +15 -0
  35. package/components/document-builder/src/plugins/paste-handler/filters/replacemsfootnotes.d.ts +54 -0
  36. package/components/document-builder/src/plugins/paste-handler/filters/replacetabswithinprewithspaces.d.ts +24 -0
  37. package/components/document-builder/src/plugins/paste-handler/filters/space.d.ts +27 -0
  38. package/components/document-builder/src/plugins/paste-handler/filters/table.d.ts +16 -0
  39. package/components/document-builder/src/plugins/paste-handler/filters/utils.d.ts +25 -0
  40. package/components/document-builder/src/plugins/paste-handler/index.d.ts +35 -0
  41. package/components/document-builder/src/plugins/paste-handler/normalizers/googledocsnormalizer.d.ts +31 -0
  42. package/components/document-builder/src/plugins/paste-handler/normalizers/googlesheetsnormalizer.d.ts +31 -0
  43. package/components/document-builder/src/plugins/paste-handler/normalizers/mswordnormalizer.d.ts +29 -0
  44. package/components/document-builder/src/plugins/paste-handler/types.d.ts +30 -0
  45. package/components/document-builder/src/plugins/table-custom/index.d.ts +34 -0
  46. package/components/document-builder/src/plugins/variable/variable.plugin.d.ts +39 -0
  47. package/components/index.d.ts +4 -0
  48. package/components/mini-editor/index.d.ts +2 -0
  49. package/components/mini-editor/src/mini-editor.component.d.ts +90 -0
  50. package/components/mini-editor/src/mini-editor.model.d.ts +44 -0
  51. package/components/section/src/section.component.d.ts +10 -11
  52. package/components/side-drawer/src/side-drawer.component.d.ts +11 -24
  53. package/components/tab-router/src/components/tab-router-item/tab-router-item.component.d.ts +4 -1
  54. package/components/tab-router/src/components/tab-router-outlet/tab-router-outlet.component.d.ts +3 -15
  55. package/components/table/src/components/column-filter/column-filter.component.d.ts +3 -3
  56. package/components/table/src/components/desktop-cell/desktop-cell.component.d.ts +12 -2
  57. package/components/table/src/components/desktop-cell-view/desktop-cell-view.component.d.ts +12 -2
  58. package/components/table/src/components/external-filter/external-filter.component.d.ts +1 -1
  59. package/components/table/src/components/selector-action/action-filter.pipe.d.ts +11 -10
  60. package/components/table/src/components/selector-action/selector-action.component.d.ts +5 -3
  61. package/components/table/src/directives/index.d.ts +2 -0
  62. package/components/table/src/directives/sd-table-column-filter-def.directive.d.ts +9 -0
  63. package/components/table/src/directives/sticky-shadow.directive.d.ts +17 -0
  64. package/components/table/src/models/table-column.model.d.ts +34 -34
  65. package/components/table/src/models/table-command.model.d.ts +7 -3
  66. package/components/table/src/models/table-item.model.d.ts +5 -4
  67. package/components/table/src/models/table-option-config.model.d.ts +5 -0
  68. package/components/table/src/models/table-option-export.model.d.ts +3 -2
  69. package/components/table/src/models/table-option-selector.model.d.ts +11 -10
  70. package/components/table/src/models/table-option.model.d.ts +10 -9
  71. package/components/table/src/services/index.d.ts +3 -0
  72. package/components/table/src/services/table-export/table-export.service.d.ts +26 -0
  73. package/components/table/src/services/table-filter/table-filter.model.d.ts +5 -4
  74. package/components/table/src/services/table-format/table-format.service.d.ts +16 -0
  75. package/components/table/src/table.component.d.ts +39 -53
  76. package/components/upload-file/src/configurations/upload-file.configuration.d.ts +1 -1
  77. package/components/upload-file/src/services/upload-file.service.d.ts +0 -1
  78. package/components/upload-file/src/upload-file.component.d.ts +49 -54
  79. package/components/view/index.d.ts +1 -0
  80. package/components/view/src/view.component.d.ts +16 -0
  81. package/components/workflow/src/models/form-generic-component.model.d.ts +5 -4
  82. package/components/workflow/src/models/index.d.ts +1 -0
  83. package/directives/index.d.ts +1 -0
  84. package/directives/src/sd-href.directive.d.ts +9 -0
  85. package/fesm2022/sd-angular-core-components-avatar.mjs +103 -0
  86. package/fesm2022/sd-angular-core-components-avatar.mjs.map +1 -0
  87. package/fesm2022/sd-angular-core-components-badge.mjs +101 -91
  88. package/fesm2022/sd-angular-core-components-badge.mjs.map +1 -1
  89. package/fesm2022/sd-angular-core-components-button.mjs +70 -96
  90. package/fesm2022/sd-angular-core-components-button.mjs.map +1 -1
  91. package/fesm2022/sd-angular-core-components-code-editor.mjs +129 -0
  92. package/fesm2022/sd-angular-core-components-code-editor.mjs.map +1 -0
  93. package/fesm2022/sd-angular-core-components-document-builder.mjs +3994 -608
  94. package/fesm2022/sd-angular-core-components-document-builder.mjs.map +1 -1
  95. package/fesm2022/sd-angular-core-components-history.mjs +1 -1
  96. package/fesm2022/sd-angular-core-components-history.mjs.map +1 -1
  97. package/fesm2022/sd-angular-core-components-import-excel.mjs +1 -1
  98. package/fesm2022/sd-angular-core-components-import-excel.mjs.map +1 -1
  99. package/fesm2022/sd-angular-core-components-mini-editor.mjs +326 -0
  100. package/fesm2022/sd-angular-core-components-mini-editor.mjs.map +1 -0
  101. package/fesm2022/sd-angular-core-components-preview.mjs +1 -1
  102. package/fesm2022/sd-angular-core-components-preview.mjs.map +1 -1
  103. package/fesm2022/sd-angular-core-components-section.mjs +24 -42
  104. package/fesm2022/sd-angular-core-components-section.mjs.map +1 -1
  105. package/fesm2022/sd-angular-core-components-side-drawer.mjs +78 -84
  106. package/fesm2022/sd-angular-core-components-side-drawer.mjs.map +1 -1
  107. package/fesm2022/sd-angular-core-components-tab-router.mjs +152 -226
  108. package/fesm2022/sd-angular-core-components-tab-router.mjs.map +1 -1
  109. package/fesm2022/sd-angular-core-components-table.mjs +1129 -1131
  110. package/fesm2022/sd-angular-core-components-table.mjs.map +1 -1
  111. package/fesm2022/sd-angular-core-components-upload-file.mjs +339 -444
  112. package/fesm2022/sd-angular-core-components-upload-file.mjs.map +1 -1
  113. package/fesm2022/sd-angular-core-components-view.mjs +45 -0
  114. package/fesm2022/sd-angular-core-components-view.mjs.map +1 -0
  115. package/fesm2022/sd-angular-core-components-workflow.mjs +47 -57
  116. package/fesm2022/sd-angular-core-components-workflow.mjs.map +1 -1
  117. package/fesm2022/sd-angular-core-components.mjs +4 -0
  118. package/fesm2022/sd-angular-core-components.mjs.map +1 -1
  119. package/fesm2022/sd-angular-core-directives.mjs +80 -27
  120. package/fesm2022/sd-angular-core-directives.mjs.map +1 -1
  121. package/fesm2022/sd-angular-core-forms-autocomplete.mjs +274 -364
  122. package/fesm2022/sd-angular-core-forms-autocomplete.mjs.map +1 -1
  123. package/fesm2022/sd-angular-core-forms-chip-calendar.mjs +5 -2
  124. package/fesm2022/sd-angular-core-forms-chip-calendar.mjs.map +1 -1
  125. package/fesm2022/sd-angular-core-forms-chip.mjs +5 -2
  126. package/fesm2022/sd-angular-core-forms-chip.mjs.map +1 -1
  127. package/fesm2022/sd-angular-core-forms-date-range.mjs +160 -245
  128. package/fesm2022/sd-angular-core-forms-date-range.mjs.map +1 -1
  129. package/fesm2022/sd-angular-core-forms-date.mjs +153 -273
  130. package/fesm2022/sd-angular-core-forms-date.mjs.map +1 -1
  131. package/fesm2022/sd-angular-core-forms-datetime.mjs +152 -288
  132. package/fesm2022/sd-angular-core-forms-datetime.mjs.map +1 -1
  133. package/fesm2022/sd-angular-core-forms-input-number.mjs +191 -338
  134. package/fesm2022/sd-angular-core-forms-input-number.mjs.map +1 -1
  135. package/fesm2022/sd-angular-core-forms-input.mjs +149 -287
  136. package/fesm2022/sd-angular-core-forms-input.mjs.map +1 -1
  137. package/fesm2022/sd-angular-core-forms-radio.mjs +3 -2
  138. package/fesm2022/sd-angular-core-forms-radio.mjs.map +1 -1
  139. package/fesm2022/sd-angular-core-forms-select.mjs +375 -448
  140. package/fesm2022/sd-angular-core-forms-select.mjs.map +1 -1
  141. package/fesm2022/sd-angular-core-forms-textarea.mjs +138 -227
  142. package/fesm2022/sd-angular-core-forms-textarea.mjs.map +1 -1
  143. package/fesm2022/sd-angular-core-modules-keycloak.mjs +126 -0
  144. package/fesm2022/sd-angular-core-modules-keycloak.mjs.map +1 -0
  145. package/fesm2022/sd-angular-core-modules-layout.mjs +454 -453
  146. package/fesm2022/sd-angular-core-modules-layout.mjs.map +1 -1
  147. package/fesm2022/sd-angular-core-modules.mjs +1 -1
  148. package/fesm2022/sd-angular-core-services-api.mjs +5 -10
  149. package/fesm2022/sd-angular-core-services-api.mjs.map +1 -1
  150. package/fesm2022/sd-angular-core-services-confirm.mjs +2 -2
  151. package/fesm2022/sd-angular-core-services-confirm.mjs.map +1 -1
  152. package/fesm2022/sd-angular-core-services-docx.mjs +173 -0
  153. package/fesm2022/sd-angular-core-services-docx.mjs.map +1 -0
  154. package/fesm2022/sd-angular-core-services-notify.mjs +2 -2
  155. package/fesm2022/sd-angular-core-services-notify.mjs.map +1 -1
  156. package/fesm2022/sd-angular-core-services.mjs +1 -0
  157. package/fesm2022/sd-angular-core-services.mjs.map +1 -1
  158. package/fesm2022/sd-angular-core-utilities-extensions.mjs +21 -45
  159. package/fesm2022/sd-angular-core-utilities-extensions.mjs.map +1 -1
  160. package/fesm2022/sd-angular-core-utilities-models.mjs +15 -1
  161. package/fesm2022/sd-angular-core-utilities-models.mjs.map +1 -1
  162. package/forms/autocomplete/src/autocomplete.component.d.ts +50 -55
  163. package/forms/chip/src/chip.component.d.ts +3 -2
  164. package/forms/chip-calendar/src/chip-calendar.component.d.ts +3 -2
  165. package/forms/date/src/date.component.d.ts +43 -46
  166. package/forms/date-range/src/date-range.component.d.ts +30 -34
  167. package/forms/datetime/src/datetime.component.d.ts +43 -49
  168. package/forms/input/src/input.component.d.ts +48 -57
  169. package/forms/input-number/src/input-number.component.d.ts +48 -54
  170. package/forms/select/src/select.component.d.ts +62 -64
  171. package/forms/textarea/src/textarea.component.d.ts +36 -42
  172. package/modules/index.d.ts +1 -1
  173. package/modules/keycloak/index.d.ts +4 -0
  174. package/modules/keycloak/keycloak.configuration.d.ts +11 -0
  175. package/modules/keycloak/keycloak.interceptor.d.ts +2 -0
  176. package/modules/keycloak/keycloak.module.d.ts +18 -0
  177. package/modules/keycloak/keycloak.service.d.ts +14 -0
  178. package/modules/layout/components/layout-main/layout-main.component.d.ts +7 -12
  179. package/modules/layout/components/page/page.component.d.ts +5 -7
  180. package/modules/layout/components/sidebar-v1/components/sidebar/sidebar.component.d.ts +22 -29
  181. package/modules/layout/components/sidebar-v1/components/user/user.component.d.ts +11 -17
  182. package/modules/layout/components/sidebar-v1/main.component.d.ts +14 -14
  183. package/modules/layout/configurations/layout.configuration.d.ts +46 -3
  184. package/modules/layout/modules/forbidden/pages/root/root.component.d.ts +3 -8
  185. package/modules/layout/modules/home/components/home-page/home-page.component.d.ts +2 -5
  186. package/modules/layout/modules/not-found/pages/root/root.component.d.ts +3 -8
  187. package/modules/layout/pipes/high-light-search.pipe.d.ts +1 -1
  188. package/modules/layout/services/index.d.ts +1 -0
  189. package/modules/layout/services/layout.service.d.ts +10 -0
  190. package/modules/layout/services/menu/menu.model.d.ts +2 -0
  191. package/modules/layout/services/storage/storage.service.d.ts +0 -3
  192. package/package.json +93 -70
  193. package/sd-angular-core-19.0.0-beta.60.tgz +0 -0
  194. package/services/api/src/api.model.d.ts +6 -1
  195. package/services/confirm/src/lib/confirm.service.d.ts +1 -0
  196. package/services/docx/index.d.ts +1 -0
  197. package/services/docx/src/lib/docx.model.d.ts +9 -0
  198. package/services/docx/src/lib/docx.service.d.ts +13 -0
  199. package/services/docx/src/public-api.d.ts +2 -0
  200. package/services/index.d.ts +1 -0
  201. package/services/notify/index.d.ts +1 -0
  202. package/services/notify/src/notify.model.d.ts +1 -1
  203. package/services/notify/src/notify.service.d.ts +5 -5
  204. package/utilities/extensions/src/string.extension.d.ts +2 -0
  205. package/utilities/extensions/src/utility.extension.d.ts +1 -0
  206. package/utilities/models/index.d.ts +3 -0
  207. package/utilities/models/src/filter.model.d.ts +14 -2
  208. package/utilities/models/src/icon.model.d.ts +2 -0
  209. package/utilities/models/src/nested-key-of.model.d.ts +5 -0
  210. package/utilities/models/src/pattern.model.d.ts +1 -1
  211. package/utilities/models/src/unwrap-signal.model.d.ts +6 -0
  212. package/components/document-builder/src/plugins/comment/comment.plugin.d.ts +0 -4
  213. package/components/document-builder/src/plugins/table-fit/table-fit.plugin.d.ts +0 -4
  214. package/fesm2022/sd-angular-core-modules-oidc.mjs +0 -127
  215. package/fesm2022/sd-angular-core-modules-oidc.mjs.map +0 -1
  216. package/modules/oidc/dynamic-sts.loader.d.ts +0 -11
  217. package/modules/oidc/index.d.ts +0 -2
  218. package/modules/oidc/oidc.configuration.d.ts +0 -11
  219. package/modules/oidc/oidc.module.d.ts +0 -14
package/README.md CHANGED
@@ -1,64 +1,717 @@
1
- # SdAngular
1
+ # @sd-angular/core
2
2
 
3
- This project was generated using [Angular CLI](https://github.com/angular/angular-cli) version 19.1.0.
3
+ > **VI** Thư viện UI nội bộ xây dựng trên Angular Material, hỗ trợ Angular 19+
4
+ > **EN** — Internal UI component library built on Angular Material, supporting Angular 19+
4
5
 
5
- ## Code scaffolding
6
+ [![Version](https://img.shields.io/badge/version-19.0.0--beta.47-blue)](./package.json)
7
+ [![Angular](https://img.shields.io/badge/Angular-19%2B-red)](https://angular.dev)
8
+ [![Angular Material](https://img.shields.io/badge/Angular_Material-19%2B-purple)](https://material.angular.io)
6
9
 
7
- Angular CLI includes powerful code scaffolding tools. To generate a new component, run:
10
+ ---
11
+
12
+ ## Table of Contents / Mục lục
13
+
14
+ - [Getting Started / Cài đặt](#getting-started--cài-đặt)
15
+ - [Theming / SCSS Customization](#theming--scss-customization)
16
+ - [Components](#components)
17
+ - [SdButton](#sdbutton)
18
+ - [SdBadge](#sdbadge)
19
+ - [SdSection](#sdsection)
20
+ - [SdModal](#sdmodal)
21
+ - [SdTable](#sdtable)
22
+ - [SdAvatar](#sdavatar)
23
+ - [Other Components](#other-components--các-component-khác)
24
+ - [Form Components](#form-components)
25
+ - [CRUD Patterns / Code mẫu CRUD](#crud-patterns--code-mẫu-crud)
26
+ - [Contributing Guide / Hướng dẫn đóng góp](#contributing-guide--hướng-dẫn-đóng-góp)
27
+
28
+ ---
29
+
30
+ ## Getting Started / Cài đặt
31
+
32
+ ### Prerequisites / Yêu cầu
33
+
34
+ | Dependency | Version |
35
+ |---|---|
36
+ | `@angular/core` | `^19.0.0 \|\| ^20.0.0 \|\| ^21.0.0` |
37
+ | `@angular/material` | `^19.0.0 \|\| ^20.0.0 \|\| ^21.0.0` |
38
+ | `@angular/material-moment-adapter` | `^19.0.0 \|\| ^20.0.0 \|\| ^21.0.0` |
39
+
40
+ ### Installation / Cài đặt
8
41
 
9
42
  ```bash
10
- ng generate component component-name
43
+ npm install @sd-angular/core
11
44
  ```
12
45
 
13
- For a complete list of available schematics (such as `components`, `directives`, or `pipes`), run:
46
+ ### Setup
14
47
 
15
- ```bash
16
- ng generate --help
48
+ **1. Import global styles / Import style toàn cục**
49
+
50
+ Thêm vào `angular.json` (hoặc `styles.scss` của app):
51
+
52
+ ```json
53
+ // angular.json
54
+ {
55
+ "styles": [
56
+ "node_modules/@sd-angular/core/assets/scss/sd-core.scss"
57
+ ]
58
+ }
17
59
  ```
18
60
 
19
- ## Building
61
+ hoặc trong `styles.scss`:
20
62
 
21
- To build the library, run:
63
+ ```scss
64
+ @use '@sd-angular/core/assets/scss/sd-core';
65
+ ```
22
66
 
23
- ```bash
24
- ng build sd-angular
67
+ **2. Import Material Icons font / Font icon**
68
+
69
+ Thêm vào `index.html`:
70
+
71
+ ```html
72
+ <link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined" rel="stylesheet" />
73
+ <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;600&display=swap" rel="stylesheet" />
74
+ ```
75
+
76
+ **3. Configure providers / Cấu hình providers**
77
+
78
+ ```typescript
79
+ // app.config.ts
80
+ import { provideAnimationsAsync } from '@angular/platform-browser/animations/async';
81
+
82
+ export const appConfig: ApplicationConfig = {
83
+ providers: [
84
+ provideAnimationsAsync(),
85
+ // ... các providers khác
86
+ ],
87
+ };
25
88
  ```
26
89
 
27
- This command will compile your project, and the build artifacts will be placed in the `dist/` directory.
90
+ ---
28
91
 
29
- ### Publishing the Library
92
+ ## Theming / SCSS Customization
30
93
 
31
- Once the project is built, you can publish your library by following these steps:
94
+ ### CSS Variables
32
95
 
33
- 1. Navigate to the `dist` directory:
96
+ `@sd-angular/core` sử dụng CSS custom properties (variables) để quản lý màu sắc. Mỗi màu được expose dưới dạng `--sd-<color>`.
34
97
 
35
- ```bash
36
- cd dist/sd-angular
37
- ```
98
+ **Available color tokens / Các biến màu sắc:**
38
99
 
39
- 2. Run the `npm publish` command to publish your library to the npm registry:
40
- ```bash
41
- npm publish
42
- ```
100
+ | Variable | Default | Description |
101
+ |---|---|---|
102
+ | `--sd-primary` | `#2A66F4` | Màu chính |
103
+ | `--sd-primary-light` | `#EAF1FF` | Màu chính nhạt |
104
+ | `--sd-primary-dark` | `#1C4AD9` | Màu chính đậm |
105
+ | `--sd-secondary` | `#212121` | Màu phụ |
106
+ | `--sd-secondary-light` | `#E9E9E9` | Màu phụ nhạt |
107
+ | `--sd-success` | `#4CAF50` | Thành công |
108
+ | `--sd-success-light` | `#DBEFDC` | Thành công nhạt |
109
+ | `--sd-warning` | `#FF9600` | Cảnh báo |
110
+ | `--sd-warning-light` | `#FFEACC` | Cảnh báo nhạt |
111
+ | `--sd-error` | `#F82C13` | Lỗi |
112
+ | `--sd-error-light` | `#FED5D0` | Lỗi nhạt |
113
+ | `--sd-info` | `#2962FF` | Thông tin |
114
+ | `--sd-info-light` | `#E7E9FF` | Thông tin nhạt |
115
+ | `--sd-black500` | `#212121` | Xám đậm nhất |
116
+ | `--sd-black400` | `#757575` | Xám đậm |
117
+ | `--sd-black300` | `#BFBFBF` | Xám trung |
118
+ | `--sd-black200` | `#E6E6E6` | Xám nhạt |
119
+ | `--sd-black100` | `#F2F2F2` | Xám nhạt nhất |
43
120
 
44
- ## Running unit tests
121
+ ### Custom Theme / Tuỳ chỉnh theme
45
122
 
46
- To execute unit tests with the [Karma](https://karma-runner.github.io) test runner, use the following command:
123
+ Ghi đè theme mặc định bằng cách truyền map SCSS vào mixin `theme()`:
47
124
 
48
- ```bash
49
- ng test
125
+ ```scss
126
+ // styles.scss
127
+ @use '@sd-angular/core/assets/scss/themes/default' as default;
128
+
129
+ html {
130
+ @include default.theme((
131
+ primary: #7C3AED,
132
+ primary-light: #EDE9FE,
133
+ primary-dark: #5B21B6,
134
+ success: #10B981,
135
+ error: #EF4444,
136
+ ));
137
+ }
138
+ ```
139
+
140
+ Chỉ cần override các màu muốn thay đổi — các màu còn lại giữ nguyên giá trị mặc định.
141
+
142
+ ### Utility Classes / Các class tiện ích
143
+
144
+ Thư viện cung cấp sẵn các utility class:
145
+
146
+ ```html
147
+ <!-- Text color -->
148
+ <span class="text-primary">Text màu primary</span>
149
+ <span class="text-error">Text màu error</span>
150
+
151
+ <!-- Background -->
152
+ <div class="bg-primary-light">Background nhạt</div>
153
+
154
+ <!-- Spacing (đơn vị px, từ 0–200) -->
155
+ <div class="mt-16 mb-8 px-24">margin-top: 16px, padding: 0 24px</div>
156
+
157
+ <!-- Gap -->
158
+ <div class="d-flex gap-8">gap: 8px</div>
159
+
160
+ <!-- Grid -->
161
+ <div class="sd-grid-container grid-cols-3">
162
+ <div class="col-span-2">Chiếm 2 cột</div>
163
+ <div class="col-span-1">Chiếm 1 cột</div>
164
+ </div>
165
+
166
+ <!-- Bootstrap grid -->
167
+ <div class="row">
168
+ <div class="col-6">50%</div>
169
+ <div class="col-6">50%</div>
170
+ </div>
171
+ ```
172
+
173
+ ---
174
+
175
+ ## Components
176
+
177
+ > Tất cả component đều là **standalone** và sử dụng **Angular Signals** API.
178
+ > All components are **standalone** and use **Angular Signals** API.
179
+
180
+ ### SdButton
181
+
182
+ ```typescript
183
+ import { SdButton } from '@sd-angular/core/components/button';
184
+ ```
185
+
186
+ **Inputs:**
187
+
188
+ | Input | Type | Default | Description |
189
+ |---|---|---|---|
190
+ | `type` | `'fill' \| 'light' \| 'outline' \| 'link'` | `'light'` | Kiểu nút |
191
+ | `color` | `SdColor` | `'secondary'` | Màu sắc |
192
+ | `size` | `'sm' \| 'md' \| 'lg'` | `'sm'` | Kích thước |
193
+ | `title` | `string` | — | Nhãn nút |
194
+ | `prefixIcon` | `string` | — | Icon Material trước text |
195
+ | `suffixIcon` | `string` | — | Icon Material sau text |
196
+ | `disabled` | `boolean` | `false` | Vô hiệu hoá |
197
+ | `loading` | `boolean` | `false` | Trạng thái loading (tự chặn click) |
198
+ | `tooltip` | `string` | — | Tooltip khi hover |
199
+ | `width` | `string` | — | CSS width tuỳ chỉnh |
200
+
201
+ **Output:** `(click): EventEmitter<Event>` — có throttle 300ms, tự chặn khi `disabled` hoặc `loading`.
202
+
203
+ ```html
204
+ <sd-button type="fill" color="primary" title="Lưu" prefixIcon="save" (click)="onSave()" />
205
+ <sd-button type="outline" color="error" prefixIcon="delete" tooltip="Xoá" />
206
+ <sd-button type="light" title="Huỷ" (click)="modal.close()" />
207
+ <sd-button type="fill" color="primary" title="Đang xử lý" [loading]="true" />
208
+ ```
209
+
210
+ ---
211
+
212
+ ### SdBadge
213
+
214
+ ```typescript
215
+ import { SdBadge } from '@sd-angular/core/components/badge';
216
+ ```
217
+
218
+ **Inputs:**
219
+
220
+ | Input | Type | Default | Description |
221
+ |---|---|---|---|
222
+ | `type` | `'tag' \| 'round' \| 'icon'` | `'icon'` | Kiểu badge |
223
+ | `color` | `SdColor` | `'secondary'` | Màu sắc |
224
+ | `title` | `string \| number` | — | Nội dung hiển thị |
225
+ | `icon` | `string` | — | Icon Material |
226
+ | `size` | `SdSize` | `'sm'` | Kích thước |
227
+ | `tooltip` | `string` | — | Tooltip |
228
+
229
+ Shorthand color inputs (boolean): `primary`, `secondary`, `success`, `info`, `warning`, `error`.
230
+
231
+ ```html
232
+ <sd-badge type="tag" color="success" title="Hoạt động" />
233
+ <sd-badge type="round" [warning]="true" title="Chờ duyệt" />
234
+ <sd-badge type="icon" color="error" icon="close" title="Từ chối" />
235
+ ```
236
+
237
+ ---
238
+
239
+ ### SdSection
240
+
241
+ ```typescript
242
+ import { SdSection } from '@sd-angular/core/components/section';
243
+ ```
244
+
245
+ **Inputs:**
246
+
247
+ | Input | Type | Default | Description |
248
+ |---|---|---|---|
249
+ | `title` | `string` | *required* | Tiêu đề section |
250
+ | `subTitle` | `string` | — | Tiêu đề phụ |
251
+ | `icon` | `string` | — | Icon Material |
252
+ | `iconColor` | `SdColor` | `'primary'` | Màu icon |
253
+ | `collapsable` | `boolean` | `false` | Cho phép thu gọn |
254
+ | `collapsed` | `boolean` | `false` | Trạng thái ban đầu thu gọn |
255
+ | `hideHeader` | `boolean` | `false` | Ẩn phần header |
256
+
257
+ ```html
258
+ <sd-section title="Thông tin cơ bản" icon="person" iconColor="primary">
259
+ <!-- nội dung -->
260
+ </sd-section>
261
+
262
+ <sd-section title="Cài đặt nâng cao" icon="settings" collapsable [collapsed]="true">
263
+ <!-- nội dung ẩn mặc định -->
264
+ </sd-section>
265
+ ```
266
+
267
+ ---
268
+
269
+ ### SdModal
270
+
271
+ ```typescript
272
+ import { SdModal } from '@sd-angular/core/components/modal';
273
+ ```
274
+
275
+ **Inputs:**
276
+
277
+ | Input | Type | Default | Description |
278
+ |---|---|---|---|
279
+ | `title` | `string` | — | Tiêu đề modal |
280
+ | `color` | `SdColor` | `'primary'` | Màu header |
281
+ | `width` | `'sx' \| 'sm' \| 'md' \| 'lg' \| string` | `'md'` | Độ rộng (md = 60vw) |
282
+ | `height` | `string` | `'auto'` | Chiều cao |
283
+ | `view` | `'dialog' \| 'bottom-sheet'` | auto | Tự động bottom-sheet trên mobile |
284
+ | `lazyLoadContent` | `boolean` | `true` | Lazy render nội dung |
285
+
286
+ **Output:** `(sdClosed): EventEmitter` — phát ra khi modal đóng.
287
+
288
+ **Methods** (dùng qua `@ViewChild`):
289
+ - `modal.open()` — mở modal
290
+ - `modal.close()` — đóng modal
291
+
292
+ > ⚠️ Nội dung modal phải đặt trong `<ng-template>`.
293
+
294
+ ```html
295
+ <sd-modal #myModal title="Thêm mới" width="md" (sdClosed)="onClosed()">
296
+ <ng-template>
297
+ <div class="modal-body p-16">
298
+ <!-- nội dung form -->
299
+ </div>
300
+ <div class="modal-footer d-flex justify-content-end gap-8 p-16">
301
+ <sd-button title="Huỷ" (click)="myModal.close()" />
302
+ <sd-button type="fill" color="primary" title="Lưu" (click)="onSave()" />
303
+ </div>
304
+ </ng-template>
305
+ </sd-modal>
306
+
307
+ <sd-button title="Mở modal" prefixIcon="add" (click)="myModal.open()" />
308
+ ```
309
+
310
+ ---
311
+
312
+ ### SdTable
313
+
314
+ ```typescript
315
+ import { SdTable } from '@sd-angular/core/components/table';
316
+ import type { SdTableOption, SdTableColumn } from '@sd-angular/core/components/table';
317
+ ```
318
+
319
+ SdTable nhận một object `option` duy nhất kiểu `SdTableOption<T>`.
320
+
321
+ **Column types / Kiểu cột:**
322
+
323
+ | `type` | Mô tả |
324
+ |---|---|
325
+ | `'string'` | Văn bản |
326
+ | `'number'` | Số (tự format) |
327
+ | `'boolean'` | True/False |
328
+ | `'date'` | Ngày |
329
+ | `'datetime'` | Ngày giờ |
330
+ | `'time'` | Giờ |
331
+ | `'values'` | Enum từ danh sách cố định |
332
+ | `'lazy-values'` | Enum load async |
333
+ | `'children'` | Cột nhóm (multi-header) |
334
+
335
+ **Local table:**
336
+
337
+ ```typescript
338
+ option: SdTableOption<Product> = {
339
+ type: 'local',
340
+ items: () => this.products,
341
+ columns: [
342
+ { field: 'code', type: 'string', title: 'Mã', width: '120px' },
343
+ { field: 'name', type: 'string', title: 'Tên', sortable: true },
344
+ { field: 'price', type: 'number', title: 'Đơn giá', align: 'right' },
345
+ { field: 'active', type: 'boolean', title: 'Kích hoạt',
346
+ useBadge: (val) => ({ color: val ? 'success' : 'secondary', title: val ? 'Có' : 'Không' })
347
+ },
348
+ ],
349
+ paginate: { pageSize: 20 },
350
+ reload: { visible: true },
351
+ };
352
+ ```
353
+
354
+ **Server-side table:**
355
+
356
+ ```typescript
357
+ option: SdTableOption<Product> = {
358
+ type: 'server',
359
+ items: async (filterRequest, pagingReq) => {
360
+ const res = await this.service.search({
361
+ keyword: filterRequest.keyword,
362
+ page: pagingReq.page,
363
+ pageSize: pagingReq.pageSize,
364
+ });
365
+ return { items: res.data, total: res.total };
366
+ },
367
+ columns: [...],
368
+ command: {
369
+ align: 'right',
370
+ commands: [
371
+ { icon: 'edit', color: 'primary', title: 'Sửa', click: (row) => this.onEdit(row) },
372
+ { icon: 'delete', color: 'error', title: 'Xoá', click: (row) => this.onDelete(row) },
373
+ ],
374
+ },
375
+ };
376
+ ```
377
+
378
+ ```html
379
+ <sd-table #sdTable [option]="option" />
380
+ ```
381
+
382
+ ---
383
+
384
+ ### SdAvatar
385
+
386
+ ```typescript
387
+ import { SdAvatar } from '@sd-angular/core/components/avatar';
388
+ ```
389
+
390
+ ```html
391
+ <sd-avatar src="/api/avatar/123" name="Nguyễn Văn A" size="md" />
392
+ <sd-avatar name="NVA" color="primary" size="lg" />
50
393
  ```
51
394
 
52
- ## Running end-to-end tests
395
+ ---
53
396
 
54
- For end-to-end (e2e) testing, run:
397
+ ### Other Components / Các component khác
398
+
399
+ | Component | Import | Mô tả |
400
+ |---|---|---|
401
+ | `SdTabRouter` | `@sd-angular/core/components/tab-router` | Tab navigation với Angular Router |
402
+ | `SdSideDrawer` | `@sd-angular/core/components/side-drawer` | Drawer layout trái/phải |
403
+ | `SdUploadFile` | `@sd-angular/core/components/upload-file` | Upload file |
404
+ | `SdQuickAction` | `@sd-angular/core/components/quick-action` | Nút action dạng icon |
405
+ | `SdHistory` | `@sd-angular/core/components/history` | Lịch sử thay đổi |
406
+ | `SdImportExcel` | `@sd-angular/core/components/import-excel` | Wizard import Excel |
407
+ | `SdQueryBuilder` | `@sd-angular/core/components/query-builder` | Visual query builder |
408
+ | `SdWorkflow` | `@sd-angular/core/components/workflow` | Workflow builder |
409
+ | `SdCodeEditor` | `@sd-angular/core/components/code-editor` | Code editor (PrismJS) |
410
+ | `SdMiniEditor` | `@sd-angular/core/components/mini-editor` | Rich text editor nhỏ |
411
+ | `SdDocumentBuilder` | `@sd-angular/core/components/document-builder` | Document builder |
412
+ | `SdAnchorMain` | `@sd-angular/core/components/anchor` | Anchor / mục lục cuộn trang |
413
+ | `SdView` | `@sd-angular/core/components/view` | View wrapper read-only |
414
+
415
+ ---
416
+
417
+ ## Form Components
418
+
419
+ ```typescript
420
+ import {
421
+ SdInput, // Text input
422
+ SdInputNumber, // Number input
423
+ SdSelect, // Dropdown
424
+ SdAutocomplete, // Autocomplete
425
+ SdDate, // Date picker
426
+ SdSearch, // Search với debounce
427
+ } from '@sd-angular/core/forms';
428
+ ```
429
+
430
+ ```html
431
+ <sd-input [(ngModel)]="form.name" label="Họ tên" [required]="true" />
432
+
433
+ <sd-input-number [(ngModel)]="form.price" label="Đơn giá" [min]="0" suffix="VNĐ" />
434
+
435
+ <sd-select [(ngModel)]="form.status" label="Trạng thái"
436
+ [items]="statusList" valueField="value" displayField="label" />
437
+
438
+ <sd-date [(ngModel)]="form.birthday" label="Ngày sinh" />
439
+ ```
440
+
441
+ ---
442
+
443
+ ## CRUD Patterns / Code mẫu CRUD
444
+
445
+ ### List Component
446
+
447
+ ```typescript
448
+ // product-list.component.ts
449
+ import { Component, OnInit, ViewChild, signal } from '@angular/core';
450
+ import { SdTable, SdTableOption } from '@sd-angular/core/components/table';
451
+ import { SdButton } from '@sd-angular/core/components/button';
452
+ import { SdModal } from '@sd-angular/core/components/modal';
453
+ import { SdSection } from '@sd-angular/core/components/section';
454
+ import { SdInput, SdSelect } from '@sd-angular/core/forms';
455
+
456
+ interface Product {
457
+ id: number;
458
+ code: string;
459
+ name: string;
460
+ price: number;
461
+ status: 'ACTIVE' | 'INACTIVE';
462
+ }
463
+
464
+ @Component({
465
+ selector: 'app-product-list',
466
+ templateUrl: './product-list.component.html',
467
+ standalone: true,
468
+ imports: [SdTable, SdButton, SdModal, SdSection, SdInput, SdSelect],
469
+ })
470
+ export class ProductListComponent implements OnInit {
471
+ @ViewChild('formModal') formModal!: SdModal;
472
+ @ViewChild('sdTable') sdTable?: SdTable<Product>;
473
+
474
+ selectedItem: Product | null = null;
475
+ formData: Partial<Product> = {};
476
+ isSaving = signal(false);
477
+
478
+ readonly STATUS_LIST = [
479
+ { value: 'ACTIVE', label: 'Hoạt động' },
480
+ { value: 'INACTIVE', label: 'Dừng' },
481
+ ];
482
+
483
+ option!: SdTableOption<Product>;
484
+
485
+ constructor(private service: ProductService) {}
486
+
487
+ ngOnInit() {
488
+ this.option = {
489
+ type: 'server',
490
+ items: async (filter, paging) => this.service.search(filter, paging),
491
+ columns: [
492
+ { field: 'code', type: 'string', title: 'Mã', width: '120px' },
493
+ { field: 'name', type: 'string', title: 'Tên', sortable: true },
494
+ { field: 'price', type: 'number', title: 'Đơn giá', align: 'right' },
495
+ {
496
+ field: 'status', type: 'values', title: 'Trạng thái',
497
+ option: { items: this.STATUS_LIST, valueField: 'value', displayField: 'label' },
498
+ useBadge: (val) => ({
499
+ color: val === 'ACTIVE' ? 'success' : 'secondary',
500
+ title: this.STATUS_LIST.find(s => s.value === val)?.label,
501
+ }),
502
+ },
503
+ ],
504
+ command: {
505
+ align: 'right',
506
+ commands: [
507
+ { icon: 'edit', color: 'primary', title: 'Sửa', click: (row) => this.openForm(row) },
508
+ { icon: 'delete', color: 'error', title: 'Xoá', click: (row) => this.onDelete(row) },
509
+ ],
510
+ },
511
+ paginate: { pageSize: 20 },
512
+ reload: { visible: true },
513
+ };
514
+ }
515
+
516
+ openForm(item?: Product) {
517
+ this.selectedItem = item || null;
518
+ this.formData = item ? { ...item } : { status: 'ACTIVE' };
519
+ this.formModal.open();
520
+ }
521
+
522
+ async onSave() {
523
+ this.isSaving.set(true);
524
+ try {
525
+ if (this.selectedItem) {
526
+ await this.service.update(this.selectedItem.id, this.formData);
527
+ } else {
528
+ await this.service.create(this.formData);
529
+ }
530
+ this.formModal.close();
531
+ this.sdTable?.reload?.();
532
+ } finally {
533
+ this.isSaving.set(false);
534
+ }
535
+ }
536
+
537
+ async onDelete(item: Product) {
538
+ if (!confirm(`Xoá "${item.name}"?`)) return;
539
+ await this.service.delete(item.id);
540
+ this.sdTable?.reload?.();
541
+ }
542
+ }
543
+ ```
544
+
545
+ ### Template
546
+
547
+ ```html
548
+ <!-- product-list.component.html -->
549
+ <div class="d-flex justify-content-between align-items-center mb-16">
550
+ <h2>Danh sách sản phẩm</h2>
551
+ <sd-button type="fill" color="primary" title="Thêm mới"
552
+ prefixIcon="add" (click)="openForm()" />
553
+ </div>
554
+
555
+ <sd-table #sdTable [option]="option" />
556
+
557
+ <sd-modal #formModal [title]="selectedItem ? 'Chỉnh sửa' : 'Thêm mới'" width="md">
558
+ <ng-template>
559
+ <div class="modal-body p-16">
560
+ <sd-section title="Thông tin sản phẩm" icon="inventory">
561
+ <div class="row">
562
+ <div class="col-6">
563
+ <sd-input [(ngModel)]="formData.code" label="Mã" [required]="true" />
564
+ </div>
565
+ <div class="col-6">
566
+ <sd-select [(ngModel)]="formData.status" label="Trạng thái"
567
+ [items]="STATUS_LIST" valueField="value" displayField="label" />
568
+ </div>
569
+ <div class="col-12">
570
+ <sd-input [(ngModel)]="formData.name" label="Tên sản phẩm" [required]="true" />
571
+ </div>
572
+ <div class="col-6">
573
+ <sd-input-number [(ngModel)]="formData.price" label="Đơn giá" suffix="VNĐ" />
574
+ </div>
575
+ </div>
576
+ </sd-section>
577
+ </div>
578
+ <div class="modal-footer d-flex justify-content-end gap-8 p-16">
579
+ <sd-button title="Huỷ" (click)="formModal.close()" />
580
+ <sd-button type="fill" color="primary" title="Lưu"
581
+ prefixIcon="save" [loading]="isSaving()" (click)="onSave()" />
582
+ </div>
583
+ </ng-template>
584
+ </sd-modal>
585
+ ```
586
+
587
+ ---
588
+
589
+ ## Contributing Guide / Hướng dẫn đóng góp
590
+
591
+ ### Cấu trúc thư viện / Project structure
592
+
593
+ ```
594
+ sd-angular/
595
+ ├── src/
596
+ │ └── public-api.ts # Entry point chính
597
+ ├── assets/
598
+ │ └── scss/
599
+ │ ├── sd-core.scss # SCSS entry (import vào app)
600
+ │ ├── core/ # Base utilities (color, grid, form, ...)
601
+ │ └── themes/ # Theme mặc định + Material theme
602
+ ├── components/ # UI Components
603
+ │ ├── button/
604
+ │ ├── table/
605
+ │ ├── modal/
606
+ │ └── ...
607
+ ├── forms/ # Form components
608
+ │ ├── input/
609
+ │ ├── select/
610
+ │ └── ...
611
+ ├── directives/ # Angular directives
612
+ ├── pipes/ # Angular pipes
613
+ ├── services/ # Shared services
614
+ ├── utilities/ # Types, models, helpers
615
+ └── modules/ # Feature modules (layout, permission, ...)
616
+ ```
617
+
618
+ ### Thêm component mới / Adding a new component
619
+
620
+ **1. Tạo thư mục component:**
621
+
622
+ ```
623
+ components/
624
+ └── my-component/
625
+ ├── index.ts # Export public API
626
+ ├── ng-package.json # ng-packagr entry
627
+ └── src/
628
+ ├── my-component.component.ts
629
+ ├── my-component.component.html
630
+ └── my-component.component.scss
631
+ ```
632
+
633
+ **2. `ng-package.json`:**
634
+
635
+ ```json
636
+ {
637
+ "$schema": "../../../../node_modules/ng-packagr/ng-package.schema.json",
638
+ "lib": {
639
+ "entryFile": "index.ts"
640
+ }
641
+ }
642
+ ```
643
+
644
+ **3. `index.ts`:**
645
+
646
+ ```typescript
647
+ export * from './src/my-component.component';
648
+ ```
649
+
650
+ **4. Component template:**
651
+
652
+ ```typescript
653
+ // my-component.component.ts
654
+ import { ChangeDetectionStrategy, Component, input } from '@angular/core';
655
+ import { SdBaseSecureComponent } from '@sd-angular/core/components/base';
656
+ import { SdColor } from '@sd-angular/core/utilities';
657
+
658
+ @Component({
659
+ selector: 'sd-my-component',
660
+ templateUrl: './my-component.component.html',
661
+ styleUrls: ['./my-component.component.scss'],
662
+ changeDetection: ChangeDetectionStrategy.OnPush,
663
+ standalone: true,
664
+ imports: [],
665
+ })
666
+ export class SdMyComponent extends SdBaseSecureComponent {
667
+ color = input<SdColor, SdColor | undefined | null>('primary', {
668
+ transform: (value) => value || 'primary',
669
+ });
670
+
671
+ title = input<string | undefined | null>(undefined);
672
+ }
673
+ ```
674
+
675
+ **5. Export từ `components/index.ts`:**
676
+
677
+ ```typescript
678
+ // components/index.ts
679
+ export * from '@sd-angular/core/components/my-component';
680
+ ```
681
+
682
+ ### Quy ước / Conventions
683
+
684
+ | Mục | Quy ước |
685
+ |---|---|
686
+ | Selector | `sd-<tên-component>` |
687
+ | Class name | `Sd<TênComponent>` (Pascal) |
688
+ | Input | Dùng `input<T>()` signal, **không** dùng `@Input()` decorator |
689
+ | Null safety | Input transform phải handle `null/undefined` |
690
+ | Base class | Extend `SdBaseSecureComponent` cho component có permission |
691
+ | Change detection | Luôn dùng `ChangeDetectionStrategy.OnPush` |
692
+ | Standalone | Luôn `standalone: true` |
693
+ | Colors | Dùng `SdColor` type, không hardcode màu |
694
+
695
+ ### Build
55
696
 
56
697
  ```bash
57
- ng e2e
698
+ # Build toàn bộ thư viện
699
+ ng-packagr -p ng-package.json
700
+
701
+ # Watch mode
702
+ ng-packagr -p ng-package.json --watch
58
703
  ```
59
704
 
60
- Angular CLI does not come with an end-to-end testing framework by default. You can choose one that suits your needs.
705
+ ### Versioning
706
+
707
+ Thư viện tuân theo [Semantic Versioning](https://semver.org):
708
+
709
+ - `MAJOR` — Breaking changes (thay đổi API không tương thích)
710
+ - `MINOR` — Tính năng mới (tương thích ngược)
711
+ - `PATCH` — Bug fixes
712
+
713
+ ---
61
714
 
62
- ## Additional Resources
715
+ ## License
63
716
 
64
- For more information on using the Angular CLI, including detailed command references, visit the [Angular CLI Overview and Command Reference](https://angular.dev/tools/cli) page.
717
+ Internal use only © SD Team