platformcommons-web-lib 1.0.0

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 (208) hide show
  1. package/commons-shared-web-ui-1.0.0.tgz +0 -0
  2. package/documentation/alert.md +123 -0
  3. package/documentation/button-dropdown.md +126 -0
  4. package/documentation/button.md +184 -0
  5. package/documentation/cards-usage-guidelines.md +131 -0
  6. package/documentation/configurable-form.md +605 -0
  7. package/documentation/confirmation-modal.md +250 -0
  8. package/documentation/filter-sidebar.md +178 -0
  9. package/documentation/filter-table-selector.md +228 -0
  10. package/documentation/form-builder.md +597 -0
  11. package/documentation/form-components.md +384 -0
  12. package/documentation/nav.md +427 -0
  13. package/documentation/pagination.md +181 -0
  14. package/documentation/side-nav-documentation.md +169 -0
  15. package/documentation/smart-form.md +2177 -0
  16. package/documentation/smart-table.md +1198 -0
  17. package/documentation/snackbar.md +118 -0
  18. package/documentation/style-externalization.md +88 -0
  19. package/documentation/summary-card.md +279 -0
  20. package/ng-package.json +28 -0
  21. package/package.json +54 -0
  22. package/src/lib/modules/alert/alert.models.ts +6 -0
  23. package/src/lib/modules/alert/alert.module.ts +16 -0
  24. package/src/lib/modules/alert/alert.theme.scss +85 -0
  25. package/src/lib/modules/alert/components/alert/alert.component.html +27 -0
  26. package/src/lib/modules/alert/components/alert/alert.component.scss +92 -0
  27. package/src/lib/modules/alert/components/alert/alert.component.ts +81 -0
  28. package/src/lib/modules/button/button.models.ts +13 -0
  29. package/src/lib/modules/button/button.module.ts +16 -0
  30. package/src/lib/modules/button/button.theme.scss +121 -0
  31. package/src/lib/modules/button/components/button/button.component.html +22 -0
  32. package/src/lib/modules/button/components/button/button.component.scss +88 -0
  33. package/src/lib/modules/button/components/button/button.component.ts +67 -0
  34. package/src/lib/modules/button-dropdown/button-dropdown.models.ts +26 -0
  35. package/src/lib/modules/button-dropdown/button-dropdown.module.ts +22 -0
  36. package/src/lib/modules/button-dropdown/button-dropdown.theme.scss +87 -0
  37. package/src/lib/modules/button-dropdown/components/button-dropdown/button-dropdown.component.html +41 -0
  38. package/src/lib/modules/button-dropdown/components/button-dropdown/button-dropdown.component.scss +135 -0
  39. package/src/lib/modules/button-dropdown/components/button-dropdown/button-dropdown.component.ts +160 -0
  40. package/src/lib/modules/configurable-form/component/configurable-form.component.html +294 -0
  41. package/src/lib/modules/configurable-form/component/configurable-form.component.scss +503 -0
  42. package/src/lib/modules/configurable-form/component/configurable-form.component.ts +628 -0
  43. package/src/lib/modules/configurable-form/configurable-form.examples.ts +154 -0
  44. package/src/lib/modules/configurable-form/configurable-form.model.ts +131 -0
  45. package/src/lib/modules/configurable-form/configurable-form.module.ts +19 -0
  46. package/src/lib/modules/configurable-form/configurable-form.theme.scss +78 -0
  47. package/src/lib/modules/confirmation-modal/components/confirmation-modal/confirmation-modal.component.html +77 -0
  48. package/src/lib/modules/confirmation-modal/components/confirmation-modal/confirmation-modal.component.scss +395 -0
  49. package/src/lib/modules/confirmation-modal/components/confirmation-modal/confirmation-modal.component.ts +266 -0
  50. package/src/lib/modules/confirmation-modal/confirmation-modal.models.ts +71 -0
  51. package/src/lib/modules/confirmation-modal/confirmation-modal.module.ts +20 -0
  52. package/src/lib/modules/confirmation-modal/confirmation-modal.theme.scss +87 -0
  53. package/src/lib/modules/filter/components/filter/filter.component.html +131 -0
  54. package/src/lib/modules/filter/components/filter/filter.component.scss +245 -0
  55. package/src/lib/modules/filter/components/filter/filter.component.ts +216 -0
  56. package/src/lib/modules/filter/filter.models.ts +88 -0
  57. package/src/lib/modules/filter/filter.module.ts +24 -0
  58. package/src/lib/modules/filter/filter.theme.scss +92 -0
  59. package/src/lib/modules/filter-sidebar/components/filter-sidebar/filter-sidebar.component.html +112 -0
  60. package/src/lib/modules/filter-sidebar/components/filter-sidebar/filter-sidebar.component.scss +186 -0
  61. package/src/lib/modules/filter-sidebar/components/filter-sidebar/filter-sidebar.component.ts +163 -0
  62. package/src/lib/modules/filter-sidebar/filter-sidebar.models.ts +95 -0
  63. package/src/lib/modules/filter-sidebar/filter-sidebar.module.ts +24 -0
  64. package/src/lib/modules/filter-sidebar/filter-sidebar.theme.scss +38 -0
  65. package/src/lib/modules/filter-table-selector/components/filter-table-selector/filter-table-selector.component.html +73 -0
  66. package/src/lib/modules/filter-table-selector/components/filter-table-selector/filter-table-selector.component.scss +321 -0
  67. package/src/lib/modules/filter-table-selector/components/filter-table-selector/filter-table-selector.component.ts +361 -0
  68. package/src/lib/modules/filter-table-selector/filter-table-selector.models.ts +91 -0
  69. package/src/lib/modules/filter-table-selector/filter-table-selector.module.ts +22 -0
  70. package/src/lib/modules/filter-table-selector/filter-table-selector.theme.scss +36 -0
  71. package/src/lib/modules/form-builder/components/field-configurator/configurator-config-panel/configurator-config-panel.component.html +63 -0
  72. package/src/lib/modules/form-builder/components/field-configurator/configurator-config-panel/configurator-config-panel.component.scss +496 -0
  73. package/src/lib/modules/form-builder/components/field-configurator/configurator-config-panel/configurator-config-panel.component.ts +445 -0
  74. package/src/lib/modules/form-builder/components/field-configurator/configurator-tree/configurator-tree.component.html +75 -0
  75. package/src/lib/modules/form-builder/components/field-configurator/configurator-tree/configurator-tree.component.scss +210 -0
  76. package/src/lib/modules/form-builder/components/field-configurator/configurator-tree/configurator-tree.component.ts +55 -0
  77. package/src/lib/modules/form-builder/components/field-configurator/field-configurator.component.html +25 -0
  78. package/src/lib/modules/form-builder/components/field-configurator/field-configurator.component.scss +82 -0
  79. package/src/lib/modules/form-builder/components/field-configurator/field-configurator.component.ts +95 -0
  80. package/src/lib/modules/form-builder/components/field-selection/field-selection.component.html +20 -0
  81. package/src/lib/modules/form-builder/components/field-selection/field-selection.component.scss +37 -0
  82. package/src/lib/modules/form-builder/components/field-selection/field-selection.component.ts +94 -0
  83. package/src/lib/modules/form-builder/components/field-selection/group-node/group-node.component.html +46 -0
  84. package/src/lib/modules/form-builder/components/field-selection/group-node/group-node.component.scss +102 -0
  85. package/src/lib/modules/form-builder/components/field-selection/group-node/group-node.component.ts +50 -0
  86. package/src/lib/modules/form-builder/components/field-selection/selection-field-node/selection-field-node.component.html +35 -0
  87. package/src/lib/modules/form-builder/components/field-selection/selection-field-node/selection-field-node.component.scss +67 -0
  88. package/src/lib/modules/form-builder/components/field-selection/selection-field-node/selection-field-node.component.ts +34 -0
  89. package/src/lib/modules/form-builder/components/field-selection/selection-section-node/selection-section-node.component.html +68 -0
  90. package/src/lib/modules/form-builder/components/field-selection/selection-section-node/selection-section-node.component.scss +113 -0
  91. package/src/lib/modules/form-builder/components/field-selection/selection-section-node/selection-section-node.component.ts +74 -0
  92. package/src/lib/modules/form-builder/configs/field-type-schema.map.ts +533 -0
  93. package/src/lib/modules/form-builder/form-builder.module.ts +36 -0
  94. package/src/lib/modules/form-builder/form-builder.theme.scss +212 -0
  95. package/src/lib/modules/form-builder/index.ts +9 -0
  96. package/src/lib/modules/form-builder/models/builder.models.ts +7 -0
  97. package/src/lib/modules/form-builder/models/field-configurator.models.ts +38 -0
  98. package/src/lib/modules/form-builder/models/field-selection.models.ts +51 -0
  99. package/src/lib/modules/form-builder/services/field-configurator.service.ts +258 -0
  100. package/src/lib/modules/form-builder/services/field-selection.service.ts +300 -0
  101. package/src/lib/modules/form-builder/services/form-schema-tree.service.ts +652 -0
  102. package/src/lib/modules/form-builder/tokens/builder.tokens.ts +10 -0
  103. package/src/lib/modules/form-builder/utils/constants.ts +43 -0
  104. package/src/lib/modules/form-components/components/checkbox/_theme.scss +63 -0
  105. package/src/lib/modules/form-components/components/checkbox/checkbox.component.html +29 -0
  106. package/src/lib/modules/form-components/components/checkbox/checkbox.component.scss +111 -0
  107. package/src/lib/modules/form-components/components/checkbox/checkbox.component.ts +207 -0
  108. package/src/lib/modules/form-components/components/checkbox/checkbox.models.ts +35 -0
  109. package/src/lib/modules/form-components/components/datepicker/_theme.scss +82 -0
  110. package/src/lib/modules/form-components/components/datepicker/datepicker.component.html +42 -0
  111. package/src/lib/modules/form-components/components/datepicker/datepicker.component.scss +115 -0
  112. package/src/lib/modules/form-components/components/datepicker/datepicker.component.ts +267 -0
  113. package/src/lib/modules/form-components/components/datepicker/datepicker.models.ts +45 -0
  114. package/src/lib/modules/form-components/components/dropdown/_theme.scss +91 -0
  115. package/src/lib/modules/form-components/components/dropdown/dropdown.component.html +74 -0
  116. package/src/lib/modules/form-components/components/dropdown/dropdown.component.scss +252 -0
  117. package/src/lib/modules/form-components/components/dropdown/dropdown.component.ts +377 -0
  118. package/src/lib/modules/form-components/components/dropdown/dropdown.models.ts +53 -0
  119. package/src/lib/modules/form-components/components/input/_theme.scss +77 -0
  120. package/src/lib/modules/form-components/components/input/input.component.html +51 -0
  121. package/src/lib/modules/form-components/components/input/input.component.scss +128 -0
  122. package/src/lib/modules/form-components/components/input/input.component.ts +250 -0
  123. package/src/lib/modules/form-components/components/input/input.models.ts +55 -0
  124. package/src/lib/modules/form-components/components/radio/_theme.scss +61 -0
  125. package/src/lib/modules/form-components/components/radio/radio.component.html +22 -0
  126. package/src/lib/modules/form-components/components/radio/radio.component.scss +107 -0
  127. package/src/lib/modules/form-components/components/radio/radio.component.ts +181 -0
  128. package/src/lib/modules/form-components/components/radio/radio.models.ts +39 -0
  129. package/src/lib/modules/form-components/components/search/_theme.scss +73 -0
  130. package/src/lib/modules/form-components/components/search/search.component.html +15 -0
  131. package/src/lib/modules/form-components/components/search/search.component.scss +87 -0
  132. package/src/lib/modules/form-components/components/search/search.component.ts +213 -0
  133. package/src/lib/modules/form-components/components/search/search.models.ts +40 -0
  134. package/src/lib/modules/form-components/components/toggle/_theme.scss +45 -0
  135. package/src/lib/modules/form-components/components/toggle/toggle.component.html +15 -0
  136. package/src/lib/modules/form-components/components/toggle/toggle.component.scss +81 -0
  137. package/src/lib/modules/form-components/components/toggle/toggle.component.ts +166 -0
  138. package/src/lib/modules/form-components/components/toggle/toggle.models.ts +27 -0
  139. package/src/lib/modules/form-components/directives/click-outside.directive.ts +22 -0
  140. package/src/lib/modules/form-components/form-components.module.ts +41 -0
  141. package/src/lib/modules/form-components/form-components.theme.scss +25 -0
  142. package/src/lib/modules/material/material.module.ts +94 -0
  143. package/src/lib/modules/nav/components/nav/nav.component.html +34 -0
  144. package/src/lib/modules/nav/components/nav/nav.component.scss +171 -0
  145. package/src/lib/modules/nav/components/nav/nav.component.ts +82 -0
  146. package/src/lib/modules/nav/nav.models.ts +31 -0
  147. package/src/lib/modules/nav/nav.module.ts +17 -0
  148. package/src/lib/modules/nav/nav.theme.scss +86 -0
  149. package/src/lib/modules/pagination/components/pagination/pagination.component.html +52 -0
  150. package/src/lib/modules/pagination/components/pagination/pagination.component.scss +155 -0
  151. package/src/lib/modules/pagination/components/pagination/pagination.component.ts +109 -0
  152. package/src/lib/modules/pagination/pagination.module.ts +17 -0
  153. package/src/lib/modules/pagination/pagination.theme.scss +66 -0
  154. package/src/lib/modules/side-nav/components/side-nav/side-nav.component.html +56 -0
  155. package/src/lib/modules/side-nav/components/side-nav/side-nav.component.scss +342 -0
  156. package/src/lib/modules/side-nav/components/side-nav/side-nav.component.ts +135 -0
  157. package/src/lib/modules/side-nav/side-nav.models.ts +38 -0
  158. package/src/lib/modules/side-nav/side-nav.module.ts +16 -0
  159. package/src/lib/modules/side-nav/side-nav.theme.scss +111 -0
  160. package/src/lib/modules/smart-form/components/form-field/form-field.component.html +1109 -0
  161. package/src/lib/modules/smart-form/components/form-field/form-field.component.scss +1860 -0
  162. package/src/lib/modules/smart-form/components/form-field/form-field.component.ts +2232 -0
  163. package/src/lib/modules/smart-form/components/form-section/form-section.component.html +64 -0
  164. package/src/lib/modules/smart-form/components/form-section/form-section.component.scss +209 -0
  165. package/src/lib/modules/smart-form/components/form-section/form-section.component.ts +119 -0
  166. package/src/lib/modules/smart-form/components/smart-form/smart-form.component.html +253 -0
  167. package/src/lib/modules/smart-form/components/smart-form/smart-form.component.scss +689 -0
  168. package/src/lib/modules/smart-form/components/smart-form/smart-form.component.ts +1087 -0
  169. package/src/lib/modules/smart-form/index.ts +10 -0
  170. package/src/lib/modules/smart-form/models/form-schema.model.ts +700 -0
  171. package/src/lib/modules/smart-form/models/hierarchy-config.model.ts +21 -0
  172. package/src/lib/modules/smart-form/services/expression.service.ts +75 -0
  173. package/src/lib/modules/smart-form/services/smart-form-controller.service.ts +65 -0
  174. package/src/lib/modules/smart-form/smart-form.examples.ts +1324 -0
  175. package/src/lib/modules/smart-form/smart-form.module.ts +36 -0
  176. package/src/lib/modules/smart-form/smart-form.theme.scss +890 -0
  177. package/src/lib/modules/smart-form/utils/translation.utils.ts +82 -0
  178. package/src/lib/modules/smart-form/utils/trusted-url.pipe.ts +25 -0
  179. package/src/lib/modules/smart-form/utils/validation.utils.ts +98 -0
  180. package/src/lib/modules/smart-table/components/smart-table/smart-table.component.html +283 -0
  181. package/src/lib/modules/smart-table/components/smart-table/smart-table.component.scss +685 -0
  182. package/src/lib/modules/smart-table/components/smart-table/smart-table.component.ts +1118 -0
  183. package/src/lib/modules/smart-table/models/table-config.model.ts +202 -0
  184. package/src/lib/modules/smart-table/smart-table.module.ts +30 -0
  185. package/src/lib/modules/smart-table/smart-table.theme.scss +335 -0
  186. package/src/lib/modules/smart-table/utils/safe-html.pipe.ts +22 -0
  187. package/src/lib/modules/smart-table/utils/smart-table.utils.ts +18 -0
  188. package/src/lib/modules/snackbar/components/snackbar.component.html +41 -0
  189. package/src/lib/modules/snackbar/components/snackbar.component.scss +99 -0
  190. package/src/lib/modules/snackbar/components/snackbar.component.ts +18 -0
  191. package/src/lib/modules/snackbar/models/snackbar.models.ts +10 -0
  192. package/src/lib/modules/snackbar/services/snackbar.service.ts +40 -0
  193. package/src/lib/modules/snackbar/snackbar.module.ts +11 -0
  194. package/src/lib/modules/snackbar/snackbar.theme.scss +93 -0
  195. package/src/lib/modules/summary-card/components/summary-card/summary-card.component.html +47 -0
  196. package/src/lib/modules/summary-card/components/summary-card/summary-card.component.scss +199 -0
  197. package/src/lib/modules/summary-card/components/summary-card/summary-card.component.ts +126 -0
  198. package/src/lib/modules/summary-card/summary-card.module.ts +18 -0
  199. package/src/lib/modules/summary-card/summary-card.theme.scss +176 -0
  200. package/src/lib/shared-ui.module.ts +44 -0
  201. package/src/lib/styles/global.scss +152 -0
  202. package/src/lib/styles/utilities.scss +250 -0
  203. package/src/lib/utils/constants.ts +11 -0
  204. package/src/lib/utils/storage.utils.ts +37 -0
  205. package/src/lib/utils/string.utils.ts +23 -0
  206. package/src/lib/utils/translation.utils.ts +87 -0
  207. package/src/public-api.ts +104 -0
  208. package/tsconfig.lib.json +15 -0
