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

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 (256) hide show
  1. package/assets/scss/README.md +433 -353
  2. package/assets/scss/core/form.scss +43 -1
  3. package/assets/scss/core/utilities/_base.scss +6 -6
  4. package/assets/scss/core/utilities/_grid.scss +4 -3
  5. package/assets/scss/core/utilities/_index.scss +1 -1
  6. package/assets/scss/core/utilities/_sizing.scss +2 -2
  7. package/assets/scss/sd-core.scss +0 -2
  8. package/components/badge/src/badge.component.d.ts +20 -3
  9. package/components/button/src/button.component.d.ts +2 -1
  10. package/components/ckeditor-styles/index.d.ts +1 -0
  11. package/components/ckeditor-styles/src/ckeditor-styles.component.d.ts +25 -0
  12. package/components/form-generic/src/models/form-generic-component.model.d.ts +5 -6
  13. package/components/form-generic/src/models/form-generic-expression.model.d.ts +1 -1
  14. package/components/history/models/history.model.d.ts +2 -2
  15. package/components/inform/index.d.ts +2 -0
  16. package/components/inform/src/inform-action.directive.d.ts +9 -0
  17. package/components/inform/src/inform.component.d.ts +59 -0
  18. package/components/modal/src/modal.component.d.ts +3 -2
  19. package/components/query-bar/src/{actions-bar.component.d.ts → components/actions-bar/actions-bar.component.d.ts} +8 -11
  20. package/components/query-bar/src/{build-chip.component.d.ts → components/build-chip/build-chip.component.d.ts} +2 -2
  21. package/components/query-bar/src/{chip-popover.component.d.ts → components/chip-popover/chip-popover.component.d.ts} +2 -2
  22. package/components/query-bar/src/{field-picker.component.d.ts → components/field-picker/field-picker.component.d.ts} +1 -1
  23. package/components/query-bar/src/{inline-chip.component.d.ts → components/inline-chip/inline-chip.component.d.ts} +2 -2
  24. package/components/query-bar/src/{inline-value-chip.component.d.ts → components/inline-value-chip/inline-value-chip.component.d.ts} +2 -2
  25. package/components/query-bar/src/{popover-chip.component.d.ts → components/popover-chip/popover-chip.component.d.ts} +2 -2
  26. package/components/query-bar/src/{saved-filters-menu.component.d.ts → components/saved-filters-menu/saved-filters-menu.component.d.ts} +1 -1
  27. package/components/query-bar/src/query-bar.component.d.ts +3 -3
  28. package/components/query-bar/src/query-bar.model.d.ts +1 -1
  29. package/components/section/src/section.component.d.ts +2 -1
  30. package/components/stepper/index.d.ts +2 -0
  31. package/components/stepper/src/step.component.d.ts +17 -0
  32. package/components/stepper/src/stepper.component.d.ts +33 -0
  33. package/components/tab/index.d.ts +2 -0
  34. package/components/tab/src/tab-group.component.d.ts +37 -0
  35. package/components/tab/src/tab.component.d.ts +13 -0
  36. package/components/tab-router/src/decorators/tab.decorator.d.ts +2 -2
  37. package/components/tab-router/src/models/tab-router.model.d.ts +2 -2
  38. package/components/table/index.d.ts +1 -0
  39. package/components/table/src/configurations/table.configuration.d.ts +3 -3
  40. package/components/table/src/directives/index.d.ts +1 -0
  41. package/components/table/src/directives/sd-table-group-def.directive.d.ts +44 -0
  42. package/components/table/src/models/index.d.ts +1 -0
  43. package/components/table/src/models/table-column.model.d.ts +13 -13
  44. package/components/table/src/models/table-command.model.d.ts +3 -2
  45. package/components/table/src/models/table-item.model.d.ts +19 -4
  46. package/components/table/src/models/table-option-export.model.d.ts +3 -3
  47. package/components/table/src/models/table-option-group.model.d.ts +19 -2
  48. package/components/table/src/models/table-option-selector.model.d.ts +17 -1
  49. package/components/table/src/models/table-option.model.d.ts +11 -2
  50. package/components/table/src/pipes/sd-group.pipe.d.ts +15 -1
  51. package/components/table/src/services/table-filter/table-filter.model.d.ts +9 -9
  52. package/components/table/src/services/table-filter/table-filter.service.d.ts +2 -2
  53. package/components/table/src/table.component.d.ts +29 -4
  54. package/fesm2022/sd-angular-core-components-anchor.mjs +2 -2
  55. package/fesm2022/sd-angular-core-components-anchor.mjs.map +1 -1
  56. package/fesm2022/sd-angular-core-components-badge.mjs +18 -3
  57. package/fesm2022/sd-angular-core-components-badge.mjs.map +1 -1
  58. package/fesm2022/sd-angular-core-components-button.mjs +2 -2
  59. package/fesm2022/sd-angular-core-components-button.mjs.map +1 -1
  60. package/fesm2022/sd-angular-core-components-ckeditor-styles.mjs +38 -0
  61. package/fesm2022/sd-angular-core-components-ckeditor-styles.mjs.map +1 -0
  62. package/fesm2022/sd-angular-core-components-document-builder.mjs +10 -8
  63. package/fesm2022/sd-angular-core-components-document-builder.mjs.map +1 -1
  64. package/fesm2022/sd-angular-core-components-editor.mjs +3 -2
  65. package/fesm2022/sd-angular-core-components-editor.mjs.map +1 -1
  66. package/fesm2022/sd-angular-core-components-form-generic.mjs +49 -48
  67. package/fesm2022/sd-angular-core-components-form-generic.mjs.map +1 -1
  68. package/fesm2022/sd-angular-core-components-history.mjs +3 -2
  69. package/fesm2022/sd-angular-core-components-history.mjs.map +1 -1
  70. package/fesm2022/sd-angular-core-components-inform.mjs +190 -0
  71. package/fesm2022/sd-angular-core-components-inform.mjs.map +1 -0
  72. package/fesm2022/sd-angular-core-components-mini-editor.mjs +4 -3
  73. package/fesm2022/sd-angular-core-components-mini-editor.mjs.map +1 -1
  74. package/fesm2022/sd-angular-core-components-modal.mjs +2 -2
  75. package/fesm2022/sd-angular-core-components-modal.mjs.map +1 -1
  76. package/fesm2022/sd-angular-core-components-operator.mjs +1 -1
  77. package/fesm2022/sd-angular-core-components-operator.mjs.map +1 -1
  78. package/fesm2022/sd-angular-core-components-query-bar.mjs +15 -22
  79. package/fesm2022/sd-angular-core-components-query-bar.mjs.map +1 -1
  80. package/fesm2022/sd-angular-core-components-section.mjs.map +1 -1
  81. package/fesm2022/sd-angular-core-components-splitter.mjs +5 -2
  82. package/fesm2022/sd-angular-core-components-splitter.mjs.map +1 -1
  83. package/fesm2022/sd-angular-core-components-stepper.mjs +140 -0
  84. package/fesm2022/sd-angular-core-components-stepper.mjs.map +1 -0
  85. package/fesm2022/sd-angular-core-components-tab-router.mjs +3 -3
  86. package/fesm2022/sd-angular-core-components-tab-router.mjs.map +1 -1
  87. package/fesm2022/sd-angular-core-components-tab.mjs +145 -0
  88. package/fesm2022/sd-angular-core-components-tab.mjs.map +1 -0
  89. package/fesm2022/sd-angular-core-components-table.mjs +284 -95
  90. package/fesm2022/sd-angular-core-components-table.mjs.map +1 -1
  91. package/fesm2022/sd-angular-core-components-upload-file.mjs +5 -6
  92. package/fesm2022/sd-angular-core-components-upload-file.mjs.map +1 -1
  93. package/fesm2022/sd-angular-core-directives.mjs +4 -4
  94. package/fesm2022/sd-angular-core-directives.mjs.map +1 -1
  95. package/fesm2022/sd-angular-core-forms-autocomplete.mjs +5 -4
  96. package/fesm2022/sd-angular-core-forms-autocomplete.mjs.map +1 -1
  97. package/fesm2022/sd-angular-core-forms-checkbox.mjs.map +1 -1
  98. package/fesm2022/sd-angular-core-forms-chip-calendar.mjs.map +1 -1
  99. package/fesm2022/sd-angular-core-forms-chip.mjs.map +1 -1
  100. package/fesm2022/sd-angular-core-forms-date-range.mjs +3 -2
  101. package/fesm2022/sd-angular-core-forms-date-range.mjs.map +1 -1
  102. package/fesm2022/sd-angular-core-forms-date.mjs +5 -4
  103. package/fesm2022/sd-angular-core-forms-date.mjs.map +1 -1
  104. package/fesm2022/sd-angular-core-forms-datetime.mjs +5 -4
  105. package/fesm2022/sd-angular-core-forms-datetime.mjs.map +1 -1
  106. package/fesm2022/sd-angular-core-forms-input-color.mjs +117 -0
  107. package/fesm2022/sd-angular-core-forms-input-color.mjs.map +1 -0
  108. package/fesm2022/sd-angular-core-forms-input-number.mjs +24 -2
  109. package/fesm2022/sd-angular-core-forms-input-number.mjs.map +1 -1
  110. package/fesm2022/sd-angular-core-forms-input.mjs +26 -2
  111. package/fesm2022/sd-angular-core-forms-input.mjs.map +1 -1
  112. package/fesm2022/sd-angular-core-forms-radio.mjs.map +1 -1
  113. package/fesm2022/sd-angular-core-forms-select.mjs +10 -10
  114. package/fesm2022/sd-angular-core-forms-select.mjs.map +1 -1
  115. package/fesm2022/sd-angular-core-forms-switch.mjs.map +1 -1
  116. package/fesm2022/sd-angular-core-forms-textarea.mjs.map +1 -1
  117. package/fesm2022/sd-angular-core-i18n.mjs +10 -0
  118. package/fesm2022/sd-angular-core-i18n.mjs.map +1 -1
  119. package/fesm2022/sd-angular-core-modules-auth.mjs +4 -4
  120. package/fesm2022/sd-angular-core-modules-auth.mjs.map +1 -1
  121. package/fesm2022/sd-angular-core-modules-authom.mjs +1 -1
  122. package/fesm2022/sd-angular-core-modules-authom.mjs.map +1 -1
  123. package/fesm2022/sd-angular-core-modules-layout.mjs +14 -14
  124. package/fesm2022/sd-angular-core-modules-layout.mjs.map +1 -1
  125. package/fesm2022/sd-angular-core-modules-permission.mjs +3 -3
  126. package/fesm2022/sd-angular-core-modules-permission.mjs.map +1 -1
  127. package/fesm2022/sd-angular-core-pipes.mjs +2 -2
  128. package/fesm2022/sd-angular-core-pipes.mjs.map +1 -1
  129. package/fesm2022/sd-angular-core-services-api.mjs +3 -3
  130. package/fesm2022/sd-angular-core-services-api.mjs.map +1 -1
  131. package/fesm2022/sd-angular-core-services-cache.mjs +3 -2
  132. package/fesm2022/sd-angular-core-services-cache.mjs.map +1 -1
  133. package/fesm2022/sd-angular-core-services-confirm.mjs.map +1 -1
  134. package/fesm2022/sd-angular-core-services-excel.mjs +6 -5
  135. package/fesm2022/sd-angular-core-services-excel.mjs.map +1 -1
  136. package/fesm2022/sd-angular-core-services-notify.mjs +3 -3
  137. package/fesm2022/sd-angular-core-services-notify.mjs.map +1 -1
  138. package/fesm2022/sd-angular-core-services-storage.mjs +2 -2
  139. package/fesm2022/sd-angular-core-services-storage.mjs.map +1 -1
  140. package/fesm2022/sd-angular-core-utilities-models.mjs.map +1 -1
  141. package/forms/autocomplete/src/autocomplete.component.d.ts +2 -1
  142. package/forms/checkbox/src/checkbox.component.d.ts +1 -1
  143. package/forms/chip/src/chip.component.d.ts +1 -1
  144. package/forms/chip-calendar/src/chip-calendar.component.d.ts +1 -1
  145. package/forms/date/src/date.component.d.ts +2 -1
  146. package/forms/date-range/src/date-range.component.d.ts +2 -1
  147. package/forms/datetime/src/datetime.component.d.ts +2 -1
  148. package/forms/input/src/input.component.d.ts +6 -2
  149. package/forms/input-color/index.d.ts +1 -0
  150. package/forms/input-color/src/input-color.component.d.ts +32 -0
  151. package/forms/input-number/src/input-number.component.d.ts +6 -2
  152. package/forms/radio/src/radio.component.d.ts +1 -1
  153. package/forms/select/src/select.component.d.ts +5 -5
  154. package/forms/switch/src/switch.component.d.ts +1 -1
  155. package/forms/textarea/src/textarea.component.d.ts +2 -1
  156. package/i18n/src/en.d.ts +2 -0
  157. package/modules/auth/configurations/auth.configuration.d.ts +4 -4
  158. package/modules/layout/configurations/layout.configuration.d.ts +3 -3
  159. package/modules/permission/src/configurations/permission.configuration.d.ts +3 -3
  160. package/package.json +123 -103
  161. package/sd-angular-core-19.0.0-beta.105.tgz +0 -0
  162. package/services/confirm/src/lib/components/dialog-confirm/dialog-confirm.component.d.ts +3 -3
  163. package/services/confirm/src/lib/confirm.service.d.ts +9 -9
  164. package/utilities/models/src/icon.model.d.ts +1 -1
  165. package/assets/scss/bootstrap-4.6.2/_alert.scss +0 -52
  166. package/assets/scss/bootstrap-4.6.2/_badge.scss +0 -54
  167. package/assets/scss/bootstrap-4.6.2/_breadcrumb.scss +0 -42
  168. package/assets/scss/bootstrap-4.6.2/_button-group.scss +0 -163
  169. package/assets/scss/bootstrap-4.6.2/_buttons.scss +0 -142
  170. package/assets/scss/bootstrap-4.6.2/_card.scss +0 -286
  171. package/assets/scss/bootstrap-4.6.2/_carousel.scss +0 -200
  172. package/assets/scss/bootstrap-4.6.2/_close.scss +0 -40
  173. package/assets/scss/bootstrap-4.6.2/_code.scss +0 -48
  174. package/assets/scss/bootstrap-4.6.2/_custom-forms.scss +0 -526
  175. package/assets/scss/bootstrap-4.6.2/_dropdown.scss +0 -192
  176. package/assets/scss/bootstrap-4.6.2/_forms.scss +0 -347
  177. package/assets/scss/bootstrap-4.6.2/_functions.scss +0 -190
  178. package/assets/scss/bootstrap-4.6.2/_grid.scss +0 -73
  179. package/assets/scss/bootstrap-4.6.2/_images.scss +0 -42
  180. package/assets/scss/bootstrap-4.6.2/_input-group.scss +0 -211
  181. package/assets/scss/bootstrap-4.6.2/_jumbotron.scss +0 -17
  182. package/assets/scss/bootstrap-4.6.2/_list-group.scss +0 -154
  183. package/assets/scss/bootstrap-4.6.2/_media.scss +0 -8
  184. package/assets/scss/bootstrap-4.6.2/_mixins.scss +0 -47
  185. package/assets/scss/bootstrap-4.6.2/_modal.scss +0 -240
  186. package/assets/scss/bootstrap-4.6.2/_nav.scss +0 -125
  187. package/assets/scss/bootstrap-4.6.2/_navbar.scss +0 -332
  188. package/assets/scss/bootstrap-4.6.2/_pagination.scss +0 -74
  189. package/assets/scss/bootstrap-4.6.2/_popover.scss +0 -170
  190. package/assets/scss/bootstrap-4.6.2/_print.scss +0 -132
  191. package/assets/scss/bootstrap-4.6.2/_progress.scss +0 -47
  192. package/assets/scss/bootstrap-4.6.2/_reboot.scss +0 -484
  193. package/assets/scss/bootstrap-4.6.2/_root.scss +0 -19
  194. package/assets/scss/bootstrap-4.6.2/_spinners.scss +0 -65
  195. package/assets/scss/bootstrap-4.6.2/_tables.scss +0 -185
  196. package/assets/scss/bootstrap-4.6.2/_toasts.scss +0 -46
  197. package/assets/scss/bootstrap-4.6.2/_tooltip.scss +0 -115
  198. package/assets/scss/bootstrap-4.6.2/_transitions.scss +0 -26
  199. package/assets/scss/bootstrap-4.6.2/_type.scss +0 -125
  200. package/assets/scss/bootstrap-4.6.2/_utilities.scss +0 -18
  201. package/assets/scss/bootstrap-4.6.2/_variables.scss +0 -1150
  202. package/assets/scss/bootstrap-4.6.2/bootstrap-grid.scss +0 -30
  203. package/assets/scss/bootstrap-4.6.2/bootstrap-reboot.scss +0 -12
  204. package/assets/scss/bootstrap-4.6.2/bootstrap.scss +0 -44
  205. package/assets/scss/bootstrap-4.6.2/mixins/_alert.scss +0 -13
  206. package/assets/scss/bootstrap-4.6.2/mixins/_background-variant.scss +0 -23
  207. package/assets/scss/bootstrap-4.6.2/mixins/_badge.scss +0 -17
  208. package/assets/scss/bootstrap-4.6.2/mixins/_border-radius.scss +0 -76
  209. package/assets/scss/bootstrap-4.6.2/mixins/_box-shadow.scss +0 -20
  210. package/assets/scss/bootstrap-4.6.2/mixins/_breakpoints.scss +0 -123
  211. package/assets/scss/bootstrap-4.6.2/mixins/_buttons.scss +0 -110
  212. package/assets/scss/bootstrap-4.6.2/mixins/_caret.scss +0 -62
  213. package/assets/scss/bootstrap-4.6.2/mixins/_clearfix.scss +0 -7
  214. package/assets/scss/bootstrap-4.6.2/mixins/_deprecate.scss +0 -10
  215. package/assets/scss/bootstrap-4.6.2/mixins/_float.scss +0 -14
  216. package/assets/scss/bootstrap-4.6.2/mixins/_forms.scss +0 -195
  217. package/assets/scss/bootstrap-4.6.2/mixins/_gradients.scss +0 -45
  218. package/assets/scss/bootstrap-4.6.2/mixins/_grid-framework.scss +0 -80
  219. package/assets/scss/bootstrap-4.6.2/mixins/_grid.scss +0 -69
  220. package/assets/scss/bootstrap-4.6.2/mixins/_hover.scss +0 -37
  221. package/assets/scss/bootstrap-4.6.2/mixins/_image.scss +0 -36
  222. package/assets/scss/bootstrap-4.6.2/mixins/_list-group.scss +0 -21
  223. package/assets/scss/bootstrap-4.6.2/mixins/_lists.scss +0 -7
  224. package/assets/scss/bootstrap-4.6.2/mixins/_nav-divider.scss +0 -11
  225. package/assets/scss/bootstrap-4.6.2/mixins/_pagination.scss +0 -22
  226. package/assets/scss/bootstrap-4.6.2/mixins/_reset-text.scss +0 -17
  227. package/assets/scss/bootstrap-4.6.2/mixins/_resize.scss +0 -6
  228. package/assets/scss/bootstrap-4.6.2/mixins/_screen-reader.scss +0 -34
  229. package/assets/scss/bootstrap-4.6.2/mixins/_size.scss +0 -7
  230. package/assets/scss/bootstrap-4.6.2/mixins/_table-row.scss +0 -39
  231. package/assets/scss/bootstrap-4.6.2/mixins/_text-emphasis.scss +0 -17
  232. package/assets/scss/bootstrap-4.6.2/mixins/_text-hide.scss +0 -11
  233. package/assets/scss/bootstrap-4.6.2/mixins/_text-truncate.scss +0 -8
  234. package/assets/scss/bootstrap-4.6.2/mixins/_transition.scss +0 -26
  235. package/assets/scss/bootstrap-4.6.2/mixins/_visibility.scss +0 -8
  236. package/assets/scss/bootstrap-4.6.2/utilities/_align.scss +0 -8
  237. package/assets/scss/bootstrap-4.6.2/utilities/_background.scss +0 -19
  238. package/assets/scss/bootstrap-4.6.2/utilities/_borders.scss +0 -75
  239. package/assets/scss/bootstrap-4.6.2/utilities/_clearfix.scss +0 -3
  240. package/assets/scss/bootstrap-4.6.2/utilities/_display.scss +0 -26
  241. package/assets/scss/bootstrap-4.6.2/utilities/_embed.scss +0 -39
  242. package/assets/scss/bootstrap-4.6.2/utilities/_flex.scss +0 -51
  243. package/assets/scss/bootstrap-4.6.2/utilities/_float.scss +0 -11
  244. package/assets/scss/bootstrap-4.6.2/utilities/_interactions.scss +0 -5
  245. package/assets/scss/bootstrap-4.6.2/utilities/_overflow.scss +0 -5
  246. package/assets/scss/bootstrap-4.6.2/utilities/_position.scss +0 -32
  247. package/assets/scss/bootstrap-4.6.2/utilities/_screenreaders.scss +0 -11
  248. package/assets/scss/bootstrap-4.6.2/utilities/_shadows.scss +0 -6
  249. package/assets/scss/bootstrap-4.6.2/utilities/_sizing.scss +0 -20
  250. package/assets/scss/bootstrap-4.6.2/utilities/_spacing.scss +0 -73
  251. package/assets/scss/bootstrap-4.6.2/utilities/_stretched-link.scss +0 -19
  252. package/assets/scss/bootstrap-4.6.2/utilities/_text.scss +0 -72
  253. package/assets/scss/bootstrap-4.6.2/utilities/_visibility.scss +0 -13
  254. package/assets/scss/bootstrap-4.6.2/vendor/_rfs.scss +0 -228
  255. package/assets/scss/core/bootstrap.scss +0 -13
  256. package/sd-angular-core-19.0.0-beta.103.tgz +0 -0
@@ -34,17 +34,16 @@ import { SdButton } from '@sd-angular/core/components/button';
34
34
  import { SdQuickAction } from '@sd-angular/core/components/quick-action';
35
35
  import { SdTooltipDirective, SdScrollDirective, SdDesktopDirective, SdMobileDirective, SdHoverCopyDirective } from '@sd-angular/core/directives';
36
36
  import { SdSafeHtmlPipe, SdFormatNumberPipe } from '@sd-angular/core/pipes';
37
- import { SdUtilities, StringUtilities, SD_EMPTY_STR, DateUtilities as DateUtilities$1 } from '@sd-angular/core/utilities';
38
- import { SdUtilities as SdUtilities$1, DateUtilities, ArrayUtilities, NumberUtilities } from '@sd-angular/core/utilities/extensions';
37
+ import { BrowserUtilities, Utilities } from '@sdcorejs/utils/fns';
38
+ import { DateUtilities, ArrayUtilities, NumberUtilities } from '@sd-angular/core/utilities/extensions';
39
39
  import { SdBadge } from '@sd-angular/core/components/badge';
40
40
  import { SdOperator } from '@sd-angular/core/components/operator';
41
41
  import { SdInput, SdInputNumber, SdSelect, SdDate, SdDatetime, SdDateRange as SdDateRange$1, SdCheckbox, SdSwitch } from '@sd-angular/core/forms';
42
42
  import { SdDateRange } from '@sd-angular/core/forms/date-range';
43
- import { OPERATORS } from '@sdcorejs/utils/constants';
43
+ import { OPERATORS, EMPTY_STR } from '@sdcorejs/utils/constants';
44
44
  import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
45
45
  import { SdSection } from '@sd-angular/core/components/section';
46
46
  import { TranslatePipe, I18nService } from '@sd-angular/core/i18n';
47
- import { BrowserUtilities } from '@sdcorejs/utils/fns';
48
47
  import { SdSideDrawer } from '@sd-angular/core/components/side-drawer';
49
48
  import { MatSlideToggleModule } from '@angular/material/slide-toggle';
50
49
  import { SdModal } from '@sd-angular/core/components/modal';
@@ -53,6 +52,7 @@ import * as i4 from '@angular/material/button';
53
52
  import { MatButtonModule } from '@angular/material/button';
54
53
  import * as i2$1 from '@angular/material/tooltip';
55
54
  import { MatTooltipModule } from '@angular/material/tooltip';
55
+ import { StringUtilities, DateUtilities as DateUtilities$1 } from '@sd-angular/core/utilities';
56
56
  import * as i5$1 from '@angular/material/chips';
57
57
  import { MatChipsModule } from '@angular/material/chips';
58
58
 
@@ -120,6 +120,34 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImpo
120
120
  }]
121
121
  }] });
122
122
 
123
+ /**
124
+ * Directive cung cấp custom template render group header row trong sd-table.
125
+ * Thay thế cho htmlTemplate callback cũ — cho phép Angular template binding,
126
+ * pipes, components con (sd-badge, sd-button, …) bên trong.
127
+ *
128
+ * Ví dụ:
129
+ * ```html
130
+ * <sd-table [option]="opt">
131
+ * <ng-template sdTableGroupDef let-values="values" let-items="items" let-indeterminate="indeterminate">
132
+ * <b>Khách hàng: {{ values.customerName }}</b>
133
+ * <span>{{ items.length }} đơn hàng</span>
134
+ * </ng-template>
135
+ * </sd-table>
136
+ * ```
137
+ */
138
+ class SdTableGroupDefDirective {
139
+ static ngTemplateContextGuard(_dir, _ctx) {
140
+ return true;
141
+ }
142
+ templateRef = inject(TemplateRef);
143
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SdTableGroupDefDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
144
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.21", type: SdTableGroupDefDirective, isStandalone: true, selector: "[sdTableGroupDef]", ngImport: i0 });
145
+ }
146
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SdTableGroupDefDirective, decorators: [{
147
+ type: Directive,
148
+ args: [{ selector: '[sdTableGroupDef]' }]
149
+ }] });
150
+
123
151
  class SdTableTitleDefDirective {
124
152
  static ngTemplateContextGuard(_dir, _ctx) {
125
153
  return true;
@@ -252,11 +280,11 @@ class ColumnFilterComponent {
252
280
  // Blur input: commit giá trị KHÔNG trigger reload.
253
281
  onFilterCommit = () => this.filterCommit.emit();
254
282
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: ColumnFilterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
255
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: ColumnFilterComponent, isStandalone: true, selector: "column-filter", inputs: { autoIdInput: { classPropertyName: "autoIdInput", publicName: "autoId", isSignal: true, isRequired: false, transformFunction: null }, column: { classPropertyName: "column", publicName: "column", isSignal: true, isRequired: true, transformFunction: null }, columnFilter: { classPropertyName: "columnFilter", publicName: "columnFilter", isSignal: true, isRequired: false, transformFunction: null }, cacheValues: { classPropertyName: "cacheValues", publicName: "cacheValues", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, operator: { classPropertyName: "operator", publicName: "operator", isSignal: true, isRequired: false, transformFunction: null }, isMobile: { classPropertyName: "isMobile", publicName: "isMobile", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { operator: "operatorChange", filterChange: "filterChange", filterCommit: "filterCommit" }, ngImport: i0, template: "@let _column = column();\r\n@let _columnFilter = columnFilter();\r\n@let _autoId = autoId();\r\n@let _templateRef = templateRef();\r\n@let _operators = operators();\r\n@let _items = items();\r\n@let _label = label();\r\n@let _context = { columnFilter: _columnFilter, autoId: _autoId };\r\n\r\n<div class=\"d-flex c-inline-column align-items-end\" style=\"width: 100%; max-width: 100%\">\r\n @if (\r\n _column.type === 'string' ||\r\n _column.type === 'number' ||\r\n _column.type === 'boolean' ||\r\n _column.type === 'values' ||\r\n _column.type === 'lazy-values' ||\r\n _column.type === 'date' ||\r\n _column.type === 'datetime' ||\r\n _column.type === 'time'\r\n ) {\r\n <!-- Operator filter -->\r\n @if (_operators.length) {\r\n <div class=\"d-flex align-items-center\" [ngClass]=\"operatorWrapperClass()\">\r\n <sd-operator [(model)]=\"operator\" [operators]=\"operatorValues()\" />\r\n </div>\r\n }\r\n\r\n <!-- N\u1EBFu filter nh\u1EADn v\u00E0o template -->\r\n @if (_templateRef) {\r\n <ng-container *ngTemplateOutlet=\"_templateRef; context: _context\"></ng-container>\r\n }\r\n <!-- M\u1EB7c \u0111\u1ECBnh theo type v\u00E0 gi\u00E1 tr\u1ECB values defined c\u1EE7a column -->\r\n @else {\r\n @if (_column.type === 'string') {\r\n <sd-input\r\n [autoId]=\"_autoId\"\r\n style=\"flex: 1 1 0%; min-width: 0\"\r\n size=\"sm\"\r\n type=\"text\"\r\n [label]=\"_label\"\r\n [(model)]=\"_columnFilter[_column.field]\"\r\n (keyupEnter)=\"onFilterChange()\"\r\n (sdBlur)=\"onFilterCommit()\"\r\n [disabled]=\"_column.filter?.disabled\"\r\n hideInlineError>\r\n </sd-input>\r\n } @else if (_column.type === 'number') {\r\n @if (!_column.filter?.type) {\r\n <sd-input-number\r\n [autoId]=\"_autoId\"\r\n style=\"flex: 1 1 0%; min-width: 0\"\r\n size=\"sm\"\r\n [label]=\"_label\"\r\n [(model)]=\"_columnFilter[_column.field]\"\r\n (keyupEnter)=\"onFilterChange()\"\r\n (sdBlur)=\"onFilterCommit()\"\r\n [disabled]=\"_column.filter?.disabled\"\r\n hideInlineError>\r\n </sd-input-number>\r\n } @else if (_column.filter?.type === 'split-number') {\r\n <ng-container\r\n *ngTemplateOutlet=\"splitNumberTpl; context: { field: _column.field, disabled: _column.filter?.disabled }\">\r\n </ng-container>\r\n }\r\n } @else if (_column.type === 'boolean') {\r\n <sd-select\r\n minWidthPanel=\"200px\"\r\n [autoId]=\"_autoId\"\r\n style=\"flex: 1 1 0%; min-width: 0\"\r\n [style.width]=\"'100%'\"\r\n size=\"sm\"\r\n [label]=\"_label\"\r\n [items]=\"[\r\n { value: '1', display: _column.option?.displayOnTrue || 'True' },\r\n { value: '0', display: _column.option?.displayOnFalse || 'False' },\r\n ]\"\r\n valueField=\"value\"\r\n displayField=\"display\"\r\n [(model)]=\"_columnFilter[_column.field]\"\r\n (sdChange)=\"onFilterChange()\"\r\n [disabled]=\"_column.filter?.disabled\"\r\n hideInlineError>\r\n <ng-template sdItemDef let-item=\"item\">\r\n @if (item.value === '1') {\r\n <sd-badge color=\"success\" [title]=\"_column.option?.displayOnTrue || 'True'\"> </sd-badge>\r\n } @else {\r\n <sd-badge color=\"error\" [title]=\"_column.option?.displayOnFalse || 'False'\"> </sd-badge>\r\n }\r\n </ng-template>\r\n </sd-select>\r\n } @else if (_column.type === 'values') {\r\n <sd-select\r\n minWidthPanel=\"200px\"\r\n [autoId]=\"_autoId\"\r\n style=\"flex: 1 1 0%; min-width: 0\"\r\n [style.width]=\"'100%'\"\r\n size=\"sm\"\r\n [label]=\"_label\"\r\n [items]=\"_items\"\r\n [valueField]=\"_column.option.valueField\"\r\n [displayField]=\"_column.option.displayField\"\r\n [(model)]=\"_columnFilter[_column.field]\"\r\n (sdChange)=\"onFilterChange()\"\r\n [disabled]=\"_column.filter?.disabled\"\r\n [multiple]=\"_column.option.selection === 'MULTIPLE'\"\r\n hideInlineError>\r\n </sd-select>\r\n } @else if (_column.type === 'lazy-values') {\r\n <sd-select\r\n minWidthPanel=\"200px\"\r\n [autoId]=\"_autoId\"\r\n style=\"flex: 1 1 0%; min-width: 0\"\r\n [style.width]=\"'100%'\"\r\n size=\"sm\"\r\n [label]=\"_label\"\r\n [items]=\"_items\"\r\n [valueField]=\"_column.option.valueField\"\r\n [displayField]=\"_column.option.displayField\"\r\n [(model)]=\"_columnFilter[_column.field]\"\r\n (sdChange)=\"onFilterChange()\"\r\n [disabled]=\"_column.filter?.disabled\"\r\n [multiple]=\"_column.option.selection === 'MULTIPLE'\"\r\n hideInlineError>\r\n </sd-select>\r\n } @else if (_column.type === 'date' || _column.type === 'datetime' || _column.type === 'time') {\r\n @if (!_column.filter?.type || _column.filter?.type === 'daterange') {\r\n <sd-date-range\r\n style=\"flex: 1 1 0%; min-width: 0\"\r\n size=\"sm\"\r\n [label]=\"_label\"\r\n [(model)]=\"_columnFilter[_column.field]\"\r\n (sdChange)=\"onFilterChange()\"\r\n [disabled]=\"_column.filter?.disabled\"\r\n hideInlineError>\r\n </sd-date-range>\r\n } @else if (_column.filter?.type === 'date') {\r\n <sd-date\r\n [autoId]=\"_autoId\"\r\n style=\"flex: 1 1 0%; min-width: 0\"\r\n type=\"date\"\r\n size=\"sm\"\r\n [label]=\"_label\"\r\n [(model)]=\"_columnFilter[_column.field]\"\r\n (sdChange)=\"onFilterChange()\"\r\n [disabled]=\"_column.filter?.disabled\"\r\n hideInlineError>\r\n </sd-date>\r\n } @else if (_column.filter?.type === 'split-date') {\r\n <ng-container\r\n *ngTemplateOutlet=\"splitDateTpl; context: { field: _column.field, disabled: _column.filter?.disabled }\">\r\n </ng-container>\r\n }\r\n }\r\n }\r\n } @else {\r\n <sd-input [autoId]=\"_autoId\" style=\"flex: 1 1 0%; min-width: 0\" type=\"text\" size=\"sm\" disabled></sd-input>\r\n }\r\n</div>\r\n\r\n<!-- ================================================ -->\r\n<!-- Split from/to templates (\u0111\u01B0a xu\u1ED1ng cu\u1ED1i file) -->\r\n<!-- ================================================ -->\r\n<ng-template #splitNumberTpl let-field=\"field\" let-disabled=\"disabled\">\r\n <div class=\"d-flex align-items-center\" style=\"flex: 1 1 0%; min-width: 0\">\r\n <sd-input-number\r\n [autoId]=\"_autoId + '-from'\"\r\n style=\"flex: 1 1 0%; min-width: 0\"\r\n size=\"sm\"\r\n [label]=\"_label\"\r\n [(model)]=\"_columnFilter[field].from\"\r\n (sdChange)=\"onFilterChange()\"\r\n (sdBlur)=\"onFilterCommit()\"\r\n [disabled]=\"disabled\"\r\n hideInlineError>\r\n </sd-input-number>\r\n <div class=\"mx-4\">-</div>\r\n <sd-input-number\r\n [autoId]=\"_autoId + '-to'\"\r\n style=\"flex: 1 1 0%; min-width: 0\"\r\n size=\"sm\"\r\n [(model)]=\"_columnFilter[field].to\"\r\n (sdChange)=\"onFilterChange()\"\r\n (sdBlur)=\"onFilterCommit()\"\r\n [disabled]=\"disabled\"\r\n hideInlineError>\r\n </sd-input-number>\r\n </div>\r\n</ng-template>\r\n\r\n<ng-template #splitDateTpl let-field=\"field\" let-disabled=\"disabled\">\r\n <div class=\"d-flex align-items-center\" style=\"flex: 1 1 0%; min-width: 0\">\r\n <sd-date\r\n [autoId]=\"_autoId + '-from'\"\r\n style=\"flex: 1 1 0%; min-width: 0\"\r\n type=\"date\"\r\n size=\"sm\"\r\n [label]=\"_label\"\r\n [(model)]=\"_columnFilter[field].from\"\r\n (sdChange)=\"onFilterChange()\"\r\n [disabled]=\"disabled\"\r\n hideInlineError>\r\n </sd-date>\r\n <div class=\"mx-4\">-</div>\r\n <sd-date\r\n [autoId]=\"_autoId + '-to'\"\r\n style=\"flex: 1 1 0%; min-width: 0\"\r\n type=\"date\"\r\n size=\"sm\"\r\n [(model)]=\"_columnFilter[field].to\"\r\n (sdChange)=\"onFilterChange()\"\r\n [disabled]=\"disabled\"\r\n hideInlineError>\r\n </sd-date>\r\n </div>\r\n</ng-template>\r\n", styles: [":host ::ng-deep .c-inline-column .mat-mdc-text-field-wrapper{background-color:#fff}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: SdOperator, selector: "sd-operator", inputs: ["model", "operators", "disabled", "autoId"], outputs: ["modelChange"] }, { kind: "component", type: SdInput, selector: "sd-input", inputs: ["autoId", "name", "appearance", "floatLabel", "size", "form", "label", "helperText", "placeholder", "type", "hideInlineError", "blurOnEnter", "required", "readonly", "disabled", "viewed", "minlength", "maxlength", "pattern", "patternErrorMessage", "validator", "inlineError", "hyperlink", "model"], outputs: ["modelChange", "sdChange", "sdFocus", "sdBlur", "keyupEnter", "sdFocusForceBlur"] }, { kind: "component", type: SdInputNumber, selector: "sd-input-number", inputs: ["autoId", "name", "size", "form", "label", "helperText", "placeholder", "hideInlineError", "blurOnEnter", "required", "readonly", "disabled", "viewed", "type", "precision", "format", "min", "max", "validator", "inlineError", "hyperlink", "appearance", "floatLabel", "model"], outputs: ["modelChange", "sdChange", "sdFocus", "sdBlur", "keyupEnter", "sdFocusForceBlur"] }, { kind: "component", type: SdSelect, selector: "sd-select", inputs: ["autoId", "name", "size", "form", "label", "helperText", "placeholder", "valueField", "displayField", "disabledField", "cacheChecksum", "limit", "hyperlink", "minWidthPanel", "hideInlineError", "required", "disabled", "viewed", "multiple", "bare", "validator", "inlineError", "appearance", "floatLabel", "items", "model"], outputs: ["modelChange", "sdChange", "sdSelection"] }, { kind: "component", type: SdDate, selector: "sd-date", inputs: ["autoId", "name", "size", "form", "label", "helperText", "placeholder", "hideInlineError", "required", "disabled", "viewed", "bare", "inlineError", "hyperlink", "appearance", "floatLabel", "min", "minDate", "max", "maxDate", "model"], outputs: ["modelChange", "sdChange", "sdFocus"] }, { kind: "component", type: SdDateRange, selector: "sd-date-range", inputs: ["autoId", "name", "size", "form", "label", "helperText", "hideInlineError", "required", "disabled", "bare", "viewed", "appearance", "floatLabel", "min", "max", "model"], outputs: ["modelChange", "sdChange"] }, { kind: "component", type: SdBadge, selector: "sd-badge", inputs: ["type", "color", "primary", "secondary", "success", "info", "warning", "error", "fontSet", "title", "description", "tooltip", "icon", "size"], outputs: ["click"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
283
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: ColumnFilterComponent, isStandalone: true, selector: "column-filter", inputs: { autoIdInput: { classPropertyName: "autoIdInput", publicName: "autoId", isSignal: true, isRequired: false, transformFunction: null }, column: { classPropertyName: "column", publicName: "column", isSignal: true, isRequired: true, transformFunction: null }, columnFilter: { classPropertyName: "columnFilter", publicName: "columnFilter", isSignal: true, isRequired: false, transformFunction: null }, cacheValues: { classPropertyName: "cacheValues", publicName: "cacheValues", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, operator: { classPropertyName: "operator", publicName: "operator", isSignal: true, isRequired: false, transformFunction: null }, isMobile: { classPropertyName: "isMobile", publicName: "isMobile", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { operator: "operatorChange", filterChange: "filterChange", filterCommit: "filterCommit" }, ngImport: i0, template: "@let _column = column();\r\n@let _columnFilter = columnFilter();\r\n@let _autoId = autoId();\r\n@let _templateRef = templateRef();\r\n@let _operators = operators();\r\n@let _items = items();\r\n@let _label = label();\r\n@let _context = { columnFilter: _columnFilter, autoId: _autoId };\r\n\r\n<div class=\"d-flex c-inline-column align-items-end\" style=\"width: 100%; max-width: 100%\">\r\n @if (\r\n _column.type === 'string' ||\r\n _column.type === 'number' ||\r\n _column.type === 'boolean' ||\r\n _column.type === 'values' ||\r\n _column.type === 'lazy-values' ||\r\n _column.type === 'date' ||\r\n _column.type === 'datetime' ||\r\n _column.type === 'time'\r\n ) {\r\n <!-- Operator filter -->\r\n @if (_operators.length) {\r\n <div class=\"d-flex align-items-center\" [ngClass]=\"operatorWrapperClass()\">\r\n <sd-operator [(model)]=\"operator\" [operators]=\"operatorValues()\" />\r\n </div>\r\n }\r\n\r\n <!-- N\u1EBFu filter nh\u1EADn v\u00E0o template -->\r\n @if (_templateRef) {\r\n <ng-container *ngTemplateOutlet=\"_templateRef; context: _context\"></ng-container>\r\n }\r\n <!-- M\u1EB7c \u0111\u1ECBnh theo type v\u00E0 gi\u00E1 tr\u1ECB values defined c\u1EE7a column -->\r\n @else {\r\n @if (_column.type === 'string') {\r\n <sd-input\r\n [autoId]=\"_autoId\"\r\n style=\"flex: 1 1 0%; min-width: 0\"\r\n size=\"sm\"\r\n type=\"text\"\r\n [label]=\"_label\"\r\n [(model)]=\"_columnFilter[_column.field]\"\r\n (keyupEnter)=\"onFilterChange()\"\r\n (sdBlur)=\"onFilterCommit()\"\r\n (cleared)=\"onFilterChange()\"\r\n [disabled]=\"_column.filter?.disabled\"\r\n hideInlineError>\r\n </sd-input>\r\n } @else if (_column.type === 'number') {\r\n @if (!_column.filter?.type) {\r\n <sd-input-number\r\n [autoId]=\"_autoId\"\r\n style=\"flex: 1 1 0%; min-width: 0\"\r\n size=\"sm\"\r\n [label]=\"_label\"\r\n [(model)]=\"_columnFilter[_column.field]\"\r\n (keyupEnter)=\"onFilterChange()\"\r\n (sdBlur)=\"onFilterCommit()\"\r\n (cleared)=\"onFilterChange()\"\r\n [disabled]=\"_column.filter?.disabled\"\r\n hideInlineError>\r\n </sd-input-number>\r\n } @else if (_column.filter?.type === 'split-number') {\r\n <ng-container\r\n *ngTemplateOutlet=\"splitNumberTpl; context: { field: _column.field, disabled: _column.filter?.disabled }\">\r\n </ng-container>\r\n }\r\n } @else if (_column.type === 'boolean') {\r\n <sd-select\r\n minWidthPanel=\"200px\"\r\n [autoId]=\"_autoId\"\r\n style=\"flex: 1 1 0%; min-width: 0\"\r\n [style.width]=\"'100%'\"\r\n size=\"sm\"\r\n [label]=\"_label\"\r\n [items]=\"[\r\n { value: '1', display: _column.option?.displayOnTrue || 'True' },\r\n { value: '0', display: _column.option?.displayOnFalse || 'False' },\r\n ]\"\r\n valueField=\"value\"\r\n displayField=\"display\"\r\n [(model)]=\"_columnFilter[_column.field]\"\r\n (sdChange)=\"onFilterChange()\"\r\n [disabled]=\"_column.filter?.disabled\"\r\n hideInlineError>\r\n <ng-template sdItemDef let-item=\"item\">\r\n @if (item.value === '1') {\r\n <sd-badge color=\"success\" [title]=\"_column.option?.displayOnTrue || 'True'\"> </sd-badge>\r\n } @else {\r\n <sd-badge color=\"error\" [title]=\"_column.option?.displayOnFalse || 'False'\"> </sd-badge>\r\n }\r\n </ng-template>\r\n </sd-select>\r\n } @else if (_column.type === 'values') {\r\n <sd-select\r\n minWidthPanel=\"200px\"\r\n [autoId]=\"_autoId\"\r\n style=\"flex: 1 1 0%; min-width: 0\"\r\n [style.width]=\"'100%'\"\r\n size=\"sm\"\r\n [label]=\"_label\"\r\n [items]=\"_items\"\r\n [valueField]=\"_column.option.valueField\"\r\n [displayField]=\"_column.option.displayField\"\r\n [(model)]=\"_columnFilter[_column.field]\"\r\n (sdChange)=\"onFilterChange()\"\r\n [disabled]=\"_column.filter?.disabled\"\r\n [multiple]=\"_column.option.selection === 'MULTIPLE'\"\r\n hideInlineError>\r\n </sd-select>\r\n } @else if (_column.type === 'lazy-values') {\r\n <sd-select\r\n minWidthPanel=\"200px\"\r\n [autoId]=\"_autoId\"\r\n style=\"flex: 1 1 0%; min-width: 0\"\r\n [style.width]=\"'100%'\"\r\n size=\"sm\"\r\n [label]=\"_label\"\r\n [items]=\"_items\"\r\n [valueField]=\"_column.option.valueField\"\r\n [displayField]=\"_column.option.displayField\"\r\n [(model)]=\"_columnFilter[_column.field]\"\r\n (sdChange)=\"onFilterChange()\"\r\n [disabled]=\"_column.filter?.disabled\"\r\n [multiple]=\"_column.option.selection === 'MULTIPLE'\"\r\n hideInlineError>\r\n </sd-select>\r\n } @else if (_column.type === 'date' || _column.type === 'datetime' || _column.type === 'time') {\r\n @if (!_column.filter?.type || _column.filter?.type === 'daterange') {\r\n <sd-date-range\r\n style=\"flex: 1 1 0%; min-width: 0\"\r\n size=\"sm\"\r\n [label]=\"_label\"\r\n [(model)]=\"_columnFilter[_column.field]\"\r\n (sdChange)=\"onFilterChange()\"\r\n [disabled]=\"_column.filter?.disabled\"\r\n hideInlineError>\r\n </sd-date-range>\r\n } @else if (_column.filter?.type === 'date') {\r\n <sd-date\r\n [autoId]=\"_autoId\"\r\n style=\"flex: 1 1 0%; min-width: 0\"\r\n type=\"date\"\r\n size=\"sm\"\r\n [label]=\"_label\"\r\n [(model)]=\"_columnFilter[_column.field]\"\r\n (sdChange)=\"onFilterChange()\"\r\n [disabled]=\"_column.filter?.disabled\"\r\n hideInlineError>\r\n </sd-date>\r\n } @else if (_column.filter?.type === 'split-date') {\r\n <ng-container\r\n *ngTemplateOutlet=\"splitDateTpl; context: { field: _column.field, disabled: _column.filter?.disabled }\">\r\n </ng-container>\r\n }\r\n }\r\n }\r\n } @else {\r\n <sd-input [autoId]=\"_autoId\" style=\"flex: 1 1 0%; min-width: 0\" type=\"text\" size=\"sm\" disabled></sd-input>\r\n }\r\n</div>\r\n\r\n<!-- ================================================ -->\r\n<!-- Split from/to templates (\u0111\u01B0a xu\u1ED1ng cu\u1ED1i file) -->\r\n<!-- ================================================ -->\r\n<ng-template #splitNumberTpl let-field=\"field\" let-disabled=\"disabled\">\r\n <div class=\"d-flex align-items-center\" style=\"flex: 1 1 0%; min-width: 0\">\r\n <sd-input-number\r\n [autoId]=\"_autoId + '-from'\"\r\n style=\"flex: 1 1 0%; min-width: 0\"\r\n size=\"sm\"\r\n [label]=\"_label\"\r\n [(model)]=\"_columnFilter[field].from\"\r\n (sdChange)=\"onFilterChange()\"\r\n (sdBlur)=\"onFilterCommit()\"\r\n (cleared)=\"onFilterChange()\"\r\n [disabled]=\"disabled\"\r\n hideInlineError>\r\n </sd-input-number>\r\n <div class=\"mx-4\">-</div>\r\n <sd-input-number\r\n [autoId]=\"_autoId + '-to'\"\r\n style=\"flex: 1 1 0%; min-width: 0\"\r\n size=\"sm\"\r\n [(model)]=\"_columnFilter[field].to\"\r\n (sdChange)=\"onFilterChange()\"\r\n (sdBlur)=\"onFilterCommit()\"\r\n (cleared)=\"onFilterChange()\"\r\n [disabled]=\"disabled\"\r\n hideInlineError>\r\n </sd-input-number>\r\n </div>\r\n</ng-template>\r\n\r\n<ng-template #splitDateTpl let-field=\"field\" let-disabled=\"disabled\">\r\n <div class=\"d-flex align-items-center\" style=\"flex: 1 1 0%; min-width: 0\">\r\n <sd-date\r\n [autoId]=\"_autoId + '-from'\"\r\n style=\"flex: 1 1 0%; min-width: 0\"\r\n type=\"date\"\r\n size=\"sm\"\r\n [label]=\"_label\"\r\n [(model)]=\"_columnFilter[field].from\"\r\n (sdChange)=\"onFilterChange()\"\r\n [disabled]=\"disabled\"\r\n hideInlineError>\r\n </sd-date>\r\n <div class=\"mx-4\">-</div>\r\n <sd-date\r\n [autoId]=\"_autoId + '-to'\"\r\n style=\"flex: 1 1 0%; min-width: 0\"\r\n type=\"date\"\r\n size=\"sm\"\r\n [(model)]=\"_columnFilter[field].to\"\r\n (sdChange)=\"onFilterChange()\"\r\n [disabled]=\"disabled\"\r\n hideInlineError>\r\n </sd-date>\r\n </div>\r\n</ng-template>\r\n", styles: [":host ::ng-deep .c-inline-column .mat-mdc-text-field-wrapper{background-color:#fff}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: SdOperator, selector: "sd-operator", inputs: ["model", "operators", "disabled", "autoId"], outputs: ["modelChange"] }, { kind: "component", type: SdInput, selector: "sd-input", inputs: ["autoId", "name", "appearance", "floatLabel", "size", "form", "label", "helperText", "placeholder", "type", "hideInlineError", "blurOnEnter", "required", "readonly", "disabled", "viewed", "minlength", "maxlength", "pattern", "patternErrorMessage", "validator", "inlineError", "hyperlink", "model"], outputs: ["modelChange", "sdChange", "sdFocus", "sdBlur", "keyupEnter", "cleared", "sdFocusForceBlur"] }, { kind: "component", type: SdInputNumber, selector: "sd-input-number", inputs: ["autoId", "name", "size", "form", "label", "helperText", "placeholder", "hideInlineError", "blurOnEnter", "required", "readonly", "disabled", "viewed", "type", "precision", "format", "min", "max", "validator", "inlineError", "hyperlink", "appearance", "floatLabel", "model"], outputs: ["modelChange", "sdChange", "sdFocus", "sdBlur", "keyupEnter", "cleared", "sdFocusForceBlur"] }, { kind: "component", type: SdSelect, selector: "sd-select", inputs: ["autoId", "name", "size", "form", "label", "helperText", "placeholder", "valueField", "displayField", "disabledField", "cacheChecksum", "limit", "hyperlink", "minWidthPanel", "hideInlineError", "required", "disabled", "viewed", "multiple", "bare", "validator", "inlineError", "appearance", "floatLabel", "items", "model"], outputs: ["modelChange", "sdChange", "sdSelection"] }, { kind: "component", type: SdDate, selector: "sd-date", inputs: ["autoId", "name", "size", "form", "label", "helperText", "placeholder", "hideInlineError", "required", "disabled", "viewed", "bare", "inlineError", "hyperlink", "appearance", "floatLabel", "min", "minDate", "max", "maxDate", "model"], outputs: ["modelChange", "sdChange", "sdFocus"] }, { kind: "component", type: SdDateRange, selector: "sd-date-range", inputs: ["autoId", "name", "size", "form", "label", "helperText", "hideInlineError", "required", "disabled", "bare", "viewed", "appearance", "floatLabel", "min", "max", "model"], outputs: ["modelChange", "sdChange"] }, { kind: "component", type: SdBadge, selector: "sd-badge", inputs: ["type", "color", "primary", "secondary", "success", "info", "warning", "error", "fontSet", "title", "description", "tooltip", "icon", "size"], outputs: ["click"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
256
284
  }
257
285
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: ColumnFilterComponent, decorators: [{
258
286
  type: Component,
259
- args: [{ selector: 'column-filter', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [CommonModule, SdOperator, SdInput, SdInputNumber, SdSelect, SdDate, SdDateRange, SdBadge], template: "@let _column = column();\r\n@let _columnFilter = columnFilter();\r\n@let _autoId = autoId();\r\n@let _templateRef = templateRef();\r\n@let _operators = operators();\r\n@let _items = items();\r\n@let _label = label();\r\n@let _context = { columnFilter: _columnFilter, autoId: _autoId };\r\n\r\n<div class=\"d-flex c-inline-column align-items-end\" style=\"width: 100%; max-width: 100%\">\r\n @if (\r\n _column.type === 'string' ||\r\n _column.type === 'number' ||\r\n _column.type === 'boolean' ||\r\n _column.type === 'values' ||\r\n _column.type === 'lazy-values' ||\r\n _column.type === 'date' ||\r\n _column.type === 'datetime' ||\r\n _column.type === 'time'\r\n ) {\r\n <!-- Operator filter -->\r\n @if (_operators.length) {\r\n <div class=\"d-flex align-items-center\" [ngClass]=\"operatorWrapperClass()\">\r\n <sd-operator [(model)]=\"operator\" [operators]=\"operatorValues()\" />\r\n </div>\r\n }\r\n\r\n <!-- N\u1EBFu filter nh\u1EADn v\u00E0o template -->\r\n @if (_templateRef) {\r\n <ng-container *ngTemplateOutlet=\"_templateRef; context: _context\"></ng-container>\r\n }\r\n <!-- M\u1EB7c \u0111\u1ECBnh theo type v\u00E0 gi\u00E1 tr\u1ECB values defined c\u1EE7a column -->\r\n @else {\r\n @if (_column.type === 'string') {\r\n <sd-input\r\n [autoId]=\"_autoId\"\r\n style=\"flex: 1 1 0%; min-width: 0\"\r\n size=\"sm\"\r\n type=\"text\"\r\n [label]=\"_label\"\r\n [(model)]=\"_columnFilter[_column.field]\"\r\n (keyupEnter)=\"onFilterChange()\"\r\n (sdBlur)=\"onFilterCommit()\"\r\n [disabled]=\"_column.filter?.disabled\"\r\n hideInlineError>\r\n </sd-input>\r\n } @else if (_column.type === 'number') {\r\n @if (!_column.filter?.type) {\r\n <sd-input-number\r\n [autoId]=\"_autoId\"\r\n style=\"flex: 1 1 0%; min-width: 0\"\r\n size=\"sm\"\r\n [label]=\"_label\"\r\n [(model)]=\"_columnFilter[_column.field]\"\r\n (keyupEnter)=\"onFilterChange()\"\r\n (sdBlur)=\"onFilterCommit()\"\r\n [disabled]=\"_column.filter?.disabled\"\r\n hideInlineError>\r\n </sd-input-number>\r\n } @else if (_column.filter?.type === 'split-number') {\r\n <ng-container\r\n *ngTemplateOutlet=\"splitNumberTpl; context: { field: _column.field, disabled: _column.filter?.disabled }\">\r\n </ng-container>\r\n }\r\n } @else if (_column.type === 'boolean') {\r\n <sd-select\r\n minWidthPanel=\"200px\"\r\n [autoId]=\"_autoId\"\r\n style=\"flex: 1 1 0%; min-width: 0\"\r\n [style.width]=\"'100%'\"\r\n size=\"sm\"\r\n [label]=\"_label\"\r\n [items]=\"[\r\n { value: '1', display: _column.option?.displayOnTrue || 'True' },\r\n { value: '0', display: _column.option?.displayOnFalse || 'False' },\r\n ]\"\r\n valueField=\"value\"\r\n displayField=\"display\"\r\n [(model)]=\"_columnFilter[_column.field]\"\r\n (sdChange)=\"onFilterChange()\"\r\n [disabled]=\"_column.filter?.disabled\"\r\n hideInlineError>\r\n <ng-template sdItemDef let-item=\"item\">\r\n @if (item.value === '1') {\r\n <sd-badge color=\"success\" [title]=\"_column.option?.displayOnTrue || 'True'\"> </sd-badge>\r\n } @else {\r\n <sd-badge color=\"error\" [title]=\"_column.option?.displayOnFalse || 'False'\"> </sd-badge>\r\n }\r\n </ng-template>\r\n </sd-select>\r\n } @else if (_column.type === 'values') {\r\n <sd-select\r\n minWidthPanel=\"200px\"\r\n [autoId]=\"_autoId\"\r\n style=\"flex: 1 1 0%; min-width: 0\"\r\n [style.width]=\"'100%'\"\r\n size=\"sm\"\r\n [label]=\"_label\"\r\n [items]=\"_items\"\r\n [valueField]=\"_column.option.valueField\"\r\n [displayField]=\"_column.option.displayField\"\r\n [(model)]=\"_columnFilter[_column.field]\"\r\n (sdChange)=\"onFilterChange()\"\r\n [disabled]=\"_column.filter?.disabled\"\r\n [multiple]=\"_column.option.selection === 'MULTIPLE'\"\r\n hideInlineError>\r\n </sd-select>\r\n } @else if (_column.type === 'lazy-values') {\r\n <sd-select\r\n minWidthPanel=\"200px\"\r\n [autoId]=\"_autoId\"\r\n style=\"flex: 1 1 0%; min-width: 0\"\r\n [style.width]=\"'100%'\"\r\n size=\"sm\"\r\n [label]=\"_label\"\r\n [items]=\"_items\"\r\n [valueField]=\"_column.option.valueField\"\r\n [displayField]=\"_column.option.displayField\"\r\n [(model)]=\"_columnFilter[_column.field]\"\r\n (sdChange)=\"onFilterChange()\"\r\n [disabled]=\"_column.filter?.disabled\"\r\n [multiple]=\"_column.option.selection === 'MULTIPLE'\"\r\n hideInlineError>\r\n </sd-select>\r\n } @else if (_column.type === 'date' || _column.type === 'datetime' || _column.type === 'time') {\r\n @if (!_column.filter?.type || _column.filter?.type === 'daterange') {\r\n <sd-date-range\r\n style=\"flex: 1 1 0%; min-width: 0\"\r\n size=\"sm\"\r\n [label]=\"_label\"\r\n [(model)]=\"_columnFilter[_column.field]\"\r\n (sdChange)=\"onFilterChange()\"\r\n [disabled]=\"_column.filter?.disabled\"\r\n hideInlineError>\r\n </sd-date-range>\r\n } @else if (_column.filter?.type === 'date') {\r\n <sd-date\r\n [autoId]=\"_autoId\"\r\n style=\"flex: 1 1 0%; min-width: 0\"\r\n type=\"date\"\r\n size=\"sm\"\r\n [label]=\"_label\"\r\n [(model)]=\"_columnFilter[_column.field]\"\r\n (sdChange)=\"onFilterChange()\"\r\n [disabled]=\"_column.filter?.disabled\"\r\n hideInlineError>\r\n </sd-date>\r\n } @else if (_column.filter?.type === 'split-date') {\r\n <ng-container\r\n *ngTemplateOutlet=\"splitDateTpl; context: { field: _column.field, disabled: _column.filter?.disabled }\">\r\n </ng-container>\r\n }\r\n }\r\n }\r\n } @else {\r\n <sd-input [autoId]=\"_autoId\" style=\"flex: 1 1 0%; min-width: 0\" type=\"text\" size=\"sm\" disabled></sd-input>\r\n }\r\n</div>\r\n\r\n<!-- ================================================ -->\r\n<!-- Split from/to templates (\u0111\u01B0a xu\u1ED1ng cu\u1ED1i file) -->\r\n<!-- ================================================ -->\r\n<ng-template #splitNumberTpl let-field=\"field\" let-disabled=\"disabled\">\r\n <div class=\"d-flex align-items-center\" style=\"flex: 1 1 0%; min-width: 0\">\r\n <sd-input-number\r\n [autoId]=\"_autoId + '-from'\"\r\n style=\"flex: 1 1 0%; min-width: 0\"\r\n size=\"sm\"\r\n [label]=\"_label\"\r\n [(model)]=\"_columnFilter[field].from\"\r\n (sdChange)=\"onFilterChange()\"\r\n (sdBlur)=\"onFilterCommit()\"\r\n [disabled]=\"disabled\"\r\n hideInlineError>\r\n </sd-input-number>\r\n <div class=\"mx-4\">-</div>\r\n <sd-input-number\r\n [autoId]=\"_autoId + '-to'\"\r\n style=\"flex: 1 1 0%; min-width: 0\"\r\n size=\"sm\"\r\n [(model)]=\"_columnFilter[field].to\"\r\n (sdChange)=\"onFilterChange()\"\r\n (sdBlur)=\"onFilterCommit()\"\r\n [disabled]=\"disabled\"\r\n hideInlineError>\r\n </sd-input-number>\r\n </div>\r\n</ng-template>\r\n\r\n<ng-template #splitDateTpl let-field=\"field\" let-disabled=\"disabled\">\r\n <div class=\"d-flex align-items-center\" style=\"flex: 1 1 0%; min-width: 0\">\r\n <sd-date\r\n [autoId]=\"_autoId + '-from'\"\r\n style=\"flex: 1 1 0%; min-width: 0\"\r\n type=\"date\"\r\n size=\"sm\"\r\n [label]=\"_label\"\r\n [(model)]=\"_columnFilter[field].from\"\r\n (sdChange)=\"onFilterChange()\"\r\n [disabled]=\"disabled\"\r\n hideInlineError>\r\n </sd-date>\r\n <div class=\"mx-4\">-</div>\r\n <sd-date\r\n [autoId]=\"_autoId + '-to'\"\r\n style=\"flex: 1 1 0%; min-width: 0\"\r\n type=\"date\"\r\n size=\"sm\"\r\n [(model)]=\"_columnFilter[field].to\"\r\n (sdChange)=\"onFilterChange()\"\r\n [disabled]=\"disabled\"\r\n hideInlineError>\r\n </sd-date>\r\n </div>\r\n</ng-template>\r\n", styles: [":host ::ng-deep .c-inline-column .mat-mdc-text-field-wrapper{background-color:#fff}\n"] }]
287
+ args: [{ selector: 'column-filter', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [CommonModule, SdOperator, SdInput, SdInputNumber, SdSelect, SdDate, SdDateRange, SdBadge], template: "@let _column = column();\r\n@let _columnFilter = columnFilter();\r\n@let _autoId = autoId();\r\n@let _templateRef = templateRef();\r\n@let _operators = operators();\r\n@let _items = items();\r\n@let _label = label();\r\n@let _context = { columnFilter: _columnFilter, autoId: _autoId };\r\n\r\n<div class=\"d-flex c-inline-column align-items-end\" style=\"width: 100%; max-width: 100%\">\r\n @if (\r\n _column.type === 'string' ||\r\n _column.type === 'number' ||\r\n _column.type === 'boolean' ||\r\n _column.type === 'values' ||\r\n _column.type === 'lazy-values' ||\r\n _column.type === 'date' ||\r\n _column.type === 'datetime' ||\r\n _column.type === 'time'\r\n ) {\r\n <!-- Operator filter -->\r\n @if (_operators.length) {\r\n <div class=\"d-flex align-items-center\" [ngClass]=\"operatorWrapperClass()\">\r\n <sd-operator [(model)]=\"operator\" [operators]=\"operatorValues()\" />\r\n </div>\r\n }\r\n\r\n <!-- N\u1EBFu filter nh\u1EADn v\u00E0o template -->\r\n @if (_templateRef) {\r\n <ng-container *ngTemplateOutlet=\"_templateRef; context: _context\"></ng-container>\r\n }\r\n <!-- M\u1EB7c \u0111\u1ECBnh theo type v\u00E0 gi\u00E1 tr\u1ECB values defined c\u1EE7a column -->\r\n @else {\r\n @if (_column.type === 'string') {\r\n <sd-input\r\n [autoId]=\"_autoId\"\r\n style=\"flex: 1 1 0%; min-width: 0\"\r\n size=\"sm\"\r\n type=\"text\"\r\n [label]=\"_label\"\r\n [(model)]=\"_columnFilter[_column.field]\"\r\n (keyupEnter)=\"onFilterChange()\"\r\n (sdBlur)=\"onFilterCommit()\"\r\n (cleared)=\"onFilterChange()\"\r\n [disabled]=\"_column.filter?.disabled\"\r\n hideInlineError>\r\n </sd-input>\r\n } @else if (_column.type === 'number') {\r\n @if (!_column.filter?.type) {\r\n <sd-input-number\r\n [autoId]=\"_autoId\"\r\n style=\"flex: 1 1 0%; min-width: 0\"\r\n size=\"sm\"\r\n [label]=\"_label\"\r\n [(model)]=\"_columnFilter[_column.field]\"\r\n (keyupEnter)=\"onFilterChange()\"\r\n (sdBlur)=\"onFilterCommit()\"\r\n (cleared)=\"onFilterChange()\"\r\n [disabled]=\"_column.filter?.disabled\"\r\n hideInlineError>\r\n </sd-input-number>\r\n } @else if (_column.filter?.type === 'split-number') {\r\n <ng-container\r\n *ngTemplateOutlet=\"splitNumberTpl; context: { field: _column.field, disabled: _column.filter?.disabled }\">\r\n </ng-container>\r\n }\r\n } @else if (_column.type === 'boolean') {\r\n <sd-select\r\n minWidthPanel=\"200px\"\r\n [autoId]=\"_autoId\"\r\n style=\"flex: 1 1 0%; min-width: 0\"\r\n [style.width]=\"'100%'\"\r\n size=\"sm\"\r\n [label]=\"_label\"\r\n [items]=\"[\r\n { value: '1', display: _column.option?.displayOnTrue || 'True' },\r\n { value: '0', display: _column.option?.displayOnFalse || 'False' },\r\n ]\"\r\n valueField=\"value\"\r\n displayField=\"display\"\r\n [(model)]=\"_columnFilter[_column.field]\"\r\n (sdChange)=\"onFilterChange()\"\r\n [disabled]=\"_column.filter?.disabled\"\r\n hideInlineError>\r\n <ng-template sdItemDef let-item=\"item\">\r\n @if (item.value === '1') {\r\n <sd-badge color=\"success\" [title]=\"_column.option?.displayOnTrue || 'True'\"> </sd-badge>\r\n } @else {\r\n <sd-badge color=\"error\" [title]=\"_column.option?.displayOnFalse || 'False'\"> </sd-badge>\r\n }\r\n </ng-template>\r\n </sd-select>\r\n } @else if (_column.type === 'values') {\r\n <sd-select\r\n minWidthPanel=\"200px\"\r\n [autoId]=\"_autoId\"\r\n style=\"flex: 1 1 0%; min-width: 0\"\r\n [style.width]=\"'100%'\"\r\n size=\"sm\"\r\n [label]=\"_label\"\r\n [items]=\"_items\"\r\n [valueField]=\"_column.option.valueField\"\r\n [displayField]=\"_column.option.displayField\"\r\n [(model)]=\"_columnFilter[_column.field]\"\r\n (sdChange)=\"onFilterChange()\"\r\n [disabled]=\"_column.filter?.disabled\"\r\n [multiple]=\"_column.option.selection === 'MULTIPLE'\"\r\n hideInlineError>\r\n </sd-select>\r\n } @else if (_column.type === 'lazy-values') {\r\n <sd-select\r\n minWidthPanel=\"200px\"\r\n [autoId]=\"_autoId\"\r\n style=\"flex: 1 1 0%; min-width: 0\"\r\n [style.width]=\"'100%'\"\r\n size=\"sm\"\r\n [label]=\"_label\"\r\n [items]=\"_items\"\r\n [valueField]=\"_column.option.valueField\"\r\n [displayField]=\"_column.option.displayField\"\r\n [(model)]=\"_columnFilter[_column.field]\"\r\n (sdChange)=\"onFilterChange()\"\r\n [disabled]=\"_column.filter?.disabled\"\r\n [multiple]=\"_column.option.selection === 'MULTIPLE'\"\r\n hideInlineError>\r\n </sd-select>\r\n } @else if (_column.type === 'date' || _column.type === 'datetime' || _column.type === 'time') {\r\n @if (!_column.filter?.type || _column.filter?.type === 'daterange') {\r\n <sd-date-range\r\n style=\"flex: 1 1 0%; min-width: 0\"\r\n size=\"sm\"\r\n [label]=\"_label\"\r\n [(model)]=\"_columnFilter[_column.field]\"\r\n (sdChange)=\"onFilterChange()\"\r\n [disabled]=\"_column.filter?.disabled\"\r\n hideInlineError>\r\n </sd-date-range>\r\n } @else if (_column.filter?.type === 'date') {\r\n <sd-date\r\n [autoId]=\"_autoId\"\r\n style=\"flex: 1 1 0%; min-width: 0\"\r\n type=\"date\"\r\n size=\"sm\"\r\n [label]=\"_label\"\r\n [(model)]=\"_columnFilter[_column.field]\"\r\n (sdChange)=\"onFilterChange()\"\r\n [disabled]=\"_column.filter?.disabled\"\r\n hideInlineError>\r\n </sd-date>\r\n } @else if (_column.filter?.type === 'split-date') {\r\n <ng-container\r\n *ngTemplateOutlet=\"splitDateTpl; context: { field: _column.field, disabled: _column.filter?.disabled }\">\r\n </ng-container>\r\n }\r\n }\r\n }\r\n } @else {\r\n <sd-input [autoId]=\"_autoId\" style=\"flex: 1 1 0%; min-width: 0\" type=\"text\" size=\"sm\" disabled></sd-input>\r\n }\r\n</div>\r\n\r\n<!-- ================================================ -->\r\n<!-- Split from/to templates (\u0111\u01B0a xu\u1ED1ng cu\u1ED1i file) -->\r\n<!-- ================================================ -->\r\n<ng-template #splitNumberTpl let-field=\"field\" let-disabled=\"disabled\">\r\n <div class=\"d-flex align-items-center\" style=\"flex: 1 1 0%; min-width: 0\">\r\n <sd-input-number\r\n [autoId]=\"_autoId + '-from'\"\r\n style=\"flex: 1 1 0%; min-width: 0\"\r\n size=\"sm\"\r\n [label]=\"_label\"\r\n [(model)]=\"_columnFilter[field].from\"\r\n (sdChange)=\"onFilterChange()\"\r\n (sdBlur)=\"onFilterCommit()\"\r\n (cleared)=\"onFilterChange()\"\r\n [disabled]=\"disabled\"\r\n hideInlineError>\r\n </sd-input-number>\r\n <div class=\"mx-4\">-</div>\r\n <sd-input-number\r\n [autoId]=\"_autoId + '-to'\"\r\n style=\"flex: 1 1 0%; min-width: 0\"\r\n size=\"sm\"\r\n [(model)]=\"_columnFilter[field].to\"\r\n (sdChange)=\"onFilterChange()\"\r\n (sdBlur)=\"onFilterCommit()\"\r\n (cleared)=\"onFilterChange()\"\r\n [disabled]=\"disabled\"\r\n hideInlineError>\r\n </sd-input-number>\r\n </div>\r\n</ng-template>\r\n\r\n<ng-template #splitDateTpl let-field=\"field\" let-disabled=\"disabled\">\r\n <div class=\"d-flex align-items-center\" style=\"flex: 1 1 0%; min-width: 0\">\r\n <sd-date\r\n [autoId]=\"_autoId + '-from'\"\r\n style=\"flex: 1 1 0%; min-width: 0\"\r\n type=\"date\"\r\n size=\"sm\"\r\n [label]=\"_label\"\r\n [(model)]=\"_columnFilter[field].from\"\r\n (sdChange)=\"onFilterChange()\"\r\n [disabled]=\"disabled\"\r\n hideInlineError>\r\n </sd-date>\r\n <div class=\"mx-4\">-</div>\r\n <sd-date\r\n [autoId]=\"_autoId + '-to'\"\r\n style=\"flex: 1 1 0%; min-width: 0\"\r\n type=\"date\"\r\n size=\"sm\"\r\n [(model)]=\"_columnFilter[field].to\"\r\n (sdChange)=\"onFilterChange()\"\r\n [disabled]=\"disabled\"\r\n hideInlineError>\r\n </sd-date>\r\n </div>\r\n</ng-template>\r\n", styles: [":host ::ng-deep .c-inline-column .mat-mdc-text-field-wrapper{background-color:#fff}\n"] }]
260
288
  }], ctorParameters: () => [] });
261
289
 
262
290
  // Đối với filter loại values, items có thể là 1 mảng, có thể là 1 hàm, do đó cần xử lý nếu là hàm có thể xử lý gọi API
@@ -316,23 +344,26 @@ const flattenTree = (roots, option, visited = new Set()) => {
316
344
  return roots;
317
345
  const maxDepth = option.maxDepth;
318
346
  const result = [];
319
- const walk = (rows, level) => {
320
- for (const row of rows) {
347
+ const walk = (rows, level, parentPath) => {
348
+ rows.forEach((row, siblingIdx) => {
321
349
  if (visited.has(row.meta.id))
322
- continue;
350
+ return;
323
351
  visited.add(row.meta.id);
324
352
  row.meta.tree ??= { level, hasChildren: false, isExpanded: false };
325
353
  row.meta.tree.level = level;
354
+ // why: hierarchical numbering (1, 1.2, 1.2.1, ...) — STT template join('.').
355
+ const indexPath = [...parentPath, siblingIdx + 1];
356
+ row.meta.tree.indexPath = indexPath;
326
357
  result.push(row);
327
358
  const canDescend = row.meta.tree.isExpanded && row.meta.tree.hasChildren;
328
359
  const depthOk = maxDepth === undefined || level < maxDepth;
329
360
  if (!canDescend || !depthOk)
330
- continue;
361
+ return;
331
362
  const children = row.meta.tree.childItems ?? [];
332
- walk(children, level + 1);
333
- }
363
+ walk(children, level + 1, indexPath);
364
+ });
334
365
  };
335
- walk(roots, 0);
366
+ walk(roots, 0, []);
336
367
  return result;
337
368
  };
338
369
  /** Thu thập mọi SdTableItem đã format trong cây (kể cả node đang collapse). */
@@ -534,7 +565,7 @@ class ExternalFilterComponent {
534
565
  });
535
566
  };
536
567
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: ExternalFilterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
537
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: ExternalFilterComponent, isStandalone: true, selector: "external-filter", inputs: { autoIdInput: { classPropertyName: "autoIdInput", publicName: "autoId", isSignal: true, isRequired: false, transformFunction: null }, filter: { classPropertyName: "filter", publicName: "filter", isSignal: true, isRequired: false, transformFunction: null }, externalFilters: { classPropertyName: "externalFilters", publicName: "externalFilters", isSignal: true, isRequired: false, transformFunction: null }, filterRegister: { classPropertyName: "filterRegister", publicName: "filterRegister", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@let _filter = filter();\n@let _autoId = autoId();\n@let _items = filterItems();\n@let _externalFilter = externalFilter();\n@let _inlineExternal = inlineExternal();\n@let _filtered = filtered();\n@let _col = col();\n\n@if (!_filter?.disabled) {\n @if (!isMobileOrTablet && _items.length) {\n <sd-section\n [hideHeader]=\"_filter?.hideExternalFilterToolbar\"\n icon=\"filter_alt\"\n iconColor=\"secondary\"\n [title]=\"'core.component.table.filter' | translate\"\n collapsable>\n <div class=\"d-flex mr-4\" sdHeaderRight>\n <sd-button\n [autoId]=\"_autoId + 'clear'\"\n [disabled]=\"!_filtered\"\n type=\"link\"\n prefixIcon=\"cleaning_services\"\n [tooltip]=\"'core.component.table.clear-selection' | translate\"\n (click)=\"$event.stopPropagation(); clearFilter($event)\"></sd-button>\n <sd-button\n [autoId]=\"_autoId + 'setting'\"\n type=\"link\"\n prefixIcon=\"settings\"\n [tooltip]=\"'core.component.table.customize' | translate\"\n [matMenuTriggerFor]=\"menu\"\n (click)=\"$event.stopPropagation()\"></sd-button>\n <mat-menu #menu=\"matMenu\" class=\"sd-custom-panel-filter-configuration\" [attr.data-autoid]=\"_autoId + 'setting-menu'\">\n @for (externalFilter of _items; track externalFilter.field) {\n <button\n [attr.data-autoid]=\"_autoId + 'setting-' + externalFilter.field\"\n mat-menu-item\n (click)=\"onCheckboxChange($event, externalFilter)\"\n [disabled]=\"externalFilter.required\">\n <sd-checkbox\n [autoId]=\"_autoId + 'setting-' + externalFilter.field + '-checkbox'\"\n [label]=\"externalFilter.title\"\n [model]=\"_inlineExternal[externalFilter.field]\"\n [disabled]=\"externalFilter.required\" />\n </button>\n }\n </mat-menu>\n </div>\n <div class=\"row mx-0\" style=\"row-gap: 16px\">\n @for (item of _items; track item.field) {\n @if (_inlineExternal[item.field]) {\n <div class=\"col-md-3 col-sm-6 px-8\" [class.col-lg-2]=\"_col === 2\" [class.col-lg-3]=\"_col === 3\">\n @if (item.type === 'string') {\n <sd-input\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n type=\"text\"\n [(model)]=\"_externalFilter[item.field]\"\n (keyupEnter)=\"onKeyupEnter()\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-input>\n } @else if (item.type === 'number') {\n <sd-input-number\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [(model)]=\"_externalFilter[item.field]\"\n (keyupEnter)=\"onKeyupEnter()\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-input-number>\n } @else if (item.type === 'boolean') {\n <sd-select\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [items]=\"[\n { value: true, display: item.option?.displayOnTrue || 'True' },\n { value: false, display: item.option?.displayOnFalse || 'False' },\n ]\"\n valueField=\"value\"\n displayField=\"display\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n } @else if (item.type === 'date') {\n <sd-date\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n [min]=\"item.minDate\"\n [max]=\"item.maxDate\"\n hideInlineError>\n </sd-date>\n } @else if (item.type === 'datetime') {\n <sd-datetime\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n [min]=\"item.minDate\"\n [max]=\"item.maxDate\"\n hideInlineError>\n </sd-datetime>\n } @else if (item.type === 'daterange') {\n <sd-date-range\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n [form]=\"form\"\n [required]=\"item.required\"\n [min]=\"item.minDate\"\n [max]=\"item.maxDate\"\n appearance=\"outline\"\n hideInlineError>\n </sd-date-range>\n } @else if (item.type === 'values') {\n @if (item.option.selection === 'MULTIPLE') {\n <sd-select\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [items]=\"item.option.items | filterValues | async\"\n [valueField]=\"item.option.valueField\"\n [displayField]=\"item.option.displayField\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n multiple\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n } @else if (item.option.selection === 'AUTOCOMPLETE') {\n <sd-select\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [items]=\"item.option.items | filterValues | async\"\n [valueField]=\"item.option.valueField\"\n [displayField]=\"item.option.displayField\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n } @else if (item.option.selection === 'MULTIPLEAUTOCOMPLETE') {\n <sd-select\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [items]=\"item.option.items | filterValues | async\"\n [valueField]=\"item.option.valueField\"\n [displayField]=\"item.option.displayField\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n multiple\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n } @else {\n <sd-select\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [items]=\"item.option.items | filterValues | async\"\n [valueField]=\"item.option.valueField\"\n [displayField]=\"item.option.displayField\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n }\n } @else if (item.type === 'lazy-values') {\n @if (item.option.selection === 'MULTIPLE') {\n <sd-select\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [items]=\"item.option.items\"\n [valueField]=\"item.option.valueField\"\n [displayField]=\"item.option.displayField\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n multiple\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n } @else {\n <sd-select\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [items]=\"item.option.items\"\n [valueField]=\"item.option.valueField\"\n [displayField]=\"item.option.displayField\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n }\n } @else if (item.type === 'custom' && item.filterDef) {\n <ng-container\n *ngTemplateOutlet=\"\n item.filterDef;\n context: { form: form, externalFilter: _externalFilter, autoId: _autoId + item.field }\n \">\n </ng-container>\n }\n </div>\n }\n }\n </div>\n @if (_filter?.manualFilter) {\n <div class=\"d-flex justify-content-end mt-16 px-8\">\n <sd-button\n [autoId]=\"_autoId + 'submit'\"\n [disabled]=\"form.invalid\"\n type=\"fill\"\n color=\"primary\"\n [title]=\"'core.component.table.search' | translate\"\n prefixIcon=\"filter_alt\"\n (click)=\"onSubmit()\">\n </sd-button>\n </div>\n }\n </sd-section>\n }\n}\n", styles: [":host{display:block;padding-left:0;padding-right:0}::ng-deep .sd-custom-panel-filter-configuration{width:240px;max-height:550px;overflow-y:auto}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i2.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i2.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i2.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: SdSection, selector: "sd-section", inputs: ["title", "subTitle", "icon", "iconColor", "collapsed", "collapsable", "hideHeader", "noPaddingBody"], outputs: ["collapsedChange"] }, { kind: "component", type: SdInput, selector: "sd-input", inputs: ["autoId", "name", "appearance", "floatLabel", "size", "form", "label", "helperText", "placeholder", "type", "hideInlineError", "blurOnEnter", "required", "readonly", "disabled", "viewed", "minlength", "maxlength", "pattern", "patternErrorMessage", "validator", "inlineError", "hyperlink", "model"], outputs: ["modelChange", "sdChange", "sdFocus", "sdBlur", "keyupEnter", "sdFocusForceBlur"] }, { kind: "component", type: SdInputNumber, selector: "sd-input-number", inputs: ["autoId", "name", "size", "form", "label", "helperText", "placeholder", "hideInlineError", "blurOnEnter", "required", "readonly", "disabled", "viewed", "type", "precision", "format", "min", "max", "validator", "inlineError", "hyperlink", "appearance", "floatLabel", "model"], outputs: ["modelChange", "sdChange", "sdFocus", "sdBlur", "keyupEnter", "sdFocusForceBlur"] }, { kind: "component", type: SdSelect, selector: "sd-select", inputs: ["autoId", "name", "size", "form", "label", "helperText", "placeholder", "valueField", "displayField", "disabledField", "cacheChecksum", "limit", "hyperlink", "minWidthPanel", "hideInlineError", "required", "disabled", "viewed", "multiple", "bare", "validator", "inlineError", "appearance", "floatLabel", "items", "model"], outputs: ["modelChange", "sdChange", "sdSelection"] }, { kind: "component", type: SdDate, selector: "sd-date", inputs: ["autoId", "name", "size", "form", "label", "helperText", "placeholder", "hideInlineError", "required", "disabled", "viewed", "bare", "inlineError", "hyperlink", "appearance", "floatLabel", "min", "minDate", "max", "maxDate", "model"], outputs: ["modelChange", "sdChange", "sdFocus"] }, { kind: "component", type: SdDatetime, selector: "sd-datetime", inputs: ["autoId", "name", "size", "form", "label", "helperText", "placeholder", "hideInlineError", "required", "disabled", "viewed", "showSeconds", "bare", "inlineError", "hyperlink", "appearance", "floatLabel", "min", "minDate", "max", "maxDate", "model"], outputs: ["modelChange", "sdChange", "sdFocus"] }, { kind: "component", type: SdDateRange$1, selector: "sd-date-range", inputs: ["autoId", "name", "size", "form", "label", "helperText", "hideInlineError", "required", "disabled", "bare", "viewed", "appearance", "floatLabel", "min", "max", "model"], outputs: ["modelChange", "sdChange"] }, { kind: "component", type: SdButton, selector: "sd-button", inputs: ["autoId", "type", "color", "size", "fontSet", "title", "width", "tooltip", "prefixIcon", "suffixIcon", "disabled", "loading", "block", "htmlType"], outputs: ["click"] }, { kind: "pipe", type: FilterValuesPipe, name: "filterValues" }, { kind: "component", type: SdCheckbox, selector: "sd-checkbox", inputs: ["autoId", "name", "form", "label", "color", "disabled", "viewed", "inlineError", "model"], outputs: ["modelChange", "sdChange"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
568
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: ExternalFilterComponent, isStandalone: true, selector: "external-filter", inputs: { autoIdInput: { classPropertyName: "autoIdInput", publicName: "autoId", isSignal: true, isRequired: false, transformFunction: null }, filter: { classPropertyName: "filter", publicName: "filter", isSignal: true, isRequired: false, transformFunction: null }, externalFilters: { classPropertyName: "externalFilters", publicName: "externalFilters", isSignal: true, isRequired: false, transformFunction: null }, filterRegister: { classPropertyName: "filterRegister", publicName: "filterRegister", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@let _filter = filter();\n@let _autoId = autoId();\n@let _items = filterItems();\n@let _externalFilter = externalFilter();\n@let _inlineExternal = inlineExternal();\n@let _filtered = filtered();\n@let _col = col();\n\n@if (!_filter?.disabled) {\n @if (!isMobileOrTablet && _items.length) {\n <sd-section\n [hideHeader]=\"_filter?.hideExternalFilterToolbar\"\n icon=\"filter_alt\"\n iconColor=\"secondary\"\n [title]=\"'core.component.table.filter' | translate\"\n collapsable>\n <div class=\"d-flex mr-4\" sdHeaderRight>\n <sd-button\n [autoId]=\"_autoId + 'clear'\"\n [disabled]=\"!_filtered\"\n type=\"link\"\n prefixIcon=\"cleaning_services\"\n [tooltip]=\"'core.component.table.clear-selection' | translate\"\n (click)=\"$event.stopPropagation(); clearFilter($event)\"></sd-button>\n <sd-button\n [autoId]=\"_autoId + 'setting'\"\n type=\"link\"\n prefixIcon=\"settings\"\n [tooltip]=\"'core.component.table.customize' | translate\"\n [matMenuTriggerFor]=\"menu\"\n (click)=\"$event.stopPropagation()\"></sd-button>\n <mat-menu #menu=\"matMenu\" class=\"sd-custom-panel-filter-configuration\" [attr.data-autoid]=\"_autoId + 'setting-menu'\">\n @for (externalFilter of _items; track externalFilter.field) {\n <button\n [attr.data-autoid]=\"_autoId + 'setting-' + externalFilter.field\"\n mat-menu-item\n (click)=\"onCheckboxChange($event, externalFilter)\"\n [disabled]=\"externalFilter.required\">\n <sd-checkbox\n [autoId]=\"_autoId + 'setting-' + externalFilter.field + '-checkbox'\"\n [label]=\"externalFilter.title\"\n [model]=\"_inlineExternal[externalFilter.field]\"\n [disabled]=\"externalFilter.required\" />\n </button>\n }\n </mat-menu>\n </div>\n <div class=\"row mx-0\" style=\"row-gap: 16px\">\n @for (item of _items; track item.field) {\n @if (_inlineExternal[item.field]) {\n <div class=\"col-md-3 col-sm-6 px-8\" [class.col-lg-2]=\"_col === 2\" [class.col-lg-3]=\"_col === 3\">\n @if (item.type === 'string') {\n <sd-input\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n type=\"text\"\n [(model)]=\"_externalFilter[item.field]\"\n (keyupEnter)=\"onKeyupEnter()\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-input>\n } @else if (item.type === 'number') {\n <sd-input-number\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [(model)]=\"_externalFilter[item.field]\"\n (keyupEnter)=\"onKeyupEnter()\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-input-number>\n } @else if (item.type === 'boolean') {\n <sd-select\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [items]=\"[\n { value: true, display: item.option?.displayOnTrue || 'True' },\n { value: false, display: item.option?.displayOnFalse || 'False' },\n ]\"\n valueField=\"value\"\n displayField=\"display\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n } @else if (item.type === 'date') {\n <sd-date\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n [min]=\"item.minDate\"\n [max]=\"item.maxDate\"\n hideInlineError>\n </sd-date>\n } @else if (item.type === 'datetime') {\n <sd-datetime\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n [min]=\"item.minDate\"\n [max]=\"item.maxDate\"\n hideInlineError>\n </sd-datetime>\n } @else if (item.type === 'daterange') {\n <sd-date-range\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n [form]=\"form\"\n [required]=\"item.required\"\n [min]=\"item.minDate\"\n [max]=\"item.maxDate\"\n appearance=\"outline\"\n hideInlineError>\n </sd-date-range>\n } @else if (item.type === 'values') {\n @if (item.option.selection === 'MULTIPLE') {\n <sd-select\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [items]=\"item.option.items | filterValues | async\"\n [valueField]=\"item.option.valueField\"\n [displayField]=\"item.option.displayField\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n multiple\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n } @else if (item.option.selection === 'AUTOCOMPLETE') {\n <sd-select\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [items]=\"item.option.items | filterValues | async\"\n [valueField]=\"item.option.valueField\"\n [displayField]=\"item.option.displayField\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n } @else if (item.option.selection === 'MULTIPLEAUTOCOMPLETE') {\n <sd-select\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [items]=\"item.option.items | filterValues | async\"\n [valueField]=\"item.option.valueField\"\n [displayField]=\"item.option.displayField\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n multiple\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n } @else {\n <sd-select\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [items]=\"item.option.items | filterValues | async\"\n [valueField]=\"item.option.valueField\"\n [displayField]=\"item.option.displayField\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n }\n } @else if (item.type === 'lazy-values') {\n @if (item.option.selection === 'MULTIPLE') {\n <sd-select\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [items]=\"item.option.items\"\n [valueField]=\"item.option.valueField\"\n [displayField]=\"item.option.displayField\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n multiple\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n } @else {\n <sd-select\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [items]=\"item.option.items\"\n [valueField]=\"item.option.valueField\"\n [displayField]=\"item.option.displayField\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n }\n } @else if (item.type === 'custom' && item.filterDef) {\n <ng-container\n *ngTemplateOutlet=\"\n item.filterDef;\n context: { form: form, externalFilter: _externalFilter, autoId: _autoId + item.field }\n \">\n </ng-container>\n }\n </div>\n }\n }\n </div>\n @if (_filter?.manualFilter) {\n <div class=\"d-flex justify-content-end mt-16 px-8\">\n <sd-button\n [autoId]=\"_autoId + 'submit'\"\n [disabled]=\"form.invalid\"\n type=\"fill\"\n color=\"primary\"\n [title]=\"'core.component.table.search' | translate\"\n prefixIcon=\"filter_alt\"\n (click)=\"onSubmit()\">\n </sd-button>\n </div>\n }\n </sd-section>\n }\n}\n", styles: [":host{display:block;padding-left:0;padding-right:0}::ng-deep .sd-custom-panel-filter-configuration{width:240px;max-height:550px;overflow-y:auto}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i2.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i2.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i2.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: SdSection, selector: "sd-section", inputs: ["title", "subTitle", "icon", "iconColor", "collapsed", "collapsable", "hideHeader", "noPaddingBody"], outputs: ["collapsedChange"] }, { kind: "component", type: SdInput, selector: "sd-input", inputs: ["autoId", "name", "appearance", "floatLabel", "size", "form", "label", "helperText", "placeholder", "type", "hideInlineError", "blurOnEnter", "required", "readonly", "disabled", "viewed", "minlength", "maxlength", "pattern", "patternErrorMessage", "validator", "inlineError", "hyperlink", "model"], outputs: ["modelChange", "sdChange", "sdFocus", "sdBlur", "keyupEnter", "cleared", "sdFocusForceBlur"] }, { kind: "component", type: SdInputNumber, selector: "sd-input-number", inputs: ["autoId", "name", "size", "form", "label", "helperText", "placeholder", "hideInlineError", "blurOnEnter", "required", "readonly", "disabled", "viewed", "type", "precision", "format", "min", "max", "validator", "inlineError", "hyperlink", "appearance", "floatLabel", "model"], outputs: ["modelChange", "sdChange", "sdFocus", "sdBlur", "keyupEnter", "cleared", "sdFocusForceBlur"] }, { kind: "component", type: SdSelect, selector: "sd-select", inputs: ["autoId", "name", "size", "form", "label", "helperText", "placeholder", "valueField", "displayField", "disabledField", "cacheChecksum", "limit", "hyperlink", "minWidthPanel", "hideInlineError", "required", "disabled", "viewed", "multiple", "bare", "validator", "inlineError", "appearance", "floatLabel", "items", "model"], outputs: ["modelChange", "sdChange", "sdSelection"] }, { kind: "component", type: SdDate, selector: "sd-date", inputs: ["autoId", "name", "size", "form", "label", "helperText", "placeholder", "hideInlineError", "required", "disabled", "viewed", "bare", "inlineError", "hyperlink", "appearance", "floatLabel", "min", "minDate", "max", "maxDate", "model"], outputs: ["modelChange", "sdChange", "sdFocus"] }, { kind: "component", type: SdDatetime, selector: "sd-datetime", inputs: ["autoId", "name", "size", "form", "label", "helperText", "placeholder", "hideInlineError", "required", "disabled", "viewed", "showSeconds", "bare", "inlineError", "hyperlink", "appearance", "floatLabel", "min", "minDate", "max", "maxDate", "model"], outputs: ["modelChange", "sdChange", "sdFocus"] }, { kind: "component", type: SdDateRange$1, selector: "sd-date-range", inputs: ["autoId", "name", "size", "form", "label", "helperText", "hideInlineError", "required", "disabled", "bare", "viewed", "appearance", "floatLabel", "min", "max", "model"], outputs: ["modelChange", "sdChange"] }, { kind: "component", type: SdButton, selector: "sd-button", inputs: ["autoId", "type", "color", "size", "fontSet", "title", "width", "tooltip", "prefixIcon", "suffixIcon", "disabled", "loading", "block", "htmlType"], outputs: ["click"] }, { kind: "pipe", type: FilterValuesPipe, name: "filterValues" }, { kind: "component", type: SdCheckbox, selector: "sd-checkbox", inputs: ["autoId", "name", "form", "label", "color", "disabled", "viewed", "inlineError", "model"], outputs: ["modelChange", "sdChange"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
538
569
  }
539
570
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: ExternalFilterComponent, decorators: [{
540
571
  type: Component,
@@ -630,7 +661,7 @@ class MobileFilterComponent {
630
661
  this.drawer().close();
631
662
  };
632
663
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: MobileFilterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
633
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: MobileFilterComponent, isStandalone: true, selector: "mobile-filter", inputs: { autoIdInput: { classPropertyName: "autoIdInput", publicName: "autoId", isSignal: true, isRequired: false, transformFunction: null }, filter: { classPropertyName: "filter", publicName: "filter", isSignal: true, isRequired: false, transformFunction: null }, externalFilters: { classPropertyName: "externalFilters", publicName: "externalFilters", isSignal: true, isRequired: false, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null }, filterDefs: { classPropertyName: "filterDefs", publicName: "filterDefs", isSignal: true, isRequired: false, transformFunction: null }, filterRegister: { classPropertyName: "filterRegister", publicName: "filterRegister", isSignal: true, isRequired: false, transformFunction: null }, cacheValues: { classPropertyName: "cacheValues", publicName: "cacheValues", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "drawer", first: true, predicate: SdSideDrawer, descendants: true, isSignal: true }], ngImport: i0, template: "@let _autoId = autoId();\n@let _externalFilters = externalFilterItems();\n@let _columns = columnItems();\n@let _filterDefs = filterDefItems();\n@let _workingColumnFilter = workingColumnFilter();\n@let _workingColumnOperator = workingColumnOperator();\n@let _workingExternalFilter = workingExternalFilter();\n@let _cacheValues = cacheValues();\n\n<sd-side-drawer\n #drawer\n [title]=\"'core.component.table.filter' | translate\"\n width=\"90vw\">\n <div class=\"mobile-filter-body\">\n <!-- ============================ -->\n <!-- 1. External filters (inline) -->\n <!-- ============================ -->\n @if (_externalFilters.length) {\n <section class=\"mobile-filter-section\">\n @for (item of _externalFilters; track item.field) {\n <div class=\"mobile-filter-row\">\n @if (item.type === 'string') {\n <sd-input\n [autoId]=\"_autoId + 'ext-' + item.field\"\n size=\"sm\"\n [label]=\"item.title\"\n type=\"text\"\n [(model)]=\"_workingExternalFilter[item.field]\"\n appearance=\"outline\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-input>\n } @else if (item.type === 'number') {\n <sd-input-number\n [autoId]=\"_autoId + 'ext-' + item.field\"\n size=\"sm\"\n [label]=\"item.title\"\n [(model)]=\"_workingExternalFilter[item.field]\"\n appearance=\"outline\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-input-number>\n } @else if (item.type === 'boolean') {\n <sd-select\n [autoId]=\"_autoId + 'ext-' + item.field\"\n size=\"sm\"\n [label]=\"item.title\"\n [items]=\"[\n { value: true, display: item.option?.displayOnTrue || 'True' },\n { value: false, display: item.option?.displayOnFalse || 'False' },\n ]\"\n valueField=\"value\"\n displayField=\"display\"\n [(model)]=\"_workingExternalFilter[item.field]\"\n appearance=\"outline\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n } @else if (item.type === 'date') {\n <sd-date\n [autoId]=\"_autoId + 'ext-' + item.field\"\n size=\"sm\"\n [label]=\"item.title\"\n [(model)]=\"_workingExternalFilter[item.field]\"\n appearance=\"outline\"\n [required]=\"item.required\"\n [min]=\"item.minDate\"\n [max]=\"item.maxDate\"\n hideInlineError>\n </sd-date>\n } @else if (item.type === 'datetime') {\n <sd-datetime\n [autoId]=\"_autoId + 'ext-' + item.field\"\n size=\"sm\"\n [label]=\"item.title\"\n [(model)]=\"_workingExternalFilter[item.field]\"\n appearance=\"outline\"\n [required]=\"item.required\"\n [min]=\"item.minDate\"\n [max]=\"item.maxDate\"\n hideInlineError>\n </sd-datetime>\n } @else if (item.type === 'daterange') {\n <sd-date-range\n [autoId]=\"_autoId + 'ext-' + item.field\"\n size=\"sm\"\n [label]=\"item.title\"\n [(model)]=\"_workingExternalFilter[item.field]\"\n [required]=\"item.required\"\n [min]=\"item.minDate\"\n [max]=\"item.maxDate\"\n appearance=\"outline\"\n hideInlineError>\n </sd-date-range>\n } @else if (item.type === 'values') {\n <sd-select\n [autoId]=\"_autoId + 'ext-' + item.field\"\n size=\"sm\"\n [label]=\"item.title\"\n [items]=\"item.option.items | filterValues | async\"\n [valueField]=\"item.option.valueField\"\n [displayField]=\"item.option.displayField\"\n [(model)]=\"_workingExternalFilter[item.field]\"\n appearance=\"outline\"\n [multiple]=\"item.option.selection === 'MULTIPLE' || item.option.selection === 'MULTIPLEAUTOCOMPLETE'\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n } @else if (item.type === 'lazy-values') {\n <sd-select\n [autoId]=\"_autoId + 'ext-' + item.field\"\n size=\"sm\"\n [label]=\"item.title\"\n [items]=\"item.option.items\"\n [valueField]=\"item.option.valueField\"\n [displayField]=\"item.option.displayField\"\n [(model)]=\"_workingExternalFilter[item.field]\"\n appearance=\"outline\"\n [multiple]=\"item.option.selection === 'MULTIPLE'\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n } @else if (item.type === 'custom' && item.filterDef) {\n <ng-container\n *ngTemplateOutlet=\"\n item.filterDef;\n context: { externalFilter: _workingExternalFilter, autoId: _autoId + 'ext-' + item.field }\n \">\n </ng-container>\n }\n </div>\n }\n </section>\n }\n\n <!-- ============================ -->\n <!-- 2. Custom filterDef templates -->\n <!-- ============================ -->\n @if (_filterDefs.length) {\n <section class=\"mobile-filter-section\">\n @for (def of _filterDefs; track def.sdTableFilterDef()) {\n <div class=\"mobile-filter-row\" [attr.data-autoid]=\"_autoId + 'def-' + def.sdTableFilterDef()\">\n <ng-container\n *ngTemplateOutlet=\"def.templateRef!; context: { externalFilter: _workingExternalFilter }\">\n </ng-container>\n </div>\n }\n </section>\n }\n\n <!-- ============================ -->\n <!-- 3. Column filters -->\n <!-- ============================ -->\n @if (_columns.length) {\n <section class=\"mobile-filter-section\">\n @for (column of _columns; track column.field) {\n <div class=\"mobile-filter-row\" [attr.data-autoid]=\"_autoId + 'col-' + column.field\">\n <column-filter\n [autoId]=\"_autoId + 'col'\"\n [column]=\"column\"\n [columnFilter]=\"_workingColumnFilter\"\n [operator]=\"$any(_workingColumnOperator[column.field])\"\n (operatorChange)=\"_workingColumnOperator[column.field] = $event!\"\n [cacheValues]=\"_cacheValues\"\n isMobile>\n </column-filter>\n </div>\n }\n </section>\n }\n </div>\n\n <ng-container sdFooter>\n <div class=\"mobile-filter-footer\">\n <sd-button\n [autoId]=\"_autoId + 'cancel'\"\n class=\"mobile-filter-action\"\n (click)=\"onCancel()\"\n [title]=\"'core.confirm.no' | translate\"\n type=\"link\"\n color=\"secondary\">\n </sd-button>\n <sd-button\n [autoId]=\"_autoId + 'apply'\"\n class=\"mobile-filter-action\"\n (click)=\"onApply()\"\n [title]=\"'core.confirm.yes' | translate\"\n type=\"fill\"\n color=\"primary\">\n </sd-button>\n </div>\n </ng-container>\n</sd-side-drawer>\n", styles: [".mobile-filter-body{display:flex;flex-direction:column;gap:16px;padding:8px 0}.mobile-filter-section{display:flex;flex-direction:column;gap:12px}.mobile-filter-row{display:flex;flex-direction:column}.mobile-filter-footer{display:flex;gap:8px;width:100%}.mobile-filter-action{flex:1 1 50%}.mobile-filter-action ::ng-deep button{width:100%}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "component", type: SdSideDrawer, selector: "sd-side-drawer", inputs: ["title", "width", "hideClose", "disableBackdropClose", "drawerClass", "autoId"], outputs: ["sdClosed"] }, { kind: "component", type: SdButton, selector: "sd-button", inputs: ["autoId", "type", "color", "size", "fontSet", "title", "width", "tooltip", "prefixIcon", "suffixIcon", "disabled", "loading", "block", "htmlType"], outputs: ["click"] }, { kind: "component", type: ColumnFilterComponent, selector: "column-filter", inputs: ["autoId", "column", "columnFilter", "cacheValues", "value", "operator", "isMobile"], outputs: ["operatorChange", "filterChange", "filterCommit"] }, { kind: "component", type: SdInput, selector: "sd-input", inputs: ["autoId", "name", "appearance", "floatLabel", "size", "form", "label", "helperText", "placeholder", "type", "hideInlineError", "blurOnEnter", "required", "readonly", "disabled", "viewed", "minlength", "maxlength", "pattern", "patternErrorMessage", "validator", "inlineError", "hyperlink", "model"], outputs: ["modelChange", "sdChange", "sdFocus", "sdBlur", "keyupEnter", "sdFocusForceBlur"] }, { kind: "component", type: SdInputNumber, selector: "sd-input-number", inputs: ["autoId", "name", "size", "form", "label", "helperText", "placeholder", "hideInlineError", "blurOnEnter", "required", "readonly", "disabled", "viewed", "type", "precision", "format", "min", "max", "validator", "inlineError", "hyperlink", "appearance", "floatLabel", "model"], outputs: ["modelChange", "sdChange", "sdFocus", "sdBlur", "keyupEnter", "sdFocusForceBlur"] }, { kind: "component", type: SdSelect, selector: "sd-select", inputs: ["autoId", "name", "size", "form", "label", "helperText", "placeholder", "valueField", "displayField", "disabledField", "cacheChecksum", "limit", "hyperlink", "minWidthPanel", "hideInlineError", "required", "disabled", "viewed", "multiple", "bare", "validator", "inlineError", "appearance", "floatLabel", "items", "model"], outputs: ["modelChange", "sdChange", "sdSelection"] }, { kind: "component", type: SdDate, selector: "sd-date", inputs: ["autoId", "name", "size", "form", "label", "helperText", "placeholder", "hideInlineError", "required", "disabled", "viewed", "bare", "inlineError", "hyperlink", "appearance", "floatLabel", "min", "minDate", "max", "maxDate", "model"], outputs: ["modelChange", "sdChange", "sdFocus"] }, { kind: "component", type: SdDatetime, selector: "sd-datetime", inputs: ["autoId", "name", "size", "form", "label", "helperText", "placeholder", "hideInlineError", "required", "disabled", "viewed", "showSeconds", "bare", "inlineError", "hyperlink", "appearance", "floatLabel", "min", "minDate", "max", "maxDate", "model"], outputs: ["modelChange", "sdChange", "sdFocus"] }, { kind: "component", type: SdDateRange$1, selector: "sd-date-range", inputs: ["autoId", "name", "size", "form", "label", "helperText", "hideInlineError", "required", "disabled", "bare", "viewed", "appearance", "floatLabel", "min", "max", "model"], outputs: ["modelChange", "sdChange"] }, { kind: "pipe", type: FilterValuesPipe, name: "filterValues" }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
664
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: MobileFilterComponent, isStandalone: true, selector: "mobile-filter", inputs: { autoIdInput: { classPropertyName: "autoIdInput", publicName: "autoId", isSignal: true, isRequired: false, transformFunction: null }, filter: { classPropertyName: "filter", publicName: "filter", isSignal: true, isRequired: false, transformFunction: null }, externalFilters: { classPropertyName: "externalFilters", publicName: "externalFilters", isSignal: true, isRequired: false, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null }, filterDefs: { classPropertyName: "filterDefs", publicName: "filterDefs", isSignal: true, isRequired: false, transformFunction: null }, filterRegister: { classPropertyName: "filterRegister", publicName: "filterRegister", isSignal: true, isRequired: false, transformFunction: null }, cacheValues: { classPropertyName: "cacheValues", publicName: "cacheValues", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "drawer", first: true, predicate: SdSideDrawer, descendants: true, isSignal: true }], ngImport: i0, template: "@let _autoId = autoId();\n@let _externalFilters = externalFilterItems();\n@let _columns = columnItems();\n@let _filterDefs = filterDefItems();\n@let _workingColumnFilter = workingColumnFilter();\n@let _workingColumnOperator = workingColumnOperator();\n@let _workingExternalFilter = workingExternalFilter();\n@let _cacheValues = cacheValues();\n\n<sd-side-drawer\n #drawer\n [title]=\"'core.component.table.filter' | translate\"\n width=\"90vw\">\n <div class=\"mobile-filter-body\">\n <!-- ============================ -->\n <!-- 1. External filters (inline) -->\n <!-- ============================ -->\n @if (_externalFilters.length) {\n <section class=\"mobile-filter-section\">\n @for (item of _externalFilters; track item.field) {\n <div class=\"mobile-filter-row\">\n @if (item.type === 'string') {\n <sd-input\n [autoId]=\"_autoId + 'ext-' + item.field\"\n size=\"sm\"\n [label]=\"item.title\"\n type=\"text\"\n [(model)]=\"_workingExternalFilter[item.field]\"\n appearance=\"outline\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-input>\n } @else if (item.type === 'number') {\n <sd-input-number\n [autoId]=\"_autoId + 'ext-' + item.field\"\n size=\"sm\"\n [label]=\"item.title\"\n [(model)]=\"_workingExternalFilter[item.field]\"\n appearance=\"outline\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-input-number>\n } @else if (item.type === 'boolean') {\n <sd-select\n [autoId]=\"_autoId + 'ext-' + item.field\"\n size=\"sm\"\n [label]=\"item.title\"\n [items]=\"[\n { value: true, display: item.option?.displayOnTrue || 'True' },\n { value: false, display: item.option?.displayOnFalse || 'False' },\n ]\"\n valueField=\"value\"\n displayField=\"display\"\n [(model)]=\"_workingExternalFilter[item.field]\"\n appearance=\"outline\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n } @else if (item.type === 'date') {\n <sd-date\n [autoId]=\"_autoId + 'ext-' + item.field\"\n size=\"sm\"\n [label]=\"item.title\"\n [(model)]=\"_workingExternalFilter[item.field]\"\n appearance=\"outline\"\n [required]=\"item.required\"\n [min]=\"item.minDate\"\n [max]=\"item.maxDate\"\n hideInlineError>\n </sd-date>\n } @else if (item.type === 'datetime') {\n <sd-datetime\n [autoId]=\"_autoId + 'ext-' + item.field\"\n size=\"sm\"\n [label]=\"item.title\"\n [(model)]=\"_workingExternalFilter[item.field]\"\n appearance=\"outline\"\n [required]=\"item.required\"\n [min]=\"item.minDate\"\n [max]=\"item.maxDate\"\n hideInlineError>\n </sd-datetime>\n } @else if (item.type === 'daterange') {\n <sd-date-range\n [autoId]=\"_autoId + 'ext-' + item.field\"\n size=\"sm\"\n [label]=\"item.title\"\n [(model)]=\"_workingExternalFilter[item.field]\"\n [required]=\"item.required\"\n [min]=\"item.minDate\"\n [max]=\"item.maxDate\"\n appearance=\"outline\"\n hideInlineError>\n </sd-date-range>\n } @else if (item.type === 'values') {\n <sd-select\n [autoId]=\"_autoId + 'ext-' + item.field\"\n size=\"sm\"\n [label]=\"item.title\"\n [items]=\"item.option.items | filterValues | async\"\n [valueField]=\"item.option.valueField\"\n [displayField]=\"item.option.displayField\"\n [(model)]=\"_workingExternalFilter[item.field]\"\n appearance=\"outline\"\n [multiple]=\"item.option.selection === 'MULTIPLE' || item.option.selection === 'MULTIPLEAUTOCOMPLETE'\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n } @else if (item.type === 'lazy-values') {\n <sd-select\n [autoId]=\"_autoId + 'ext-' + item.field\"\n size=\"sm\"\n [label]=\"item.title\"\n [items]=\"item.option.items\"\n [valueField]=\"item.option.valueField\"\n [displayField]=\"item.option.displayField\"\n [(model)]=\"_workingExternalFilter[item.field]\"\n appearance=\"outline\"\n [multiple]=\"item.option.selection === 'MULTIPLE'\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n } @else if (item.type === 'custom' && item.filterDef) {\n <ng-container\n *ngTemplateOutlet=\"\n item.filterDef;\n context: { externalFilter: _workingExternalFilter, autoId: _autoId + 'ext-' + item.field }\n \">\n </ng-container>\n }\n </div>\n }\n </section>\n }\n\n <!-- ============================ -->\n <!-- 2. Custom filterDef templates -->\n <!-- ============================ -->\n @if (_filterDefs.length) {\n <section class=\"mobile-filter-section\">\n @for (def of _filterDefs; track def.sdTableFilterDef()) {\n <div class=\"mobile-filter-row\" [attr.data-autoid]=\"_autoId + 'def-' + def.sdTableFilterDef()\">\n <ng-container\n *ngTemplateOutlet=\"def.templateRef!; context: { externalFilter: _workingExternalFilter }\">\n </ng-container>\n </div>\n }\n </section>\n }\n\n <!-- ============================ -->\n <!-- 3. Column filters -->\n <!-- ============================ -->\n @if (_columns.length) {\n <section class=\"mobile-filter-section\">\n @for (column of _columns; track column.field) {\n <div class=\"mobile-filter-row\" [attr.data-autoid]=\"_autoId + 'col-' + column.field\">\n <column-filter\n [autoId]=\"_autoId + 'col'\"\n [column]=\"column\"\n [columnFilter]=\"_workingColumnFilter\"\n [operator]=\"$any(_workingColumnOperator[column.field])\"\n (operatorChange)=\"_workingColumnOperator[column.field] = $event!\"\n [cacheValues]=\"_cacheValues\"\n isMobile>\n </column-filter>\n </div>\n }\n </section>\n }\n </div>\n\n <ng-container sdFooter>\n <div class=\"mobile-filter-footer\">\n <sd-button\n [autoId]=\"_autoId + 'cancel'\"\n class=\"mobile-filter-action\"\n (click)=\"onCancel()\"\n [title]=\"'core.confirm.no' | translate\"\n type=\"link\"\n color=\"secondary\">\n </sd-button>\n <sd-button\n [autoId]=\"_autoId + 'apply'\"\n class=\"mobile-filter-action\"\n (click)=\"onApply()\"\n [title]=\"'core.confirm.yes' | translate\"\n type=\"fill\"\n color=\"primary\">\n </sd-button>\n </div>\n </ng-container>\n</sd-side-drawer>\n", styles: [".mobile-filter-body{display:flex;flex-direction:column;gap:16px;padding:8px 0}.mobile-filter-section{display:flex;flex-direction:column;gap:12px}.mobile-filter-row{display:flex;flex-direction:column}.mobile-filter-footer{display:flex;gap:8px;width:100%}.mobile-filter-action{flex:1 1 50%}.mobile-filter-action ::ng-deep button{width:100%}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "component", type: SdSideDrawer, selector: "sd-side-drawer", inputs: ["title", "width", "hideClose", "disableBackdropClose", "drawerClass", "autoId"], outputs: ["sdClosed"] }, { kind: "component", type: SdButton, selector: "sd-button", inputs: ["autoId", "type", "color", "size", "fontSet", "title", "width", "tooltip", "prefixIcon", "suffixIcon", "disabled", "loading", "block", "htmlType"], outputs: ["click"] }, { kind: "component", type: ColumnFilterComponent, selector: "column-filter", inputs: ["autoId", "column", "columnFilter", "cacheValues", "value", "operator", "isMobile"], outputs: ["operatorChange", "filterChange", "filterCommit"] }, { kind: "component", type: SdInput, selector: "sd-input", inputs: ["autoId", "name", "appearance", "floatLabel", "size", "form", "label", "helperText", "placeholder", "type", "hideInlineError", "blurOnEnter", "required", "readonly", "disabled", "viewed", "minlength", "maxlength", "pattern", "patternErrorMessage", "validator", "inlineError", "hyperlink", "model"], outputs: ["modelChange", "sdChange", "sdFocus", "sdBlur", "keyupEnter", "cleared", "sdFocusForceBlur"] }, { kind: "component", type: SdInputNumber, selector: "sd-input-number", inputs: ["autoId", "name", "size", "form", "label", "helperText", "placeholder", "hideInlineError", "blurOnEnter", "required", "readonly", "disabled", "viewed", "type", "precision", "format", "min", "max", "validator", "inlineError", "hyperlink", "appearance", "floatLabel", "model"], outputs: ["modelChange", "sdChange", "sdFocus", "sdBlur", "keyupEnter", "cleared", "sdFocusForceBlur"] }, { kind: "component", type: SdSelect, selector: "sd-select", inputs: ["autoId", "name", "size", "form", "label", "helperText", "placeholder", "valueField", "displayField", "disabledField", "cacheChecksum", "limit", "hyperlink", "minWidthPanel", "hideInlineError", "required", "disabled", "viewed", "multiple", "bare", "validator", "inlineError", "appearance", "floatLabel", "items", "model"], outputs: ["modelChange", "sdChange", "sdSelection"] }, { kind: "component", type: SdDate, selector: "sd-date", inputs: ["autoId", "name", "size", "form", "label", "helperText", "placeholder", "hideInlineError", "required", "disabled", "viewed", "bare", "inlineError", "hyperlink", "appearance", "floatLabel", "min", "minDate", "max", "maxDate", "model"], outputs: ["modelChange", "sdChange", "sdFocus"] }, { kind: "component", type: SdDatetime, selector: "sd-datetime", inputs: ["autoId", "name", "size", "form", "label", "helperText", "placeholder", "hideInlineError", "required", "disabled", "viewed", "showSeconds", "bare", "inlineError", "hyperlink", "appearance", "floatLabel", "min", "minDate", "max", "maxDate", "model"], outputs: ["modelChange", "sdChange", "sdFocus"] }, { kind: "component", type: SdDateRange$1, selector: "sd-date-range", inputs: ["autoId", "name", "size", "form", "label", "helperText", "hideInlineError", "required", "disabled", "bare", "viewed", "appearance", "floatLabel", "min", "max", "model"], outputs: ["modelChange", "sdChange"] }, { kind: "pipe", type: FilterValuesPipe, name: "filterValues" }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
634
665
  }
635
666
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: MobileFilterComponent, decorators: [{
636
667
  type: Component,
@@ -693,7 +724,7 @@ class ActionFilterPipe {
693
724
  if ('children' in action) {
694
725
  const children = [];
695
726
  for (const childAction of action.children) {
696
- const key = SdUtilities.hash(childAction);
727
+ const key = Utilities.hash(childAction);
697
728
  if (selectedItems.every(e => e?.meta?.selector?.actions?.includes(key))) {
698
729
  children.push(childAction);
699
730
  }
@@ -703,7 +734,7 @@ class ActionFilterPipe {
703
734
  }
704
735
  }
705
736
  else {
706
- const key = SdUtilities.hash(action);
737
+ const key = Utilities.hash(action);
707
738
  if (selectedItems.every(e => e?.meta?.selector?.actions?.includes(key))) {
708
739
  results.push(action);
709
740
  }
@@ -781,6 +812,7 @@ class ConfigService {
781
812
  REORDER: 'sdReorder',
782
813
  INDEX: 'sdIndex',
783
814
  TREE_TOGGLE: 'sdTreeToggle',
815
+ FILLER: 'sdFiller',
784
816
  };
785
817
  #prefix = 'TABLE_CONFIG';
786
818
  #storage;
@@ -793,7 +825,7 @@ class ConfigService {
793
825
  #loadConfiguredTable = (option) => {
794
826
  // Nếu không có key thì không lấy được setting
795
827
  if (!option?.key) {
796
- return this.storageService.create(SdUtilities$1.hash(option), {
828
+ return this.storageService.create(Utilities.hash(option), {
797
829
  type: 'session', // Nếu không có key thì lưu theo session
798
830
  default: this.#default(option),
799
831
  });
@@ -840,10 +872,10 @@ class ConfigService {
840
872
  result.firstHeaders.push(this.#COLUMNS.COMMAND);
841
873
  result.displayedColumns.push(this.#COLUMNS.COMMAND);
842
874
  }
843
- if (group?.fields?.length) {
844
- result.firstHeaders.push(this.#COLUMNS.GROUP);
845
- result.displayedColumns.push(this.#COLUMNS.GROUP);
846
- }
875
+ // why: group header row dùng matRowDef RIÊNG với column list ['sdGroupHeader'] qua predicate
876
+ // when:isGroupHeader — KHÔNG inject vào displayedColumns/firstHeaders để tránh colspan trick
877
+ // (TDs khác vẫn render gây overflow row). Data row dùng displayedColumns nguyên vẹn.
878
+ // group option vẫn cần khai báo (qua option.group) để SdGroupPipe biết bucket items.
847
879
  // sdIndex đặt sau selector / tree / command-left / group, ngay trước data columns
848
880
  if (option.index?.enabled) {
849
881
  result.firstHeaders.push(this.#COLUMNS.INDEX);
@@ -919,9 +951,19 @@ class ConfigService {
919
951
  result.firstHeaders.push(this.#COLUMNS.COMMAND);
920
952
  result.displayedColumns.push(this.#COLUMNS.COMMAND);
921
953
  }
954
+ // why: filler column ở cuối hấp thụ leftover space — opt-in qua option.filler.enabled.
955
+ // Khi bật, ngăn các cột utility (selection, index, command) bị table-layout auto stretch trên màn rộng.
956
+ if (option.filler?.enabled) {
957
+ result.firstHeaders.push(this.#COLUMNS.FILLER);
958
+ result.displayedColumns.push(this.#COLUMNS.FILLER);
959
+ }
922
960
  result.multipleHeader = result.secondHeaders.length > 0;
923
- // Sub infomation không thể có footer
924
- result.displayedFooters = result.displayedColumns.filter(val => val !== this.#COLUMNS.SUBINFORMATION && val !== this.#COLUMNS.TREE_TOGGLE);
961
+ // Sub infomation không thể có footer; filler cũng không cần footer cell.
962
+ result.displayedFooters = result.displayedColumns.filter(val => val !== this.#COLUMNS.SUBINFORMATION && val !== this.#COLUMNS.TREE_TOGGLE && val !== this.#COLUMNS.FILLER);
963
+ if (option.filler?.enabled) {
964
+ // Footer cũng cần filler cuối để giữ width đồng bộ với data row
965
+ result.displayedFooters.push(this.#COLUMNS.FILLER);
966
+ }
925
967
  if (option?.rowReorder?.enabled) {
926
968
  result.displayedColumns.unshift(this.#COLUMNS.REORDER);
927
969
  result.firstHeaders.unshift(this.#COLUMNS.REORDER);
@@ -1061,7 +1103,7 @@ class ConfigComponent {
1061
1103
  this.dragDisabled = true;
1062
1104
  }
1063
1105
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: ConfigComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1064
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: ConfigComponent, isStandalone: true, selector: "config", inputs: { tableOption: { classPropertyName: "tableOption", publicName: "tableOption", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { changes: "changes" }, providers: [ConfigService], viewQueries: [{ propertyName: "modal", first: true, predicate: SdModal, descendants: true, isSignal: true }, { propertyName: "table", first: true, predicate: MatTable, descendants: true, isSignal: true }], ngImport: i0, template: "@let _configuration = configuration();\r\n\r\n<sd-modal width=\"sm\" [title]=\"'core.component.table.setup' | translate\" #modal>\r\n @if (_configuration) {\r\n <div class=\"c-container\">\r\n <div class=\"c-table\" style=\"max-height: 70vh\">\r\n <table\r\n mat-table\r\n [dataSource]=\"_configuration.columns!\"\r\n cdkDropList\r\n [cdkDropListData]=\"_configuration.columns\"\r\n (cdkDropListDropped)=\"dropTable($event)\">\r\n <ng-container matColumnDef=\"invisible\">\r\n <th mat-header-cell class=\"c-th text-center px-4\" *matHeaderCellDef style=\"width: 96px\">\r\n {{ 'core.component.form-builder.display' | translate }}\r\n </th>\r\n <td class=\"text-center px-4\" mat-cell *matCellDef=\"let item\">\r\n <div class=\"d-flex\" style=\"gap: 8px\">\r\n <div class=\"c-handle\" (mousedown)=\"handleMouseDown()\" (mouseup)=\"handleMouseUp()\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\" viewBox=\"0 0 24 24\" width=\"24px\" fill=\"#5f6368\">\r\n <path d=\"M0 0h24v24H0V0z\" fill=\"none\" />\r\n <path\r\n d=\"M11 18c0 1.1-.9 2-2 2s-2-.9-2-2 .9-2 2-2 2 .9 2 2zm-2-8c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0-6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm6 4c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z\" />\r\n </svg>\r\n </div>\r\n <sd-switch [model]=\"!item.invisible\" (modelChange)=\"item.invisible = !item.invisible\" />\r\n </div>\r\n </td>\r\n </ng-container>\r\n <ng-container matColumnDef=\"title\">\r\n <th mat-header-cell class=\"c-th px-4\" *matHeaderCellDef>\r\n {{ 'core.component.table.column-header' | translate }}\r\n </th>\r\n <td class=\"px-4\" mat-cell *matCellDef=\"let item\">\r\n <sd-input class=\"pb-4\" [placeholder]=\"item?.origin?.title\" [(model)]=\"item.title\" hideInlineError></sd-input>\r\n </td>\r\n </ng-container>\r\n <ng-container matColumnDef=\"width\">\r\n <th mat-header-cell class=\"c-th px-4\" *matHeaderCellDef style=\"width: 80px\">\r\n {{ 'core.component.table.width' | translate }}\r\n </th>\r\n <td class=\"px-4\" mat-cell *matCellDef=\"let item\">\r\n <sd-input class=\"pb-4\" [placeholder]=\"item?.origin?.width\" [(model)]=\"item.width\" hideInlineError></sd-input>\r\n </td>\r\n </ng-container>\r\n <ng-container matColumnDef=\"fixed\">\r\n <th mat-header-cell class=\"c-th text-center px-4\" *matHeaderCellDef style=\"width: 80px\">\r\n {{ 'core.component.table.fixed' | translate }}\r\n </th>\r\n <td class=\"text-center px-4\" mat-cell *matCellDef=\"let item\">\r\n <sd-switch [(model)]=\"item.fixed\" />\r\n </td>\r\n </ng-container>\r\n\r\n <ng-container matColumnDef=\"truncate\">\r\n <th mat-header-cell class=\"c-th text-center px-4\" *matHeaderCellDef style=\"width: 100px\">\r\n {{ 'core.component.table.char-limit' | translate }}\r\n </th>\r\n <td class=\"text-center px-4\" mat-cell *matCellDef=\"let item\">\r\n <sd-switch [(model)]=\"item.truncate\" />\r\n </td>\r\n </ng-container>\r\n\r\n <tr mat-header-row *matHeaderRowDef=\"['invisible', 'title', 'width', 'fixed', 'truncate']; sticky: true\"></tr>\r\n <tr\r\n mat-row\r\n *matRowDef=\"let row; columns: ['invisible', 'title', 'width', 'fixed', 'truncate']\"\r\n cdkDrag\r\n [cdkDragData]=\"row\"\r\n cdkDragLockAxis=\"y\"\r\n [cdkDragDisabled]=\"dragDisabled\">\r\n </tr>\r\n </table>\r\n </div>\r\n </div>\r\n }\r\n <ng-container sdFooter>\r\n <sd-button class=\"mr-8\" (click)=\"close()\" [title]=\"'core.component.table.skip' | translate\" color=\"secondary\"> </sd-button>\r\n <sd-button class=\"mr-8\" (click)=\"onReset()\" [title]=\"'core.component.form-builder.default' | translate\" color=\"primary\"> </sd-button>\r\n <sd-button (click)=\"onSave()\" [title]=\"'core.component.table.apply' | translate\" type=\"fill\" color=\"primary\"> </sd-button>\r\n </ng-container>\r\n</sd-modal>\r\n", styles: [".c-table{position:relative;overflow:auto}.c-table table{width:100%}.c-table .c-th{font-weight:500;font-size:14px;line-height:20px;color:#000}.c-container{position:relative;min-height:200px}.c-handle{color:#ccc;cursor:move}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: MatTableModule }, { kind: "component", type: i6.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i6.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i6.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i6.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i6.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i6.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i6.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i6.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i6.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i6.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "ngmodule", type: MatSlideToggleModule }, { kind: "ngmodule", type: CdkTableModule }, { kind: "ngmodule", type: DragDropModule }, { kind: "directive", type: i11.CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: i11.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "component", type: SdButton, selector: "sd-button", inputs: ["autoId", "type", "color", "size", "fontSet", "title", "width", "tooltip", "prefixIcon", "suffixIcon", "disabled", "loading", "block", "htmlType"], outputs: ["click"] }, { kind: "component", type: SdInput, selector: "sd-input", inputs: ["autoId", "name", "appearance", "floatLabel", "size", "form", "label", "helperText", "placeholder", "type", "hideInlineError", "blurOnEnter", "required", "readonly", "disabled", "viewed", "minlength", "maxlength", "pattern", "patternErrorMessage", "validator", "inlineError", "hyperlink", "model"], outputs: ["modelChange", "sdChange", "sdFocus", "sdBlur", "keyupEnter", "sdFocusForceBlur"] }, { kind: "component", type: SdModal, selector: "sd-modal", inputs: ["autoId", "title", "color", "width", "height", "view", "modalClass", "lazyLoadContent", "hideClose", "disableBackdropClose"], outputs: ["sdClosed"] }, { kind: "component", type: SdSwitch, selector: "sd-switch", inputs: ["autoId", "name", "form", "label", "color", "disabled", "viewed", "hideInlineError", "required", "model"], outputs: ["modelChange", "sdChange"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] });
1106
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: ConfigComponent, isStandalone: true, selector: "config", inputs: { tableOption: { classPropertyName: "tableOption", publicName: "tableOption", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { changes: "changes" }, providers: [ConfigService], viewQueries: [{ propertyName: "modal", first: true, predicate: SdModal, descendants: true, isSignal: true }, { propertyName: "table", first: true, predicate: MatTable, descendants: true, isSignal: true }], ngImport: i0, template: "@let _configuration = configuration();\r\n\r\n<sd-modal width=\"sm\" [title]=\"'core.component.table.setup' | translate\" #modal>\r\n @if (_configuration) {\r\n <div class=\"c-container\">\r\n <div class=\"c-table\" style=\"max-height: 70vh\">\r\n <table\r\n mat-table\r\n [dataSource]=\"_configuration.columns!\"\r\n cdkDropList\r\n [cdkDropListData]=\"_configuration.columns\"\r\n (cdkDropListDropped)=\"dropTable($event)\">\r\n <ng-container matColumnDef=\"invisible\">\r\n <th mat-header-cell class=\"c-th text-center px-4\" *matHeaderCellDef style=\"width: 96px\">\r\n {{ 'core.component.form-builder.display' | translate }}\r\n </th>\r\n <td class=\"text-center px-4\" mat-cell *matCellDef=\"let item\">\r\n <div class=\"d-flex\" style=\"gap: 8px\">\r\n <div class=\"c-handle\" (mousedown)=\"handleMouseDown()\" (mouseup)=\"handleMouseUp()\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\" viewBox=\"0 0 24 24\" width=\"24px\" fill=\"#5f6368\">\r\n <path d=\"M0 0h24v24H0V0z\" fill=\"none\" />\r\n <path\r\n d=\"M11 18c0 1.1-.9 2-2 2s-2-.9-2-2 .9-2 2-2 2 .9 2 2zm-2-8c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0-6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm6 4c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z\" />\r\n </svg>\r\n </div>\r\n <sd-switch [model]=\"!item.invisible\" (modelChange)=\"item.invisible = !item.invisible\" />\r\n </div>\r\n </td>\r\n </ng-container>\r\n <ng-container matColumnDef=\"title\">\r\n <th mat-header-cell class=\"c-th px-4\" *matHeaderCellDef>\r\n {{ 'core.component.table.column-header' | translate }}\r\n </th>\r\n <td class=\"px-4\" mat-cell *matCellDef=\"let item\">\r\n <sd-input class=\"pb-4\" [placeholder]=\"item?.origin?.title\" [(model)]=\"item.title\" hideInlineError></sd-input>\r\n </td>\r\n </ng-container>\r\n <ng-container matColumnDef=\"width\">\r\n <th mat-header-cell class=\"c-th px-4\" *matHeaderCellDef style=\"width: 80px\">\r\n {{ 'core.component.table.width' | translate }}\r\n </th>\r\n <td class=\"px-4\" mat-cell *matCellDef=\"let item\">\r\n <sd-input class=\"pb-4\" [placeholder]=\"item?.origin?.width\" [(model)]=\"item.width\" hideInlineError></sd-input>\r\n </td>\r\n </ng-container>\r\n <ng-container matColumnDef=\"fixed\">\r\n <th mat-header-cell class=\"c-th text-center px-4\" *matHeaderCellDef style=\"width: 80px\">\r\n {{ 'core.component.table.fixed' | translate }}\r\n </th>\r\n <td class=\"text-center px-4\" mat-cell *matCellDef=\"let item\">\r\n <sd-switch [(model)]=\"item.fixed\" />\r\n </td>\r\n </ng-container>\r\n\r\n <ng-container matColumnDef=\"truncate\">\r\n <th mat-header-cell class=\"c-th text-center px-4\" *matHeaderCellDef style=\"width: 100px\">\r\n {{ 'core.component.table.char-limit' | translate }}\r\n </th>\r\n <td class=\"text-center px-4\" mat-cell *matCellDef=\"let item\">\r\n <sd-switch [(model)]=\"item.truncate\" />\r\n </td>\r\n </ng-container>\r\n\r\n <tr mat-header-row *matHeaderRowDef=\"['invisible', 'title', 'width', 'fixed', 'truncate']; sticky: true\"></tr>\r\n <tr\r\n mat-row\r\n *matRowDef=\"let row; columns: ['invisible', 'title', 'width', 'fixed', 'truncate']\"\r\n cdkDrag\r\n [cdkDragData]=\"row\"\r\n cdkDragLockAxis=\"y\"\r\n [cdkDragDisabled]=\"dragDisabled\">\r\n </tr>\r\n </table>\r\n </div>\r\n </div>\r\n }\r\n <ng-container sdFooter>\r\n <sd-button class=\"mr-8\" (click)=\"close()\" [title]=\"'core.component.table.skip' | translate\" color=\"secondary\"> </sd-button>\r\n <sd-button class=\"mr-8\" (click)=\"onReset()\" [title]=\"'core.component.form-builder.default' | translate\" color=\"primary\"> </sd-button>\r\n <sd-button (click)=\"onSave()\" [title]=\"'core.component.table.apply' | translate\" type=\"fill\" color=\"primary\"> </sd-button>\r\n </ng-container>\r\n</sd-modal>\r\n", styles: [".c-table{position:relative;overflow:auto}.c-table table{width:100%}.c-table .c-th{font-weight:500;font-size:14px;line-height:20px;color:#000}.c-container{position:relative;min-height:200px}.c-handle{color:#ccc;cursor:move}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: MatTableModule }, { kind: "component", type: i6.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i6.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i6.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i6.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i6.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i6.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i6.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i6.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i6.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i6.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "ngmodule", type: MatSlideToggleModule }, { kind: "ngmodule", type: CdkTableModule }, { kind: "ngmodule", type: DragDropModule }, { kind: "directive", type: i11.CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: i11.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "component", type: SdButton, selector: "sd-button", inputs: ["autoId", "type", "color", "size", "fontSet", "title", "width", "tooltip", "prefixIcon", "suffixIcon", "disabled", "loading", "block", "htmlType"], outputs: ["click"] }, { kind: "component", type: SdInput, selector: "sd-input", inputs: ["autoId", "name", "appearance", "floatLabel", "size", "form", "label", "helperText", "placeholder", "type", "hideInlineError", "blurOnEnter", "required", "readonly", "disabled", "viewed", "minlength", "maxlength", "pattern", "patternErrorMessage", "validator", "inlineError", "hyperlink", "model"], outputs: ["modelChange", "sdChange", "sdFocus", "sdBlur", "keyupEnter", "cleared", "sdFocusForceBlur"] }, { kind: "component", type: SdModal, selector: "sd-modal", inputs: ["autoId", "title", "color", "width", "height", "view", "modalClass", "lazyLoadContent", "hideClose", "disableBackdropClose"], outputs: ["sdClosed"] }, { kind: "component", type: SdSwitch, selector: "sd-switch", inputs: ["autoId", "name", "form", "label", "color", "disabled", "viewed", "hideInlineError", "required", "model"], outputs: ["modelChange", "sdChange"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] });
1065
1107
  }
1066
1108
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: ConfigComponent, decorators: [{
1067
1109
  type: Component,
@@ -1150,7 +1192,7 @@ class DesktopCellComponent {
1150
1192
  item = input.required();
1151
1193
  cellDef = input.required({});
1152
1194
  value = computed(() => {
1153
- return SdUtilities.getNestedValue(this.item()?.data, this.column()?.field);
1195
+ return Utilities.getNestedValue(this.item()?.data, this.column()?.field);
1154
1196
  });
1155
1197
  key = computed(() => {
1156
1198
  const data = this.item()?.data;
@@ -1415,7 +1457,7 @@ class SdPopupExport {
1415
1457
  if (!this.exportOption?.key) {
1416
1458
  return null;
1417
1459
  }
1418
- return SdUtilities.hash({
1460
+ return Utilities.hash({
1419
1461
  prefix,
1420
1462
  key: this.exportOption?.key,
1421
1463
  });
@@ -1666,7 +1708,7 @@ class SdPopupExport {
1666
1708
  return '';
1667
1709
  };
1668
1710
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SdPopupExport, deps: [{ token: i0.ChangeDetectorRef }, { token: i1$1.SdLoadingService }, { token: i1$1.SdExcelService }, { token: i1$1.SdNotifyService }, { token: i1$1.SdConfirmService }], target: i0.ɵɵFactoryTarget.Component });
1669
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.21", type: SdPopupExport, isStandalone: true, selector: "sd-popup-export", inputs: { _tableOption: ["tableOption", "_tableOption"], configuration: "configuration" }, outputs: { export: "export" }, viewQueries: [{ propertyName: "modal", first: true, predicate: ["modal"], descendants: true }, { propertyName: "listGroups", first: true, predicate: ["listGroups"], descendants: true }], ngImport: i0, template: "<sd-modal width=\"907px\" [title]=\"'Exported template'\" #modal>\r\n <div class=\"row\">\r\n <div *ngIf=\"!files?.length\" class=\"col-12\">\r\n <div class=\"c-empty\">\r\n <img class=\"sd-image-data-empty\" alt=\"empty-image\" />\r\n <div class=\"T14R\">{{ 'There are no exported templates' }}</div>\r\n </div>\r\n </div>\r\n <ng-container *ngIf=\"files?.length\">\r\n <div class=\"col-12\">\r\n <div class=\"c-table\" style=\"max-height: 50vh\">\r\n <table mat-table [dataSource]=\"files\">\r\n <ng-container matColumnDef=\"stt\">\r\n <th mat-header-cell class=\"c-th text-center px-5\" *matHeaderCellDef style=\"width: 50px\">#</th>\r\n <td class=\"text-center px-5\" mat-cell *matCellDef=\"let item; let idx = index\">\r\n {{ idx + 1 }}\r\n </td>\r\n </ng-container>\r\n <ng-container matColumnDef=\"fileName\">\r\n <th mat-header-cell class=\"c-th px-5\" *matHeaderCellDef>\r\n {{ 'File name' }}\r\n </th>\r\n <td class=\"px-5\" mat-cell *matCellDef=\"let item\">\r\n {{ item.fileName }}\r\n </td>\r\n </ng-container>\r\n <ng-container matColumnDef=\"action\">\r\n <th mat-header-cell class=\"c-th px-5\" *matHeaderCellDef style=\"width: 80px\"></th>\r\n <td class=\"px-5\" mat-cell *matCellDef=\"let item\">\r\n <div class=\"d-flex\">\r\n <button mat-icon-button aria-label=\"delete\" (click)=\"removeFile(item)\">\r\n <mat-icon>delete</mat-icon>\r\n </button>\r\n <button mat-icon-button aria-label=\"download\" (click)=\"onExport(item)\">\r\n <mat-icon>download</mat-icon>\r\n </button>\r\n </div>\r\n </td>\r\n </ng-container>\r\n <tr mat-header-row *matHeaderRowDef=\"['stt', 'fileName', 'action']; sticky: true\"></tr>\r\n <tr mat-row *matRowDef=\"let row; columns: ['stt', 'fileName', 'action']\"></tr>\r\n </table>\r\n </div>\r\n </div>\r\n <div *ngIf=\"files.length < 5\" class=\"col-12 mt-10\">\r\n <sd-button class=\"mr-4\" [title]=\"'New template'\" (click)=\"enableCreating = true\" color=\"info\" [disabled]=\"enableCreating\">\r\n </sd-button>\r\n <sd-button *ngIf=\"exportOption?.enableUpload\" [title]=\"'Upload template'\" (click)=\"uploadTemplate()\" type=\"outline\">\r\n </sd-button>\r\n </div>\r\n </ng-container>\r\n <ng-container *ngIf=\"enableCreating || !files?.length\">\r\n <div class=\"col-12 mt-20\">\r\n <div class=\"T14R\">{{ 'Select columns for creating template' }}:</div>\r\n </div>\r\n <div class=\"col-12\">\r\n <mat-chip-listbox selectable=\"true\" multiple=\"true\">\r\n <ng-container *ngFor=\"let column of columns\">\r\n <mat-chip-option [selected]=\"selected[column.field]\" (click)=\"selected[column.field] = !selected[column.field]\">\r\n {{ column.title }}\r\n </mat-chip-option>\r\n </ng-container>\r\n </mat-chip-listbox>\r\n </div>\r\n <div class=\"col-12 row\">\r\n <div class=\"col-10\">\r\n <sd-input [form]=\"form\" [label]=\"'Template name'\" [(model)]=\"templateName\" [validator]=\"templateNameValidator\"></sd-input>\r\n </div>\r\n <div class=\"col-2 mt-8\">\r\n <sd-button width=\"100%\" [title]=\"'Save'\" color=\"info\" (click)=\"createTemplate()\"> </sd-button>\r\n </div>\r\n </div>\r\n </ng-container>\r\n </div>\r\n</sd-modal>\r\n", styles: [".c-radio-group{display:flex;flex-direction:column;margin:15px 0}.c-radio-button{margin:5px}.c-empty{display:flex;flex-direction:column;justify-content:center;align-items:center;position:static;height:116px;background:#f6f6f6;border-radius:4px}.c-table{position:relative;overflow:auto}.c-table table{width:100%}.c-table .c-th{font-weight:500;font-size:14px;line-height:20px;color:#000}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: MatTableModule }, { kind: "component", type: i6.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i6.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i6.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i6.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i6.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i6.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i6.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i6.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i6.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i6.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i5.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatChipsModule }, { kind: "component", type: i5$1.MatChipListbox, selector: "mat-chip-listbox", inputs: ["multiple", "aria-orientation", "selectable", "compareWith", "required", "hideSingleSelectionIndicator", "value"], outputs: ["change"] }, { kind: "component", type: i5$1.MatChipOption, selector: "mat-basic-chip-option, [mat-basic-chip-option], mat-chip-option, [mat-chip-option]", inputs: ["selectable", "selected"], outputs: ["selectionChange"] }, { kind: "component", type: SdButton, selector: "sd-button", inputs: ["autoId", "type", "color", "size", "fontSet", "title", "width", "tooltip", "prefixIcon", "suffixIcon", "disabled", "loading", "block", "htmlType"], outputs: ["click"] }, { kind: "component", type: SdInput, selector: "sd-input", inputs: ["autoId", "name", "appearance", "floatLabel", "size", "form", "label", "helperText", "placeholder", "type", "hideInlineError", "blurOnEnter", "required", "readonly", "disabled", "viewed", "minlength", "maxlength", "pattern", "patternErrorMessage", "validator", "inlineError", "hyperlink", "model"], outputs: ["modelChange", "sdChange", "sdFocus", "sdBlur", "keyupEnter", "sdFocusForceBlur"] }, { kind: "component", type: SdModal, selector: "sd-modal", inputs: ["autoId", "title", "color", "width", "height", "view", "modalClass", "lazyLoadContent", "hideClose", "disableBackdropClose"], outputs: ["sdClosed"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1711
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.21", type: SdPopupExport, isStandalone: true, selector: "sd-popup-export", inputs: { _tableOption: ["tableOption", "_tableOption"], configuration: "configuration" }, outputs: { export: "export" }, viewQueries: [{ propertyName: "modal", first: true, predicate: ["modal"], descendants: true }, { propertyName: "listGroups", first: true, predicate: ["listGroups"], descendants: true }], ngImport: i0, template: "<sd-modal width=\"907px\" [title]=\"'Exported template'\" #modal>\r\n <div class=\"row\">\r\n <div *ngIf=\"!files?.length\" class=\"col-12\">\r\n <div class=\"c-empty\">\r\n <img class=\"sd-image-data-empty\" alt=\"empty-image\" />\r\n <div class=\"T14R\">{{ 'There are no exported templates' }}</div>\r\n </div>\r\n </div>\r\n <ng-container *ngIf=\"files?.length\">\r\n <div class=\"col-12\">\r\n <div class=\"c-table\" style=\"max-height: 50vh\">\r\n <table mat-table [dataSource]=\"files\">\r\n <ng-container matColumnDef=\"stt\">\r\n <th mat-header-cell class=\"c-th text-center px-5\" *matHeaderCellDef style=\"width: 50px\">#</th>\r\n <td class=\"text-center px-5\" mat-cell *matCellDef=\"let item; let idx = index\">\r\n {{ idx + 1 }}\r\n </td>\r\n </ng-container>\r\n <ng-container matColumnDef=\"fileName\">\r\n <th mat-header-cell class=\"c-th px-5\" *matHeaderCellDef>\r\n {{ 'File name' }}\r\n </th>\r\n <td class=\"px-5\" mat-cell *matCellDef=\"let item\">\r\n {{ item.fileName }}\r\n </td>\r\n </ng-container>\r\n <ng-container matColumnDef=\"action\">\r\n <th mat-header-cell class=\"c-th px-5\" *matHeaderCellDef style=\"width: 80px\"></th>\r\n <td class=\"px-5\" mat-cell *matCellDef=\"let item\">\r\n <div class=\"d-flex\">\r\n <button mat-icon-button aria-label=\"delete\" (click)=\"removeFile(item)\">\r\n <mat-icon>delete</mat-icon>\r\n </button>\r\n <button mat-icon-button aria-label=\"download\" (click)=\"onExport(item)\">\r\n <mat-icon>download</mat-icon>\r\n </button>\r\n </div>\r\n </td>\r\n </ng-container>\r\n <tr mat-header-row *matHeaderRowDef=\"['stt', 'fileName', 'action']; sticky: true\"></tr>\r\n <tr mat-row *matRowDef=\"let row; columns: ['stt', 'fileName', 'action']\"></tr>\r\n </table>\r\n </div>\r\n </div>\r\n <div *ngIf=\"files.length < 5\" class=\"col-12 mt-10\">\r\n <sd-button class=\"mr-4\" [title]=\"'New template'\" (click)=\"enableCreating = true\" color=\"info\" [disabled]=\"enableCreating\">\r\n </sd-button>\r\n <sd-button *ngIf=\"exportOption?.enableUpload\" [title]=\"'Upload template'\" (click)=\"uploadTemplate()\" type=\"outline\">\r\n </sd-button>\r\n </div>\r\n </ng-container>\r\n <ng-container *ngIf=\"enableCreating || !files?.length\">\r\n <div class=\"col-12 mt-20\">\r\n <div class=\"T14R\">{{ 'Select columns for creating template' }}:</div>\r\n </div>\r\n <div class=\"col-12\">\r\n <mat-chip-listbox selectable=\"true\" multiple=\"true\">\r\n <ng-container *ngFor=\"let column of columns\">\r\n <mat-chip-option [selected]=\"selected[column.field]\" (click)=\"selected[column.field] = !selected[column.field]\">\r\n {{ column.title }}\r\n </mat-chip-option>\r\n </ng-container>\r\n </mat-chip-listbox>\r\n </div>\r\n <div class=\"col-12 row\">\r\n <div class=\"col-10\">\r\n <sd-input [form]=\"form\" [label]=\"'Template name'\" [(model)]=\"templateName\" [validator]=\"templateNameValidator\"></sd-input>\r\n </div>\r\n <div class=\"col-2 mt-8\">\r\n <sd-button width=\"100%\" [title]=\"'Save'\" color=\"info\" (click)=\"createTemplate()\"> </sd-button>\r\n </div>\r\n </div>\r\n </ng-container>\r\n </div>\r\n</sd-modal>\r\n", styles: [".c-radio-group{display:flex;flex-direction:column;margin:15px 0}.c-radio-button{margin:5px}.c-empty{display:flex;flex-direction:column;justify-content:center;align-items:center;position:static;height:116px;background:#f6f6f6;border-radius:4px}.c-table{position:relative;overflow:auto}.c-table table{width:100%}.c-table .c-th{font-weight:500;font-size:14px;line-height:20px;color:#000}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: MatTableModule }, { kind: "component", type: i6.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i6.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i6.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i6.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i6.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i6.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i6.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i6.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i6.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i6.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i5.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatChipsModule }, { kind: "component", type: i5$1.MatChipListbox, selector: "mat-chip-listbox", inputs: ["multiple", "aria-orientation", "selectable", "compareWith", "required", "hideSingleSelectionIndicator", "value"], outputs: ["change"] }, { kind: "component", type: i5$1.MatChipOption, selector: "mat-basic-chip-option, [mat-basic-chip-option], mat-chip-option, [mat-chip-option]", inputs: ["selectable", "selected"], outputs: ["selectionChange"] }, { kind: "component", type: SdButton, selector: "sd-button", inputs: ["autoId", "type", "color", "size", "fontSet", "title", "width", "tooltip", "prefixIcon", "suffixIcon", "disabled", "loading", "block", "htmlType"], outputs: ["click"] }, { kind: "component", type: SdInput, selector: "sd-input", inputs: ["autoId", "name", "appearance", "floatLabel", "size", "form", "label", "helperText", "placeholder", "type", "hideInlineError", "blurOnEnter", "required", "readonly", "disabled", "viewed", "minlength", "maxlength", "pattern", "patternErrorMessage", "validator", "inlineError", "hyperlink", "model"], outputs: ["modelChange", "sdChange", "sdFocus", "sdBlur", "keyupEnter", "cleared", "sdFocusForceBlur"] }, { kind: "component", type: SdModal, selector: "sd-modal", inputs: ["autoId", "title", "color", "width", "height", "view", "modalClass", "lazyLoadContent", "hideClose", "disableBackdropClose"], outputs: ["sdClosed"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1670
1712
  }
1671
1713
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SdPopupExport, decorators: [{
1672
1714
  type: Component,
@@ -1933,7 +1975,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImpo
1933
1975
  const MapToSdTableItem = (item) => ({
1934
1976
  data: item,
1935
1977
  meta: {
1936
- id: SdUtilities.hash({ data: item }),
1978
+ id: Utilities.hash({ data: item }),
1937
1979
  display: {},
1938
1980
  expand: {
1939
1981
  isExpanding: false,
@@ -1946,56 +1988,76 @@ const MapToSdTableItem = (item) => ({
1946
1988
  });
1947
1989
 
1948
1990
  class SdGroupPipe {
1949
- transform(items, gridOption) {
1950
- if (gridOption.tree) {
1991
+ /**
1992
+ * Nhóm items theo `option.group.fields`. Mỗi group sinh ra 1 synthetic SdTableItem
1993
+ * (group header) đặt trước children. Header có `meta.group.isGroupHeader = true` + `key`
1994
+ * + `values` + `items` + `isExpanded` để template + table consume.
1995
+ *
1996
+ * Khi `option.group.collapsible = true` + group đang collapse → children bị lọc khỏi output.
1997
+ *
1998
+ * `expandState` (optional, owned by component) — Map<key, expanded> giữ trạng thái
1999
+ * expand/collapse qua các lần transform. Pipe đọc state từ Map; nếu key chưa tồn tại,
2000
+ * dùng `!option.group.defaultCollapsed`. Pipe ghi state về Map cho lần read sau.
2001
+ *
2002
+ * @example
2003
+ * `_items | sdGroup: _tableOption : groupExpandState`
2004
+ */
2005
+ transform(items, gridOption, expandState) {
2006
+ if (gridOption?.tree) {
1951
2007
  if (typeof ngDevMode !== 'undefined' && ngDevMode && gridOption.group) {
1952
2008
  console.warn('[sd-table] option.tree and option.group cannot be used together. group is ignored.');
1953
2009
  }
1954
2010
  return items;
1955
2011
  }
1956
- const { group } = gridOption;
1957
- if (!group) {
2012
+ const group = gridOption?.group;
2013
+ if (!group?.fields?.length)
1958
2014
  return items;
1959
- }
1960
- const { fields, htmlTemplate } = group;
1961
- if (!fields?.length) {
1962
- return items;
1963
- }
1964
- const groupItem = {};
2015
+ const fields = group.fields;
2016
+ const collapsible = !!group.collapsible;
2017
+ const defaultExpanded = !group.defaultCollapsed;
2018
+ // Bucket items theo combined field-value hash.
2019
+ // Field hỗ trợ dot-notation (vd 'customer.id') — resolve qua getNestedValue.
2020
+ const buckets = new Map();
1965
2021
  for (const item of items) {
1966
- let obj = {};
1967
- for (const field of fields) {
1968
- obj = {
1969
- ...obj,
1970
- ...(item[field] ?? { [field]: item[field] }),
1971
- };
2022
+ const values = {};
2023
+ for (const f of fields)
2024
+ values[f] = Utilities.getNestedValue(item.data, f);
2025
+ const key = Utilities.hash(values);
2026
+ let bucket = buckets.get(key);
2027
+ if (!bucket) {
2028
+ bucket = { values, items: [] };
2029
+ buckets.set(key, bucket);
1972
2030
  }
1973
- const key = SdUtilities.hash(obj);
1974
- if (!groupItem[key]) {
1975
- groupItem[key] = [];
1976
- }
1977
- groupItem[key].push(item);
2031
+ bucket.items.push(item);
1978
2032
  }
1979
- const results = [];
1980
- for (const key of Object.keys(groupItem)) {
1981
- const result = MapToSdTableItem({});
1982
- result.meta.group.items = groupItem[key];
1983
- result.meta.group.htmlTemplate = htmlTemplate(groupItem[key]);
1984
- results.push(result);
1985
- for (const item of groupItem[key]) {
1986
- results.push(item);
2033
+ const result = [];
2034
+ buckets.forEach((bucket, key) => {
2035
+ const isExpanded = expandState?.has(key) ? !!expandState.get(key) : defaultExpanded;
2036
+ if (collapsible && expandState)
2037
+ expandState.set(key, isExpanded);
2038
+ const header = MapToSdTableItem({});
2039
+ header.meta.group = {
2040
+ isGroupHeader: true,
2041
+ key,
2042
+ values: bucket.values,
2043
+ items: bucket.items,
2044
+ isExpanded,
2045
+ };
2046
+ header.meta.selector.selectable = false;
2047
+ result.push(header);
2048
+ if (!collapsible || isExpanded) {
2049
+ for (const child of bucket.items)
2050
+ result.push(child);
1987
2051
  }
1988
- }
1989
- return results;
2052
+ });
2053
+ return result;
1990
2054
  }
1991
2055
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SdGroupPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
1992
2056
  static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.2.21", ngImport: i0, type: SdGroupPipe, isStandalone: true, name: "sdGroup" });
1993
2057
  }
1994
2058
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SdGroupPipe, decorators: [{
1995
2059
  type: Pipe,
1996
- args: [{
1997
- name: 'sdGroup',
1998
- }]
2060
+ args: [{ name: 'sdGroup' }]
1999
2061
  }] });
2000
2062
 
2001
2063
  class SdSelectionDisabledPipe {
@@ -2021,7 +2083,7 @@ class SdSelectionDisabledPipe {
2021
2083
  const availableActions = actions.filter(action => {
2022
2084
  if ('children' in action) {
2023
2085
  for (const childAction of action.children) {
2024
- const key = SdUtilities.hash(childAction);
2086
+ const key = Utilities.hash(childAction);
2025
2087
  if (selectedItems.every(e => e.meta.selector?.actions?.includes(key))) {
2026
2088
  return true;
2027
2089
  }
@@ -2029,7 +2091,7 @@ class SdSelectionDisabledPipe {
2029
2091
  return false;
2030
2092
  }
2031
2093
  else {
2032
- const key = SdUtilities.hash(action);
2094
+ const key = Utilities.hash(action);
2033
2095
  return selectedItems.every(e => e.meta.selector?.actions?.includes(key));
2034
2096
  }
2035
2097
  });
@@ -2037,13 +2099,13 @@ class SdSelectionDisabledPipe {
2037
2099
  for (const action of availableActions) {
2038
2100
  if ('children' in action) {
2039
2101
  for (const childAction of action.children) {
2040
- if (rowData.meta.selector?.actions?.includes(SdUtilities.hash(childAction))) {
2102
+ if (rowData.meta.selector?.actions?.includes(Utilities.hash(childAction))) {
2041
2103
  return false;
2042
2104
  }
2043
2105
  }
2044
2106
  }
2045
2107
  else {
2046
- if (rowData.meta.selector?.actions?.includes(SdUtilities.hash(action))) {
2108
+ if (rowData.meta.selector?.actions?.includes(Utilities.hash(action))) {
2047
2109
  return false;
2048
2110
  }
2049
2111
  }
@@ -2110,7 +2172,7 @@ class SdSelectionVisiblePipe {
2110
2172
  let hasGroup = false;
2111
2173
  for (const child of action.children) {
2112
2174
  const { hidden, isGrouped } = child;
2113
- const key = SdUtilities.hash(child);
2175
+ const key = Utilities.hash(child);
2114
2176
  if (isGrouped) {
2115
2177
  hasGroup = true;
2116
2178
  }
@@ -2132,15 +2194,15 @@ class SdSelectionVisiblePipe {
2132
2194
  }
2133
2195
  }
2134
2196
  if (flag) {
2135
- rowData.meta.selector.actions.push(SdUtilities.hash(action));
2197
+ rowData.meta.selector.actions.push(Utilities.hash(action));
2136
2198
  if (hasGroup) {
2137
- groupedActions.push(SdUtilities.hash(action));
2199
+ groupedActions.push(Utilities.hash(action));
2138
2200
  }
2139
2201
  }
2140
2202
  }
2141
2203
  else {
2142
2204
  const { hidden, isGrouped } = action;
2143
- const key = SdUtilities.hash(action);
2205
+ const key = Utilities.hash(action);
2144
2206
  if (typeof hidden === 'function') {
2145
2207
  if (!hidden(rowData.data)) {
2146
2208
  rowData.meta.selector.actions.push(key);
@@ -2252,11 +2314,11 @@ class TableExportService {
2252
2314
  for (const item of exportItems) {
2253
2315
  const obj = {};
2254
2316
  const handle = async (exportColumn) => {
2255
- obj[exportColumn.field] = SdUtilities.getNestedValue(item, exportColumn.field);
2317
+ obj[exportColumn.field] = Utilities.getNestedValue(item, exportColumn.field);
2256
2318
  const column = allColumns.find(e => e.field === exportColumn.field);
2257
2319
  const exportedColumn = allExportedColumns.find(e => e.field === exportColumn.field);
2258
2320
  if (exportedColumn?.transform) {
2259
- obj[exportedColumn.field] = exportedColumn.transform(SdUtilities.getNestedValue(item, exportedColumn.field), item);
2321
+ obj[exportedColumn.field] = exportedColumn.transform(Utilities.getNestedValue(item, exportedColumn.field), item);
2260
2322
  return;
2261
2323
  }
2262
2324
  if (!column)
@@ -2271,7 +2333,7 @@ class TableExportService {
2271
2333
  }
2272
2334
  if (!columns.some(e => e.field === column.field))
2273
2335
  return;
2274
- const itemValue = SdUtilities.getNestedValue(item, column.field);
2336
+ const itemValue = Utilities.getNestedValue(item, column.field);
2275
2337
  const fieldStr = column.field;
2276
2338
  if (column.transform) {
2277
2339
  const transform = column.transform(itemValue, item, { isExport: true });
@@ -2451,8 +2513,8 @@ class TableFormatService {
2451
2513
  const data = column.option.items();
2452
2514
  cacheValues[column.field] = (Array.isArray(data) ? data : []).map(e => ({
2453
2515
  ...e,
2454
- [column.option.valueField]: SdUtilities.getNestedValue(e, column.option.valueField),
2455
- [column.option.displayField]: SdUtilities.getNestedValue(e, column.option.displayField),
2516
+ [column.option.valueField]: Utilities.getNestedValue(e, column.option.valueField),
2517
+ [column.option.displayField]: Utilities.getNestedValue(e, column.option.displayField),
2456
2518
  }));
2457
2519
  cacheObjValues[column.field] = ArrayUtilities.toObject(column.option.valueField, cacheValues[column.field]);
2458
2520
  }
@@ -2471,8 +2533,8 @@ class TableFormatService {
2471
2533
  else {
2472
2534
  cacheValues[column.field] = column.option.items.map(e => ({
2473
2535
  ...e,
2474
- [column.option.valueField]: SdUtilities.getNestedValue(e, column.option.valueField),
2475
- [column.option.displayField]: SdUtilities.getNestedValue(e, column.option.displayField),
2536
+ [column.option.valueField]: Utilities.getNestedValue(e, column.option.valueField),
2537
+ [column.option.displayField]: Utilities.getNestedValue(e, column.option.displayField),
2476
2538
  }));
2477
2539
  cacheObjValues[column.field] = ArrayUtilities.toObject(column.option.valueField, cacheValues[column.field]);
2478
2540
  }
@@ -2483,8 +2545,8 @@ class TableFormatService {
2483
2545
  for (const result of results) {
2484
2546
  cacheValues[result.key] = result.data.map(e => ({
2485
2547
  ...e,
2486
- [result.valueField]: SdUtilities.getNestedValue(e, result.valueField),
2487
- [result.displayField]: SdUtilities.getNestedValue(e, result.displayField),
2548
+ [result.valueField]: Utilities.getNestedValue(e, result.valueField),
2549
+ [result.displayField]: Utilities.getNestedValue(e, result.displayField),
2488
2550
  }));
2489
2551
  cacheObjValues[result.key] = ArrayUtilities.toObject(result.valueField, cacheValues[result.key]);
2490
2552
  }
@@ -2503,7 +2565,7 @@ class TableFormatService {
2503
2565
  const { option: { views, valueField, displayField }, } = column;
2504
2566
  cacheObjValues[fieldStr] = cacheObjValues[fieldStr] || {};
2505
2567
  const values = ArrayUtilities.distinct(items
2506
- .map(item => SdUtilities.getNestedValue(item.data, fieldStr))
2568
+ .map(item => Utilities.getNestedValue(item.data, fieldStr))
2507
2569
  .filter(val => val?.toString())
2508
2570
  .reduce((current, next) => [...current, ...(Array.isArray(next) ? next : [next])], [])
2509
2571
  .filter(val => !Object.keys(cacheObjValues[fieldStr]).includes(val)));
@@ -2512,10 +2574,10 @@ class TableFormatService {
2512
2574
  console.error(err);
2513
2575
  return [];
2514
2576
  }))
2515
- .filter((item) => values.includes(SdUtilities.getNestedValue(item, valueField)))
2577
+ .filter((item) => values.includes(Utilities.getNestedValue(item, valueField)))
2516
2578
  .map((e) => ({
2517
- [valueField]: SdUtilities.getNestedValue(e, valueField),
2518
- [displayField]: SdUtilities.getNestedValue(e, displayField),
2579
+ [valueField]: Utilities.getNestedValue(e, valueField),
2580
+ [displayField]: Utilities.getNestedValue(e, displayField),
2519
2581
  }));
2520
2582
  Object.assign(cacheObjValues[fieldStr], ArrayUtilities.toObject(valueField, lazyItems) || {});
2521
2583
  }
@@ -2523,7 +2585,7 @@ class TableFormatService {
2523
2585
  // Format dữ liệu cho từng hàng
2524
2586
  for (const item of items) {
2525
2587
  const rowData = item.data;
2526
- const value = SdUtilities.getNestedValue(rowData, fieldStr);
2588
+ const value = Utilities.getNestedValue(rowData, fieldStr);
2527
2589
  item.meta.display[fieldStr] = {
2528
2590
  badge: undefined,
2529
2591
  cellStyle: column.align === 'right' ? { 'text-align': 'right!important' } : undefined,
@@ -2571,7 +2633,7 @@ class TableFormatService {
2571
2633
  }
2572
2634
  }
2573
2635
  if (display.data === null || display.data === undefined || display.data === '') {
2574
- display.data = SD_EMPTY_STR;
2636
+ display.data = EMPTY_STR;
2575
2637
  display.badge = undefined;
2576
2638
  }
2577
2639
  }
@@ -2667,7 +2729,7 @@ class SdTableFilterService {
2667
2729
  register = (filter, args) => {
2668
2730
  let cacheSession = false;
2669
2731
  const { id, columns, externalFilters } = args;
2670
- const tempKey = SdUtilities.hash({
2732
+ const tempKey = Utilities.hash({
2671
2733
  id,
2672
2734
  columns: columns?.map(e => e.field).filter(field => !!field) || [],
2673
2735
  externalFilters: externalFilters?.map(e => e.field).filter(field => !!field) || [],
@@ -2917,6 +2979,7 @@ class SdTable extends SdBaseSecureComponent {
2917
2979
  paginator = viewChild(MatPaginator);
2918
2980
  sort = viewChild(MatSort);
2919
2981
  sdSubInformation = contentChild(SdTableExpandDefDirective);
2982
+ sdGroupDef = contentChild(SdTableGroupDefDirective);
2920
2983
  sdCellDefs = contentChildren(SdTableCellDefDirective);
2921
2984
  sdFooterDefs = contentChildren(SdMaterialFooterDefDirective);
2922
2985
  sdFilterDefs = contentChildren(SdTableFilterDefDirective);
@@ -3167,7 +3230,7 @@ class SdTable extends SdBaseSecureComponent {
3167
3230
  const { field, type } = column;
3168
3231
  const filterValue = (rawColumnFilter[field] || '').toString().trim().toLowerCase();
3169
3232
  // SỬA: Dùng getNestedValue để hỗ trợ nested field trong filterLocal
3170
- const rawColVal = SdUtilities.getNestedValue(item, field);
3233
+ const rawColVal = Utilities.getNestedValue(item, field);
3171
3234
  const columnValue = (rawColVal || '').toString().trim().toLowerCase();
3172
3235
  if (filterValue) {
3173
3236
  if (!columnValue && type !== 'datetime' && type !== 'date' && type !== 'time') {
@@ -3182,7 +3245,7 @@ class SdTable extends SdBaseSecureComponent {
3182
3245
  const columnType = column;
3183
3246
  const isMultiple = columnType.option.selection === 'MULTIPLE';
3184
3247
  if (isMultiple && Array.isArray(rawColVal)) {
3185
- const columnValues = rawColVal.map((i) => (SdUtilities.getNestedValue(i, columnType.option.valueField) ?? '').toString().trim().toLowerCase()) ?? [];
3248
+ const columnValues = rawColVal.map((i) => (Utilities.getNestedValue(i, columnType.option.valueField) ?? '').toString().trim().toLowerCase()) ?? [];
3186
3249
  const filterValues = rawColumnFilter[field]?.map((v) => (v ?? '').toString().trim().toLowerCase());
3187
3250
  if (filterValues?.length && filterValues.every(fv => !columnValues.includes(fv))) {
3188
3251
  return false;
@@ -3259,8 +3322,8 @@ class SdTable extends SdBaseSecureComponent {
3259
3322
  const data = tableItemCurrent.data;
3260
3323
  const next = tableItemNext.data;
3261
3324
  // SỬA: Dùng getNestedValue cho sorting
3262
- const dataVal = SdUtilities.getNestedValue(data, field);
3263
- const nextVal = SdUtilities.getNestedValue(next, field);
3325
+ const dataVal = Utilities.getNestedValue(data, field);
3326
+ const nextVal = Utilities.getNestedValue(next, field);
3264
3327
  if (type === 'number') {
3265
3328
  return (dataVal || 0) - (nextVal || 0);
3266
3329
  }
@@ -3427,6 +3490,9 @@ class SdTable extends SdBaseSecureComponent {
3427
3490
  await this.#expandDefaultBranches(this.items(), treeOpt);
3428
3491
  this.treeRevision.update(n => n + 1);
3429
3492
  }
3493
+ // Restore selection từ preservedSelectedMap (chỉ khi preserveSelection bật).
3494
+ // Phải chạy TRƯỚC applyDefaultSelected để user-selection ưu tiên hơn default.
3495
+ this.#restorePreservedSelection();
3430
3496
  // Áp dụng defaultSelected: pre-select các item thỏa predicate
3431
3497
  this.#applyDefaultSelected();
3432
3498
  await this.tableOption()?.reload?.onReload?.(this.items(), additionArgs);
@@ -3674,6 +3740,12 @@ class SdTable extends SdBaseSecureComponent {
3674
3740
  this.#getSelectionRows()
3675
3741
  .filter(e => e !== rowData)
3676
3742
  .forEach(e => (e.meta.selector.isSelected = false));
3743
+ // single + preserve: chỉ giữ MỘT item trong map (item vừa chọn nếu isSelected,
3744
+ // hoặc empty nếu vừa bỏ chọn). Off-page items có thể đã ở trong map → xoá hết
3745
+ // trước khi #updateSelectedItems sync entry mới.
3746
+ if (this.#preserveEnabled()) {
3747
+ this.#preservedSelectedMap.clear();
3748
+ }
3677
3749
  opt.selector?.onSelect?.(rowData.data, selectedData());
3678
3750
  this.isSelectAll.set(false);
3679
3751
  this.#updateSelectedItems();
@@ -3699,6 +3771,10 @@ class SdTable extends SdBaseSecureComponent {
3699
3771
  items = items || this.items();
3700
3772
  this.isSelectAll.set(false);
3701
3773
  items?.forEach(e => (e.meta.selector.isSelected = false));
3774
+ // User explicit X — clear toàn bộ preserved map (bao gồm cả off-page items).
3775
+ if (this.#preserveEnabled()) {
3776
+ this.#preservedSelectedMap.clear();
3777
+ }
3702
3778
  this.#updateSelectedItems();
3703
3779
  };
3704
3780
  #getSelectionRows = () => {
@@ -3725,6 +3801,83 @@ class SdTable extends SdBaseSecureComponent {
3725
3801
  const visible = this.#getSelectionRows();
3726
3802
  this.isSelectAll.set(visible.length > 0 && visible.every(e => e.meta.selector?.isSelected));
3727
3803
  };
3804
+ // ==========================================
3805
+ // GROUP HELPERS — sync selection + expand state cho group header rows
3806
+ // ==========================================
3807
+ /** Children selectable của 1 group header (lọc bỏ children không selectable). */
3808
+ #groupSelectableChildren = (header) => {
3809
+ const children = header.meta.group?.items || [];
3810
+ return children.filter(c => c.meta.selector?.selectable !== false);
3811
+ };
3812
+ /** true nếu MỌI selectable child trong group đều selected. Group rỗng (không child) → false. */
3813
+ isGroupAllSelected = (header) => {
3814
+ const sel = this.#groupSelectableChildren(header);
3815
+ return sel.length > 0 && sel.every(c => c.meta.selector.isSelected);
3816
+ };
3817
+ /** true nếu CÓ MỘT VÀI selectable child selected nhưng KHÔNG phải tất cả. */
3818
+ isGroupIndeterminate = (header) => {
3819
+ const sel = this.#groupSelectableChildren(header);
3820
+ if (sel.length === 0)
3821
+ return false;
3822
+ const some = sel.some(c => c.meta.selector.isSelected);
3823
+ const all = sel.every(c => c.meta.selector.isSelected);
3824
+ return some && !all;
3825
+ };
3826
+ /** Toggle select-all cho 1 group: set isSelected cho mọi selectable child, sync state. */
3827
+ onSelectGroup = (header, checked) => {
3828
+ const sel = this.#groupSelectableChildren(header);
3829
+ sel.forEach(c => (c.meta.selector.isSelected = checked));
3830
+ const opt = this.tableOption();
3831
+ opt?.selector?.onSelectAll?.(this.#getSelectedRowData());
3832
+ this.#syncSelectAllState();
3833
+ this.#updateSelectedItems();
3834
+ };
3835
+ // Map<groupKey, isExpanded> — table own state, pass vào SdGroupPipe arg 3.
3836
+ // why: pipe stateless, persist toggle qua các lần re-eval bằng Map external. Mutate Map
3837
+ // KHÔNG tự re-trigger pipe (default pure: true) — gọi items.update để invalidate input.
3838
+ groupExpandState = new Map();
3839
+ /** Toggle expand/collapse cho 1 group (chỉ ý nghĩa khi option.group.collapsible). */
3840
+ toggleGroupExpand = (header) => {
3841
+ if (!header.meta.group?.key)
3842
+ return;
3843
+ const key = header.meta.group.key;
3844
+ const defaultExpanded = !this.tableOption()?.group?.defaultCollapsed;
3845
+ const current = this.groupExpandState.has(key)
3846
+ ? !!this.groupExpandState.get(key)
3847
+ : defaultExpanded;
3848
+ this.groupExpandState.set(key, !current);
3849
+ header.meta.group.isExpanded = !current;
3850
+ // why: trigger pipe re-eval — Map mutation không thay đổi reference items() nên cần update.
3851
+ this.items.update(arr => [...arr]);
3852
+ };
3853
+ /**
3854
+ * Predicate cho matRowDef.when — phân biệt group header row vs data row.
3855
+ * Group header row dùng matRowDef riêng với column list ['sdGroupHeader'] (1 cell duy nhất).
3856
+ * Data row dùng displayedColumns nguyên vẹn.
3857
+ */
3858
+ isGroupHeaderRow = (_idx, row) => row?.meta?.group?.isGroupHeader === true;
3859
+ isDataRow = (_idx, row) => row?.meta?.group?.isGroupHeader !== true;
3860
+ /**
3861
+ * Colspan cho cell sdGroupHeader trên group row = displayedColumns.length.
3862
+ * Span TOÀN BỘ width data row vì group row chỉ có 1 cell.
3863
+ */
3864
+ sdGroupColspan = computed(() => (this.configuration()?.displayedColumns?.length || 1));
3865
+ /** Build context object truyền vào SdTableGroupDefDirective template. */
3866
+ groupContext = (header) => {
3867
+ const g = header.meta.group;
3868
+ const items = g?.items || [];
3869
+ return {
3870
+ items,
3871
+ data: items.map(i => i.data),
3872
+ key: g?.key || '',
3873
+ values: g?.values || {},
3874
+ isExpanded: g?.isExpanded ?? true,
3875
+ isSelected: this.isGroupAllSelected(header),
3876
+ indeterminate: this.isGroupIndeterminate(header),
3877
+ toggleExpand: () => this.toggleGroupExpand(header),
3878
+ toggleSelect: () => this.onSelectGroup(header, !this.isGroupAllSelected(header)),
3879
+ };
3880
+ };
3728
3881
  rowStyle = (row, index) => {
3729
3882
  const fn = this.tableOption()?.style?.rowCss;
3730
3883
  if (!fn)
@@ -3735,8 +3888,44 @@ class SdTable extends SdBaseSecureComponent {
3735
3888
  : undefined;
3736
3889
  return fn(row.data, index, ctx);
3737
3890
  };
3891
+ // why: khi preserveSelection bật, giữ map nội bộ id → SdTableItem để selection
3892
+ // không mất qua filter / paginate / sort / reload (kể cả server re-fetch tạo refs mới).
3893
+ // Map chỉ bị clear khi user gọi onClearSelection (nút X) hoặc bỏ chọn từng item.
3894
+ #preservedSelectedMap = new Map();
3895
+ #preserveEnabled = () => this.tableOption()?.selector?.preserveSelection === true;
3896
+ // Restore isSelected cho item visible nào id đã có trong preserved map.
3897
+ // Đồng thời update reference trong map sang SdTableItem mới (cần thiết khi server
3898
+ // re-fetch tạo refs mới, ta muốn map giữ ref hiện hành để các tham chiếu downstream OK).
3899
+ #restorePreservedSelection = () => {
3900
+ if (!this.#preserveEnabled())
3901
+ return;
3902
+ const rows = this.#getSelectionRows();
3903
+ rows.forEach(item => {
3904
+ if (this.#preservedSelectedMap.has(item.meta.id)) {
3905
+ item.meta.selector.isSelected = true;
3906
+ this.#preservedSelectedMap.set(item.meta.id, item);
3907
+ }
3908
+ });
3909
+ };
3738
3910
  #updateSelectedItems = () => {
3739
- this.selectedTableItems.set(this.#getSelectionRows().filter(item => item.meta.selector.isSelected));
3911
+ const rows = this.#getSelectionRows();
3912
+ if (this.#preserveEnabled()) {
3913
+ // Sync map theo state visible: add nếu selected, remove nếu deselected.
3914
+ // Off-page items giữ nguyên trong map (không bị visit ở đây).
3915
+ rows.forEach(item => {
3916
+ const id = item.meta.id;
3917
+ if (item.meta.selector.isSelected) {
3918
+ this.#preservedSelectedMap.set(id, item);
3919
+ }
3920
+ else {
3921
+ this.#preservedSelectedMap.delete(id);
3922
+ }
3923
+ });
3924
+ this.selectedTableItems.set(Array.from(this.#preservedSelectedMap.values()));
3925
+ }
3926
+ else {
3927
+ this.selectedTableItems.set(rows.filter(item => item.meta.selector.isSelected));
3928
+ }
3740
3929
  this.#ref.detectChanges();
3741
3930
  };
3742
3931
  clearFilter = () => {
@@ -4082,7 +4271,7 @@ class SdTable extends SdBaseSecureComponent {
4082
4271
  provide: MatPaginatorIntl,
4083
4272
  useClass: MatPaginatorIntlCro,
4084
4273
  },
4085
- ], queries: [{ propertyName: "sdSubInformation", first: true, predicate: SdTableExpandDefDirective, descendants: true, isSignal: true }, { propertyName: "sdCellDefs", predicate: SdTableCellDefDirective, isSignal: true }, { propertyName: "sdFooterDefs", predicate: SdMaterialFooterDefDirective, isSignal: true }, { propertyName: "sdFilterDefs", predicate: SdTableFilterDefDirective, isSignal: true }, { propertyName: "sdTitleDefs", predicate: SdTableTitleDefDirective, isSignal: true }], viewQueries: [{ propertyName: "table", first: true, predicate: MatTable, descendants: true, isSignal: true }, { propertyName: "configComponent", first: true, predicate: ConfigComponent, descendants: true, isSignal: true }, { propertyName: "sdPopupExport", first: true, predicate: SdPopupExport, descendants: true, isSignal: true }, { propertyName: "scroll", first: true, predicate: SdScrollDirective, descendants: true, isSignal: true }, { propertyName: "quickAction", first: true, predicate: SdQuickAction, descendants: true, isSignal: true }, { propertyName: "externalFilter", first: true, predicate: ExternalFilterComponent, descendants: true, isSignal: true }, { propertyName: "mobileFilter", first: true, predicate: MobileFilterComponent, descendants: true, isSignal: true }, { propertyName: "paginator", first: true, predicate: MatPaginator, descendants: true, isSignal: true }, { propertyName: "sort", first: true, predicate: MatSort, descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "@let _configuration = configuration();\r\n@let _tableOption = tableOption()!;\r\n@let _loading = loading();\r\n@let _items = items();\r\n@let _total = total();\r\n@let _isFiltered = isFiltered();\r\n@let _requireFiltered = requireFiltered();\r\n@let _export = _tableOption?.export;\r\n@let _exporting = exporting();\r\n@let _titleDef = titleDef();\r\n\r\n@if (_configuration) {\r\n @if (!_tableOption.filter?.disabled && !!_tableOption.filter?.externalFilters?.length && filterRegister) {\r\n <external-filter\r\n class=\"mb-16\"\r\n [autoId]=\"autoId()\"\r\n [filterRegister]=\"filterRegister\"\r\n [filter]=\"_tableOption.filter!\"\r\n [externalFilters]=\"_tableOption.filter?.externalFilters!\">\r\n </external-filter>\r\n }\r\n @let groupedItems = _items | sdTree: _tableOption.tree : treeRevision() | sdGroup: _tableOption;\r\n <ng-content select=\"[sdTableTop]\"></ng-content>\r\n <div class=\"c-container\">\r\n @if (_loading) {\r\n <div class=\"c-loading\">\r\n <mat-spinner></mat-spinner>\r\n </div>\r\n }\r\n <div\r\n class=\"c-table\"\r\n sdScroll\r\n stickyShadow\r\n [style.max-height]=\"_tableOption.style?.maxHeight\"\r\n [style.min-height]=\"_tableOption.style?.minHeight\">\r\n <table\r\n mat-table\r\n [dataSource]=\"groupedItems\"\r\n [trackBy]=\"trackBy\"\r\n matSort\r\n [matSortDisabled]=\"!_tableOption.sort?.enable\"\r\n multiTemplateDataRows\r\n cdkDropList\r\n [cdkDropListData]=\"groupedItems\"\r\n [cdkDropListDisabled]=\"!_tableOption.rowReorder?.enabled\"\r\n [cdkDropListSortPredicate]=\"reorderSortPredicate\"\r\n (cdkDropListDropped)=\"onReorderDrop($event)\">\r\n @if (_tableOption.rowReorder?.enabled) {\r\n <ng-container matColumnDef=\"sdReorder\">\r\n <th mat-header-cell *matHeaderCellDef class=\"sd-reorder-header\" [attr.rowspan]=\"_configuration.multipleHeader ? 2 : 1\"></th>\r\n <td mat-cell *matCellDef=\"let row\" class=\"sd-reorder-cell\">\r\n @if (!row.meta?.group?.items?.length) {\r\n <mat-icon cdkDragHandle [class.sd-reorder-disabled]=\"isReorderDisabled(row)\">\r\n {{ _tableOption.rowReorder?.icon || 'drag_indicator' }}\r\n </mat-icon>\r\n }\r\n </td>\r\n <td mat-footer-cell *matFooterCellDef></td>\r\n </ng-container>\r\n }\r\n\r\n @if (_tableOption.tree) {\r\n <ng-container matColumnDef=\"sdTreeToggle\">\r\n <th\r\n mat-header-cell\r\n *matHeaderCellDef\r\n class=\"sd-tree-toggle-cell p-0\"\r\n [attr.rowspan]=\"_configuration.multipleHeader ? 2 : 1\"></th>\r\n <td mat-cell *matCellDef=\"let row\" class=\"sd-tree-toggle-cell p-0\">\r\n @if (row.meta?.tree) {\r\n <div\r\n class=\"sd-tree-toggle-inner\"\r\n [style.padding-left.px]=\"(row.meta.tree.level ?? 0) * (_tableOption.tree?.indentSize ?? 20)\">\r\n @if (row.meta.tree.hasChildren) {\r\n @if (row.meta.tree.isExpanding) {\r\n <div class=\"lds-ring sd-tree-spinner\">\r\n <div></div>\r\n <div></div>\r\n <div></div>\r\n <div></div>\r\n </div>\r\n } @else {\r\n <sd-button\r\n type=\"link\"\r\n [prefixIcon]=\"row.meta.tree.isExpanded ? 'expand_less' : 'expand_more'\"\r\n (click)=\"onTreeToggle(row); $event.stopPropagation()\"\r\n width=\"35px\">\r\n </sd-button>\r\n }\r\n }\r\n </div>\r\n }\r\n </td>\r\n <td mat-footer-cell *matFooterCellDef></td>\r\n </ng-container>\r\n }\r\n\r\n <ng-container matColumnDef=\"sdSubInformation\" sticky>\r\n <td class=\"p-0\" mat-cell *matCellDef=\"let item\" [attr.colspan]=\"_configuration.displayedColumns.length\">\r\n @if (sdSubInformation()?.templateRef) {\r\n @if (_tableOption.expand?.always) {\r\n <ng-container *ngTemplateOutlet=\"sdSubInformation()?.templateRef!; context: { item: item }\"> </ng-container>\r\n } @else {\r\n <div [@detailExpand]=\"item.isExpanded ? 'expanded' : 'collapsed'\">\r\n @if (item.isExpanded) {\r\n <ng-container *ngTemplateOutlet=\"sdSubInformation()?.templateRef!; context: { item: item }\"> </ng-container>\r\n }\r\n </div>\r\n }\r\n }\r\n </td>\r\n <td mat-footer-cell *matFooterCellDef></td>\r\n </ng-container>\r\n\r\n <ng-container matColumnDef=\"sdSubInformationAction\" stickyEnd>\r\n <th class=\"p-0\" mat-header-cell *matHeaderCellDef style=\"width: 1px\" [attr.rowspan]=\"_configuration.multipleHeader ? 2 : 1\"></th>\r\n <td mat-cell *matCellDef=\"let element\">\r\n @if (!element.isExpanding && !_tableOption.expand?.always) {\r\n <sd-button\r\n type=\"link\"\r\n [prefixIcon]=\"element.isExpanded ? 'expand_less' : 'expand_more'\"\r\n (click)=\"onExpand(element)\"\r\n width=\"35px\">\r\n </sd-button>\r\n }\r\n @if (element.isExpanding) {\r\n <div class=\"lds-ring\">\r\n <div></div>\r\n <div></div>\r\n <div></div>\r\n <div></div>\r\n </div>\r\n }\r\n </td>\r\n </ng-container>\r\n\r\n <ng-container matColumnDef=\"sdSelection\" sticky>\r\n <th class=\"sd-selection-cell p-0\" mat-header-cell *matHeaderCellDef [attr.rowspan]=\"_configuration.multipleHeader ? 2 : 1\">\r\n @let visibleSelectAll = _items | selectionVisibleSelectAll: _tableOption.selector | async;\r\n @if (visibleSelectAll) {\r\n <mat-checkbox\r\n class=\"c-selection px-8\"\r\n color=\"primary\"\r\n [ngModel]=\"isSelectAll()\"\r\n (ngModelChange)=\"isSelectAll.set($event)\"\r\n (change)=\"onSelectAll()\">\r\n </mat-checkbox>\r\n }\r\n </th>\r\n\r\n <td class=\"sd-selection-cell p-0\" mat-cell *matCellDef=\"let item\">\r\n @let visible = item | selectionVisible: _tableOption.selector;\r\n @if (visible) {\r\n @if (_tableOption.selector?.single) {\r\n <mat-radio-button\r\n class=\"c-selection px-8\"\r\n color=\"primary\"\r\n [checked]=\"item.meta.selector.isSelected\"\r\n (change)=\"item.meta.selector.isSelected = true; onSelect(item)\"\r\n [disabled]=\"selectedTableItems() | selectionDisabled: item : _tableOption.selector!\">\r\n </mat-radio-button>\r\n } @else {\r\n <mat-checkbox\r\n class=\"c-selection px-8\"\r\n color=\"primary\"\r\n [(ngModel)]=\"item.meta.selector.isSelected\"\r\n (change)=\"onSelect(item)\"\r\n [disabled]=\"selectedTableItems() | selectionDisabled: item : _tableOption.selector!\">\r\n </mat-checkbox>\r\n }\r\n }\r\n </td>\r\n <td mat-footer-cell *matFooterCellDef></td>\r\n </ng-container>\r\n @if (_tableOption.index?.enabled) {\r\n @let _pageOffset = pageOffset();\r\n <ng-container matColumnDef=\"sdIndex\" sticky>\r\n <th\r\n class=\"text-center p-0\"\r\n mat-header-cell\r\n *matHeaderCellDef\r\n [style.width]=\"_tableOption.index?.width || '50px'\"\r\n [attr.rowspan]=\"_configuration.multipleHeader ? 2 : 1\">\r\n {{ _tableOption.index?.title || '#' }}\r\n </th>\r\n <td class=\"text-center px-4\" mat-cell *matCellDef=\"let item; let i = index\">\r\n @if (!item?.sdGroup) {\r\n {{ _pageOffset + i + 1 }}\r\n }\r\n </td>\r\n <td mat-footer-cell *matFooterCellDef></td>\r\n </ng-container>\r\n }\r\n <ng-container\r\n matColumnDef=\"sdCommand\"\r\n [sticky]=\"_tableOption.command?.align !== 'right'\"\r\n [stickyEnd]=\"_tableOption.command?.align === 'right'\">\r\n <th class=\"p-0\" mat-header-cell *matHeaderCellDef style=\"width: 50px\" [attr.rowspan]=\"_configuration.multipleHeader ? 2 : 1\"></th>\r\n <td class=\"px-8\" mat-cell *matCellDef=\"let item\">\r\n <desktop-command\r\n [autoId]=\"autoId()\"\r\n [commands]=\"_tableOption.command?.commands || _tableOption.commands || []\"\r\n [item]=\"item\"\r\n [itemIndex]=\"groupedItems.indexOf(item)\"></desktop-command>\r\n </td>\r\n <td mat-footer-cell *matFooterCellDef></td>\r\n </ng-container>\r\n <ng-container matColumnDef=\"sdGroup\">\r\n <th mat-header-cell *matHeaderCellDef class=\"px-8 py-8\" [attr.rowspan]=\"_configuration.multipleHeader ? 2 : 1\"></th>\r\n <td class=\"p-0\" mat-cell *matCellDef=\"let item\" [attr.colspan]=\"!item?.sdGroup ? 1 : _configuration.displayedColumns.length\">\r\n <div [innerHtml]=\"item?.sdGroup?.htmlTemplate | sdSafeHtml\"></div>\r\n </td>\r\n <td mat-footer-cell *matFooterCellDef></td>\r\n </ng-container>\r\n @for (column of _configuration.firstColumns; track column.field) {\r\n <ng-container [matColumnDef]=\"column.field\" [sticky]=\"_configuration.fixedColumn[column.field]\">\r\n <th\r\n mat-header-cell\r\n *matHeaderCellDef\r\n class=\"px-8 py-8 c-th\"\r\n [sdColumnResize]=\"!!_tableOption.config?.resizable && column.type !== 'children'\"\r\n [minWidth]=\"column.minWidth\"\r\n [maxWidth]=\"column.maxWidth\"\r\n (resizeEnd)=\"onColumnResize(column.field, $event)\"\r\n [style.width]=\"column.width\"\r\n [style.min-width]=\"column.minWidth || column.width\"\r\n [style.max-width]=\"column.maxWidth\"\r\n [attr.rowspan]=\"_configuration.multipleHeader && column.type !== 'children' ? 2 : 1\"\r\n [attr.colspan]=\"column.type === 'children' ? column.children.length : 1\">\r\n <div>\r\n @if (column.type === 'children') {\r\n <div\r\n aria-hidden=\"true\"\r\n class=\"c-header-title\"\r\n [class.justify-content-end]=\"column.align === 'right'\"\r\n [class.text-right]=\"column.align === 'right'\">\r\n <column-title [column]=\"column\" [titleDef]=\"_titleDef[column.field]\"></column-title>\r\n </div>\r\n } @else {\r\n <div\r\n aria-hidden=\"true\"\r\n mat-sort-header\r\n class=\"c-header-title\"\r\n [class.justify-content-end]=\"column.align === 'right'\"\r\n [class.text-right]=\"column.align === 'right'\"\r\n [disabled]=\"!column.sortable\">\r\n <column-title [column]=\"column\" [titleDef]=\"_titleDef[column.field]\"></column-title>\r\n </div>\r\n @let hideInlineFilter =\r\n _tableOption.filter?.disabled ||\r\n _tableOption.filter?.hideInlineFilter === true ||\r\n (_tableOption.filter?.hideInlineFilter === 'auto' && !_isFiltered && _total! <= 10);\r\n @if (!hideInlineFilter) {\r\n <ng-container *sdDesktop>\r\n <column-filter\r\n [autoId]=\"autoId()\"\r\n [value]=\"columnFilter?.[column.field!]!\"\r\n [operator]=\"columnOperator[column.field]\"\r\n (operatorChange)=\"columnOperator[column.field] = $event!; onOperatorChange(column, $event)\"\r\n [columnFilter]=\"columnFilter!\"\r\n [cacheValues]=\"cacheValues\"\r\n [column]=\"column\"\r\n (filterChange)=\"onFilterChange()\"\r\n (filterCommit)=\"onFilterCommit()\">\r\n </column-filter>\r\n </ng-container>\r\n }\r\n }\r\n </div>\r\n </th>\r\n <td\r\n class=\"c-td px-0\"\r\n [class.d-none]=\"column.type === 'children'\"\r\n mat-cell\r\n *matCellDef=\"let item\"\r\n [sdHoverCopy]=\"(item.data && item.data[column.field]) || ''\"\r\n [sdHoverCopyDisabled]=\"!column.cell?.copiable\">\r\n @if (column.type !== 'children' && !item?.sdGroup) {\r\n <desktop-cell class=\"d-block px-8\" [column]=\"column\" [item]=\"item\" [cellDef]=\"cellDef()\"> </desktop-cell>\r\n }\r\n </td>\r\n <td mat-footer-cell *matFooterCellDef>\r\n <ng-container *ngIf=\"footerDef()[column.field]\">\r\n <ng-container *ngTemplateOutlet=\"footerDef()[column.field].templateRef; context: { items: _items, column: column }\">\r\n </ng-container>\r\n </ng-container>\r\n </td>\r\n </ng-container>\r\n }\r\n @for (column of _configuration.secondColumns; track column.field) {\r\n <ng-container [matColumnDef]=\"column.field\">\r\n <th\r\n mat-header-cell\r\n *matHeaderCellDef\r\n class=\"c-th px-8\"\r\n [style.width]=\"column.width\"\r\n [style.min-width]=\"column.minWidth || column.width\"\r\n [style.max-width]=\"column.maxWidth\">\r\n <div>\r\n <div\r\n aria-hidden=\"true\"\r\n mat-sort-header\r\n class=\"c-header-title\"\r\n [class.justify-content-end]=\"column.align === 'right'\"\r\n [class.text-right]=\"column.align === 'right'\"\r\n [disabled]=\"!column.sortable\">\r\n <column-title [column]=\"column\" [titleDef]=\"_titleDef[column.field]\"></column-title>\r\n </div>\r\n @if (!_tableOption.filter?.disabled && !_tableOption.filter?.hideInlineFilter && columnOperator) {\r\n <ng-container *sdDesktop>\r\n <column-filter\r\n [autoId]=\"autoId()\"\r\n [value]=\"columnFilter?.[column.field!]!\"\r\n [operator]=\"columnOperator[column.field]\"\r\n [columnFilter]=\"columnFilter!\"\r\n [cacheValues]=\"cacheValues\"\r\n [column]=\"column\"\r\n (operatorChange)=\"columnOperator[column.field] = $event!; onOperatorChange(column, $event)\"\r\n (filterChange)=\"onFilterChange()\"\r\n (filterCommit)=\"onFilterCommit()\">\r\n </column-filter>\r\n </ng-container>\r\n }\r\n </div>\r\n </th>\r\n <td\r\n class=\"c-td px-0\"\r\n mat-cell\r\n *matCellDef=\"let item\"\r\n [sdHoverCopy]=\"item[column.field]\"\r\n [sdHoverCopyDisabled]=\"!column.cell?.copiable\">\r\n @if (column.type !== 'children') {\r\n <desktop-cell class=\"d-block px-8\" [column]=\"column\" [item]=\"item\" [cellDef]=\"cellDef()\"> </desktop-cell>\r\n }\r\n </td>\r\n <td mat-footer-cell *matFooterCellDef>\r\n <ng-container *ngIf=\"footerDef()[column.field]\">\r\n <ng-container *ngTemplateOutlet=\"footerDef()[column.field].templateRef; context: { items: _items, column: column }\">\r\n </ng-container>\r\n </ng-container>\r\n </td>\r\n </ng-container>\r\n }\r\n <tr class=\"c-first-header\" mat-header-row *matHeaderRowDef=\"_configuration.firstHeaders; sticky: true\"></tr>\r\n @if (!!_configuration.secondHeaders.length) {\r\n <tr class=\"c-second-header\" mat-header-row *matHeaderRowDef=\"_configuration.secondHeaders; sticky: true\"></tr>\r\n }\r\n <tr\r\n mat-row\r\n cdkDrag\r\n [cdkDragData]=\"row\"\r\n [cdkDragDisabled]=\"\r\n !_tableOption.rowReorder?.enabled ||\r\n !!row.meta?.group?.items?.length ||\r\n (row.meta?.tree?.level ?? 0) > 0 ||\r\n isReorderDisabled(row)\r\n \"\r\n *matRowDef=\"let row; columns: _configuration.displayedColumns\"\r\n matRipple\r\n class=\"c-row\"\r\n [class.sd-tree-row]=\"!!_tableOption.tree\"\r\n [ngClass]=\"_tableOption.tree ? 'sd-tree-level-' + (row.meta?.tree?.level ?? 0) : null\"\r\n [ngStyle]=\"rowStyle(row)\"\r\n [class.selected]=\"row.meta.selector.isSelected\"></tr>\r\n\r\n <tr mat-row *matRowDef=\"let row; columns: ['sdSubInformation']\" class=\"c-detail-row\"></tr>\r\n @if (hasFooter() && !!_configuration.displayedFooters.length) {\r\n <tr mat-footer-row *matFooterRowDef=\"_configuration.displayedFooters; sticky: true\"></tr>\r\n }\r\n </table>\r\n @if (!_loading && !_total) {\r\n <div class=\"c-no-data-row\">\r\n @if (_isFiltered) {\r\n @if (tableConfiguration?.images?.filterEmpty) {\r\n <img class=\"c-image\" [src]=\"tableConfiguration!.images!.filterEmpty\" alt=\"filter-empty\" />\r\n } @else {\r\n <img class=\"c-image sd-image-filter-empty\" alt=\"filter-empty\" />\r\n }\r\n <div class=\"T16M\">{{ 'core.component.table.no-results' | translate }}</div>\r\n <div class=\"T16R text-secondary\">{{ 'core.component.table.no-results-hint' | translate }}</div>\r\n } @else {\r\n @if (_requireFiltered) {\r\n @if (tableConfiguration?.images?.filterRequired) {\r\n <img class=\"c-image\" [src]=\"tableConfiguration!.images!.filterRequired\" alt=\"filter-required\" />\r\n } @else {\r\n <img class=\"c-image sd-image-filter-required\" alt=\"filter-required\" />\r\n }\r\n <div class=\"T16R text-secondary\">{{ 'core.component.table.choose-filter-hint' | translate }}</div>\r\n } @else {\r\n @if (tableConfiguration?.images?.dataEmpty) {\r\n <img class=\"c-image\" [src]=\"tableConfiguration!.images!.dataEmpty\" alt=\"data-empty\" />\r\n } @else {\r\n <img class=\"c-image sd-image-data-empty\" alt=\"data-empty\" />\r\n }\r\n <div class=\"T16R text-secondary\">{{ 'core.component.table.no-data' | translate }}</div>\r\n }\r\n }\r\n </div>\r\n }\r\n </div>\r\n <div class=\"c-paginator\">\r\n <div class=\"c-action\">\r\n <ng-container *sdDesktop>\r\n @if (_tableOption.reload?.visible) {\r\n <sd-button\r\n class=\"mr-8\"\r\n [title]=\"'core.component.table.reload' | translate\"\r\n prefixIcon=\"refresh\"\r\n (click)=\"reload()\"\r\n [disabled]=\"!_items.length\"\r\n type=\"link\">\r\n </sd-button>\r\n }\r\n </ng-container>\r\n @if (_export && _items.length) {\r\n @if (_export.type === 'custom') {\r\n <sd-button class=\"mr-8\" [title]=\"exportTitle()\" prefixIcon=\"get_app\" (click)=\"exportCustom()\" type=\"link\"> </sd-button>\r\n } @else {\r\n @if (_export.visible) {\r\n @if (_exporting) {\r\n <sd-button class=\"mr-8\" [loading]=\"_exporting\" [title]=\"exportTitle()\" prefixIcon=\"get_app\" type=\"link\"> </sd-button>\r\n } @else {\r\n @if (_export.visible === 'ALL' || !_export.visible) {\r\n <sd-button class=\"mr-8\" [title]=\"exportTitle()\" prefixIcon=\"get_app\" [matMenuTriggerFor]=\"menu\" type=\"link\"> </sd-button>\r\n <mat-menu #menu=\"matMenu\">\r\n <button mat-menu-item (click)=\"exportExcel()\" type=\"button\">\r\n <mat-icon fontSet=\"material-icons-outlined\">file_download</mat-icon>\r\n <span> {{ 'core.component.table.export-excel' | translate }}</span>\r\n </button>\r\n <button mat-menu-item (click)=\"exportCSV()\" type=\"button\">\r\n <mat-icon fontSet=\"material-icons-outlined\">file_download</mat-icon>\r\n <span> {{ 'core.component.table.export-csv' | translate }}</span>\r\n </button>\r\n </mat-menu>\r\n } @else if (_export.visible === 'EXCEL') {\r\n <sd-button class=\"mr-8\" [title]=\"exportTitle()\" prefixIcon=\"get_app\" (click)=\"exportExcel()\" type=\"link\"> </sd-button>\r\n } @else if (_export.visible === 'CSV') {\r\n <sd-button class=\"mr-8\" [title]=\"exportTitle()\" prefixIcon=\"get_app\" (click)=\"exportCSV()\" type=\"link\"> </sd-button>\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n <ng-container *sdDesktop>\r\n @if (configComponent()) {\r\n <sd-button\r\n class=\"mr-8\"\r\n [title]=\"'core.component.table.setup-short' | translate\"\r\n prefixIcon=\"settings\"\r\n (click)=\"configComponent()!.open()\"\r\n type=\"link\">\r\n </sd-button>\r\n }\r\n </ng-container>\r\n <!-- Mobile: n\u00FAt Filter m\u1EDF mobile-filter drawer (inline filter \u1EA9n tr\u00EAn mobile) -->\r\n <ng-container *sdMobile>\r\n @if (!_tableOption.filter?.disabled && mobileFilter()) {\r\n <sd-button\r\n [autoId]=\"autoId() + 'mobile-filter-open'\"\r\n class=\"mr-8\"\r\n prefixIcon=\"filter_alt\"\r\n (click)=\"mobileFilter()!.open()\"\r\n type=\"link\">\r\n </sd-button>\r\n }\r\n </ng-container>\r\n </div>\r\n @let hidePaginator = !_tableOption.paginate?.pageSize || _total === undefined || _total <= _tableOption.paginate?.pageSize!;\r\n <!-- Desktop paginator: full config (pageSize dropdown, first/last buttons) -->\r\n <ng-container *sdDesktop>\r\n <mat-paginator\r\n [class.d-none]=\"_tableOption.paginate?.hidden || hidePaginator\"\r\n [length]=\"_total\"\r\n [pageSize]=\"_tableOption.paginate?.pageSize\"\r\n [pageSizeOptions]=\"_tableOption.paginate?.pages!\"\r\n [showFirstLastButtons]=\"_tableOption.paginate?.showFirstLastButtons\"\r\n [hidePageSize]=\"_tableOption.paginate?.hidePageSize\"></mat-paginator>\r\n </ng-container>\r\n <!-- Mobile paginator: \u1EA9n pageSize dropdown + first/last buttons \u0111\u1EC3 ti\u1EBFt ki\u1EC7m kh\u00F4ng gian -->\r\n <ng-container *sdMobile>\r\n <mat-paginator\r\n [class.d-none]=\"_tableOption.paginate?.hidden || hidePaginator\"\r\n [length]=\"_total\"\r\n [pageSize]=\"_tableOption.paginate?.pageSize\"\r\n [showFirstLastButtons]=\"false\"\r\n hidePageSize></mat-paginator>\r\n </ng-container>\r\n <!-- \"\u0110ang hi\u1EC3n th\u1ECB...\" ch\u1EC9 desktop -->\r\n <ng-container *sdDesktop>\r\n @if (!_tableOption.paginate?.hidden && hidePaginator && _total !== undefined && _total > 0) {\r\n <div class=\"T14R pr-16\">\r\n {{ 'core.component.table.showing' | translate }} <span class=\"T14M ml-2\">1-{{ _total }}/{{ _total }}</span>\r\n </div>\r\n }\r\n </ng-container>\r\n </div>\r\n </div>\r\n <selector-action [tableOption]=\"_tableOption\" [selectedTableItems]=\"selectedTableItems()\" (clear)=\"onClearSelection(groupedItems)\" />\r\n @if (_tableOption.config?.visible) {\r\n <config [tableOption]=\"_tableOption\" />\r\n }\r\n <!-- Mobile filter drawer \u2014 ch\u1EC9 instantiate khi c\u1EA7n render tr\u00EAn mobile -->\r\n @if (!_tableOption.filter?.disabled && filterRegister) {\r\n <mobile-filter\r\n [autoId]=\"autoId()\"\r\n [filter]=\"_tableOption.filter!\"\r\n [externalFilters]=\"_tableOption.filter?.externalFilters!\"\r\n [columns]=\"_configuration.firstColumns\"\r\n [filterDefs]=\"sdFilterDefs()\"\r\n [filterRegister]=\"filterRegister\"\r\n [cacheValues]=\"cacheValues\">\r\n </mobile-filter>\r\n }\r\n}\r\n", styles: [":host{display:flex;flex-direction:column;overflow:auto;width:100%;height:100%}:host .c-header-title{height:40px;display:flex;align-items:center}:host .c-container{position:relative;min-height:50px;display:flex;flex-direction:column;flex:1}:host .c-container .c-table{position:relative;flex:1;display:flex;flex-direction:column}:host .c-container .c-table table{border-collapse:separate;width:100%}:host .c-container .c-table table tr.c-first-header.mat-mdc-header-row{height:40px}:host .c-container .c-table table tr.c-second-header.mat-mdc-header-row{height:40px}:host .c-container .c-table table tr.c-detail-row{height:0}:host .c-container .c-table table tr.c-row.activated{background-color:#e5ecff}:host .c-container .c-table table tr.c-row.selected{background-color:#eef2ff}:host .c-container .c-table table tr.c-row:not(.selected):not(.activated):hover{background-color:#f5f5f5}:host .c-container .c-table table tr.c-row td{border-bottom-width:0}:host .c-container .c-table table tr.c-row.c-expandable{cursor:pointer}:host .c-container .c-table table tr.c-row.c-expandable:hover{background:#f5f5f5}:host .c-container .c-table table th.mat-mdc-header-cell{background-color:#f2f3f4;border-bottom:0!important}:host .c-container .c-table table td.mat-mdc-cell,:host .c-container .c-table table td.mat-mdc-footer-cell,:host .c-container .c-table table th.mat-mdc-header-cell{border-bottom-color:#f2f2f2!important}:host .c-container .c-table .c-th{vertical-align:middle;font-weight:500;font-size:14px;line-height:20px;color:#212121}:host .c-container .c-table .c-th.sd-col-resize-host{position:relative}:host .c-container .c-table .c-th.sd-resizing{-webkit-user-select:none;user-select:none}:host .c-container .c-table .c-th .sd-col-resize-handle{position:absolute;top:0;right:0;width:6px;height:100%;cursor:col-resize;-webkit-user-select:none;user-select:none;z-index:2}:host .c-container .c-table .c-th .sd-col-resize-handle:hover{background:#00000014}:host .c-container .c-table .c-td:first{padding-left:10px}:host .c-container .c-table .c-no-data-row{flex:1;width:100%;position:sticky;left:0;display:flex;flex-direction:column;align-items:center;justify-content:center}:host .c-container .c-table .c-no-data-row .c-image{margin-bottom:16px;width:96px}:host .c-container .c-loading{position:absolute;inset:0 0 56px;background:#00000026;z-index:2;display:flex;align-items:center;justify-content:center}:host .c-container .c-paginator{display:flex;flex-direction:row;justify-content:space-between;align-items:center;background-color:#fff}:host .c-container .c-paginator .c-action{padding:5px}:host .c-container .c-empty{text-align:center;background-color:#fff;border:none!important}:host .c-container .c-empty mat-icon{font-size:150px;margin-top:30px;margin-bottom:30px;opacity:.2;width:auto;height:auto}:host button.c-btn-add{background-color:#fff;box-shadow:0 2px 4px #2f313629}:host .lds-ring{display:inline-block;position:relative;width:40px;height:40px}:host .lds-ring div{box-sizing:border-box;display:block;position:absolute;width:32px;height:32px;margin:4px;border:4px solid #cef;border-radius:50%;animation:lds-ring 1.2s cubic-bezier(.5,0,.5,1) infinite;border-color:#cef transparent transparent transparent}:host .lds-ring div:nth-child(1){animation-delay:-.45s}:host .lds-ring div:nth-child(2){animation-delay:-.3s}:host .lds-ring div:nth-child(3){animation-delay:-.15s}@keyframes lds-ring{0%{transform:rotate(0)}to{transform:rotate(360deg)}}:host .sd-reorder-header,:host .sd-reorder-cell{width:40px;min-width:40px;padding:0 4px;box-sizing:border-box}:host .sd-reorder-cell mat-icon{cursor:grab;color:#00000061;display:flex;align-items:center}:host .sd-reorder-cell mat-icon:active{cursor:grabbing}:host .sd-reorder-cell mat-icon.sd-reorder-disabled{opacity:.3;cursor:not-allowed;pointer-events:none}:host ::ng-deep .mat-sort-header-content{display:block;text-align:left;width:100%}:host ::ng-deep .mat-select-arrow{color:#a6a6a6}:host ::ng-deep .mat-sort-header-disabled{background-image:none!important;cursor:default!important;padding-right:0!important}:host ::ng-deep .mat-sort-header-container{align-items:start!important}:host ::ng-deep .mat-sort-header-arrow{margin-top:4px!important}:host ::ng-deep .mat-sort-header-arrow{display:none!important}:host ::ng-deep .mat-sort-header{cursor:pointer}:host ::ng-deep .mat-sort-header[aria-sort]{background-repeat:no-repeat;background-position:center right 0;background-size:16px 16px;cursor:pointer;padding-right:24px}:host ::ng-deep .mat-sort-header[aria-sort=none]{background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='24px' viewBox='0 0 24 24' width='24px' fill='%23000000'%3E%3Cpath d='M0 0h24v24H0V0z' fill='none'/%3E%3Cpath fill='%237A7A7A' d='M12 5.83L15.17 9l1.41-1.41L12 3 7.41 7.59 8.83 9 12 5.83zm0 12.34L8.83 15l-1.41 1.41L12 21l4.59-4.59L15.17 15 12 18.17z'/%3E%3C/svg%3E\")}:host ::ng-deep .mat-sort-header[aria-sort=ascending]{background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='24px' viewBox='0 0 24 24' width='24px' fill='%23000000'%3E%3Cpath d='M0 0h24v24H0V0z' fill='none'/%3E%3Cpath fill='%237A7A7A' d='M4 12l1.41 1.41L11 7.83V20h2V7.83l5.58 5.59L20 12l-8-8-8 8z'/%3E%3C/svg%3E\")}:host ::ng-deep .mat-sort-header[aria-sort=descending]{background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='24px' viewBox='0 0 24 24' width='24px' fill='%23000000'%3E%3Cpath d='M0 0h24v24H0V0z' fill='none'/%3E%3Cpath fill='%237A7A7A' d='M20 12l-1.41-1.41L13 16.17V4h-2v12.17l-5.58-5.59L4 12l8 8 8-8z'/%3E%3C/svg%3E\")}:host ::ng-deep .c-paginator .mat-mdc-paginator .mdc-text-field--outlined .mat-mdc-form-field-infix,:host ::ng-deep .c-paginator .mat-mdc-paginator .mdc-text-field--no-label .mat-mdc-form-field-infix{padding-top:2px;padding-bottom:2px;min-height:32px}:host ::ng-deep .c-paginator .mat-mdc-paginator-range-label{margin:0 4px}:host ::ng-deep .c-paginator .mat-mdc-paginator-page-size-select mat-select{margin-top:2px!important}:host ::ng-deep .cdk-drag-preview{box-shadow:0 4px 12px #00000026;background:#fff;display:table;width:100%}:host ::ng-deep .cdk-drag-preview td{padding:0 8px;border-bottom:1px solid rgba(0,0,0,.12)}:host ::ng-deep .cdk-drag-placeholder{opacity:0}:host ::ng-deep .cdk-drop-list-dragging tr.c-row:not(.cdk-drag-placeholder){transition:transform .25s cubic-bezier(0,0,.2,1)}:host ::ng-deep .sd-selection-cell{width:42px;min-width:42px;max-width:42px}:host ::ng-deep .c-selection{transform:scale(.85);transform-origin:center}:host ::ng-deep .sd-tree-toggle-cell{width:40px;min-width:40px;max-width:100px}:host ::ng-deep .sd-tree-toggle-inner{display:flex;align-items:center;min-height:40px}:host ::ng-deep .sd-tree-spinner{transform:scale(.5);margin:0 auto}\n", ":host ::ng-deep .sticky-shadow-right{overflow:visible!important}:host ::ng-deep .sticky-shadow-right:after{content:\"\";position:absolute;top:0;right:0;bottom:0;width:8px;transform:translate(100%);background:linear-gradient(to right,rgba(0,0,0,.12),transparent);pointer-events:none}:host ::ng-deep .sticky-shadow-left{overflow:visible!important}:host ::ng-deep .sticky-shadow-left:after{content:\"\";position:absolute;top:0;left:0;bottom:0;width:8px;transform:translate(-100%);background:linear-gradient(to left,rgba(0,0,0,.12),transparent);pointer-events:none}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i2.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i2.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i2.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatPaginatorModule }, { kind: "component", type: i4$1.MatPaginator, selector: "mat-paginator", inputs: ["color", "pageIndex", "length", "pageSize", "pageSizeOptions", "hidePageSize", "showFirstLastButtons", "selectConfig", "disabled"], outputs: ["page"], exportAs: ["matPaginator"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i5.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTableModule }, { kind: "component", type: i6.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i6.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i6.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i6.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i6.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i6.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i6.MatFooterCellDef, selector: "[matFooterCellDef]" }, { kind: "directive", type: i6.MatFooterRowDef, selector: "[matFooterRowDef]", inputs: ["matFooterRowDef", "matFooterRowDefSticky"] }, { kind: "directive", type: i6.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i6.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "directive", type: i6.MatFooterCell, selector: "mat-footer-cell, td[mat-footer-cell]" }, { kind: "component", type: i6.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i6.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "component", type: i6.MatFooterRow, selector: "mat-footer-row, tr[mat-footer-row]", exportAs: ["matFooterRow"] }, { kind: "ngmodule", type: MatSortModule }, { kind: "directive", type: i7.MatSort, selector: "[matSort]", inputs: ["matSortActive", "matSortStart", "matSortDirection", "matSortDisableClear", "matSortDisabled"], outputs: ["matSortChange"], exportAs: ["matSort"] }, { kind: "component", type: i7.MatSortHeader, selector: "[mat-sort-header]", inputs: ["mat-sort-header", "arrowPosition", "start", "disabled", "sortActionDescription", "disableClear"], exportAs: ["matSortHeader"] }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i8.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: i9.MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "ngmodule", type: MatRadioModule }, { kind: "component", type: i10.MatRadioButton, selector: "mat-radio-button", inputs: ["id", "name", "aria-label", "aria-labelledby", "aria-describedby", "disableRipple", "tabIndex", "checked", "value", "labelPosition", "disabled", "required", "color", "disabledInteractive"], outputs: ["change"], exportAs: ["matRadioButton"] }, { kind: "ngmodule", type: DragDropModule }, { kind: "directive", type: i11.CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: i11.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: i11.CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "component", type: SdButton, selector: "sd-button", inputs: ["autoId", "type", "color", "size", "fontSet", "title", "width", "tooltip", "prefixIcon", "suffixIcon", "disabled", "loading", "block", "htmlType"], outputs: ["click"] }, { kind: "component", type: DesktopCommand, selector: "desktop-command", inputs: ["autoId", "item", "itemIndex", "commands"] }, { kind: "component", type: DesktopCellComponent, selector: "desktop-cell", inputs: ["column", "item", "cellDef"] }, { kind: "component", type: ColumnTitleComponent, selector: "column-title", inputs: ["column", "titleDef"] }, { kind: "component", type: ExternalFilterComponent, selector: "external-filter", inputs: ["autoId", "filter", "externalFilters", "filterRegister"] }, { kind: "component", type: ConfigComponent, selector: "config", inputs: ["tableOption"], outputs: ["changes"] }, { kind: "component", type: ColumnFilterComponent, selector: "column-filter", inputs: ["autoId", "column", "columnFilter", "cacheValues", "value", "operator", "isMobile"], outputs: ["operatorChange", "filterChange", "filterCommit"] }, { kind: "component", type: MobileFilterComponent, selector: "mobile-filter", inputs: ["autoId", "filter", "externalFilters", "columns", "filterDefs", "filterRegister", "cacheValues"] }, { kind: "pipe", type: SdGroupPipe, name: "sdGroup" }, { kind: "pipe", type: SdTreePipe, name: "sdTree" }, { kind: "pipe", type: SdSelectionVisiblePipe, name: "selectionVisible" }, { kind: "pipe", type: SdSelectionVisibleSelectAllPipe, name: "selectionVisibleSelectAll" }, { kind: "pipe", type: SdSafeHtmlPipe, name: "sdSafeHtml" }, { kind: "pipe", type: SdSelectionDisabledPipe, name: "selectionDisabled" }, { kind: "directive", type: SdScrollDirective, selector: "[sdScroll]" }, { kind: "directive", type: SdDesktopDirective, selector: "[sdDesktop]" }, { kind: "directive", type: SdMobileDirective, selector: "[sdMobile]" }, { kind: "directive", type: SdHoverCopyDirective, selector: "[sdHoverCopy]", inputs: ["sdHoverCopy", "sdHoverCopyDisabled"] }, { kind: "component", type: SelectorActionComponent, selector: "selector-action", inputs: ["tableOption", "selectedTableItems"], outputs: ["clear"] }, { kind: "directive", type: StickyShadowDirective, selector: "[stickyShadow]" }, { kind: "directive", type: SdColumnResizeDirective, selector: "[sdColumnResize]", inputs: ["sdColumnResize", "minWidth", "maxWidth"], outputs: ["resizeEnd"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], animations: [
4274
+ ], queries: [{ propertyName: "sdSubInformation", first: true, predicate: SdTableExpandDefDirective, descendants: true, isSignal: true }, { propertyName: "sdGroupDef", first: true, predicate: SdTableGroupDefDirective, descendants: true, isSignal: true }, { propertyName: "sdCellDefs", predicate: SdTableCellDefDirective, isSignal: true }, { propertyName: "sdFooterDefs", predicate: SdMaterialFooterDefDirective, isSignal: true }, { propertyName: "sdFilterDefs", predicate: SdTableFilterDefDirective, isSignal: true }, { propertyName: "sdTitleDefs", predicate: SdTableTitleDefDirective, isSignal: true }], viewQueries: [{ propertyName: "table", first: true, predicate: MatTable, descendants: true, isSignal: true }, { propertyName: "configComponent", first: true, predicate: ConfigComponent, descendants: true, isSignal: true }, { propertyName: "sdPopupExport", first: true, predicate: SdPopupExport, descendants: true, isSignal: true }, { propertyName: "scroll", first: true, predicate: SdScrollDirective, descendants: true, isSignal: true }, { propertyName: "quickAction", first: true, predicate: SdQuickAction, descendants: true, isSignal: true }, { propertyName: "externalFilter", first: true, predicate: ExternalFilterComponent, descendants: true, isSignal: true }, { propertyName: "mobileFilter", first: true, predicate: MobileFilterComponent, descendants: true, isSignal: true }, { propertyName: "paginator", first: true, predicate: MatPaginator, descendants: true, isSignal: true }, { propertyName: "sort", first: true, predicate: MatSort, descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "@let _configuration = configuration();\r\n@let _tableOption = tableOption()!;\r\n@let _loading = loading();\r\n@let _items = items();\r\n@let _total = total();\r\n@let _isFiltered = isFiltered();\r\n@let _requireFiltered = requireFiltered();\r\n@let _export = _tableOption?.export;\r\n@let _exporting = exporting();\r\n@let _titleDef = titleDef();\r\n\r\n@if (_configuration) {\r\n @if (!_tableOption.filter?.disabled && !!_tableOption.filter?.externalFilters?.length && filterRegister) {\r\n <external-filter\r\n class=\"mb-16\"\r\n [autoId]=\"autoId()\"\r\n [filterRegister]=\"filterRegister\"\r\n [filter]=\"_tableOption.filter!\"\r\n [externalFilters]=\"_tableOption.filter?.externalFilters!\">\r\n </external-filter>\r\n }\r\n @let groupedItems = _items | sdTree: _tableOption.tree : treeRevision() | sdGroup: _tableOption : groupExpandState;\r\n <ng-content select=\"[sdTableTop]\"></ng-content>\r\n <div class=\"c-container\">\r\n @if (_loading) {\r\n <div class=\"c-loading\">\r\n <mat-spinner></mat-spinner>\r\n </div>\r\n }\r\n <div\r\n class=\"c-table\"\r\n sdScroll\r\n stickyShadow\r\n [style.max-height]=\"_tableOption.style?.maxHeight\"\r\n [style.min-height]=\"_tableOption.style?.minHeight\">\r\n <table\r\n mat-table\r\n [dataSource]=\"groupedItems\"\r\n [trackBy]=\"trackBy\"\r\n matSort\r\n [matSortDisabled]=\"!_tableOption.sort?.enable\"\r\n multiTemplateDataRows\r\n cdkDropList\r\n [cdkDropListData]=\"groupedItems\"\r\n [cdkDropListDisabled]=\"!_tableOption.rowReorder?.enabled\"\r\n [cdkDropListSortPredicate]=\"reorderSortPredicate\"\r\n (cdkDropListDropped)=\"onReorderDrop($event)\">\r\n @if (_tableOption.rowReorder?.enabled) {\r\n <ng-container matColumnDef=\"sdReorder\">\r\n <th mat-header-cell *matHeaderCellDef class=\"sd-reorder-header\" [attr.rowspan]=\"_configuration.multipleHeader ? 2 : 1\"></th>\r\n <td mat-cell *matCellDef=\"let row\" class=\"sd-reorder-cell\">\r\n @if (!row.meta?.group?.items?.length) {\r\n <mat-icon cdkDragHandle [class.sd-reorder-disabled]=\"isReorderDisabled(row)\">\r\n {{ _tableOption.rowReorder?.icon || 'drag_indicator' }}\r\n </mat-icon>\r\n }\r\n </td>\r\n <td mat-footer-cell *matFooterCellDef></td>\r\n </ng-container>\r\n }\r\n\r\n @if (_tableOption.tree) {\r\n <ng-container matColumnDef=\"sdTreeToggle\">\r\n <th\r\n mat-header-cell\r\n *matHeaderCellDef\r\n class=\"sd-tree-toggle-cell p-0\"\r\n [attr.rowspan]=\"_configuration.multipleHeader ? 2 : 1\"></th>\r\n <td mat-cell *matCellDef=\"let row\" class=\"sd-tree-toggle-cell p-0\">\r\n @if (row.meta?.tree) {\r\n <div\r\n class=\"sd-tree-toggle-inner\"\r\n [style.padding-left.px]=\"(row.meta.tree.level ?? 0) * (_tableOption.tree?.indentSize ?? 20)\">\r\n @if (row.meta.tree.hasChildren) {\r\n @if (row.meta.tree.isExpanding) {\r\n <div class=\"lds-ring sd-tree-spinner\">\r\n <div></div>\r\n <div></div>\r\n <div></div>\r\n <div></div>\r\n </div>\r\n } @else {\r\n <sd-button\r\n type=\"link\"\r\n [prefixIcon]=\"row.meta.tree.isExpanded ? 'expand_less' : 'expand_more'\"\r\n (click)=\"onTreeToggle(row); $event.stopPropagation()\"\r\n width=\"35px\">\r\n </sd-button>\r\n }\r\n }\r\n </div>\r\n }\r\n </td>\r\n <td mat-footer-cell *matFooterCellDef></td>\r\n </ng-container>\r\n }\r\n\r\n <ng-container matColumnDef=\"sdSubInformation\" sticky>\r\n <td class=\"p-0\" mat-cell *matCellDef=\"let item\" [attr.colspan]=\"_configuration.displayedColumns.length\">\r\n @if (sdSubInformation()?.templateRef) {\r\n @if (_tableOption.expand?.always) {\r\n <ng-container *ngTemplateOutlet=\"sdSubInformation()?.templateRef!; context: { item: item }\"> </ng-container>\r\n } @else {\r\n <div [@detailExpand]=\"item.isExpanded ? 'expanded' : 'collapsed'\">\r\n @if (item.isExpanded) {\r\n <ng-container *ngTemplateOutlet=\"sdSubInformation()?.templateRef!; context: { item: item }\"> </ng-container>\r\n }\r\n </div>\r\n }\r\n }\r\n </td>\r\n <td mat-footer-cell *matFooterCellDef></td>\r\n </ng-container>\r\n\r\n <ng-container matColumnDef=\"sdSubInformationAction\" stickyEnd>\r\n <th class=\"p-0\" mat-header-cell *matHeaderCellDef style=\"width: 1px\" [attr.rowspan]=\"_configuration.multipleHeader ? 2 : 1\"></th>\r\n <td mat-cell *matCellDef=\"let element\">\r\n @if (!element.isExpanding && !_tableOption.expand?.always) {\r\n <sd-button\r\n type=\"link\"\r\n [prefixIcon]=\"element.isExpanded ? 'expand_less' : 'expand_more'\"\r\n (click)=\"onExpand(element)\"\r\n width=\"35px\">\r\n </sd-button>\r\n }\r\n @if (element.isExpanding) {\r\n <div class=\"lds-ring\">\r\n <div></div>\r\n <div></div>\r\n <div></div>\r\n <div></div>\r\n </div>\r\n }\r\n </td>\r\n </ng-container>\r\n\r\n <ng-container matColumnDef=\"sdSelection\" sticky>\r\n <th class=\"sd-selection-cell p-0\" mat-header-cell *matHeaderCellDef [attr.rowspan]=\"_configuration.multipleHeader ? 2 : 1\">\r\n @let visibleSelectAll = _items | selectionVisibleSelectAll: _tableOption.selector | async;\r\n @if (visibleSelectAll) {\r\n <mat-checkbox\r\n class=\"c-selection px-8\"\r\n color=\"primary\"\r\n [ngModel]=\"isSelectAll()\"\r\n (ngModelChange)=\"isSelectAll.set($event)\"\r\n (change)=\"onSelectAll()\">\r\n </mat-checkbox>\r\n }\r\n </th>\r\n\r\n <td class=\"sd-selection-cell p-0\" mat-cell *matCellDef=\"let item\">\r\n @let visible = item | selectionVisible: _tableOption.selector;\r\n @if (visible) {\r\n @if (_tableOption.selector?.single) {\r\n <mat-radio-button\r\n class=\"c-selection px-8\"\r\n color=\"primary\"\r\n [checked]=\"item.meta.selector.isSelected\"\r\n (change)=\"item.meta.selector.isSelected = true; onSelect(item)\"\r\n [disabled]=\"selectedTableItems() | selectionDisabled: item : _tableOption.selector!\">\r\n </mat-radio-button>\r\n } @else {\r\n <mat-checkbox\r\n class=\"c-selection px-8\"\r\n color=\"primary\"\r\n [(ngModel)]=\"item.meta.selector.isSelected\"\r\n (change)=\"onSelect(item)\"\r\n [disabled]=\"selectedTableItems() | selectionDisabled: item : _tableOption.selector!\">\r\n </mat-checkbox>\r\n }\r\n }\r\n </td>\r\n <td mat-footer-cell *matFooterCellDef></td>\r\n </ng-container>\r\n @if (_tableOption.index?.enabled) {\r\n @let _pageOffset = pageOffset();\r\n @let _indexWidth = _tableOption.index?.width || '50px';\r\n <ng-container matColumnDef=\"sdIndex\" sticky>\r\n <th\r\n class=\"text-center p-0\"\r\n mat-header-cell\r\n *matHeaderCellDef\r\n [style.width]=\"_indexWidth\"\r\n [style.min-width]=\"_indexWidth\"\r\n [style.max-width]=\"_indexWidth\"\r\n [attr.rowspan]=\"_configuration.multipleHeader ? 2 : 1\">\r\n {{ _tableOption.index?.title || '#' }}\r\n </th>\r\n <td class=\"text-center px-4\" mat-cell *matCellDef=\"let item; let i = dataIndex\" [style.min-width]=\"_indexWidth\" [style.max-width]=\"_indexWidth\">\r\n @if (!item?.meta?.group?.isGroupHeader) {\r\n @if (_tableOption.tree && item?.meta?.tree?.indexPath?.length) {\r\n <!-- why: tree \u2192 STT ph\u00E2n c\u1EA5p 1, 1.2, 1.2.1 (indexPath join '.'). T\u00F4 \u0111\u1EADm root (level 0). -->\r\n <span [class.sd-stt-root]=\"(item.meta.tree.level ?? 0) === 0\">\r\n {{ item.meta.tree.indexPath.join('.') }}\r\n </span>\r\n } @else {\r\n {{ _pageOffset + i + 1 }}\r\n }\r\n }\r\n </td>\r\n <td mat-footer-cell *matFooterCellDef [style.min-width]=\"_indexWidth\" [style.max-width]=\"_indexWidth\"></td>\r\n </ng-container>\r\n }\r\n <ng-container\r\n matColumnDef=\"sdCommand\"\r\n [sticky]=\"_tableOption.command?.align !== 'right'\"\r\n [stickyEnd]=\"_tableOption.command?.align === 'right'\">\r\n <th class=\"p-0\" mat-header-cell *matHeaderCellDef style=\"width: 50px\" [attr.rowspan]=\"_configuration.multipleHeader ? 2 : 1\"></th>\r\n <td class=\"px-8\" mat-cell *matCellDef=\"let item\">\r\n <desktop-command\r\n [autoId]=\"autoId()\"\r\n [commands]=\"_tableOption.command?.commands || _tableOption.commands || []\"\r\n [item]=\"item\"\r\n [itemIndex]=\"groupedItems.indexOf(item)\"></desktop-command>\r\n </td>\r\n <td mat-footer-cell *matFooterCellDef></td>\r\n </ng-container>\r\n <!-- why: group header row d\u00F9ng matRowDef RI\u00CANG v\u1EDBi column list ['sdGroupHeader']\r\n qua predicate when:isGroupHeaderRow. Cell colspan = displayedColumns.length \u0111\u1EC3\r\n span TO\u00C0N B\u1ED8 width data row. Tr\u00E1nh colspan trick overflow row khi c\u00E1c TD kh\u00E1c render. -->\r\n <ng-container matColumnDef=\"sdGroupHeader\">\r\n <td\r\n class=\"p-0 sd-group-header-cell\"\r\n mat-cell\r\n *matCellDef=\"let item\"\r\n [attr.colspan]=\"sdGroupColspan()\">\r\n <div class=\"sd-group-row d-flex align-items-center py-8\">\r\n <!-- why: slot 42px kh\u1EDBp width v\u1EDBi sd-selection-cell data row \u2192 checkbox group c\u0103n TR\u1EE4C d\u1ECDc \u0111\u00FAng v\u1EDBi checkbox data. -->\r\n @if (_tableOption.selector?.visible && !_tableOption.selector?.single) {\r\n <div class=\"sd-group-selection-slot d-flex align-items-center justify-content-center\">\r\n <mat-checkbox\r\n class=\"c-selection\"\r\n color=\"primary\"\r\n [checked]=\"isGroupAllSelected(item)\"\r\n [indeterminate]=\"isGroupIndeterminate(item)\"\r\n (change)=\"onSelectGroup(item, $event.checked)\">\r\n </mat-checkbox>\r\n </div>\r\n } @else {\r\n <div class=\"sd-group-selection-slot\"></div>\r\n }\r\n @if (_tableOption.group?.collapsible) {\r\n <sd-button\r\n type=\"link\"\r\n [prefixIcon]=\"item.meta.group.isExpanded ? 'expand_more' : 'chevron_right'\"\r\n width=\"32px\"\r\n (click)=\"toggleGroupExpand(item)\">\r\n </sd-button>\r\n }\r\n @if (sdGroupDef()?.templateRef; as tpl) {\r\n <ng-container *ngTemplateOutlet=\"tpl; context: groupContext(item)\"></ng-container>\r\n } @else {\r\n <span class=\"T14R\">{{ item.meta.group.values | json }}</span>\r\n }\r\n </div>\r\n </td>\r\n </ng-container>\r\n <!-- why: filler column \u1EDF cu\u1ED1i h\u1EA5p th\u1EE5 leftover space khi t\u1ED5ng width c\u00E1c c\u1ED9t data < container \u2014 gi\u1EEF cho selection/STT/command kh\u00F4ng b\u1ECB d\u00E3n. -->\r\n <ng-container matColumnDef=\"sdFiller\">\r\n <th class=\"sd-filler-cell p-0\" mat-header-cell *matHeaderCellDef [attr.rowspan]=\"_configuration.multipleHeader ? 2 : 1\"></th>\r\n <td class=\"sd-filler-cell p-0\" mat-cell *matCellDef=\"let item\"></td>\r\n <td class=\"sd-filler-cell p-0\" mat-footer-cell *matFooterCellDef></td>\r\n </ng-container>\r\n @for (column of _configuration.firstColumns; track column.field) {\r\n <ng-container [matColumnDef]=\"column.field\" [sticky]=\"_configuration.fixedColumn[column.field]\">\r\n <th\r\n mat-header-cell\r\n *matHeaderCellDef\r\n class=\"px-8 py-8 c-th\"\r\n [sdColumnResize]=\"!!_tableOption.config?.resizable && column.type !== 'children'\"\r\n [minWidth]=\"column.minWidth\"\r\n [maxWidth]=\"column.maxWidth\"\r\n (resizeEnd)=\"onColumnResize(column.field, $event)\"\r\n [style.width]=\"column.width\"\r\n [style.min-width]=\"column.minWidth || column.width\"\r\n [style.max-width]=\"column.maxWidth\"\r\n [attr.rowspan]=\"_configuration.multipleHeader && column.type !== 'children' ? 2 : 1\"\r\n [attr.colspan]=\"column.type === 'children' ? column.children.length : 1\">\r\n <div>\r\n @if (column.type === 'children') {\r\n <div\r\n aria-hidden=\"true\"\r\n class=\"c-header-title\"\r\n [class.justify-content-end]=\"column.align === 'right'\"\r\n [class.text-right]=\"column.align === 'right'\">\r\n <column-title [column]=\"column\" [titleDef]=\"_titleDef[column.field]\"></column-title>\r\n </div>\r\n } @else {\r\n <div\r\n aria-hidden=\"true\"\r\n mat-sort-header\r\n class=\"c-header-title\"\r\n [class.justify-content-end]=\"column.align === 'right'\"\r\n [class.text-right]=\"column.align === 'right'\"\r\n [disabled]=\"!column.sortable\">\r\n <column-title [column]=\"column\" [titleDef]=\"_titleDef[column.field]\"></column-title>\r\n </div>\r\n @let hideInlineFilter =\r\n _tableOption.filter?.disabled ||\r\n _tableOption.filter?.hideInlineFilter === true ||\r\n (_tableOption.filter?.hideInlineFilter === 'auto' && !_isFiltered && _total! <= 10);\r\n @if (!hideInlineFilter) {\r\n <ng-container *sdDesktop>\r\n <column-filter\r\n [autoId]=\"autoId()\"\r\n [value]=\"columnFilter?.[column.field!]!\"\r\n [operator]=\"columnOperator[column.field]\"\r\n (operatorChange)=\"columnOperator[column.field] = $event!; onOperatorChange(column, $event)\"\r\n [columnFilter]=\"columnFilter!\"\r\n [cacheValues]=\"cacheValues\"\r\n [column]=\"column\"\r\n (filterChange)=\"onFilterChange()\"\r\n (filterCommit)=\"onFilterCommit()\">\r\n </column-filter>\r\n </ng-container>\r\n }\r\n }\r\n </div>\r\n </th>\r\n <td\r\n class=\"c-td px-0\"\r\n [class.d-none]=\"column.type === 'children'\"\r\n mat-cell\r\n *matCellDef=\"let item\"\r\n [sdHoverCopy]=\"(item.data && item.data[column.field]) || ''\"\r\n [sdHoverCopyDisabled]=\"!column.cell?.copiable\">\r\n @if (column.type !== 'children' && !item?.meta?.group?.isGroupHeader) {\r\n <desktop-cell class=\"d-block px-8\" [column]=\"column\" [item]=\"item\" [cellDef]=\"cellDef()\"> </desktop-cell>\r\n }\r\n </td>\r\n <td mat-footer-cell *matFooterCellDef>\r\n <ng-container *ngIf=\"footerDef()[column.field]\">\r\n <ng-container *ngTemplateOutlet=\"footerDef()[column.field].templateRef; context: { items: _items, column: column }\">\r\n </ng-container>\r\n </ng-container>\r\n </td>\r\n </ng-container>\r\n }\r\n @for (column of _configuration.secondColumns; track column.field) {\r\n <ng-container [matColumnDef]=\"column.field\">\r\n <th\r\n mat-header-cell\r\n *matHeaderCellDef\r\n class=\"c-th px-8\"\r\n [style.width]=\"column.width\"\r\n [style.min-width]=\"column.minWidth || column.width\"\r\n [style.max-width]=\"column.maxWidth\">\r\n <div>\r\n <div\r\n aria-hidden=\"true\"\r\n mat-sort-header\r\n class=\"c-header-title\"\r\n [class.justify-content-end]=\"column.align === 'right'\"\r\n [class.text-right]=\"column.align === 'right'\"\r\n [disabled]=\"!column.sortable\">\r\n <column-title [column]=\"column\" [titleDef]=\"_titleDef[column.field]\"></column-title>\r\n </div>\r\n @if (!_tableOption.filter?.disabled && !_tableOption.filter?.hideInlineFilter && columnOperator) {\r\n <ng-container *sdDesktop>\r\n <column-filter\r\n [autoId]=\"autoId()\"\r\n [value]=\"columnFilter?.[column.field!]!\"\r\n [operator]=\"columnOperator[column.field]\"\r\n [columnFilter]=\"columnFilter!\"\r\n [cacheValues]=\"cacheValues\"\r\n [column]=\"column\"\r\n (operatorChange)=\"columnOperator[column.field] = $event!; onOperatorChange(column, $event)\"\r\n (filterChange)=\"onFilterChange()\"\r\n (filterCommit)=\"onFilterCommit()\">\r\n </column-filter>\r\n </ng-container>\r\n }\r\n </div>\r\n </th>\r\n <td\r\n class=\"c-td px-0\"\r\n mat-cell\r\n *matCellDef=\"let item\"\r\n [sdHoverCopy]=\"item[column.field]\"\r\n [sdHoverCopyDisabled]=\"!column.cell?.copiable\">\r\n @if (column.type !== 'children') {\r\n <desktop-cell class=\"d-block px-8\" [column]=\"column\" [item]=\"item\" [cellDef]=\"cellDef()\"> </desktop-cell>\r\n }\r\n </td>\r\n <td mat-footer-cell *matFooterCellDef>\r\n <ng-container *ngIf=\"footerDef()[column.field]\">\r\n <ng-container *ngTemplateOutlet=\"footerDef()[column.field].templateRef; context: { items: _items, column: column }\">\r\n </ng-container>\r\n </ng-container>\r\n </td>\r\n </ng-container>\r\n }\r\n <tr class=\"c-first-header\" mat-header-row *matHeaderRowDef=\"_configuration.firstHeaders; sticky: true\"></tr>\r\n @if (!!_configuration.secondHeaders.length) {\r\n <tr class=\"c-second-header\" mat-header-row *matHeaderRowDef=\"_configuration.secondHeaders; sticky: true\"></tr>\r\n }\r\n <!-- Group header row \u2014 ch\u1EC9 1 cell sdGroupHeader colspan to\u00E0n width. -->\r\n <tr\r\n mat-row\r\n *matRowDef=\"let row; columns: ['sdGroupHeader']; when: isGroupHeaderRow\"\r\n class=\"c-group-row-tr\"></tr>\r\n\r\n <!-- Data row \u2014 d\u00F9ng displayedColumns \u0111\u1EA7y \u0111\u1EE7; when isDataRow \u0111\u1EC3 lo\u1EA1i tr\u1EEB group header. -->\r\n <tr\r\n mat-row\r\n cdkDrag\r\n [cdkDragData]=\"row\"\r\n [cdkDragDisabled]=\"\r\n !_tableOption.rowReorder?.enabled ||\r\n !!row.meta?.group?.items?.length ||\r\n (row.meta?.tree?.level ?? 0) > 0 ||\r\n isReorderDisabled(row)\r\n \"\r\n *matRowDef=\"let row; columns: _configuration.displayedColumns; when: isDataRow\"\r\n matRipple\r\n class=\"c-row\"\r\n [class.sd-tree-row]=\"!!_tableOption.tree\"\r\n [ngClass]=\"_tableOption.tree ? 'sd-tree-level-' + (row.meta?.tree?.level ?? 0) : null\"\r\n [ngStyle]=\"rowStyle(row)\"\r\n [class.selected]=\"row.meta.selector.isSelected\"></tr>\r\n\r\n <!-- Sub-information row \u2014 also gated b\u1EDFi isDataRow \u0111\u1EC3 KH\u00D4NG render empty expand row d\u01B0\u1EDBi group header. -->\r\n <tr mat-row *matRowDef=\"let row; columns: ['sdSubInformation']; when: isDataRow\" class=\"c-detail-row\"></tr>\r\n @if (hasFooter() && !!_configuration.displayedFooters.length) {\r\n <tr mat-footer-row *matFooterRowDef=\"_configuration.displayedFooters; sticky: true\"></tr>\r\n }\r\n </table>\r\n @if (!_loading && !_total) {\r\n <div class=\"c-no-data-row\">\r\n @if (_isFiltered) {\r\n @if (tableConfiguration?.images?.filterEmpty) {\r\n <img class=\"c-image\" [src]=\"tableConfiguration!.images!.filterEmpty\" alt=\"filter-empty\" />\r\n } @else {\r\n <img class=\"c-image sd-image-filter-empty\" alt=\"filter-empty\" />\r\n }\r\n <div class=\"T16M\">{{ 'core.component.table.no-results' | translate }}</div>\r\n <div class=\"T16R text-secondary\">{{ 'core.component.table.no-results-hint' | translate }}</div>\r\n } @else {\r\n @if (_requireFiltered) {\r\n @if (tableConfiguration?.images?.filterRequired) {\r\n <img class=\"c-image\" [src]=\"tableConfiguration!.images!.filterRequired\" alt=\"filter-required\" />\r\n } @else {\r\n <img class=\"c-image sd-image-filter-required\" alt=\"filter-required\" />\r\n }\r\n <div class=\"T16R text-secondary\">{{ 'core.component.table.choose-filter-hint' | translate }}</div>\r\n } @else {\r\n @if (tableConfiguration?.images?.dataEmpty) {\r\n <img class=\"c-image\" [src]=\"tableConfiguration!.images!.dataEmpty\" alt=\"data-empty\" />\r\n } @else {\r\n <img class=\"c-image sd-image-data-empty\" alt=\"data-empty\" />\r\n }\r\n <div class=\"T16R text-secondary\">{{ 'core.component.table.no-data' | translate }}</div>\r\n }\r\n }\r\n </div>\r\n }\r\n </div>\r\n <div class=\"c-paginator\">\r\n <div class=\"c-action\">\r\n <ng-container *sdDesktop>\r\n @if (_tableOption.reload?.visible) {\r\n <sd-button\r\n class=\"mr-8\"\r\n [title]=\"'core.component.table.reload' | translate\"\r\n prefixIcon=\"refresh\"\r\n (click)=\"reload()\"\r\n [disabled]=\"!_items.length\"\r\n type=\"link\">\r\n </sd-button>\r\n }\r\n </ng-container>\r\n @if (_export && _items.length) {\r\n @if (_export.type === 'custom') {\r\n <sd-button class=\"mr-8\" [title]=\"exportTitle()\" prefixIcon=\"get_app\" (click)=\"exportCustom()\" type=\"link\"> </sd-button>\r\n } @else {\r\n @if (_export.visible) {\r\n @if (_exporting) {\r\n <sd-button class=\"mr-8\" [loading]=\"_exporting\" [title]=\"exportTitle()\" prefixIcon=\"get_app\" type=\"link\"> </sd-button>\r\n } @else {\r\n @if (_export.visible === 'ALL' || !_export.visible) {\r\n <sd-button class=\"mr-8\" [title]=\"exportTitle()\" prefixIcon=\"get_app\" [matMenuTriggerFor]=\"menu\" type=\"link\"> </sd-button>\r\n <mat-menu #menu=\"matMenu\">\r\n <button mat-menu-item (click)=\"exportExcel()\" type=\"button\">\r\n <mat-icon fontSet=\"material-icons-outlined\">file_download</mat-icon>\r\n <span> {{ 'core.component.table.export-excel' | translate }}</span>\r\n </button>\r\n <button mat-menu-item (click)=\"exportCSV()\" type=\"button\">\r\n <mat-icon fontSet=\"material-icons-outlined\">file_download</mat-icon>\r\n <span> {{ 'core.component.table.export-csv' | translate }}</span>\r\n </button>\r\n </mat-menu>\r\n } @else if (_export.visible === 'EXCEL') {\r\n <sd-button class=\"mr-8\" [title]=\"exportTitle()\" prefixIcon=\"get_app\" (click)=\"exportExcel()\" type=\"link\"> </sd-button>\r\n } @else if (_export.visible === 'CSV') {\r\n <sd-button class=\"mr-8\" [title]=\"exportTitle()\" prefixIcon=\"get_app\" (click)=\"exportCSV()\" type=\"link\"> </sd-button>\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n <ng-container *sdDesktop>\r\n @if (configComponent()) {\r\n <sd-button\r\n class=\"mr-8\"\r\n [title]=\"'core.component.table.setup-short' | translate\"\r\n prefixIcon=\"settings\"\r\n (click)=\"configComponent()!.open()\"\r\n type=\"link\">\r\n </sd-button>\r\n }\r\n </ng-container>\r\n <!-- Mobile: n\u00FAt Filter m\u1EDF mobile-filter drawer (inline filter \u1EA9n tr\u00EAn mobile) -->\r\n <ng-container *sdMobile>\r\n @if (!_tableOption.filter?.disabled && mobileFilter()) {\r\n <sd-button\r\n [autoId]=\"autoId() + 'mobile-filter-open'\"\r\n class=\"mr-8\"\r\n prefixIcon=\"filter_alt\"\r\n (click)=\"mobileFilter()!.open()\"\r\n type=\"link\">\r\n </sd-button>\r\n }\r\n </ng-container>\r\n </div>\r\n @let hidePaginator = !_tableOption.paginate?.pageSize || _total === undefined || _total <= _tableOption.paginate?.pageSize!;\r\n <!-- Desktop paginator: full config (pageSize dropdown, first/last buttons) -->\r\n <ng-container *sdDesktop>\r\n <mat-paginator\r\n [class.d-none]=\"_tableOption.paginate?.hidden || hidePaginator\"\r\n [length]=\"_total\"\r\n [pageSize]=\"_tableOption.paginate?.pageSize\"\r\n [pageSizeOptions]=\"_tableOption.paginate?.pages!\"\r\n [showFirstLastButtons]=\"_tableOption.paginate?.showFirstLastButtons\"\r\n [hidePageSize]=\"_tableOption.paginate?.hidePageSize\"></mat-paginator>\r\n </ng-container>\r\n <!-- Mobile paginator: \u1EA9n pageSize dropdown + first/last buttons \u0111\u1EC3 ti\u1EBFt ki\u1EC7m kh\u00F4ng gian -->\r\n <ng-container *sdMobile>\r\n <mat-paginator\r\n [class.d-none]=\"_tableOption.paginate?.hidden || hidePaginator\"\r\n [length]=\"_total\"\r\n [pageSize]=\"_tableOption.paginate?.pageSize\"\r\n [showFirstLastButtons]=\"false\"\r\n hidePageSize></mat-paginator>\r\n </ng-container>\r\n <!-- \"\u0110ang hi\u1EC3n th\u1ECB...\" ch\u1EC9 desktop -->\r\n <ng-container *sdDesktop>\r\n @if (!_tableOption.paginate?.hidden && hidePaginator && _total !== undefined && _total > 0) {\r\n <div class=\"T14R pr-16\">\r\n {{ 'core.component.table.showing' | translate }} <span class=\"T14M ml-2\">1-{{ _total }}/{{ _total }}</span>\r\n </div>\r\n }\r\n </ng-container>\r\n </div>\r\n </div>\r\n <selector-action [tableOption]=\"_tableOption\" [selectedTableItems]=\"selectedTableItems()\" (clear)=\"onClearSelection(groupedItems)\" />\r\n @if (_tableOption.config?.visible) {\r\n <config [tableOption]=\"_tableOption\" />\r\n }\r\n <!-- Mobile filter drawer \u2014 ch\u1EC9 instantiate khi c\u1EA7n render tr\u00EAn mobile -->\r\n @if (!_tableOption.filter?.disabled && filterRegister) {\r\n <mobile-filter\r\n [autoId]=\"autoId()\"\r\n [filter]=\"_tableOption.filter!\"\r\n [externalFilters]=\"_tableOption.filter?.externalFilters!\"\r\n [columns]=\"_configuration.firstColumns\"\r\n [filterDefs]=\"sdFilterDefs()\"\r\n [filterRegister]=\"filterRegister\"\r\n [cacheValues]=\"cacheValues\">\r\n </mobile-filter>\r\n }\r\n}\r\n", styles: [":host{display:flex;flex-direction:column;overflow:auto;width:100%;height:100%}:host .c-header-title{height:40px;display:flex;align-items:center}:host .c-container{position:relative;min-height:50px;display:flex;flex-direction:column;flex:1}:host .c-container .c-table{position:relative;flex:1;display:flex;flex-direction:column}:host .c-container .c-table table{border-collapse:separate;width:100%}:host .c-container .c-table table tr.c-first-header.mat-mdc-header-row{height:40px}:host .c-container .c-table table tr.c-second-header.mat-mdc-header-row{height:40px}:host .c-container .c-table table tr.c-detail-row{height:0}:host .c-container .c-table table tr.c-row.activated{background-color:#e5ecff}:host .c-container .c-table table tr.c-row.selected{background-color:#eef2ff}:host .c-container .c-table table tr.c-row:not(.selected):not(.activated):hover{background-color:#f5f5f5}:host .c-container .c-table table tr.c-row td{border-bottom-width:0}:host .c-container .c-table table tr.c-row.c-expandable{cursor:pointer}:host .c-container .c-table table tr.c-row.c-expandable:hover{background:#f5f5f5}:host .c-container .c-table table th.mat-mdc-header-cell{background-color:#f2f3f4;border-bottom:0!important}:host .c-container .c-table table td.mat-mdc-cell,:host .c-container .c-table table td.mat-mdc-footer-cell,:host .c-container .c-table table th.mat-mdc-header-cell{border-bottom-color:#f2f2f2!important}:host .c-container .c-table .c-th{vertical-align:middle;font-weight:500;font-size:14px;line-height:20px;color:#212121}:host .c-container .c-table .c-th.sd-col-resize-host{position:relative}:host .c-container .c-table .c-th.sd-resizing{-webkit-user-select:none;user-select:none}:host .c-container .c-table .c-th .sd-col-resize-handle{position:absolute;top:0;right:0;width:6px;height:100%;cursor:col-resize;-webkit-user-select:none;user-select:none;z-index:2}:host .c-container .c-table .c-th .sd-col-resize-handle:hover{background:#00000014}:host .c-container .c-table .c-td:first{padding-left:10px}:host .c-container .c-table .c-no-data-row{flex:1;width:100%;position:sticky;left:0;display:flex;flex-direction:column;align-items:center;justify-content:center}:host .c-container .c-table .c-no-data-row .c-image{margin-bottom:16px;width:96px}:host .c-container .c-loading{position:absolute;inset:0 0 56px;background:#00000026;z-index:2;display:flex;align-items:center;justify-content:center}:host .c-container .c-paginator{display:flex;flex-direction:row;justify-content:space-between;align-items:center;background-color:#fff}:host .c-container .c-paginator .c-action{padding:5px}:host .c-container .c-empty{text-align:center;background-color:#fff;border:none!important}:host .c-container .c-empty mat-icon{font-size:150px;margin-top:30px;margin-bottom:30px;opacity:.2;width:auto;height:auto}:host button.c-btn-add{background-color:#fff;box-shadow:0 2px 4px #2f313629}:host .lds-ring{display:inline-block;position:relative;width:40px;height:40px}:host .lds-ring div{box-sizing:border-box;display:block;position:absolute;width:32px;height:32px;margin:4px;border:4px solid #cef;border-radius:50%;animation:lds-ring 1.2s cubic-bezier(.5,0,.5,1) infinite;border-color:#cef transparent transparent transparent}:host .lds-ring div:nth-child(1){animation-delay:-.45s}:host .lds-ring div:nth-child(2){animation-delay:-.3s}:host .lds-ring div:nth-child(3){animation-delay:-.15s}@keyframes lds-ring{0%{transform:rotate(0)}to{transform:rotate(360deg)}}:host .sd-reorder-header,:host .sd-reorder-cell{width:40px;min-width:40px;padding:0 4px;box-sizing:border-box}:host .sd-reorder-cell mat-icon{cursor:grab;color:#00000061;display:flex;align-items:center}:host .sd-reorder-cell mat-icon:active{cursor:grabbing}:host .sd-reorder-cell mat-icon.sd-reorder-disabled{opacity:.3;cursor:not-allowed;pointer-events:none}:host ::ng-deep .mat-sort-header-content{display:block;text-align:left;width:100%}:host ::ng-deep .mat-select-arrow{color:#a6a6a6}:host ::ng-deep .mat-sort-header-disabled{background-image:none!important;cursor:default!important;padding-right:0!important}:host ::ng-deep .mat-sort-header-container{align-items:start!important}:host ::ng-deep .mat-sort-header-arrow{margin-top:4px!important}:host ::ng-deep .mat-sort-header-arrow{display:none!important}:host ::ng-deep .mat-sort-header{cursor:pointer}:host ::ng-deep .mat-sort-header[aria-sort]{background-repeat:no-repeat;background-position:center right 0;background-size:16px 16px;cursor:pointer;padding-right:24px}:host ::ng-deep .mat-sort-header[aria-sort=none]{background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='24px' viewBox='0 0 24 24' width='24px' fill='%23000000'%3E%3Cpath d='M0 0h24v24H0V0z' fill='none'/%3E%3Cpath fill='%237A7A7A' d='M12 5.83L15.17 9l1.41-1.41L12 3 7.41 7.59 8.83 9 12 5.83zm0 12.34L8.83 15l-1.41 1.41L12 21l4.59-4.59L15.17 15 12 18.17z'/%3E%3C/svg%3E\")}:host ::ng-deep .mat-sort-header[aria-sort=ascending]{background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='24px' viewBox='0 0 24 24' width='24px' fill='%23000000'%3E%3Cpath d='M0 0h24v24H0V0z' fill='none'/%3E%3Cpath fill='%237A7A7A' d='M4 12l1.41 1.41L11 7.83V20h2V7.83l5.58 5.59L20 12l-8-8-8 8z'/%3E%3C/svg%3E\")}:host ::ng-deep .mat-sort-header[aria-sort=descending]{background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='24px' viewBox='0 0 24 24' width='24px' fill='%23000000'%3E%3Cpath d='M0 0h24v24H0V0z' fill='none'/%3E%3Cpath fill='%237A7A7A' d='M20 12l-1.41-1.41L13 16.17V4h-2v12.17l-5.58-5.59L4 12l8 8 8-8z'/%3E%3C/svg%3E\")}:host ::ng-deep .c-paginator .mat-mdc-paginator .mdc-text-field--outlined .mat-mdc-form-field-infix,:host ::ng-deep .c-paginator .mat-mdc-paginator .mdc-text-field--no-label .mat-mdc-form-field-infix{padding-top:2px;padding-bottom:2px;min-height:32px}:host ::ng-deep .c-paginator .mat-mdc-paginator-range-label{margin:0 4px}:host ::ng-deep .c-paginator .mat-mdc-paginator-page-size-select mat-select{margin-top:2px!important}:host ::ng-deep .cdk-drag-preview{box-shadow:0 4px 12px #00000026;background:#fff;display:table;width:100%}:host ::ng-deep .cdk-drag-preview td{padding:0 8px;border-bottom:1px solid rgba(0,0,0,.12)}:host ::ng-deep .cdk-drag-placeholder{opacity:0}:host ::ng-deep .cdk-drop-list-dragging tr.c-row:not(.cdk-drag-placeholder){transition:transform .25s cubic-bezier(0,0,.2,1)}:host ::ng-deep .sd-selection-cell{width:42px;min-width:42px;max-width:42px}:host ::ng-deep .sd-filler-cell{width:auto;min-width:0;padding:0!important;border:0}:host ::ng-deep .sd-group-header-cell{background:#f5f7fc;border-top:1px solid #e6e9f2;border-bottom:1px solid #e6e9f2}:host ::ng-deep .sd-group-row{min-height:36px}:host ::ng-deep .sd-group-selection-slot{width:42px;min-width:42px;max-width:42px}:host ::ng-deep .c-selection{transform:scale(.85);transform-origin:center}:host ::ng-deep .sd-tree-toggle-cell{width:40px;min-width:40px;max-width:100px}:host ::ng-deep .sd-tree-toggle-inner{display:flex;align-items:center;min-height:40px}:host ::ng-deep .sd-tree-spinner{transform:scale(.5);margin:0 auto}:host ::ng-deep tr.c-row.sd-tree-row.sd-tree-level-0{background:#fbfcfe}:host ::ng-deep tr.c-row.sd-tree-row.sd-tree-level-0>td{font-weight:500}:host ::ng-deep tr.c-row.sd-tree-row.sd-tree-level-1{background:#fff}:host ::ng-deep tr.c-row.sd-tree-row.sd-tree-level-2{background:#fafbfd}:host ::ng-deep tr.c-row.sd-tree-row.sd-tree-level-3{background:#f6f8fb}:host ::ng-deep tr.c-row.sd-tree-row:not(.sd-tree-level-0)>td.sd-tree-toggle-cell .sd-tree-toggle-inner{border-left:1px dashed #d8dde6}:host ::ng-deep .sd-stt-root{font-weight:700;color:#1f2330}\n", ":host ::ng-deep .sticky-shadow-right{overflow:visible!important}:host ::ng-deep .sticky-shadow-right:after{content:\"\";position:absolute;top:0;right:0;bottom:0;width:8px;transform:translate(100%);background:linear-gradient(to right,rgba(0,0,0,.12),transparent);pointer-events:none}:host ::ng-deep .sticky-shadow-left{overflow:visible!important}:host ::ng-deep .sticky-shadow-left:after{content:\"\";position:absolute;top:0;left:0;bottom:0;width:8px;transform:translate(-100%);background:linear-gradient(to left,rgba(0,0,0,.12),transparent);pointer-events:none}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "pipe", type: i1.JsonPipe, name: "json" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i2.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i2.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i2.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatPaginatorModule }, { kind: "component", type: i4$1.MatPaginator, selector: "mat-paginator", inputs: ["color", "pageIndex", "length", "pageSize", "pageSizeOptions", "hidePageSize", "showFirstLastButtons", "selectConfig", "disabled"], outputs: ["page"], exportAs: ["matPaginator"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i5.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTableModule }, { kind: "component", type: i6.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i6.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i6.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i6.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i6.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i6.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i6.MatFooterCellDef, selector: "[matFooterCellDef]" }, { kind: "directive", type: i6.MatFooterRowDef, selector: "[matFooterRowDef]", inputs: ["matFooterRowDef", "matFooterRowDefSticky"] }, { kind: "directive", type: i6.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i6.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "directive", type: i6.MatFooterCell, selector: "mat-footer-cell, td[mat-footer-cell]" }, { kind: "component", type: i6.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i6.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "component", type: i6.MatFooterRow, selector: "mat-footer-row, tr[mat-footer-row]", exportAs: ["matFooterRow"] }, { kind: "ngmodule", type: MatSortModule }, { kind: "directive", type: i7.MatSort, selector: "[matSort]", inputs: ["matSortActive", "matSortStart", "matSortDirection", "matSortDisableClear", "matSortDisabled"], outputs: ["matSortChange"], exportAs: ["matSort"] }, { kind: "component", type: i7.MatSortHeader, selector: "[mat-sort-header]", inputs: ["mat-sort-header", "arrowPosition", "start", "disabled", "sortActionDescription", "disableClear"], exportAs: ["matSortHeader"] }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i8.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: i9.MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "ngmodule", type: MatRadioModule }, { kind: "component", type: i10.MatRadioButton, selector: "mat-radio-button", inputs: ["id", "name", "aria-label", "aria-labelledby", "aria-describedby", "disableRipple", "tabIndex", "checked", "value", "labelPosition", "disabled", "required", "color", "disabledInteractive"], outputs: ["change"], exportAs: ["matRadioButton"] }, { kind: "ngmodule", type: DragDropModule }, { kind: "directive", type: i11.CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: i11.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: i11.CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "component", type: SdButton, selector: "sd-button", inputs: ["autoId", "type", "color", "size", "fontSet", "title", "width", "tooltip", "prefixIcon", "suffixIcon", "disabled", "loading", "block", "htmlType"], outputs: ["click"] }, { kind: "component", type: DesktopCommand, selector: "desktop-command", inputs: ["autoId", "item", "itemIndex", "commands"] }, { kind: "component", type: DesktopCellComponent, selector: "desktop-cell", inputs: ["column", "item", "cellDef"] }, { kind: "component", type: ColumnTitleComponent, selector: "column-title", inputs: ["column", "titleDef"] }, { kind: "component", type: ExternalFilterComponent, selector: "external-filter", inputs: ["autoId", "filter", "externalFilters", "filterRegister"] }, { kind: "component", type: ConfigComponent, selector: "config", inputs: ["tableOption"], outputs: ["changes"] }, { kind: "component", type: ColumnFilterComponent, selector: "column-filter", inputs: ["autoId", "column", "columnFilter", "cacheValues", "value", "operator", "isMobile"], outputs: ["operatorChange", "filterChange", "filterCommit"] }, { kind: "component", type: MobileFilterComponent, selector: "mobile-filter", inputs: ["autoId", "filter", "externalFilters", "columns", "filterDefs", "filterRegister", "cacheValues"] }, { kind: "pipe", type: SdGroupPipe, name: "sdGroup" }, { kind: "pipe", type: SdTreePipe, name: "sdTree" }, { kind: "pipe", type: SdSelectionVisiblePipe, name: "selectionVisible" }, { kind: "pipe", type: SdSelectionVisibleSelectAllPipe, name: "selectionVisibleSelectAll" }, { kind: "pipe", type: SdSelectionDisabledPipe, name: "selectionDisabled" }, { kind: "directive", type: SdScrollDirective, selector: "[sdScroll]" }, { kind: "directive", type: SdDesktopDirective, selector: "[sdDesktop]" }, { kind: "directive", type: SdMobileDirective, selector: "[sdMobile]" }, { kind: "directive", type: SdHoverCopyDirective, selector: "[sdHoverCopy]", inputs: ["sdHoverCopy", "sdHoverCopyDisabled"] }, { kind: "component", type: SelectorActionComponent, selector: "selector-action", inputs: ["tableOption", "selectedTableItems"], outputs: ["clear"] }, { kind: "directive", type: StickyShadowDirective, selector: "[stickyShadow]" }, { kind: "directive", type: SdColumnResizeDirective, selector: "[sdColumnResize]", inputs: ["sdColumnResize", "minWidth", "maxWidth"], outputs: ["resizeEnd"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], animations: [
4086
4275
  trigger('detailExpand', [
4087
4276
  state('collapsed', style({ height: '0', minHeight: '0', visibility: 'hidden' })),
4088
4277
  state('expanded', style({ height: '*', visibility: 'visible' })),
@@ -4147,7 +4336,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImpo
4147
4336
  StickyShadowDirective,
4148
4337
  SdColumnResizeDirective,
4149
4338
  TranslatePipe,
4150
- ], template: "@let _configuration = configuration();\r\n@let _tableOption = tableOption()!;\r\n@let _loading = loading();\r\n@let _items = items();\r\n@let _total = total();\r\n@let _isFiltered = isFiltered();\r\n@let _requireFiltered = requireFiltered();\r\n@let _export = _tableOption?.export;\r\n@let _exporting = exporting();\r\n@let _titleDef = titleDef();\r\n\r\n@if (_configuration) {\r\n @if (!_tableOption.filter?.disabled && !!_tableOption.filter?.externalFilters?.length && filterRegister) {\r\n <external-filter\r\n class=\"mb-16\"\r\n [autoId]=\"autoId()\"\r\n [filterRegister]=\"filterRegister\"\r\n [filter]=\"_tableOption.filter!\"\r\n [externalFilters]=\"_tableOption.filter?.externalFilters!\">\r\n </external-filter>\r\n }\r\n @let groupedItems = _items | sdTree: _tableOption.tree : treeRevision() | sdGroup: _tableOption;\r\n <ng-content select=\"[sdTableTop]\"></ng-content>\r\n <div class=\"c-container\">\r\n @if (_loading) {\r\n <div class=\"c-loading\">\r\n <mat-spinner></mat-spinner>\r\n </div>\r\n }\r\n <div\r\n class=\"c-table\"\r\n sdScroll\r\n stickyShadow\r\n [style.max-height]=\"_tableOption.style?.maxHeight\"\r\n [style.min-height]=\"_tableOption.style?.minHeight\">\r\n <table\r\n mat-table\r\n [dataSource]=\"groupedItems\"\r\n [trackBy]=\"trackBy\"\r\n matSort\r\n [matSortDisabled]=\"!_tableOption.sort?.enable\"\r\n multiTemplateDataRows\r\n cdkDropList\r\n [cdkDropListData]=\"groupedItems\"\r\n [cdkDropListDisabled]=\"!_tableOption.rowReorder?.enabled\"\r\n [cdkDropListSortPredicate]=\"reorderSortPredicate\"\r\n (cdkDropListDropped)=\"onReorderDrop($event)\">\r\n @if (_tableOption.rowReorder?.enabled) {\r\n <ng-container matColumnDef=\"sdReorder\">\r\n <th mat-header-cell *matHeaderCellDef class=\"sd-reorder-header\" [attr.rowspan]=\"_configuration.multipleHeader ? 2 : 1\"></th>\r\n <td mat-cell *matCellDef=\"let row\" class=\"sd-reorder-cell\">\r\n @if (!row.meta?.group?.items?.length) {\r\n <mat-icon cdkDragHandle [class.sd-reorder-disabled]=\"isReorderDisabled(row)\">\r\n {{ _tableOption.rowReorder?.icon || 'drag_indicator' }}\r\n </mat-icon>\r\n }\r\n </td>\r\n <td mat-footer-cell *matFooterCellDef></td>\r\n </ng-container>\r\n }\r\n\r\n @if (_tableOption.tree) {\r\n <ng-container matColumnDef=\"sdTreeToggle\">\r\n <th\r\n mat-header-cell\r\n *matHeaderCellDef\r\n class=\"sd-tree-toggle-cell p-0\"\r\n [attr.rowspan]=\"_configuration.multipleHeader ? 2 : 1\"></th>\r\n <td mat-cell *matCellDef=\"let row\" class=\"sd-tree-toggle-cell p-0\">\r\n @if (row.meta?.tree) {\r\n <div\r\n class=\"sd-tree-toggle-inner\"\r\n [style.padding-left.px]=\"(row.meta.tree.level ?? 0) * (_tableOption.tree?.indentSize ?? 20)\">\r\n @if (row.meta.tree.hasChildren) {\r\n @if (row.meta.tree.isExpanding) {\r\n <div class=\"lds-ring sd-tree-spinner\">\r\n <div></div>\r\n <div></div>\r\n <div></div>\r\n <div></div>\r\n </div>\r\n } @else {\r\n <sd-button\r\n type=\"link\"\r\n [prefixIcon]=\"row.meta.tree.isExpanded ? 'expand_less' : 'expand_more'\"\r\n (click)=\"onTreeToggle(row); $event.stopPropagation()\"\r\n width=\"35px\">\r\n </sd-button>\r\n }\r\n }\r\n </div>\r\n }\r\n </td>\r\n <td mat-footer-cell *matFooterCellDef></td>\r\n </ng-container>\r\n }\r\n\r\n <ng-container matColumnDef=\"sdSubInformation\" sticky>\r\n <td class=\"p-0\" mat-cell *matCellDef=\"let item\" [attr.colspan]=\"_configuration.displayedColumns.length\">\r\n @if (sdSubInformation()?.templateRef) {\r\n @if (_tableOption.expand?.always) {\r\n <ng-container *ngTemplateOutlet=\"sdSubInformation()?.templateRef!; context: { item: item }\"> </ng-container>\r\n } @else {\r\n <div [@detailExpand]=\"item.isExpanded ? 'expanded' : 'collapsed'\">\r\n @if (item.isExpanded) {\r\n <ng-container *ngTemplateOutlet=\"sdSubInformation()?.templateRef!; context: { item: item }\"> </ng-container>\r\n }\r\n </div>\r\n }\r\n }\r\n </td>\r\n <td mat-footer-cell *matFooterCellDef></td>\r\n </ng-container>\r\n\r\n <ng-container matColumnDef=\"sdSubInformationAction\" stickyEnd>\r\n <th class=\"p-0\" mat-header-cell *matHeaderCellDef style=\"width: 1px\" [attr.rowspan]=\"_configuration.multipleHeader ? 2 : 1\"></th>\r\n <td mat-cell *matCellDef=\"let element\">\r\n @if (!element.isExpanding && !_tableOption.expand?.always) {\r\n <sd-button\r\n type=\"link\"\r\n [prefixIcon]=\"element.isExpanded ? 'expand_less' : 'expand_more'\"\r\n (click)=\"onExpand(element)\"\r\n width=\"35px\">\r\n </sd-button>\r\n }\r\n @if (element.isExpanding) {\r\n <div class=\"lds-ring\">\r\n <div></div>\r\n <div></div>\r\n <div></div>\r\n <div></div>\r\n </div>\r\n }\r\n </td>\r\n </ng-container>\r\n\r\n <ng-container matColumnDef=\"sdSelection\" sticky>\r\n <th class=\"sd-selection-cell p-0\" mat-header-cell *matHeaderCellDef [attr.rowspan]=\"_configuration.multipleHeader ? 2 : 1\">\r\n @let visibleSelectAll = _items | selectionVisibleSelectAll: _tableOption.selector | async;\r\n @if (visibleSelectAll) {\r\n <mat-checkbox\r\n class=\"c-selection px-8\"\r\n color=\"primary\"\r\n [ngModel]=\"isSelectAll()\"\r\n (ngModelChange)=\"isSelectAll.set($event)\"\r\n (change)=\"onSelectAll()\">\r\n </mat-checkbox>\r\n }\r\n </th>\r\n\r\n <td class=\"sd-selection-cell p-0\" mat-cell *matCellDef=\"let item\">\r\n @let visible = item | selectionVisible: _tableOption.selector;\r\n @if (visible) {\r\n @if (_tableOption.selector?.single) {\r\n <mat-radio-button\r\n class=\"c-selection px-8\"\r\n color=\"primary\"\r\n [checked]=\"item.meta.selector.isSelected\"\r\n (change)=\"item.meta.selector.isSelected = true; onSelect(item)\"\r\n [disabled]=\"selectedTableItems() | selectionDisabled: item : _tableOption.selector!\">\r\n </mat-radio-button>\r\n } @else {\r\n <mat-checkbox\r\n class=\"c-selection px-8\"\r\n color=\"primary\"\r\n [(ngModel)]=\"item.meta.selector.isSelected\"\r\n (change)=\"onSelect(item)\"\r\n [disabled]=\"selectedTableItems() | selectionDisabled: item : _tableOption.selector!\">\r\n </mat-checkbox>\r\n }\r\n }\r\n </td>\r\n <td mat-footer-cell *matFooterCellDef></td>\r\n </ng-container>\r\n @if (_tableOption.index?.enabled) {\r\n @let _pageOffset = pageOffset();\r\n <ng-container matColumnDef=\"sdIndex\" sticky>\r\n <th\r\n class=\"text-center p-0\"\r\n mat-header-cell\r\n *matHeaderCellDef\r\n [style.width]=\"_tableOption.index?.width || '50px'\"\r\n [attr.rowspan]=\"_configuration.multipleHeader ? 2 : 1\">\r\n {{ _tableOption.index?.title || '#' }}\r\n </th>\r\n <td class=\"text-center px-4\" mat-cell *matCellDef=\"let item; let i = index\">\r\n @if (!item?.sdGroup) {\r\n {{ _pageOffset + i + 1 }}\r\n }\r\n </td>\r\n <td mat-footer-cell *matFooterCellDef></td>\r\n </ng-container>\r\n }\r\n <ng-container\r\n matColumnDef=\"sdCommand\"\r\n [sticky]=\"_tableOption.command?.align !== 'right'\"\r\n [stickyEnd]=\"_tableOption.command?.align === 'right'\">\r\n <th class=\"p-0\" mat-header-cell *matHeaderCellDef style=\"width: 50px\" [attr.rowspan]=\"_configuration.multipleHeader ? 2 : 1\"></th>\r\n <td class=\"px-8\" mat-cell *matCellDef=\"let item\">\r\n <desktop-command\r\n [autoId]=\"autoId()\"\r\n [commands]=\"_tableOption.command?.commands || _tableOption.commands || []\"\r\n [item]=\"item\"\r\n [itemIndex]=\"groupedItems.indexOf(item)\"></desktop-command>\r\n </td>\r\n <td mat-footer-cell *matFooterCellDef></td>\r\n </ng-container>\r\n <ng-container matColumnDef=\"sdGroup\">\r\n <th mat-header-cell *matHeaderCellDef class=\"px-8 py-8\" [attr.rowspan]=\"_configuration.multipleHeader ? 2 : 1\"></th>\r\n <td class=\"p-0\" mat-cell *matCellDef=\"let item\" [attr.colspan]=\"!item?.sdGroup ? 1 : _configuration.displayedColumns.length\">\r\n <div [innerHtml]=\"item?.sdGroup?.htmlTemplate | sdSafeHtml\"></div>\r\n </td>\r\n <td mat-footer-cell *matFooterCellDef></td>\r\n </ng-container>\r\n @for (column of _configuration.firstColumns; track column.field) {\r\n <ng-container [matColumnDef]=\"column.field\" [sticky]=\"_configuration.fixedColumn[column.field]\">\r\n <th\r\n mat-header-cell\r\n *matHeaderCellDef\r\n class=\"px-8 py-8 c-th\"\r\n [sdColumnResize]=\"!!_tableOption.config?.resizable && column.type !== 'children'\"\r\n [minWidth]=\"column.minWidth\"\r\n [maxWidth]=\"column.maxWidth\"\r\n (resizeEnd)=\"onColumnResize(column.field, $event)\"\r\n [style.width]=\"column.width\"\r\n [style.min-width]=\"column.minWidth || column.width\"\r\n [style.max-width]=\"column.maxWidth\"\r\n [attr.rowspan]=\"_configuration.multipleHeader && column.type !== 'children' ? 2 : 1\"\r\n [attr.colspan]=\"column.type === 'children' ? column.children.length : 1\">\r\n <div>\r\n @if (column.type === 'children') {\r\n <div\r\n aria-hidden=\"true\"\r\n class=\"c-header-title\"\r\n [class.justify-content-end]=\"column.align === 'right'\"\r\n [class.text-right]=\"column.align === 'right'\">\r\n <column-title [column]=\"column\" [titleDef]=\"_titleDef[column.field]\"></column-title>\r\n </div>\r\n } @else {\r\n <div\r\n aria-hidden=\"true\"\r\n mat-sort-header\r\n class=\"c-header-title\"\r\n [class.justify-content-end]=\"column.align === 'right'\"\r\n [class.text-right]=\"column.align === 'right'\"\r\n [disabled]=\"!column.sortable\">\r\n <column-title [column]=\"column\" [titleDef]=\"_titleDef[column.field]\"></column-title>\r\n </div>\r\n @let hideInlineFilter =\r\n _tableOption.filter?.disabled ||\r\n _tableOption.filter?.hideInlineFilter === true ||\r\n (_tableOption.filter?.hideInlineFilter === 'auto' && !_isFiltered && _total! <= 10);\r\n @if (!hideInlineFilter) {\r\n <ng-container *sdDesktop>\r\n <column-filter\r\n [autoId]=\"autoId()\"\r\n [value]=\"columnFilter?.[column.field!]!\"\r\n [operator]=\"columnOperator[column.field]\"\r\n (operatorChange)=\"columnOperator[column.field] = $event!; onOperatorChange(column, $event)\"\r\n [columnFilter]=\"columnFilter!\"\r\n [cacheValues]=\"cacheValues\"\r\n [column]=\"column\"\r\n (filterChange)=\"onFilterChange()\"\r\n (filterCommit)=\"onFilterCommit()\">\r\n </column-filter>\r\n </ng-container>\r\n }\r\n }\r\n </div>\r\n </th>\r\n <td\r\n class=\"c-td px-0\"\r\n [class.d-none]=\"column.type === 'children'\"\r\n mat-cell\r\n *matCellDef=\"let item\"\r\n [sdHoverCopy]=\"(item.data && item.data[column.field]) || ''\"\r\n [sdHoverCopyDisabled]=\"!column.cell?.copiable\">\r\n @if (column.type !== 'children' && !item?.sdGroup) {\r\n <desktop-cell class=\"d-block px-8\" [column]=\"column\" [item]=\"item\" [cellDef]=\"cellDef()\"> </desktop-cell>\r\n }\r\n </td>\r\n <td mat-footer-cell *matFooterCellDef>\r\n <ng-container *ngIf=\"footerDef()[column.field]\">\r\n <ng-container *ngTemplateOutlet=\"footerDef()[column.field].templateRef; context: { items: _items, column: column }\">\r\n </ng-container>\r\n </ng-container>\r\n </td>\r\n </ng-container>\r\n }\r\n @for (column of _configuration.secondColumns; track column.field) {\r\n <ng-container [matColumnDef]=\"column.field\">\r\n <th\r\n mat-header-cell\r\n *matHeaderCellDef\r\n class=\"c-th px-8\"\r\n [style.width]=\"column.width\"\r\n [style.min-width]=\"column.minWidth || column.width\"\r\n [style.max-width]=\"column.maxWidth\">\r\n <div>\r\n <div\r\n aria-hidden=\"true\"\r\n mat-sort-header\r\n class=\"c-header-title\"\r\n [class.justify-content-end]=\"column.align === 'right'\"\r\n [class.text-right]=\"column.align === 'right'\"\r\n [disabled]=\"!column.sortable\">\r\n <column-title [column]=\"column\" [titleDef]=\"_titleDef[column.field]\"></column-title>\r\n </div>\r\n @if (!_tableOption.filter?.disabled && !_tableOption.filter?.hideInlineFilter && columnOperator) {\r\n <ng-container *sdDesktop>\r\n <column-filter\r\n [autoId]=\"autoId()\"\r\n [value]=\"columnFilter?.[column.field!]!\"\r\n [operator]=\"columnOperator[column.field]\"\r\n [columnFilter]=\"columnFilter!\"\r\n [cacheValues]=\"cacheValues\"\r\n [column]=\"column\"\r\n (operatorChange)=\"columnOperator[column.field] = $event!; onOperatorChange(column, $event)\"\r\n (filterChange)=\"onFilterChange()\"\r\n (filterCommit)=\"onFilterCommit()\">\r\n </column-filter>\r\n </ng-container>\r\n }\r\n </div>\r\n </th>\r\n <td\r\n class=\"c-td px-0\"\r\n mat-cell\r\n *matCellDef=\"let item\"\r\n [sdHoverCopy]=\"item[column.field]\"\r\n [sdHoverCopyDisabled]=\"!column.cell?.copiable\">\r\n @if (column.type !== 'children') {\r\n <desktop-cell class=\"d-block px-8\" [column]=\"column\" [item]=\"item\" [cellDef]=\"cellDef()\"> </desktop-cell>\r\n }\r\n </td>\r\n <td mat-footer-cell *matFooterCellDef>\r\n <ng-container *ngIf=\"footerDef()[column.field]\">\r\n <ng-container *ngTemplateOutlet=\"footerDef()[column.field].templateRef; context: { items: _items, column: column }\">\r\n </ng-container>\r\n </ng-container>\r\n </td>\r\n </ng-container>\r\n }\r\n <tr class=\"c-first-header\" mat-header-row *matHeaderRowDef=\"_configuration.firstHeaders; sticky: true\"></tr>\r\n @if (!!_configuration.secondHeaders.length) {\r\n <tr class=\"c-second-header\" mat-header-row *matHeaderRowDef=\"_configuration.secondHeaders; sticky: true\"></tr>\r\n }\r\n <tr\r\n mat-row\r\n cdkDrag\r\n [cdkDragData]=\"row\"\r\n [cdkDragDisabled]=\"\r\n !_tableOption.rowReorder?.enabled ||\r\n !!row.meta?.group?.items?.length ||\r\n (row.meta?.tree?.level ?? 0) > 0 ||\r\n isReorderDisabled(row)\r\n \"\r\n *matRowDef=\"let row; columns: _configuration.displayedColumns\"\r\n matRipple\r\n class=\"c-row\"\r\n [class.sd-tree-row]=\"!!_tableOption.tree\"\r\n [ngClass]=\"_tableOption.tree ? 'sd-tree-level-' + (row.meta?.tree?.level ?? 0) : null\"\r\n [ngStyle]=\"rowStyle(row)\"\r\n [class.selected]=\"row.meta.selector.isSelected\"></tr>\r\n\r\n <tr mat-row *matRowDef=\"let row; columns: ['sdSubInformation']\" class=\"c-detail-row\"></tr>\r\n @if (hasFooter() && !!_configuration.displayedFooters.length) {\r\n <tr mat-footer-row *matFooterRowDef=\"_configuration.displayedFooters; sticky: true\"></tr>\r\n }\r\n </table>\r\n @if (!_loading && !_total) {\r\n <div class=\"c-no-data-row\">\r\n @if (_isFiltered) {\r\n @if (tableConfiguration?.images?.filterEmpty) {\r\n <img class=\"c-image\" [src]=\"tableConfiguration!.images!.filterEmpty\" alt=\"filter-empty\" />\r\n } @else {\r\n <img class=\"c-image sd-image-filter-empty\" alt=\"filter-empty\" />\r\n }\r\n <div class=\"T16M\">{{ 'core.component.table.no-results' | translate }}</div>\r\n <div class=\"T16R text-secondary\">{{ 'core.component.table.no-results-hint' | translate }}</div>\r\n } @else {\r\n @if (_requireFiltered) {\r\n @if (tableConfiguration?.images?.filterRequired) {\r\n <img class=\"c-image\" [src]=\"tableConfiguration!.images!.filterRequired\" alt=\"filter-required\" />\r\n } @else {\r\n <img class=\"c-image sd-image-filter-required\" alt=\"filter-required\" />\r\n }\r\n <div class=\"T16R text-secondary\">{{ 'core.component.table.choose-filter-hint' | translate }}</div>\r\n } @else {\r\n @if (tableConfiguration?.images?.dataEmpty) {\r\n <img class=\"c-image\" [src]=\"tableConfiguration!.images!.dataEmpty\" alt=\"data-empty\" />\r\n } @else {\r\n <img class=\"c-image sd-image-data-empty\" alt=\"data-empty\" />\r\n }\r\n <div class=\"T16R text-secondary\">{{ 'core.component.table.no-data' | translate }}</div>\r\n }\r\n }\r\n </div>\r\n }\r\n </div>\r\n <div class=\"c-paginator\">\r\n <div class=\"c-action\">\r\n <ng-container *sdDesktop>\r\n @if (_tableOption.reload?.visible) {\r\n <sd-button\r\n class=\"mr-8\"\r\n [title]=\"'core.component.table.reload' | translate\"\r\n prefixIcon=\"refresh\"\r\n (click)=\"reload()\"\r\n [disabled]=\"!_items.length\"\r\n type=\"link\">\r\n </sd-button>\r\n }\r\n </ng-container>\r\n @if (_export && _items.length) {\r\n @if (_export.type === 'custom') {\r\n <sd-button class=\"mr-8\" [title]=\"exportTitle()\" prefixIcon=\"get_app\" (click)=\"exportCustom()\" type=\"link\"> </sd-button>\r\n } @else {\r\n @if (_export.visible) {\r\n @if (_exporting) {\r\n <sd-button class=\"mr-8\" [loading]=\"_exporting\" [title]=\"exportTitle()\" prefixIcon=\"get_app\" type=\"link\"> </sd-button>\r\n } @else {\r\n @if (_export.visible === 'ALL' || !_export.visible) {\r\n <sd-button class=\"mr-8\" [title]=\"exportTitle()\" prefixIcon=\"get_app\" [matMenuTriggerFor]=\"menu\" type=\"link\"> </sd-button>\r\n <mat-menu #menu=\"matMenu\">\r\n <button mat-menu-item (click)=\"exportExcel()\" type=\"button\">\r\n <mat-icon fontSet=\"material-icons-outlined\">file_download</mat-icon>\r\n <span> {{ 'core.component.table.export-excel' | translate }}</span>\r\n </button>\r\n <button mat-menu-item (click)=\"exportCSV()\" type=\"button\">\r\n <mat-icon fontSet=\"material-icons-outlined\">file_download</mat-icon>\r\n <span> {{ 'core.component.table.export-csv' | translate }}</span>\r\n </button>\r\n </mat-menu>\r\n } @else if (_export.visible === 'EXCEL') {\r\n <sd-button class=\"mr-8\" [title]=\"exportTitle()\" prefixIcon=\"get_app\" (click)=\"exportExcel()\" type=\"link\"> </sd-button>\r\n } @else if (_export.visible === 'CSV') {\r\n <sd-button class=\"mr-8\" [title]=\"exportTitle()\" prefixIcon=\"get_app\" (click)=\"exportCSV()\" type=\"link\"> </sd-button>\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n <ng-container *sdDesktop>\r\n @if (configComponent()) {\r\n <sd-button\r\n class=\"mr-8\"\r\n [title]=\"'core.component.table.setup-short' | translate\"\r\n prefixIcon=\"settings\"\r\n (click)=\"configComponent()!.open()\"\r\n type=\"link\">\r\n </sd-button>\r\n }\r\n </ng-container>\r\n <!-- Mobile: n\u00FAt Filter m\u1EDF mobile-filter drawer (inline filter \u1EA9n tr\u00EAn mobile) -->\r\n <ng-container *sdMobile>\r\n @if (!_tableOption.filter?.disabled && mobileFilter()) {\r\n <sd-button\r\n [autoId]=\"autoId() + 'mobile-filter-open'\"\r\n class=\"mr-8\"\r\n prefixIcon=\"filter_alt\"\r\n (click)=\"mobileFilter()!.open()\"\r\n type=\"link\">\r\n </sd-button>\r\n }\r\n </ng-container>\r\n </div>\r\n @let hidePaginator = !_tableOption.paginate?.pageSize || _total === undefined || _total <= _tableOption.paginate?.pageSize!;\r\n <!-- Desktop paginator: full config (pageSize dropdown, first/last buttons) -->\r\n <ng-container *sdDesktop>\r\n <mat-paginator\r\n [class.d-none]=\"_tableOption.paginate?.hidden || hidePaginator\"\r\n [length]=\"_total\"\r\n [pageSize]=\"_tableOption.paginate?.pageSize\"\r\n [pageSizeOptions]=\"_tableOption.paginate?.pages!\"\r\n [showFirstLastButtons]=\"_tableOption.paginate?.showFirstLastButtons\"\r\n [hidePageSize]=\"_tableOption.paginate?.hidePageSize\"></mat-paginator>\r\n </ng-container>\r\n <!-- Mobile paginator: \u1EA9n pageSize dropdown + first/last buttons \u0111\u1EC3 ti\u1EBFt ki\u1EC7m kh\u00F4ng gian -->\r\n <ng-container *sdMobile>\r\n <mat-paginator\r\n [class.d-none]=\"_tableOption.paginate?.hidden || hidePaginator\"\r\n [length]=\"_total\"\r\n [pageSize]=\"_tableOption.paginate?.pageSize\"\r\n [showFirstLastButtons]=\"false\"\r\n hidePageSize></mat-paginator>\r\n </ng-container>\r\n <!-- \"\u0110ang hi\u1EC3n th\u1ECB...\" ch\u1EC9 desktop -->\r\n <ng-container *sdDesktop>\r\n @if (!_tableOption.paginate?.hidden && hidePaginator && _total !== undefined && _total > 0) {\r\n <div class=\"T14R pr-16\">\r\n {{ 'core.component.table.showing' | translate }} <span class=\"T14M ml-2\">1-{{ _total }}/{{ _total }}</span>\r\n </div>\r\n }\r\n </ng-container>\r\n </div>\r\n </div>\r\n <selector-action [tableOption]=\"_tableOption\" [selectedTableItems]=\"selectedTableItems()\" (clear)=\"onClearSelection(groupedItems)\" />\r\n @if (_tableOption.config?.visible) {\r\n <config [tableOption]=\"_tableOption\" />\r\n }\r\n <!-- Mobile filter drawer \u2014 ch\u1EC9 instantiate khi c\u1EA7n render tr\u00EAn mobile -->\r\n @if (!_tableOption.filter?.disabled && filterRegister) {\r\n <mobile-filter\r\n [autoId]=\"autoId()\"\r\n [filter]=\"_tableOption.filter!\"\r\n [externalFilters]=\"_tableOption.filter?.externalFilters!\"\r\n [columns]=\"_configuration.firstColumns\"\r\n [filterDefs]=\"sdFilterDefs()\"\r\n [filterRegister]=\"filterRegister\"\r\n [cacheValues]=\"cacheValues\">\r\n </mobile-filter>\r\n }\r\n}\r\n", styles: [":host{display:flex;flex-direction:column;overflow:auto;width:100%;height:100%}:host .c-header-title{height:40px;display:flex;align-items:center}:host .c-container{position:relative;min-height:50px;display:flex;flex-direction:column;flex:1}:host .c-container .c-table{position:relative;flex:1;display:flex;flex-direction:column}:host .c-container .c-table table{border-collapse:separate;width:100%}:host .c-container .c-table table tr.c-first-header.mat-mdc-header-row{height:40px}:host .c-container .c-table table tr.c-second-header.mat-mdc-header-row{height:40px}:host .c-container .c-table table tr.c-detail-row{height:0}:host .c-container .c-table table tr.c-row.activated{background-color:#e5ecff}:host .c-container .c-table table tr.c-row.selected{background-color:#eef2ff}:host .c-container .c-table table tr.c-row:not(.selected):not(.activated):hover{background-color:#f5f5f5}:host .c-container .c-table table tr.c-row td{border-bottom-width:0}:host .c-container .c-table table tr.c-row.c-expandable{cursor:pointer}:host .c-container .c-table table tr.c-row.c-expandable:hover{background:#f5f5f5}:host .c-container .c-table table th.mat-mdc-header-cell{background-color:#f2f3f4;border-bottom:0!important}:host .c-container .c-table table td.mat-mdc-cell,:host .c-container .c-table table td.mat-mdc-footer-cell,:host .c-container .c-table table th.mat-mdc-header-cell{border-bottom-color:#f2f2f2!important}:host .c-container .c-table .c-th{vertical-align:middle;font-weight:500;font-size:14px;line-height:20px;color:#212121}:host .c-container .c-table .c-th.sd-col-resize-host{position:relative}:host .c-container .c-table .c-th.sd-resizing{-webkit-user-select:none;user-select:none}:host .c-container .c-table .c-th .sd-col-resize-handle{position:absolute;top:0;right:0;width:6px;height:100%;cursor:col-resize;-webkit-user-select:none;user-select:none;z-index:2}:host .c-container .c-table .c-th .sd-col-resize-handle:hover{background:#00000014}:host .c-container .c-table .c-td:first{padding-left:10px}:host .c-container .c-table .c-no-data-row{flex:1;width:100%;position:sticky;left:0;display:flex;flex-direction:column;align-items:center;justify-content:center}:host .c-container .c-table .c-no-data-row .c-image{margin-bottom:16px;width:96px}:host .c-container .c-loading{position:absolute;inset:0 0 56px;background:#00000026;z-index:2;display:flex;align-items:center;justify-content:center}:host .c-container .c-paginator{display:flex;flex-direction:row;justify-content:space-between;align-items:center;background-color:#fff}:host .c-container .c-paginator .c-action{padding:5px}:host .c-container .c-empty{text-align:center;background-color:#fff;border:none!important}:host .c-container .c-empty mat-icon{font-size:150px;margin-top:30px;margin-bottom:30px;opacity:.2;width:auto;height:auto}:host button.c-btn-add{background-color:#fff;box-shadow:0 2px 4px #2f313629}:host .lds-ring{display:inline-block;position:relative;width:40px;height:40px}:host .lds-ring div{box-sizing:border-box;display:block;position:absolute;width:32px;height:32px;margin:4px;border:4px solid #cef;border-radius:50%;animation:lds-ring 1.2s cubic-bezier(.5,0,.5,1) infinite;border-color:#cef transparent transparent transparent}:host .lds-ring div:nth-child(1){animation-delay:-.45s}:host .lds-ring div:nth-child(2){animation-delay:-.3s}:host .lds-ring div:nth-child(3){animation-delay:-.15s}@keyframes lds-ring{0%{transform:rotate(0)}to{transform:rotate(360deg)}}:host .sd-reorder-header,:host .sd-reorder-cell{width:40px;min-width:40px;padding:0 4px;box-sizing:border-box}:host .sd-reorder-cell mat-icon{cursor:grab;color:#00000061;display:flex;align-items:center}:host .sd-reorder-cell mat-icon:active{cursor:grabbing}:host .sd-reorder-cell mat-icon.sd-reorder-disabled{opacity:.3;cursor:not-allowed;pointer-events:none}:host ::ng-deep .mat-sort-header-content{display:block;text-align:left;width:100%}:host ::ng-deep .mat-select-arrow{color:#a6a6a6}:host ::ng-deep .mat-sort-header-disabled{background-image:none!important;cursor:default!important;padding-right:0!important}:host ::ng-deep .mat-sort-header-container{align-items:start!important}:host ::ng-deep .mat-sort-header-arrow{margin-top:4px!important}:host ::ng-deep .mat-sort-header-arrow{display:none!important}:host ::ng-deep .mat-sort-header{cursor:pointer}:host ::ng-deep .mat-sort-header[aria-sort]{background-repeat:no-repeat;background-position:center right 0;background-size:16px 16px;cursor:pointer;padding-right:24px}:host ::ng-deep .mat-sort-header[aria-sort=none]{background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='24px' viewBox='0 0 24 24' width='24px' fill='%23000000'%3E%3Cpath d='M0 0h24v24H0V0z' fill='none'/%3E%3Cpath fill='%237A7A7A' d='M12 5.83L15.17 9l1.41-1.41L12 3 7.41 7.59 8.83 9 12 5.83zm0 12.34L8.83 15l-1.41 1.41L12 21l4.59-4.59L15.17 15 12 18.17z'/%3E%3C/svg%3E\")}:host ::ng-deep .mat-sort-header[aria-sort=ascending]{background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='24px' viewBox='0 0 24 24' width='24px' fill='%23000000'%3E%3Cpath d='M0 0h24v24H0V0z' fill='none'/%3E%3Cpath fill='%237A7A7A' d='M4 12l1.41 1.41L11 7.83V20h2V7.83l5.58 5.59L20 12l-8-8-8 8z'/%3E%3C/svg%3E\")}:host ::ng-deep .mat-sort-header[aria-sort=descending]{background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='24px' viewBox='0 0 24 24' width='24px' fill='%23000000'%3E%3Cpath d='M0 0h24v24H0V0z' fill='none'/%3E%3Cpath fill='%237A7A7A' d='M20 12l-1.41-1.41L13 16.17V4h-2v12.17l-5.58-5.59L4 12l8 8 8-8z'/%3E%3C/svg%3E\")}:host ::ng-deep .c-paginator .mat-mdc-paginator .mdc-text-field--outlined .mat-mdc-form-field-infix,:host ::ng-deep .c-paginator .mat-mdc-paginator .mdc-text-field--no-label .mat-mdc-form-field-infix{padding-top:2px;padding-bottom:2px;min-height:32px}:host ::ng-deep .c-paginator .mat-mdc-paginator-range-label{margin:0 4px}:host ::ng-deep .c-paginator .mat-mdc-paginator-page-size-select mat-select{margin-top:2px!important}:host ::ng-deep .cdk-drag-preview{box-shadow:0 4px 12px #00000026;background:#fff;display:table;width:100%}:host ::ng-deep .cdk-drag-preview td{padding:0 8px;border-bottom:1px solid rgba(0,0,0,.12)}:host ::ng-deep .cdk-drag-placeholder{opacity:0}:host ::ng-deep .cdk-drop-list-dragging tr.c-row:not(.cdk-drag-placeholder){transition:transform .25s cubic-bezier(0,0,.2,1)}:host ::ng-deep .sd-selection-cell{width:42px;min-width:42px;max-width:42px}:host ::ng-deep .c-selection{transform:scale(.85);transform-origin:center}:host ::ng-deep .sd-tree-toggle-cell{width:40px;min-width:40px;max-width:100px}:host ::ng-deep .sd-tree-toggle-inner{display:flex;align-items:center;min-height:40px}:host ::ng-deep .sd-tree-spinner{transform:scale(.5);margin:0 auto}\n", ":host ::ng-deep .sticky-shadow-right{overflow:visible!important}:host ::ng-deep .sticky-shadow-right:after{content:\"\";position:absolute;top:0;right:0;bottom:0;width:8px;transform:translate(100%);background:linear-gradient(to right,rgba(0,0,0,.12),transparent);pointer-events:none}:host ::ng-deep .sticky-shadow-left{overflow:visible!important}:host ::ng-deep .sticky-shadow-left:after{content:\"\";position:absolute;top:0;left:0;bottom:0;width:8px;transform:translate(-100%);background:linear-gradient(to left,rgba(0,0,0,.12),transparent);pointer-events:none}\n"] }]
4339
+ ], template: "@let _configuration = configuration();\r\n@let _tableOption = tableOption()!;\r\n@let _loading = loading();\r\n@let _items = items();\r\n@let _total = total();\r\n@let _isFiltered = isFiltered();\r\n@let _requireFiltered = requireFiltered();\r\n@let _export = _tableOption?.export;\r\n@let _exporting = exporting();\r\n@let _titleDef = titleDef();\r\n\r\n@if (_configuration) {\r\n @if (!_tableOption.filter?.disabled && !!_tableOption.filter?.externalFilters?.length && filterRegister) {\r\n <external-filter\r\n class=\"mb-16\"\r\n [autoId]=\"autoId()\"\r\n [filterRegister]=\"filterRegister\"\r\n [filter]=\"_tableOption.filter!\"\r\n [externalFilters]=\"_tableOption.filter?.externalFilters!\">\r\n </external-filter>\r\n }\r\n @let groupedItems = _items | sdTree: _tableOption.tree : treeRevision() | sdGroup: _tableOption : groupExpandState;\r\n <ng-content select=\"[sdTableTop]\"></ng-content>\r\n <div class=\"c-container\">\r\n @if (_loading) {\r\n <div class=\"c-loading\">\r\n <mat-spinner></mat-spinner>\r\n </div>\r\n }\r\n <div\r\n class=\"c-table\"\r\n sdScroll\r\n stickyShadow\r\n [style.max-height]=\"_tableOption.style?.maxHeight\"\r\n [style.min-height]=\"_tableOption.style?.minHeight\">\r\n <table\r\n mat-table\r\n [dataSource]=\"groupedItems\"\r\n [trackBy]=\"trackBy\"\r\n matSort\r\n [matSortDisabled]=\"!_tableOption.sort?.enable\"\r\n multiTemplateDataRows\r\n cdkDropList\r\n [cdkDropListData]=\"groupedItems\"\r\n [cdkDropListDisabled]=\"!_tableOption.rowReorder?.enabled\"\r\n [cdkDropListSortPredicate]=\"reorderSortPredicate\"\r\n (cdkDropListDropped)=\"onReorderDrop($event)\">\r\n @if (_tableOption.rowReorder?.enabled) {\r\n <ng-container matColumnDef=\"sdReorder\">\r\n <th mat-header-cell *matHeaderCellDef class=\"sd-reorder-header\" [attr.rowspan]=\"_configuration.multipleHeader ? 2 : 1\"></th>\r\n <td mat-cell *matCellDef=\"let row\" class=\"sd-reorder-cell\">\r\n @if (!row.meta?.group?.items?.length) {\r\n <mat-icon cdkDragHandle [class.sd-reorder-disabled]=\"isReorderDisabled(row)\">\r\n {{ _tableOption.rowReorder?.icon || 'drag_indicator' }}\r\n </mat-icon>\r\n }\r\n </td>\r\n <td mat-footer-cell *matFooterCellDef></td>\r\n </ng-container>\r\n }\r\n\r\n @if (_tableOption.tree) {\r\n <ng-container matColumnDef=\"sdTreeToggle\">\r\n <th\r\n mat-header-cell\r\n *matHeaderCellDef\r\n class=\"sd-tree-toggle-cell p-0\"\r\n [attr.rowspan]=\"_configuration.multipleHeader ? 2 : 1\"></th>\r\n <td mat-cell *matCellDef=\"let row\" class=\"sd-tree-toggle-cell p-0\">\r\n @if (row.meta?.tree) {\r\n <div\r\n class=\"sd-tree-toggle-inner\"\r\n [style.padding-left.px]=\"(row.meta.tree.level ?? 0) * (_tableOption.tree?.indentSize ?? 20)\">\r\n @if (row.meta.tree.hasChildren) {\r\n @if (row.meta.tree.isExpanding) {\r\n <div class=\"lds-ring sd-tree-spinner\">\r\n <div></div>\r\n <div></div>\r\n <div></div>\r\n <div></div>\r\n </div>\r\n } @else {\r\n <sd-button\r\n type=\"link\"\r\n [prefixIcon]=\"row.meta.tree.isExpanded ? 'expand_less' : 'expand_more'\"\r\n (click)=\"onTreeToggle(row); $event.stopPropagation()\"\r\n width=\"35px\">\r\n </sd-button>\r\n }\r\n }\r\n </div>\r\n }\r\n </td>\r\n <td mat-footer-cell *matFooterCellDef></td>\r\n </ng-container>\r\n }\r\n\r\n <ng-container matColumnDef=\"sdSubInformation\" sticky>\r\n <td class=\"p-0\" mat-cell *matCellDef=\"let item\" [attr.colspan]=\"_configuration.displayedColumns.length\">\r\n @if (sdSubInformation()?.templateRef) {\r\n @if (_tableOption.expand?.always) {\r\n <ng-container *ngTemplateOutlet=\"sdSubInformation()?.templateRef!; context: { item: item }\"> </ng-container>\r\n } @else {\r\n <div [@detailExpand]=\"item.isExpanded ? 'expanded' : 'collapsed'\">\r\n @if (item.isExpanded) {\r\n <ng-container *ngTemplateOutlet=\"sdSubInformation()?.templateRef!; context: { item: item }\"> </ng-container>\r\n }\r\n </div>\r\n }\r\n }\r\n </td>\r\n <td mat-footer-cell *matFooterCellDef></td>\r\n </ng-container>\r\n\r\n <ng-container matColumnDef=\"sdSubInformationAction\" stickyEnd>\r\n <th class=\"p-0\" mat-header-cell *matHeaderCellDef style=\"width: 1px\" [attr.rowspan]=\"_configuration.multipleHeader ? 2 : 1\"></th>\r\n <td mat-cell *matCellDef=\"let element\">\r\n @if (!element.isExpanding && !_tableOption.expand?.always) {\r\n <sd-button\r\n type=\"link\"\r\n [prefixIcon]=\"element.isExpanded ? 'expand_less' : 'expand_more'\"\r\n (click)=\"onExpand(element)\"\r\n width=\"35px\">\r\n </sd-button>\r\n }\r\n @if (element.isExpanding) {\r\n <div class=\"lds-ring\">\r\n <div></div>\r\n <div></div>\r\n <div></div>\r\n <div></div>\r\n </div>\r\n }\r\n </td>\r\n </ng-container>\r\n\r\n <ng-container matColumnDef=\"sdSelection\" sticky>\r\n <th class=\"sd-selection-cell p-0\" mat-header-cell *matHeaderCellDef [attr.rowspan]=\"_configuration.multipleHeader ? 2 : 1\">\r\n @let visibleSelectAll = _items | selectionVisibleSelectAll: _tableOption.selector | async;\r\n @if (visibleSelectAll) {\r\n <mat-checkbox\r\n class=\"c-selection px-8\"\r\n color=\"primary\"\r\n [ngModel]=\"isSelectAll()\"\r\n (ngModelChange)=\"isSelectAll.set($event)\"\r\n (change)=\"onSelectAll()\">\r\n </mat-checkbox>\r\n }\r\n </th>\r\n\r\n <td class=\"sd-selection-cell p-0\" mat-cell *matCellDef=\"let item\">\r\n @let visible = item | selectionVisible: _tableOption.selector;\r\n @if (visible) {\r\n @if (_tableOption.selector?.single) {\r\n <mat-radio-button\r\n class=\"c-selection px-8\"\r\n color=\"primary\"\r\n [checked]=\"item.meta.selector.isSelected\"\r\n (change)=\"item.meta.selector.isSelected = true; onSelect(item)\"\r\n [disabled]=\"selectedTableItems() | selectionDisabled: item : _tableOption.selector!\">\r\n </mat-radio-button>\r\n } @else {\r\n <mat-checkbox\r\n class=\"c-selection px-8\"\r\n color=\"primary\"\r\n [(ngModel)]=\"item.meta.selector.isSelected\"\r\n (change)=\"onSelect(item)\"\r\n [disabled]=\"selectedTableItems() | selectionDisabled: item : _tableOption.selector!\">\r\n </mat-checkbox>\r\n }\r\n }\r\n </td>\r\n <td mat-footer-cell *matFooterCellDef></td>\r\n </ng-container>\r\n @if (_tableOption.index?.enabled) {\r\n @let _pageOffset = pageOffset();\r\n @let _indexWidth = _tableOption.index?.width || '50px';\r\n <ng-container matColumnDef=\"sdIndex\" sticky>\r\n <th\r\n class=\"text-center p-0\"\r\n mat-header-cell\r\n *matHeaderCellDef\r\n [style.width]=\"_indexWidth\"\r\n [style.min-width]=\"_indexWidth\"\r\n [style.max-width]=\"_indexWidth\"\r\n [attr.rowspan]=\"_configuration.multipleHeader ? 2 : 1\">\r\n {{ _tableOption.index?.title || '#' }}\r\n </th>\r\n <td class=\"text-center px-4\" mat-cell *matCellDef=\"let item; let i = dataIndex\" [style.min-width]=\"_indexWidth\" [style.max-width]=\"_indexWidth\">\r\n @if (!item?.meta?.group?.isGroupHeader) {\r\n @if (_tableOption.tree && item?.meta?.tree?.indexPath?.length) {\r\n <!-- why: tree \u2192 STT ph\u00E2n c\u1EA5p 1, 1.2, 1.2.1 (indexPath join '.'). T\u00F4 \u0111\u1EADm root (level 0). -->\r\n <span [class.sd-stt-root]=\"(item.meta.tree.level ?? 0) === 0\">\r\n {{ item.meta.tree.indexPath.join('.') }}\r\n </span>\r\n } @else {\r\n {{ _pageOffset + i + 1 }}\r\n }\r\n }\r\n </td>\r\n <td mat-footer-cell *matFooterCellDef [style.min-width]=\"_indexWidth\" [style.max-width]=\"_indexWidth\"></td>\r\n </ng-container>\r\n }\r\n <ng-container\r\n matColumnDef=\"sdCommand\"\r\n [sticky]=\"_tableOption.command?.align !== 'right'\"\r\n [stickyEnd]=\"_tableOption.command?.align === 'right'\">\r\n <th class=\"p-0\" mat-header-cell *matHeaderCellDef style=\"width: 50px\" [attr.rowspan]=\"_configuration.multipleHeader ? 2 : 1\"></th>\r\n <td class=\"px-8\" mat-cell *matCellDef=\"let item\">\r\n <desktop-command\r\n [autoId]=\"autoId()\"\r\n [commands]=\"_tableOption.command?.commands || _tableOption.commands || []\"\r\n [item]=\"item\"\r\n [itemIndex]=\"groupedItems.indexOf(item)\"></desktop-command>\r\n </td>\r\n <td mat-footer-cell *matFooterCellDef></td>\r\n </ng-container>\r\n <!-- why: group header row d\u00F9ng matRowDef RI\u00CANG v\u1EDBi column list ['sdGroupHeader']\r\n qua predicate when:isGroupHeaderRow. Cell colspan = displayedColumns.length \u0111\u1EC3\r\n span TO\u00C0N B\u1ED8 width data row. Tr\u00E1nh colspan trick overflow row khi c\u00E1c TD kh\u00E1c render. -->\r\n <ng-container matColumnDef=\"sdGroupHeader\">\r\n <td\r\n class=\"p-0 sd-group-header-cell\"\r\n mat-cell\r\n *matCellDef=\"let item\"\r\n [attr.colspan]=\"sdGroupColspan()\">\r\n <div class=\"sd-group-row d-flex align-items-center py-8\">\r\n <!-- why: slot 42px kh\u1EDBp width v\u1EDBi sd-selection-cell data row \u2192 checkbox group c\u0103n TR\u1EE4C d\u1ECDc \u0111\u00FAng v\u1EDBi checkbox data. -->\r\n @if (_tableOption.selector?.visible && !_tableOption.selector?.single) {\r\n <div class=\"sd-group-selection-slot d-flex align-items-center justify-content-center\">\r\n <mat-checkbox\r\n class=\"c-selection\"\r\n color=\"primary\"\r\n [checked]=\"isGroupAllSelected(item)\"\r\n [indeterminate]=\"isGroupIndeterminate(item)\"\r\n (change)=\"onSelectGroup(item, $event.checked)\">\r\n </mat-checkbox>\r\n </div>\r\n } @else {\r\n <div class=\"sd-group-selection-slot\"></div>\r\n }\r\n @if (_tableOption.group?.collapsible) {\r\n <sd-button\r\n type=\"link\"\r\n [prefixIcon]=\"item.meta.group.isExpanded ? 'expand_more' : 'chevron_right'\"\r\n width=\"32px\"\r\n (click)=\"toggleGroupExpand(item)\">\r\n </sd-button>\r\n }\r\n @if (sdGroupDef()?.templateRef; as tpl) {\r\n <ng-container *ngTemplateOutlet=\"tpl; context: groupContext(item)\"></ng-container>\r\n } @else {\r\n <span class=\"T14R\">{{ item.meta.group.values | json }}</span>\r\n }\r\n </div>\r\n </td>\r\n </ng-container>\r\n <!-- why: filler column \u1EDF cu\u1ED1i h\u1EA5p th\u1EE5 leftover space khi t\u1ED5ng width c\u00E1c c\u1ED9t data < container \u2014 gi\u1EEF cho selection/STT/command kh\u00F4ng b\u1ECB d\u00E3n. -->\r\n <ng-container matColumnDef=\"sdFiller\">\r\n <th class=\"sd-filler-cell p-0\" mat-header-cell *matHeaderCellDef [attr.rowspan]=\"_configuration.multipleHeader ? 2 : 1\"></th>\r\n <td class=\"sd-filler-cell p-0\" mat-cell *matCellDef=\"let item\"></td>\r\n <td class=\"sd-filler-cell p-0\" mat-footer-cell *matFooterCellDef></td>\r\n </ng-container>\r\n @for (column of _configuration.firstColumns; track column.field) {\r\n <ng-container [matColumnDef]=\"column.field\" [sticky]=\"_configuration.fixedColumn[column.field]\">\r\n <th\r\n mat-header-cell\r\n *matHeaderCellDef\r\n class=\"px-8 py-8 c-th\"\r\n [sdColumnResize]=\"!!_tableOption.config?.resizable && column.type !== 'children'\"\r\n [minWidth]=\"column.minWidth\"\r\n [maxWidth]=\"column.maxWidth\"\r\n (resizeEnd)=\"onColumnResize(column.field, $event)\"\r\n [style.width]=\"column.width\"\r\n [style.min-width]=\"column.minWidth || column.width\"\r\n [style.max-width]=\"column.maxWidth\"\r\n [attr.rowspan]=\"_configuration.multipleHeader && column.type !== 'children' ? 2 : 1\"\r\n [attr.colspan]=\"column.type === 'children' ? column.children.length : 1\">\r\n <div>\r\n @if (column.type === 'children') {\r\n <div\r\n aria-hidden=\"true\"\r\n class=\"c-header-title\"\r\n [class.justify-content-end]=\"column.align === 'right'\"\r\n [class.text-right]=\"column.align === 'right'\">\r\n <column-title [column]=\"column\" [titleDef]=\"_titleDef[column.field]\"></column-title>\r\n </div>\r\n } @else {\r\n <div\r\n aria-hidden=\"true\"\r\n mat-sort-header\r\n class=\"c-header-title\"\r\n [class.justify-content-end]=\"column.align === 'right'\"\r\n [class.text-right]=\"column.align === 'right'\"\r\n [disabled]=\"!column.sortable\">\r\n <column-title [column]=\"column\" [titleDef]=\"_titleDef[column.field]\"></column-title>\r\n </div>\r\n @let hideInlineFilter =\r\n _tableOption.filter?.disabled ||\r\n _tableOption.filter?.hideInlineFilter === true ||\r\n (_tableOption.filter?.hideInlineFilter === 'auto' && !_isFiltered && _total! <= 10);\r\n @if (!hideInlineFilter) {\r\n <ng-container *sdDesktop>\r\n <column-filter\r\n [autoId]=\"autoId()\"\r\n [value]=\"columnFilter?.[column.field!]!\"\r\n [operator]=\"columnOperator[column.field]\"\r\n (operatorChange)=\"columnOperator[column.field] = $event!; onOperatorChange(column, $event)\"\r\n [columnFilter]=\"columnFilter!\"\r\n [cacheValues]=\"cacheValues\"\r\n [column]=\"column\"\r\n (filterChange)=\"onFilterChange()\"\r\n (filterCommit)=\"onFilterCommit()\">\r\n </column-filter>\r\n </ng-container>\r\n }\r\n }\r\n </div>\r\n </th>\r\n <td\r\n class=\"c-td px-0\"\r\n [class.d-none]=\"column.type === 'children'\"\r\n mat-cell\r\n *matCellDef=\"let item\"\r\n [sdHoverCopy]=\"(item.data && item.data[column.field]) || ''\"\r\n [sdHoverCopyDisabled]=\"!column.cell?.copiable\">\r\n @if (column.type !== 'children' && !item?.meta?.group?.isGroupHeader) {\r\n <desktop-cell class=\"d-block px-8\" [column]=\"column\" [item]=\"item\" [cellDef]=\"cellDef()\"> </desktop-cell>\r\n }\r\n </td>\r\n <td mat-footer-cell *matFooterCellDef>\r\n <ng-container *ngIf=\"footerDef()[column.field]\">\r\n <ng-container *ngTemplateOutlet=\"footerDef()[column.field].templateRef; context: { items: _items, column: column }\">\r\n </ng-container>\r\n </ng-container>\r\n </td>\r\n </ng-container>\r\n }\r\n @for (column of _configuration.secondColumns; track column.field) {\r\n <ng-container [matColumnDef]=\"column.field\">\r\n <th\r\n mat-header-cell\r\n *matHeaderCellDef\r\n class=\"c-th px-8\"\r\n [style.width]=\"column.width\"\r\n [style.min-width]=\"column.minWidth || column.width\"\r\n [style.max-width]=\"column.maxWidth\">\r\n <div>\r\n <div\r\n aria-hidden=\"true\"\r\n mat-sort-header\r\n class=\"c-header-title\"\r\n [class.justify-content-end]=\"column.align === 'right'\"\r\n [class.text-right]=\"column.align === 'right'\"\r\n [disabled]=\"!column.sortable\">\r\n <column-title [column]=\"column\" [titleDef]=\"_titleDef[column.field]\"></column-title>\r\n </div>\r\n @if (!_tableOption.filter?.disabled && !_tableOption.filter?.hideInlineFilter && columnOperator) {\r\n <ng-container *sdDesktop>\r\n <column-filter\r\n [autoId]=\"autoId()\"\r\n [value]=\"columnFilter?.[column.field!]!\"\r\n [operator]=\"columnOperator[column.field]\"\r\n [columnFilter]=\"columnFilter!\"\r\n [cacheValues]=\"cacheValues\"\r\n [column]=\"column\"\r\n (operatorChange)=\"columnOperator[column.field] = $event!; onOperatorChange(column, $event)\"\r\n (filterChange)=\"onFilterChange()\"\r\n (filterCommit)=\"onFilterCommit()\">\r\n </column-filter>\r\n </ng-container>\r\n }\r\n </div>\r\n </th>\r\n <td\r\n class=\"c-td px-0\"\r\n mat-cell\r\n *matCellDef=\"let item\"\r\n [sdHoverCopy]=\"item[column.field]\"\r\n [sdHoverCopyDisabled]=\"!column.cell?.copiable\">\r\n @if (column.type !== 'children') {\r\n <desktop-cell class=\"d-block px-8\" [column]=\"column\" [item]=\"item\" [cellDef]=\"cellDef()\"> </desktop-cell>\r\n }\r\n </td>\r\n <td mat-footer-cell *matFooterCellDef>\r\n <ng-container *ngIf=\"footerDef()[column.field]\">\r\n <ng-container *ngTemplateOutlet=\"footerDef()[column.field].templateRef; context: { items: _items, column: column }\">\r\n </ng-container>\r\n </ng-container>\r\n </td>\r\n </ng-container>\r\n }\r\n <tr class=\"c-first-header\" mat-header-row *matHeaderRowDef=\"_configuration.firstHeaders; sticky: true\"></tr>\r\n @if (!!_configuration.secondHeaders.length) {\r\n <tr class=\"c-second-header\" mat-header-row *matHeaderRowDef=\"_configuration.secondHeaders; sticky: true\"></tr>\r\n }\r\n <!-- Group header row \u2014 ch\u1EC9 1 cell sdGroupHeader colspan to\u00E0n width. -->\r\n <tr\r\n mat-row\r\n *matRowDef=\"let row; columns: ['sdGroupHeader']; when: isGroupHeaderRow\"\r\n class=\"c-group-row-tr\"></tr>\r\n\r\n <!-- Data row \u2014 d\u00F9ng displayedColumns \u0111\u1EA7y \u0111\u1EE7; when isDataRow \u0111\u1EC3 lo\u1EA1i tr\u1EEB group header. -->\r\n <tr\r\n mat-row\r\n cdkDrag\r\n [cdkDragData]=\"row\"\r\n [cdkDragDisabled]=\"\r\n !_tableOption.rowReorder?.enabled ||\r\n !!row.meta?.group?.items?.length ||\r\n (row.meta?.tree?.level ?? 0) > 0 ||\r\n isReorderDisabled(row)\r\n \"\r\n *matRowDef=\"let row; columns: _configuration.displayedColumns; when: isDataRow\"\r\n matRipple\r\n class=\"c-row\"\r\n [class.sd-tree-row]=\"!!_tableOption.tree\"\r\n [ngClass]=\"_tableOption.tree ? 'sd-tree-level-' + (row.meta?.tree?.level ?? 0) : null\"\r\n [ngStyle]=\"rowStyle(row)\"\r\n [class.selected]=\"row.meta.selector.isSelected\"></tr>\r\n\r\n <!-- Sub-information row \u2014 also gated b\u1EDFi isDataRow \u0111\u1EC3 KH\u00D4NG render empty expand row d\u01B0\u1EDBi group header. -->\r\n <tr mat-row *matRowDef=\"let row; columns: ['sdSubInformation']; when: isDataRow\" class=\"c-detail-row\"></tr>\r\n @if (hasFooter() && !!_configuration.displayedFooters.length) {\r\n <tr mat-footer-row *matFooterRowDef=\"_configuration.displayedFooters; sticky: true\"></tr>\r\n }\r\n </table>\r\n @if (!_loading && !_total) {\r\n <div class=\"c-no-data-row\">\r\n @if (_isFiltered) {\r\n @if (tableConfiguration?.images?.filterEmpty) {\r\n <img class=\"c-image\" [src]=\"tableConfiguration!.images!.filterEmpty\" alt=\"filter-empty\" />\r\n } @else {\r\n <img class=\"c-image sd-image-filter-empty\" alt=\"filter-empty\" />\r\n }\r\n <div class=\"T16M\">{{ 'core.component.table.no-results' | translate }}</div>\r\n <div class=\"T16R text-secondary\">{{ 'core.component.table.no-results-hint' | translate }}</div>\r\n } @else {\r\n @if (_requireFiltered) {\r\n @if (tableConfiguration?.images?.filterRequired) {\r\n <img class=\"c-image\" [src]=\"tableConfiguration!.images!.filterRequired\" alt=\"filter-required\" />\r\n } @else {\r\n <img class=\"c-image sd-image-filter-required\" alt=\"filter-required\" />\r\n }\r\n <div class=\"T16R text-secondary\">{{ 'core.component.table.choose-filter-hint' | translate }}</div>\r\n } @else {\r\n @if (tableConfiguration?.images?.dataEmpty) {\r\n <img class=\"c-image\" [src]=\"tableConfiguration!.images!.dataEmpty\" alt=\"data-empty\" />\r\n } @else {\r\n <img class=\"c-image sd-image-data-empty\" alt=\"data-empty\" />\r\n }\r\n <div class=\"T16R text-secondary\">{{ 'core.component.table.no-data' | translate }}</div>\r\n }\r\n }\r\n </div>\r\n }\r\n </div>\r\n <div class=\"c-paginator\">\r\n <div class=\"c-action\">\r\n <ng-container *sdDesktop>\r\n @if (_tableOption.reload?.visible) {\r\n <sd-button\r\n class=\"mr-8\"\r\n [title]=\"'core.component.table.reload' | translate\"\r\n prefixIcon=\"refresh\"\r\n (click)=\"reload()\"\r\n [disabled]=\"!_items.length\"\r\n type=\"link\">\r\n </sd-button>\r\n }\r\n </ng-container>\r\n @if (_export && _items.length) {\r\n @if (_export.type === 'custom') {\r\n <sd-button class=\"mr-8\" [title]=\"exportTitle()\" prefixIcon=\"get_app\" (click)=\"exportCustom()\" type=\"link\"> </sd-button>\r\n } @else {\r\n @if (_export.visible) {\r\n @if (_exporting) {\r\n <sd-button class=\"mr-8\" [loading]=\"_exporting\" [title]=\"exportTitle()\" prefixIcon=\"get_app\" type=\"link\"> </sd-button>\r\n } @else {\r\n @if (_export.visible === 'ALL' || !_export.visible) {\r\n <sd-button class=\"mr-8\" [title]=\"exportTitle()\" prefixIcon=\"get_app\" [matMenuTriggerFor]=\"menu\" type=\"link\"> </sd-button>\r\n <mat-menu #menu=\"matMenu\">\r\n <button mat-menu-item (click)=\"exportExcel()\" type=\"button\">\r\n <mat-icon fontSet=\"material-icons-outlined\">file_download</mat-icon>\r\n <span> {{ 'core.component.table.export-excel' | translate }}</span>\r\n </button>\r\n <button mat-menu-item (click)=\"exportCSV()\" type=\"button\">\r\n <mat-icon fontSet=\"material-icons-outlined\">file_download</mat-icon>\r\n <span> {{ 'core.component.table.export-csv' | translate }}</span>\r\n </button>\r\n </mat-menu>\r\n } @else if (_export.visible === 'EXCEL') {\r\n <sd-button class=\"mr-8\" [title]=\"exportTitle()\" prefixIcon=\"get_app\" (click)=\"exportExcel()\" type=\"link\"> </sd-button>\r\n } @else if (_export.visible === 'CSV') {\r\n <sd-button class=\"mr-8\" [title]=\"exportTitle()\" prefixIcon=\"get_app\" (click)=\"exportCSV()\" type=\"link\"> </sd-button>\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n <ng-container *sdDesktop>\r\n @if (configComponent()) {\r\n <sd-button\r\n class=\"mr-8\"\r\n [title]=\"'core.component.table.setup-short' | translate\"\r\n prefixIcon=\"settings\"\r\n (click)=\"configComponent()!.open()\"\r\n type=\"link\">\r\n </sd-button>\r\n }\r\n </ng-container>\r\n <!-- Mobile: n\u00FAt Filter m\u1EDF mobile-filter drawer (inline filter \u1EA9n tr\u00EAn mobile) -->\r\n <ng-container *sdMobile>\r\n @if (!_tableOption.filter?.disabled && mobileFilter()) {\r\n <sd-button\r\n [autoId]=\"autoId() + 'mobile-filter-open'\"\r\n class=\"mr-8\"\r\n prefixIcon=\"filter_alt\"\r\n (click)=\"mobileFilter()!.open()\"\r\n type=\"link\">\r\n </sd-button>\r\n }\r\n </ng-container>\r\n </div>\r\n @let hidePaginator = !_tableOption.paginate?.pageSize || _total === undefined || _total <= _tableOption.paginate?.pageSize!;\r\n <!-- Desktop paginator: full config (pageSize dropdown, first/last buttons) -->\r\n <ng-container *sdDesktop>\r\n <mat-paginator\r\n [class.d-none]=\"_tableOption.paginate?.hidden || hidePaginator\"\r\n [length]=\"_total\"\r\n [pageSize]=\"_tableOption.paginate?.pageSize\"\r\n [pageSizeOptions]=\"_tableOption.paginate?.pages!\"\r\n [showFirstLastButtons]=\"_tableOption.paginate?.showFirstLastButtons\"\r\n [hidePageSize]=\"_tableOption.paginate?.hidePageSize\"></mat-paginator>\r\n </ng-container>\r\n <!-- Mobile paginator: \u1EA9n pageSize dropdown + first/last buttons \u0111\u1EC3 ti\u1EBFt ki\u1EC7m kh\u00F4ng gian -->\r\n <ng-container *sdMobile>\r\n <mat-paginator\r\n [class.d-none]=\"_tableOption.paginate?.hidden || hidePaginator\"\r\n [length]=\"_total\"\r\n [pageSize]=\"_tableOption.paginate?.pageSize\"\r\n [showFirstLastButtons]=\"false\"\r\n hidePageSize></mat-paginator>\r\n </ng-container>\r\n <!-- \"\u0110ang hi\u1EC3n th\u1ECB...\" ch\u1EC9 desktop -->\r\n <ng-container *sdDesktop>\r\n @if (!_tableOption.paginate?.hidden && hidePaginator && _total !== undefined && _total > 0) {\r\n <div class=\"T14R pr-16\">\r\n {{ 'core.component.table.showing' | translate }} <span class=\"T14M ml-2\">1-{{ _total }}/{{ _total }}</span>\r\n </div>\r\n }\r\n </ng-container>\r\n </div>\r\n </div>\r\n <selector-action [tableOption]=\"_tableOption\" [selectedTableItems]=\"selectedTableItems()\" (clear)=\"onClearSelection(groupedItems)\" />\r\n @if (_tableOption.config?.visible) {\r\n <config [tableOption]=\"_tableOption\" />\r\n }\r\n <!-- Mobile filter drawer \u2014 ch\u1EC9 instantiate khi c\u1EA7n render tr\u00EAn mobile -->\r\n @if (!_tableOption.filter?.disabled && filterRegister) {\r\n <mobile-filter\r\n [autoId]=\"autoId()\"\r\n [filter]=\"_tableOption.filter!\"\r\n [externalFilters]=\"_tableOption.filter?.externalFilters!\"\r\n [columns]=\"_configuration.firstColumns\"\r\n [filterDefs]=\"sdFilterDefs()\"\r\n [filterRegister]=\"filterRegister\"\r\n [cacheValues]=\"cacheValues\">\r\n </mobile-filter>\r\n }\r\n}\r\n", styles: [":host{display:flex;flex-direction:column;overflow:auto;width:100%;height:100%}:host .c-header-title{height:40px;display:flex;align-items:center}:host .c-container{position:relative;min-height:50px;display:flex;flex-direction:column;flex:1}:host .c-container .c-table{position:relative;flex:1;display:flex;flex-direction:column}:host .c-container .c-table table{border-collapse:separate;width:100%}:host .c-container .c-table table tr.c-first-header.mat-mdc-header-row{height:40px}:host .c-container .c-table table tr.c-second-header.mat-mdc-header-row{height:40px}:host .c-container .c-table table tr.c-detail-row{height:0}:host .c-container .c-table table tr.c-row.activated{background-color:#e5ecff}:host .c-container .c-table table tr.c-row.selected{background-color:#eef2ff}:host .c-container .c-table table tr.c-row:not(.selected):not(.activated):hover{background-color:#f5f5f5}:host .c-container .c-table table tr.c-row td{border-bottom-width:0}:host .c-container .c-table table tr.c-row.c-expandable{cursor:pointer}:host .c-container .c-table table tr.c-row.c-expandable:hover{background:#f5f5f5}:host .c-container .c-table table th.mat-mdc-header-cell{background-color:#f2f3f4;border-bottom:0!important}:host .c-container .c-table table td.mat-mdc-cell,:host .c-container .c-table table td.mat-mdc-footer-cell,:host .c-container .c-table table th.mat-mdc-header-cell{border-bottom-color:#f2f2f2!important}:host .c-container .c-table .c-th{vertical-align:middle;font-weight:500;font-size:14px;line-height:20px;color:#212121}:host .c-container .c-table .c-th.sd-col-resize-host{position:relative}:host .c-container .c-table .c-th.sd-resizing{-webkit-user-select:none;user-select:none}:host .c-container .c-table .c-th .sd-col-resize-handle{position:absolute;top:0;right:0;width:6px;height:100%;cursor:col-resize;-webkit-user-select:none;user-select:none;z-index:2}:host .c-container .c-table .c-th .sd-col-resize-handle:hover{background:#00000014}:host .c-container .c-table .c-td:first{padding-left:10px}:host .c-container .c-table .c-no-data-row{flex:1;width:100%;position:sticky;left:0;display:flex;flex-direction:column;align-items:center;justify-content:center}:host .c-container .c-table .c-no-data-row .c-image{margin-bottom:16px;width:96px}:host .c-container .c-loading{position:absolute;inset:0 0 56px;background:#00000026;z-index:2;display:flex;align-items:center;justify-content:center}:host .c-container .c-paginator{display:flex;flex-direction:row;justify-content:space-between;align-items:center;background-color:#fff}:host .c-container .c-paginator .c-action{padding:5px}:host .c-container .c-empty{text-align:center;background-color:#fff;border:none!important}:host .c-container .c-empty mat-icon{font-size:150px;margin-top:30px;margin-bottom:30px;opacity:.2;width:auto;height:auto}:host button.c-btn-add{background-color:#fff;box-shadow:0 2px 4px #2f313629}:host .lds-ring{display:inline-block;position:relative;width:40px;height:40px}:host .lds-ring div{box-sizing:border-box;display:block;position:absolute;width:32px;height:32px;margin:4px;border:4px solid #cef;border-radius:50%;animation:lds-ring 1.2s cubic-bezier(.5,0,.5,1) infinite;border-color:#cef transparent transparent transparent}:host .lds-ring div:nth-child(1){animation-delay:-.45s}:host .lds-ring div:nth-child(2){animation-delay:-.3s}:host .lds-ring div:nth-child(3){animation-delay:-.15s}@keyframes lds-ring{0%{transform:rotate(0)}to{transform:rotate(360deg)}}:host .sd-reorder-header,:host .sd-reorder-cell{width:40px;min-width:40px;padding:0 4px;box-sizing:border-box}:host .sd-reorder-cell mat-icon{cursor:grab;color:#00000061;display:flex;align-items:center}:host .sd-reorder-cell mat-icon:active{cursor:grabbing}:host .sd-reorder-cell mat-icon.sd-reorder-disabled{opacity:.3;cursor:not-allowed;pointer-events:none}:host ::ng-deep .mat-sort-header-content{display:block;text-align:left;width:100%}:host ::ng-deep .mat-select-arrow{color:#a6a6a6}:host ::ng-deep .mat-sort-header-disabled{background-image:none!important;cursor:default!important;padding-right:0!important}:host ::ng-deep .mat-sort-header-container{align-items:start!important}:host ::ng-deep .mat-sort-header-arrow{margin-top:4px!important}:host ::ng-deep .mat-sort-header-arrow{display:none!important}:host ::ng-deep .mat-sort-header{cursor:pointer}:host ::ng-deep .mat-sort-header[aria-sort]{background-repeat:no-repeat;background-position:center right 0;background-size:16px 16px;cursor:pointer;padding-right:24px}:host ::ng-deep .mat-sort-header[aria-sort=none]{background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='24px' viewBox='0 0 24 24' width='24px' fill='%23000000'%3E%3Cpath d='M0 0h24v24H0V0z' fill='none'/%3E%3Cpath fill='%237A7A7A' d='M12 5.83L15.17 9l1.41-1.41L12 3 7.41 7.59 8.83 9 12 5.83zm0 12.34L8.83 15l-1.41 1.41L12 21l4.59-4.59L15.17 15 12 18.17z'/%3E%3C/svg%3E\")}:host ::ng-deep .mat-sort-header[aria-sort=ascending]{background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='24px' viewBox='0 0 24 24' width='24px' fill='%23000000'%3E%3Cpath d='M0 0h24v24H0V0z' fill='none'/%3E%3Cpath fill='%237A7A7A' d='M4 12l1.41 1.41L11 7.83V20h2V7.83l5.58 5.59L20 12l-8-8-8 8z'/%3E%3C/svg%3E\")}:host ::ng-deep .mat-sort-header[aria-sort=descending]{background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='24px' viewBox='0 0 24 24' width='24px' fill='%23000000'%3E%3Cpath d='M0 0h24v24H0V0z' fill='none'/%3E%3Cpath fill='%237A7A7A' d='M20 12l-1.41-1.41L13 16.17V4h-2v12.17l-5.58-5.59L4 12l8 8 8-8z'/%3E%3C/svg%3E\")}:host ::ng-deep .c-paginator .mat-mdc-paginator .mdc-text-field--outlined .mat-mdc-form-field-infix,:host ::ng-deep .c-paginator .mat-mdc-paginator .mdc-text-field--no-label .mat-mdc-form-field-infix{padding-top:2px;padding-bottom:2px;min-height:32px}:host ::ng-deep .c-paginator .mat-mdc-paginator-range-label{margin:0 4px}:host ::ng-deep .c-paginator .mat-mdc-paginator-page-size-select mat-select{margin-top:2px!important}:host ::ng-deep .cdk-drag-preview{box-shadow:0 4px 12px #00000026;background:#fff;display:table;width:100%}:host ::ng-deep .cdk-drag-preview td{padding:0 8px;border-bottom:1px solid rgba(0,0,0,.12)}:host ::ng-deep .cdk-drag-placeholder{opacity:0}:host ::ng-deep .cdk-drop-list-dragging tr.c-row:not(.cdk-drag-placeholder){transition:transform .25s cubic-bezier(0,0,.2,1)}:host ::ng-deep .sd-selection-cell{width:42px;min-width:42px;max-width:42px}:host ::ng-deep .sd-filler-cell{width:auto;min-width:0;padding:0!important;border:0}:host ::ng-deep .sd-group-header-cell{background:#f5f7fc;border-top:1px solid #e6e9f2;border-bottom:1px solid #e6e9f2}:host ::ng-deep .sd-group-row{min-height:36px}:host ::ng-deep .sd-group-selection-slot{width:42px;min-width:42px;max-width:42px}:host ::ng-deep .c-selection{transform:scale(.85);transform-origin:center}:host ::ng-deep .sd-tree-toggle-cell{width:40px;min-width:40px;max-width:100px}:host ::ng-deep .sd-tree-toggle-inner{display:flex;align-items:center;min-height:40px}:host ::ng-deep .sd-tree-spinner{transform:scale(.5);margin:0 auto}:host ::ng-deep tr.c-row.sd-tree-row.sd-tree-level-0{background:#fbfcfe}:host ::ng-deep tr.c-row.sd-tree-row.sd-tree-level-0>td{font-weight:500}:host ::ng-deep tr.c-row.sd-tree-row.sd-tree-level-1{background:#fff}:host ::ng-deep tr.c-row.sd-tree-row.sd-tree-level-2{background:#fafbfd}:host ::ng-deep tr.c-row.sd-tree-row.sd-tree-level-3{background:#f6f8fb}:host ::ng-deep tr.c-row.sd-tree-row:not(.sd-tree-level-0)>td.sd-tree-toggle-cell .sd-tree-toggle-inner{border-left:1px dashed #d8dde6}:host ::ng-deep .sd-stt-root{font-weight:700;color:#1f2330}\n", ":host ::ng-deep .sticky-shadow-right{overflow:visible!important}:host ::ng-deep .sticky-shadow-right:after{content:\"\";position:absolute;top:0;right:0;bottom:0;width:8px;transform:translate(100%);background:linear-gradient(to right,rgba(0,0,0,.12),transparent);pointer-events:none}:host ::ng-deep .sticky-shadow-left{overflow:visible!important}:host ::ng-deep .sticky-shadow-left:after{content:\"\";position:absolute;top:0;left:0;bottom:0;width:8px;transform:translate(-100%);background:linear-gradient(to left,rgba(0,0,0,.12),transparent);pointer-events:none}\n"] }]
4151
4340
  }], ctorParameters: () => [] });
4152
4341
 
4153
4342
  const SdConvertToPagingReq = (filterRequest, args) => {
@@ -4331,5 +4520,5 @@ const SdConvertToPagingReq = (filterRequest, args) => {
4331
4520
  * Generated bundle index. Do not edit.
4332
4521
  */
4333
4522
 
4334
- export { MatPaginatorIntlCro, SD_TABLE_CONFIGURATION, SdConvertToPagingReq, SdMaterialFooterDefDirective, SdTable, SdTableCellDefDirective, SdTableExpandDefDirective, SdTableFilterDefDirective, SdTableTitleDefDirective };
4523
+ export { MatPaginatorIntlCro, SD_TABLE_CONFIGURATION, SdConvertToPagingReq, SdMaterialFooterDefDirective, SdTable, SdTableCellDefDirective, SdTableExpandDefDirective, SdTableFilterDefDirective, SdTableGroupDefDirective, SdTableTitleDefDirective };
4335
4524
  //# sourceMappingURL=sd-angular-core-components-table.mjs.map