@@ -0,0 +1,321 @@
1
+ // ─────────────────────────────────────────────────────────────────────────────
2
+ // FilterTableSelector — Layout SCSS
3
+ //
4
+ // Layout goal:
5
+ // [host] fills the modal-body (flex child of cc-modal-container)
6
+ // └── .fts-container flex-column, clips overflow
7
+ // ├── .fts-header flex-shrink:0
8
+ // ├── .fts-body flex:1, min-height:0 ← the scroll zone
9
+ // │ ├── .fts-filter-panel fixed width, scrolls independently
10
+ // │ │ └── .__content flex:1, overflow-y:auto
11
+ // │ └── .fts-table-panel flex:1, clips inner table
12
+ // │ └── .fts-table-wrapper → st-table-container scrolls
13
+ // └── .fts-footer flex-shrink:0 ← always visible
14
+ // ─────────────────────────────────────────────────────────────────────────────
15
+
16
+ :host {
17
+ // CSS custom properties
18
+ --fts-panel-bg: #ffffff;
19
+ --fts-filter-panel-width: 300px;
20
+ --fts-filter-panel-border: 1px solid #dee2e6;
21
+ --fts-header-bg: #ffffff;
22
+ --fts-header-border: 1px solid #f1f3f4;
23
+ --fts-header-height: 60px;
24
+ --fts-header-padding: 0 24px;
25
+ --fts-header-title-color: #111827;
26
+ --fts-header-title-font-size: 1.125rem;
27
+ --fts-header-title-font-weight: 600;
28
+ --fts-footer-bg: #ffffff;
29
+ --fts-footer-border: 1px solid #f1f3f4;
30
+ --fts-footer-height: 72px;
31
+ --fts-footer-padding: 0 24px;
32
+ --fts-footer-gap: 12px;
33
+ --fts-body-bg: #ffffff;
34
+ --fts-filter-section-title-color: var(--text-muted, #6b7280);
35
+ --fts-filter-section-title-font-size: 0.75rem;
36
+ --fts-filter-section-title-font-weight: 600;
37
+ --fts-selection-count-color: var(--text-muted, #6b7280);
38
+ --fts-selection-count-font-size: 0.875rem;
39
+ --fts-toolbar-border: 1px solid #f1f3f4;
40
+ --fts-divider-color: #f1f3f4;
41
+ --fts-shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
42
+ --fts-border-radius: 12px;
43
+
44
+ // Host must stretch to fill the flex modal body
45
+ display: flex;
46
+ flex-direction: column;
47
+ flex: 1;
48
+ min-height: 0;
49
+ width: 100%;
50
+ }
51
+
52
+ // ── Container ─────────────────────────────────────────────────────────────────
53
+ .fts-container {
54
+ display: flex;
55
+ flex-direction: column;
56
+ flex: 1;
57
+ min-height: 0; // Lets children shrink so scrolling activates
58
+ width: 100%;
59
+ overflow: hidden; // Must clip — prevents container from growing to content
60
+ background-color: var(--fts-panel-bg);
61
+ border: 1px solid var(--border-color, #e0e0e0);
62
+ border-radius: var(--fts-border-radius);
63
+ box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
64
+ }
65
+
66
+ // ── Optional Title Header ──────────────────────────────────────────────────────
67
+ .fts-header {
68
+ display: flex;
69
+ align-items: center;
70
+ min-height: var(--fts-header-height);
71
+ padding: var(--fts-header-padding);
72
+ border-bottom: var(--fts-header-border);
73
+ background-color: var(--fts-header-bg);
74
+ flex-shrink: 0; // Never shrinks
75
+
76
+ &__title {
77
+ margin: 0;
78
+ font-size: var(--fts-header-title-font-size);
79
+ font-weight: var(--fts-header-title-font-weight);
80
+ color: var(--fts-header-title-color);
81
+ letter-spacing: -0.01em;
82
+ }
83
+ }
84
+
85
+ // ── Body: side-by-side panels ─────────────────────────────────────────────────
86
+ .fts-body {
87
+ display: flex;
88
+ flex: 1;
89
+ min-height: 0; // Critical: prevents body from expanding past container
90
+ background-color: var(--fts-body-bg);
91
+ // No overflow on body itself — each child panel manages its own scroll
92
+ }
93
+
94
+ // ── Left: Filter Panel ────────────────────────────────────────────────────────
95
+ .fts-filter-panel {
96
+ width: var(--fts-filter-panel-width);
97
+ min-width: var(--fts-filter-panel-width);
98
+ display: flex;
99
+ flex-direction: column;
100
+ overflow: hidden; // Panel itself clips; __content handles the scroll
101
+ background-color: #fcfcfd;
102
+ border-right: 1px solid var(--fts-divider-color);
103
+
104
+ &--hidden {
105
+ display: none;
106
+ }
107
+
108
+ &__header {
109
+ padding: 20px 20px 12px 20px;
110
+ flex-shrink: 0;
111
+ }
112
+
113
+ &__title {
114
+ font-size: var(--fts-filter-section-title-font-size);
115
+ font-weight: var(--fts-filter-section-title-font-weight);
116
+ color: var(--fts-filter-section-title-color);
117
+ text-transform: uppercase;
118
+ letter-spacing: 0.05em;
119
+ }
120
+
121
+ // This is the scrolling region — grows to fill panel, scrolls on overflow
122
+ &__content {
123
+ flex: 1;
124
+ min-height: 0; // Allows this flex child to shrink & scroll
125
+ overflow-y: auto;
126
+ padding: 0;
127
+
128
+ &::-webkit-scrollbar {
129
+ width: 4px;
130
+ }
131
+
132
+ &::-webkit-scrollbar-thumb {
133
+ background: #d1d5db;
134
+ border-radius: 10px;
135
+ }
136
+ }
137
+
138
+ // SmartForm overrides (scoped to filter panel only)
139
+ ::ng-deep {
140
+
141
+ .smart-form-container,
142
+ .smart-form-wrapper {
143
+ padding: 0;
144
+ }
145
+
146
+ .form-header,
147
+ .form-actions {
148
+ display: none;
149
+ }
150
+
151
+ .form-section {
152
+ padding: 0;
153
+ }
154
+
155
+ .form-field-wrapper {
156
+ margin-bottom: 16px;
157
+
158
+ &:last-child {
159
+ margin-bottom: 0;
160
+ }
161
+ }
162
+
163
+ .field-label {
164
+ font-size: 12px;
165
+ font-weight: 500;
166
+ color: #374151;
167
+ margin-bottom: 4px;
168
+ }
169
+
170
+ input,
171
+ select,
172
+ .mat-select-trigger {
173
+ font-size: 13px !important;
174
+ border-color: #e5e7eb !important;
175
+ background-color: #ffffff !important;
176
+
177
+ &:focus {
178
+ border-color: var(--primary-color) !important;
179
+ box-shadow: 0 0 0 2px rgba(194, 30, 37, 0.05) !important;
180
+ }
181
+ }
182
+ }
183
+ }
184
+
185
+
186
+ // Override the 12-col grid gap — tight layout for the narrow filter panel
187
+ .form-section-container .section-fields.sf-grid {
188
+ gap: 2px !important;
189
+ }
190
+
191
+ // ── Right: Table Panel ────────────────────────────────────────────────────────
192
+ .fts-table-panel {
193
+ flex: 1;
194
+ min-width: 0; // Prevents horizontal overflow
195
+ display: flex;
196
+ flex-direction: column;
197
+ overflow: hidden; // Clips; inner st-table-container does the scroll
198
+ background-color: var(--fts-panel-bg);
199
+
200
+ &__toolbar {
201
+ display: flex;
202
+ align-items: center;
203
+ justify-content: flex-end;
204
+ flex-shrink: 0;
205
+ min-height: 48px;
206
+ padding: 0 24px;
207
+ background-color: var(--fts-panel-bg);
208
+ }
209
+ }
210
+
211
+ .fts-table-wrapper {
212
+ flex: 1;
213
+ min-height: 0; // Flex child must have min-height:0 to allow scroll
214
+ display: flex;
215
+ flex-direction: column;
216
+ // overflow: hidden;
217
+ overflow-y: auto;
218
+
219
+ ::ng-deep {
220
+
221
+ // Root outer — must be a flex column that fills the wrapper
222
+ .smart-table-outer {
223
+ flex: 1;
224
+ min-height: 0;
225
+ display: flex;
226
+ flex-direction: column;
227
+ overflow: hidden;
228
+ }
229
+
230
+ // Card — grows to fill remaining space, clips so table scrolls inside
231
+ .smart-table-wrapper {
232
+ flex: 1;
233
+ min-height: 0;
234
+ display: flex;
235
+ flex-direction: column;
236
+ overflow: hidden;
237
+ }
238
+
239
+ // The actual table scroll area.
240
+ // SmartTable hardcodes overflow-y:visible, so !important is required.
241
+ .st-table-container {
242
+ flex: 1;
243
+ min-height: 0;
244
+ overflow-x: auto;
245
+ overflow-y: auto !important; // Override SmartTable's own overflow-y:visible
246
+
247
+ &::-webkit-scrollbar {
248
+ width: 6px;
249
+ }
250
+
251
+ &::-webkit-scrollbar-thumb {
252
+ background: #d1d5db;
253
+ border-radius: 3px;
254
+ }
255
+ }
256
+
257
+ // Pagination sits outside .smart-table-wrapper — keep it pinned at bottom
258
+ .st-pagination {
259
+ flex-shrink: 0;
260
+ padding: 12px 24px;
261
+ border-top: 1px solid var(--fts-divider-color);
262
+ background-color: var(--fts-panel-bg);
263
+ }
264
+ }
265
+ }
266
+
267
+ // ── Selection Count Pill ──────────────────────────────────────────────────────
268
+ .fts-selection-count {
269
+ font-size: 13px;
270
+ color: #4b5563;
271
+ white-space: nowrap;
272
+ background: #f3f4f6;
273
+ padding: 4px 14px;
274
+ border-radius: 100px;
275
+ font-weight: 500;
276
+ border: 1px solid #e5e7eb;
277
+ }
278
+
279
+ // ── Footer: always visible at bottom ─────────────────────────────────────────
280
+ .fts-footer {
281
+ display: flex;
282
+ align-items: center;
283
+ justify-content: space-between;
284
+ min-height: var(--fts-footer-height);
285
+ padding: var(--fts-footer-padding);
286
+ border-top: var(--fts-footer-border);
287
+ flex-shrink: 0; // Never shrinks — always visible at the bottom
288
+ background-color: var(--fts-footer-bg);
289
+ box-shadow: 0 -4px 12px rgba(0, 0, 0, 0.05);
290
+ z-index: 10;
291
+
292
+ &__left,
293
+ &__right {
294
+ display: flex;
295
+ align-items: center;
296
+ gap: var(--fts-footer-gap);
297
+ }
298
+
299
+ ::ng-deep lib-button button {
300
+ min-width: 100px;
301
+ font-weight: 500;
302
+ letter-spacing: 0.01em;
303
+ }
304
+ }
305
+
306
+ // ── Modal Integration ─────────────────────────────────────────────────────────
307
+ // Makes the cc-modal-body behave as a flex column so :host can fill it fully.
308
+ // Without this the body grows to content height and our overflow clips nothing.
309
+ ::ng-deep {
310
+ .cc-modal-footer {
311
+ display: none !important;
312
+ }
313
+
314
+ .cc-modal-body:has(lib-filter-table-selector) {
315
+ padding: 0 !important;
316
+ overflow: hidden !important;
317
+ display: flex !important;
318
+ flex-direction: column !important;
319
+ // flex:1 is already set by confirmation-modal — no height:100% needed
320
+ }
321
+ }
@@ -0,0 +1,361 @@
1
+ import {
2
+ Component,
3
+ Input,
4
+ Output,
5
+ EventEmitter,
6
+ OnInit,
7
+ OnChanges,
8
+ SimpleChanges,
9
+ OnDestroy,
10
+ ChangeDetectorRef,
11
+ NgZone,
12
+ } from '@angular/core';
13
+ import { Subject } from 'rxjs';
14
+
15
+ import {
16
+ FilterTableSelectorConfig,
17
+ FilterParamMap,
18
+ } from '../../filter-table-selector.models';
19
+ import { FilterTableConfig } from '../../filter-table-selector.models';
20
+
21
+ @Component({
22
+ selector: 'lib-filter-table-selector',
23
+ templateUrl: './filter-table-selector.component.html',
24
+ styleUrls: ['./filter-table-selector.component.scss'],
25
+ standalone: false,
26
+ })
27
+ export class FilterTableSelectorComponent implements OnInit, OnChanges, OnDestroy {
28
+ /** Full config object driven by consuming MFE JSON. */
29
+ @Input() config!: FilterTableSelectorConfig;
30
+
31
+ /**
32
+ * Flat i18n labels map from the consuming MFE.
33
+ * Mirrors the pattern used by SmartFormComponent.
34
+ */
35
+ @Input() labels: Record<string, string> = {};
36
+
37
+ /**
38
+ * Pre-selected row identifiers.
39
+ * When provided, matching rows are pre-checked on first load and
40
+ * re-checked after each page navigation.
41
+ * Must be an array of row objects (the same shape returned by the API).
42
+ */
43
+ @Input() preSelectedRows: any[] = [];
44
+
45
+ /** Emits the array of currently selected row objects on "Add / Submit". */
46
+ @Output() onSubmit = new EventEmitter<any[]>();
47
+
48
+ /** Emits void on "Back / Cancel". */
49
+ @Output() onCancel = new EventEmitter<void>();
50
+
51
+ // ── Internal state ──────────────────────────────────────────────────────────
52
+
53
+ /** A deep-copy of tableConfig with the current filter params baked-in. */
54
+ resolvedTableConfig!: FilterTableConfig;
55
+
56
+ /** Current active filter params (merged from form submission). */
57
+ activeFilterParams: Record<string, string> = {};
58
+
59
+ /** The base API URL without any filter query params. */
60
+ private baseApiUrl: string = '';
61
+
62
+ /** All rows selected so far, tracked across pagination pages. */
63
+ selectedRows: any[] = [];
64
+
65
+ /** Total rows currently loaded in the table (reported by SmartTable rowSelect). */
66
+ totalTableItems: number = 0;
67
+
68
+ /** Serialised SmartForm JSON (with labels translated + disabled fields applied). */
69
+ resolvedFormJson: string = '';
70
+
71
+ /**
72
+ * Default values to prefill the SmartForm.
73
+ * Updated on each initialize() call and reset to config defaults on Clear Filter.
74
+ */
75
+ resolvedInitialValues: Record<string, any> = {};
76
+
77
+ /**
78
+ * Version counter — bumping this forces *ngIf to re-create the SmartForm
79
+ * component with fresh initial values (used by Clear Filter).
80
+ */
81
+ formVersion: number = 0;
82
+
83
+ /** Whether the filter panel is visible (toggled on mobile, always visible on desktop). */
84
+ filterPanelVisible: boolean = true;
85
+
86
+ /**
87
+ * Tracks the live form values as the user changes fields.
88
+ * Updated via SmartForm's (valueChange) output.
89
+ * Used when the user clicks the "Apply Filter" button in the component.
90
+ */
91
+ currentFormValues: Record<string, any> = {};
92
+
93
+ private destroy$ = new Subject<void>();
94
+
95
+ constructor(private cdr: ChangeDetectorRef, private ngZone: NgZone) { }
96
+
97
+ // ── Lifecycle ────────────────────────────────────────────────────────────────
98
+
99
+ ngOnInit(): void {
100
+ this.initialize();
101
+ }
102
+
103
+ ngOnChanges(changes: SimpleChanges): void {
104
+ if (changes['config'] && !changes['config'].isFirstChange()) {
105
+ this.initialize();
106
+ }
107
+ if (changes['preSelectedRows'] && !changes['preSelectedRows'].isFirstChange()) {
108
+ this.syncPreselection();
109
+ }
110
+ if (changes['labels'] && !changes['labels'].isFirstChange()) {
111
+ this.buildFormJson();
112
+ this.applyFilterParamsToTable();
113
+ }
114
+ }
115
+
116
+ ngOnDestroy(): void {
117
+ this.destroy$.next();
118
+ this.destroy$.complete();
119
+ }
120
+
121
+ // ── Initialisation ───────────────────────────────────────────────────────────
122
+
123
+ private initialize(): void {
124
+ if (!this.config) return;
125
+
126
+ this.baseApiUrl = this.config.tableConfig.apiUrl || '';
127
+ this.selectedRows = [...(this.preSelectedRows || [])];
128
+
129
+ const defaults = this.config.filterConfig.defaultValues || {};
130
+
131
+ // Build default filter params from defaultValues for the initial API call
132
+ this.activeFilterParams = this.buildFilterParams(defaults);
133
+
134
+ // Synchronize currentFormValues so Apply Filter works even if no changes are made yet
135
+ this.currentFormValues = { ...defaults };
136
+
137
+ this.buildFormJson();
138
+ this.applyFilterParamsToTable();
139
+
140
+ // Bump version to force SmartForm re-creation with the new defaultValues
141
+ this.formVersion++;
142
+ }
143
+
144
+ // ── Form JSON construction ───────────────────────────────────────────────────
145
+
146
+ /**
147
+ * Serialises the SmartForm config JSON.
148
+ * Applies disabledFields from filterPanelConfig.
149
+ */
150
+ private buildFormJson(overrideValues?: Record<string, any>): void {
151
+ if (!this.config?.filterConfig?.smartFormConfig) return;
152
+
153
+ // Deep-clone to avoid mutating the original config
154
+ const schema = JSON.parse(
155
+ JSON.stringify(this.config.filterConfig.smartFormConfig)
156
+ );
157
+
158
+ // Apply disabled fields and TRANSLATE LABELS
159
+ const disabled = this.config.filterConfig.disabledFields || [];
160
+ if (schema.sectionConfig?.children) {
161
+ schema.sectionConfig.children = schema.sectionConfig.children.map(
162
+ (field: any) => {
163
+ // Translate label and placeholder
164
+ if (field.label) field.label = this.translate(field.label);
165
+ if (field.placeholder) field.placeholder = this.translate(field.placeholder);
166
+
167
+ if (disabled.includes(field.name)) {
168
+ return { ...field, disabled: true };
169
+ }
170
+ return field;
171
+ }
172
+ );
173
+ }
174
+
175
+ this.resolvedFormJson = JSON.stringify(schema);
176
+
177
+ // Use override (e.g. after clear) or fall back to config defaults
178
+ const values = overrideValues !== undefined
179
+ ? overrideValues
180
+ : { ...(this.config.filterConfig.defaultValues || {}) };
181
+ this.resolvedInitialValues = values;
182
+ }
183
+
184
+ // ── Table URL resolution ─────────────────────────────────────────────────────
185
+
186
+ /**
187
+ * Rebuilds resolvedTableConfig with the current activeFilterParams appended
188
+ * to the base API URL.
189
+ */
190
+ private applyFilterParamsToTable(): void {
191
+ const paramString = Object.entries(this.activeFilterParams)
192
+ .filter(([, v]) => v !== null && v !== undefined && v !== '')
193
+ .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`)
194
+ .join('&');
195
+
196
+ const separator = this.baseApiUrl.includes('?') ? '&' : '?';
197
+ const newUrl = paramString
198
+ ? `${this.baseApiUrl}${separator}${paramString}`
199
+ : this.baseApiUrl;
200
+
201
+ // Translate Column Labels
202
+ const translatedColumns = (this.config.tableConfig.columns || []).map(col => ({
203
+ ...col,
204
+ label: this.translate(col.label)
205
+ }));
206
+
207
+ // Assign a new object reference so SmartTable's ngOnChanges fires
208
+ this.resolvedTableConfig = {
209
+ ...this.config.tableConfig,
210
+ columns: translatedColumns,
211
+ apiUrl: newUrl,
212
+ selectable: true,
213
+ multiSelect: this.config.selectionConfig.multiSelect,
214
+ };
215
+ }
216
+
217
+ // ── Filter param helpers ─────────────────────────────────────────────────────
218
+
219
+ /**
220
+ * Converts a flat form-value map to API param key/value pairs
221
+ * using the configured filterParamMapping.
222
+ */
223
+ private buildFilterParams(
224
+ formValues: Record<string, any>
225
+ ): Record<string, string> {
226
+ const mapping = this.config.filterConfig.filterParamMapping || [];
227
+ const params: Record<string, string> = {};
228
+
229
+ mapping.forEach((map: FilterParamMap) => {
230
+ const rawVal = formValues[map.formFieldName];
231
+ if (rawVal !== null && rawVal !== undefined && rawVal !== '') {
232
+ // Support arrays (multiselect) → comma-separated
233
+ const val = Array.isArray(rawVal) ? rawVal.join(',') : String(rawVal);
234
+ params[map.apiParamKey] = val;
235
+ }
236
+ });
237
+
238
+ return params;
239
+ }
240
+
241
+ // ── SmartForm event handlers ─────────────────────────────────────────────────
242
+
243
+ /**
244
+ * Called every time a form field value changes (SmartForm valueChange output).
245
+ * We track the current values so the component-level "Apply Filter" button
246
+ * can read them without relying on a form submit button inside the JSON config.
247
+ */
248
+ onFormValueChange(values: Record<string, any>): void {
249
+ this.currentFormValues = values || {};
250
+ }
251
+
252
+ /**
253
+ * Called when the user clicks the "Apply Filter" button rendered by the component.
254
+ * Builds API params from the tracked form values and reloads the table.
255
+ */
256
+ applyCurrentFilter(): void {
257
+ this.activeFilterParams = this.buildFilterParams(this.currentFormValues);
258
+ this.applyFilterParamsToTable();
259
+ }
260
+
261
+ /**
262
+ * Clear Filter: resets form to default values (preserving disabled-field values),
263
+ * reloads the table with default params.
264
+ * The form is re-created via formVersion bump so SmartForm gets fresh initialValues.
265
+ */
266
+ onClearFilter(): void {
267
+ const defaults = this.config.filterConfig.defaultValues || {};
268
+ const disabled = this.config.filterConfig.disabledFields || [];
269
+
270
+ // Build reset values: keep default values for disabled fields, clear the rest
271
+ const resetValues: Record<string, any> = {};
272
+ disabled.forEach(fieldName => {
273
+ if (defaults[fieldName] !== undefined) {
274
+ resetValues[fieldName] = defaults[fieldName];
275
+ }
276
+ });
277
+
278
+ this.currentFormValues = { ...resetValues };
279
+ this.activeFilterParams = this.buildFilterParams(resetValues);
280
+
281
+ // Destroy and recreate SmartForm with clean initial values
282
+ this.resolvedFormJson = '';
283
+ this.formVersion++;
284
+
285
+ // Use NgZone + setTimeout to ensure the *ngIf toggles in one tick, then re-renders
286
+ this.ngZone.run(() => {
287
+ setTimeout(() => {
288
+ this.buildFormJson(resetValues);
289
+ this.applyFilterParamsToTable();
290
+ }, 0);
291
+ });
292
+ }
293
+
294
+ // ── SmartTable event handlers ────────────────────────────────────────────────
295
+
296
+ /**
297
+ * Called by SmartTable's (rowSelect) output.
298
+ * Merges page-level selection with the cross-page tracking set.
299
+ */
300
+ onRowSelect(globalSelection: any[]): void {
301
+ this.selectedRows = globalSelection || [];
302
+ }
303
+
304
+ /**
305
+ * Syncs preSelectedRows into the local selectedRows (called when input changes).
306
+ */
307
+ private syncPreselection(): void {
308
+ this.selectedRows = [...(this.preSelectedRows || [])];
309
+ }
310
+
311
+ // ── Action handlers ──────────────────────────────────────────────────────────
312
+
313
+ handleSubmit(): void {
314
+ this.onSubmit.emit([...this.selectedRows]);
315
+ }
316
+
317
+ handleCancel(): void {
318
+ this.onCancel.emit();
319
+ }
320
+
321
+ // ── Label helpers ─────────────────────────────────────────────────────────────
322
+
323
+ translate(key: string): string {
324
+ return this.labels[key] || key;
325
+ }
326
+
327
+ get titleLabel(): string {
328
+ return this.translate(this.config?.title || '');
329
+ }
330
+
331
+ get submitButtonLabel(): string {
332
+ return this.translate(this.config?.selectionConfig?.submitButtonLabel || '');
333
+ }
334
+
335
+ get cancelButtonLabel(): string {
336
+ return this.translate(this.config?.selectionConfig?.cancelButtonLabel || '');
337
+ }
338
+
339
+ get clearFilterButtonLabel(): string {
340
+ const key = this.config?.filterConfig?.clearFilterLabel || 'COMMON.FILTER_TABLE.CLEAR_FILTER';
341
+ return this.translate(key) || 'Clear Filter';
342
+ }
343
+
344
+ get applyFilterButtonLabel(): string {
345
+ const key = this.config?.filterConfig?.applyFilterLabel || 'COMMON.FILTER_TABLE.APPLY_FILTER';
346
+ return this.translate(key) || 'Apply Filter';
347
+ }
348
+
349
+ get selectionCountText(): string {
350
+ if (!this.config?.selectionConfig?.selectionCountLabel) return '';
351
+ const raw = this.translate(this.config.selectionConfig.selectionCountLabel);
352
+ return raw
353
+ .replace('{selected}', String(this.selectedRows.length))
354
+ .replace('{total}', String(this.totalTableItems));
355
+ }
356
+
357
+ get hasActiveFilters(): boolean {
358
+ return Object.keys(this.activeFilterParams).length > 0;
359
+ }
360
+
361
+ }