commons-shared-web-ui 0.0.55 → 0.0.57

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 (223) hide show
  1. package/fesm2022/commons-shared-web-ui.mjs +15897 -0
  2. package/fesm2022/commons-shared-web-ui.mjs.map +1 -0
  3. package/index.d.ts +4916 -0
  4. package/package.json +34 -53
  5. package/src/lib/modules/button/button.theme.scss +4 -4
  6. package/.claude/settings.local.json +0 -10
  7. package/documentation/alert.md +0 -123
  8. package/documentation/button-dropdown.md +0 -126
  9. package/documentation/button.md +0 -184
  10. package/documentation/cards-usage-guidelines.md +0 -131
  11. package/documentation/configurable-form.md +0 -605
  12. package/documentation/confirmation-modal.md +0 -250
  13. package/documentation/filter-sidebar.md +0 -178
  14. package/documentation/filter-table-selector.md +0 -228
  15. package/documentation/form-builder.md +0 -599
  16. package/documentation/form-components.md +0 -384
  17. package/documentation/form-field-configuration.md +0 -250
  18. package/documentation/nav.md +0 -427
  19. package/documentation/pagination.md +0 -181
  20. package/documentation/side-nav-documentation.md +0 -169
  21. package/documentation/smart-form.md +0 -2765
  22. package/documentation/smart-table.md +0 -1221
  23. package/documentation/snackbar.md +0 -118
  24. package/documentation/style-externalization.md +0 -88
  25. package/documentation/summary-card.md +0 -279
  26. package/documentation/table-column-configuration.md +0 -221
  27. package/documentation/time-picker.md +0 -274
  28. package/ng-package.json +0 -30
  29. package/src/lib/modules/alert/alert.models.ts +0 -6
  30. package/src/lib/modules/alert/alert.module.ts +0 -16
  31. package/src/lib/modules/alert/components/alert/alert.component.html +0 -27
  32. package/src/lib/modules/alert/components/alert/alert.component.scss +0 -92
  33. package/src/lib/modules/alert/components/alert/alert.component.ts +0 -81
  34. package/src/lib/modules/button/button.models.ts +0 -13
  35. package/src/lib/modules/button/button.module.ts +0 -16
  36. package/src/lib/modules/button/components/button/button.component.html +0 -22
  37. package/src/lib/modules/button/components/button/button.component.scss +0 -88
  38. package/src/lib/modules/button/components/button/button.component.ts +0 -67
  39. package/src/lib/modules/button-dropdown/button-dropdown.models.ts +0 -26
  40. package/src/lib/modules/button-dropdown/button-dropdown.module.ts +0 -22
  41. package/src/lib/modules/button-dropdown/components/button-dropdown/button-dropdown.component.html +0 -41
  42. package/src/lib/modules/button-dropdown/components/button-dropdown/button-dropdown.component.scss +0 -135
  43. package/src/lib/modules/button-dropdown/components/button-dropdown/button-dropdown.component.ts +0 -160
  44. package/src/lib/modules/configurable-form/component/configurable-form.component.html +0 -294
  45. package/src/lib/modules/configurable-form/component/configurable-form.component.scss +0 -503
  46. package/src/lib/modules/configurable-form/component/configurable-form.component.ts +0 -628
  47. package/src/lib/modules/configurable-form/configurable-form.examples.ts +0 -154
  48. package/src/lib/modules/configurable-form/configurable-form.model.ts +0 -131
  49. package/src/lib/modules/configurable-form/configurable-form.module.ts +0 -19
  50. package/src/lib/modules/confirmation-modal/components/confirmation-modal/confirmation-modal.component.html +0 -77
  51. package/src/lib/modules/confirmation-modal/components/confirmation-modal/confirmation-modal.component.scss +0 -395
  52. package/src/lib/modules/confirmation-modal/components/confirmation-modal/confirmation-modal.component.ts +0 -266
  53. package/src/lib/modules/confirmation-modal/confirmation-modal.models.ts +0 -71
  54. package/src/lib/modules/confirmation-modal/confirmation-modal.module.ts +0 -20
  55. package/src/lib/modules/filter/components/filter/filter.component.html +0 -131
  56. package/src/lib/modules/filter/components/filter/filter.component.scss +0 -245
  57. package/src/lib/modules/filter/components/filter/filter.component.ts +0 -216
  58. package/src/lib/modules/filter/filter.models.ts +0 -88
  59. package/src/lib/modules/filter/filter.module.ts +0 -24
  60. package/src/lib/modules/filter-sidebar/components/filter-sidebar/filter-sidebar.component.html +0 -112
  61. package/src/lib/modules/filter-sidebar/components/filter-sidebar/filter-sidebar.component.scss +0 -186
  62. package/src/lib/modules/filter-sidebar/components/filter-sidebar/filter-sidebar.component.ts +0 -163
  63. package/src/lib/modules/filter-sidebar/filter-sidebar.models.ts +0 -95
  64. package/src/lib/modules/filter-sidebar/filter-sidebar.module.ts +0 -24
  65. package/src/lib/modules/filter-table-selector/components/filter-table-selector/filter-table-selector.component.html +0 -73
  66. package/src/lib/modules/filter-table-selector/components/filter-table-selector/filter-table-selector.component.scss +0 -321
  67. package/src/lib/modules/filter-table-selector/components/filter-table-selector/filter-table-selector.component.ts +0 -361
  68. package/src/lib/modules/filter-table-selector/filter-table-selector.models.ts +0 -91
  69. package/src/lib/modules/filter-table-selector/filter-table-selector.module.ts +0 -22
  70. package/src/lib/modules/form-builder/components/field-configurator/configurator-config-panel/configurator-config-panel.component.html +0 -63
  71. package/src/lib/modules/form-builder/components/field-configurator/configurator-config-panel/configurator-config-panel.component.scss +0 -496
  72. package/src/lib/modules/form-builder/components/field-configurator/configurator-config-panel/configurator-config-panel.component.ts +0 -445
  73. package/src/lib/modules/form-builder/components/field-configurator/configurator-tree/configurator-tree.component.html +0 -75
  74. package/src/lib/modules/form-builder/components/field-configurator/configurator-tree/configurator-tree.component.scss +0 -210
  75. package/src/lib/modules/form-builder/components/field-configurator/configurator-tree/configurator-tree.component.ts +0 -55
  76. package/src/lib/modules/form-builder/components/field-configurator/field-configurator.component.html +0 -25
  77. package/src/lib/modules/form-builder/components/field-configurator/field-configurator.component.scss +0 -82
  78. package/src/lib/modules/form-builder/components/field-configurator/field-configurator.component.ts +0 -95
  79. package/src/lib/modules/form-builder/components/field-selection/field-selection.component.html +0 -20
  80. package/src/lib/modules/form-builder/components/field-selection/field-selection.component.scss +0 -37
  81. package/src/lib/modules/form-builder/components/field-selection/field-selection.component.ts +0 -94
  82. package/src/lib/modules/form-builder/components/field-selection/group-node/group-node.component.html +0 -46
  83. package/src/lib/modules/form-builder/components/field-selection/group-node/group-node.component.scss +0 -102
  84. package/src/lib/modules/form-builder/components/field-selection/group-node/group-node.component.ts +0 -50
  85. package/src/lib/modules/form-builder/components/field-selection/selection-field-node/selection-field-node.component.html +0 -35
  86. package/src/lib/modules/form-builder/components/field-selection/selection-field-node/selection-field-node.component.scss +0 -67
  87. package/src/lib/modules/form-builder/components/field-selection/selection-field-node/selection-field-node.component.ts +0 -34
  88. package/src/lib/modules/form-builder/components/field-selection/selection-section-node/selection-section-node.component.html +0 -68
  89. package/src/lib/modules/form-builder/components/field-selection/selection-section-node/selection-section-node.component.scss +0 -113
  90. package/src/lib/modules/form-builder/components/field-selection/selection-section-node/selection-section-node.component.ts +0 -74
  91. package/src/lib/modules/form-builder/configs/field-type-schema.map.ts +0 -533
  92. package/src/lib/modules/form-builder/form-builder.module.ts +0 -36
  93. package/src/lib/modules/form-builder/index.ts +0 -9
  94. package/src/lib/modules/form-builder/models/builder.models.ts +0 -7
  95. package/src/lib/modules/form-builder/models/field-configurator.models.ts +0 -38
  96. package/src/lib/modules/form-builder/models/field-selection.models.ts +0 -51
  97. package/src/lib/modules/form-builder/services/field-configurator.service.ts +0 -258
  98. package/src/lib/modules/form-builder/services/field-selection.service.ts +0 -299
  99. package/src/lib/modules/form-builder/services/form-schema-tree.service.ts +0 -670
  100. package/src/lib/modules/form-builder/tokens/builder.tokens.ts +0 -10
  101. package/src/lib/modules/form-builder/utils/constants.ts +0 -43
  102. package/src/lib/modules/form-components/components/checkbox/checkbox.component.html +0 -29
  103. package/src/lib/modules/form-components/components/checkbox/checkbox.component.scss +0 -111
  104. package/src/lib/modules/form-components/components/checkbox/checkbox.component.ts +0 -207
  105. package/src/lib/modules/form-components/components/checkbox/checkbox.models.ts +0 -35
  106. package/src/lib/modules/form-components/components/datepicker/datepicker.component.html +0 -42
  107. package/src/lib/modules/form-components/components/datepicker/datepicker.component.scss +0 -115
  108. package/src/lib/modules/form-components/components/datepicker/datepicker.component.ts +0 -267
  109. package/src/lib/modules/form-components/components/datepicker/datepicker.models.ts +0 -45
  110. package/src/lib/modules/form-components/components/dropdown/dropdown.component.html +0 -74
  111. package/src/lib/modules/form-components/components/dropdown/dropdown.component.scss +0 -252
  112. package/src/lib/modules/form-components/components/dropdown/dropdown.component.ts +0 -377
  113. package/src/lib/modules/form-components/components/dropdown/dropdown.models.ts +0 -53
  114. package/src/lib/modules/form-components/components/input/input.component.html +0 -51
  115. package/src/lib/modules/form-components/components/input/input.component.scss +0 -128
  116. package/src/lib/modules/form-components/components/input/input.component.ts +0 -250
  117. package/src/lib/modules/form-components/components/input/input.models.ts +0 -55
  118. package/src/lib/modules/form-components/components/radio/radio.component.html +0 -22
  119. package/src/lib/modules/form-components/components/radio/radio.component.scss +0 -107
  120. package/src/lib/modules/form-components/components/radio/radio.component.ts +0 -181
  121. package/src/lib/modules/form-components/components/radio/radio.models.ts +0 -39
  122. package/src/lib/modules/form-components/components/search/search.component.html +0 -15
  123. package/src/lib/modules/form-components/components/search/search.component.scss +0 -87
  124. package/src/lib/modules/form-components/components/search/search.component.ts +0 -213
  125. package/src/lib/modules/form-components/components/search/search.models.ts +0 -40
  126. package/src/lib/modules/form-components/components/toggle/toggle.component.html +0 -15
  127. package/src/lib/modules/form-components/components/toggle/toggle.component.scss +0 -81
  128. package/src/lib/modules/form-components/components/toggle/toggle.component.ts +0 -166
  129. package/src/lib/modules/form-components/components/toggle/toggle.models.ts +0 -27
  130. package/src/lib/modules/form-components/directives/click-outside.directive.ts +0 -22
  131. package/src/lib/modules/form-components/form-components.module.ts +0 -42
  132. package/src/lib/modules/form-field-configuration/components/_ffc-controls.scss +0 -89
  133. package/src/lib/modules/form-field-configuration/components/config-field-node/config-field-node.component.html +0 -68
  134. package/src/lib/modules/form-field-configuration/components/config-field-node/config-field-node.component.scss +0 -73
  135. package/src/lib/modules/form-field-configuration/components/config-field-node/config-field-node.component.ts +0 -34
  136. package/src/lib/modules/form-field-configuration/components/config-section-node/config-section-node.component.html +0 -78
  137. package/src/lib/modules/form-field-configuration/components/config-section-node/config-section-node.component.scss +0 -83
  138. package/src/lib/modules/form-field-configuration/components/config-section-node/config-section-node.component.ts +0 -94
  139. package/src/lib/modules/form-field-configuration/components/form-field-configuration/form-field-configuration.component.html +0 -38
  140. package/src/lib/modules/form-field-configuration/components/form-field-configuration/form-field-configuration.component.scss +0 -42
  141. package/src/lib/modules/form-field-configuration/components/form-field-configuration/form-field-configuration.component.ts +0 -92
  142. package/src/lib/modules/form-field-configuration/form-field-configuration.module.ts +0 -23
  143. package/src/lib/modules/form-field-configuration/index.ts +0 -7
  144. package/src/lib/modules/form-field-configuration/models/field-configuration.models.ts +0 -62
  145. package/src/lib/modules/form-field-configuration/services/config-schema-tree.service.ts +0 -159
  146. package/src/lib/modules/form-field-configuration/services/field-configuration.service.ts +0 -228
  147. package/src/lib/modules/material/material.module.ts +0 -94
  148. package/src/lib/modules/nav/components/nav/nav.component.html +0 -34
  149. package/src/lib/modules/nav/components/nav/nav.component.scss +0 -171
  150. package/src/lib/modules/nav/components/nav/nav.component.ts +0 -82
  151. package/src/lib/modules/nav/nav.models.ts +0 -31
  152. package/src/lib/modules/nav/nav.module.ts +0 -17
  153. package/src/lib/modules/pagination/components/pagination/pagination.component.html +0 -52
  154. package/src/lib/modules/pagination/components/pagination/pagination.component.scss +0 -155
  155. package/src/lib/modules/pagination/components/pagination/pagination.component.ts +0 -109
  156. package/src/lib/modules/pagination/pagination.module.ts +0 -17
  157. package/src/lib/modules/side-nav/components/side-nav/side-nav.component.html +0 -56
  158. package/src/lib/modules/side-nav/components/side-nav/side-nav.component.scss +0 -342
  159. package/src/lib/modules/side-nav/components/side-nav/side-nav.component.ts +0 -135
  160. package/src/lib/modules/side-nav/side-nav.models.ts +0 -38
  161. package/src/lib/modules/side-nav/side-nav.module.ts +0 -16
  162. package/src/lib/modules/smart-form/components/form-field/form-field.component.html +0 -1330
  163. package/src/lib/modules/smart-form/components/form-field/form-field.component.scss +0 -2112
  164. package/src/lib/modules/smart-form/components/form-field/form-field.component.ts +0 -3006
  165. package/src/lib/modules/smart-form/components/form-section/form-section.component.html +0 -65
  166. package/src/lib/modules/smart-form/components/form-section/form-section.component.scss +0 -209
  167. package/src/lib/modules/smart-form/components/form-section/form-section.component.ts +0 -131
  168. package/src/lib/modules/smart-form/components/smart-form/smart-form.component.html +0 -253
  169. package/src/lib/modules/smart-form/components/smart-form/smart-form.component.scss +0 -689
  170. package/src/lib/modules/smart-form/components/smart-form/smart-form.component.ts +0 -1131
  171. package/src/lib/modules/smart-form/index.ts +0 -10
  172. package/src/lib/modules/smart-form/models/form-schema.model.ts +0 -793
  173. package/src/lib/modules/smart-form/models/hierarchy-config.model.ts +0 -21
  174. package/src/lib/modules/smart-form/services/expression.service.ts +0 -75
  175. package/src/lib/modules/smart-form/services/smart-form-controller.service.ts +0 -67
  176. package/src/lib/modules/smart-form/smart-form.examples.ts +0 -1324
  177. package/src/lib/modules/smart-form/smart-form.module.ts +0 -38
  178. package/src/lib/modules/smart-form/utils/translation.utils.ts +0 -82
  179. package/src/lib/modules/smart-form/utils/trusted-url.pipe.ts +0 -25
  180. package/src/lib/modules/smart-form/utils/validation.utils.ts +0 -98
  181. package/src/lib/modules/smart-table/components/smart-table/smart-table.component.html +0 -283
  182. package/src/lib/modules/smart-table/components/smart-table/smart-table.component.scss +0 -685
  183. package/src/lib/modules/smart-table/components/smart-table/smart-table.component.ts +0 -1128
  184. package/src/lib/modules/smart-table/models/table-config.model.ts +0 -213
  185. package/src/lib/modules/smart-table/smart-table.module.ts +0 -30
  186. package/src/lib/modules/smart-table/utils/safe-html.pipe.ts +0 -28
  187. package/src/lib/modules/smart-table/utils/smart-table.utils.ts +0 -18
  188. package/src/lib/modules/snackbar/components/snackbar.component.html +0 -41
  189. package/src/lib/modules/snackbar/components/snackbar.component.scss +0 -99
  190. package/src/lib/modules/snackbar/components/snackbar.component.ts +0 -18
  191. package/src/lib/modules/snackbar/models/snackbar.models.ts +0 -10
  192. package/src/lib/modules/snackbar/services/snackbar.service.ts +0 -40
  193. package/src/lib/modules/snackbar/snackbar.module.ts +0 -11
  194. package/src/lib/modules/summary-card/components/summary-card/summary-card.component.html +0 -47
  195. package/src/lib/modules/summary-card/components/summary-card/summary-card.component.scss +0 -199
  196. package/src/lib/modules/summary-card/components/summary-card/summary-card.component.ts +0 -126
  197. package/src/lib/modules/summary-card/summary-card.module.ts +0 -18
  198. package/src/lib/modules/table-column-configuration/components/_tcc-controls.scss +0 -53
  199. package/src/lib/modules/table-column-configuration/components/config-column-node/config-column-node.component.html +0 -47
  200. package/src/lib/modules/table-column-configuration/components/config-column-node/config-column-node.component.scss +0 -50
  201. package/src/lib/modules/table-column-configuration/components/config-column-node/config-column-node.component.ts +0 -33
  202. package/src/lib/modules/table-column-configuration/components/table-column-configuration/table-column-configuration.component.html +0 -30
  203. package/src/lib/modules/table-column-configuration/components/table-column-configuration/table-column-configuration.component.scss +0 -36
  204. package/src/lib/modules/table-column-configuration/components/table-column-configuration/table-column-configuration.component.ts +0 -78
  205. package/src/lib/modules/table-column-configuration/index.ts +0 -5
  206. package/src/lib/modules/table-column-configuration/models/table-column-configuration.models.ts +0 -20
  207. package/src/lib/modules/table-column-configuration/services/table-column-configuration.service.ts +0 -77
  208. package/src/lib/modules/table-column-configuration/table-column-configuration.module.ts +0 -21
  209. package/src/lib/modules/time-picker/components/time-picker/time-picker.component.html +0 -37
  210. package/src/lib/modules/time-picker/components/time-picker/time-picker.component.scss +0 -102
  211. package/src/lib/modules/time-picker/components/time-picker/time-picker.component.ts +0 -178
  212. package/src/lib/modules/time-picker/components/time-wheel-panel/time-wheel-panel.component.html +0 -78
  213. package/src/lib/modules/time-picker/components/time-wheel-panel/time-wheel-panel.component.scss +0 -226
  214. package/src/lib/modules/time-picker/components/time-wheel-panel/time-wheel-panel.component.ts +0 -595
  215. package/src/lib/modules/time-picker/models/time-picker.models.ts +0 -49
  216. package/src/lib/modules/time-picker/time-picker.module.ts +0 -23
  217. package/src/lib/shared-ui.module.ts +0 -55
  218. package/src/lib/utils/constants.ts +0 -11
  219. package/src/lib/utils/storage.utils.ts +0 -37
  220. package/src/lib/utils/string.utils.ts +0 -23
  221. package/src/lib/utils/translation.utils.ts +0 -87
  222. package/src/public-api.ts +0 -127
  223. package/tsconfig.lib.json +0 -15
@@ -1,670 +0,0 @@
1
- import { Injectable } from '@angular/core';
2
- import {
3
- FormSchema,
4
- FieldConfig,
5
- SectionConfig,
6
- } from '../../smart-form/models/form-schema.model';
7
- import {
8
- SelectionGroupNode,
9
- SelectionSectionNode,
10
- SelectionFieldNode,
11
- } from '../models/field-selection.models';
12
- import {
13
- ConfiguratorTreeNode,
14
- } from '../models/field-configurator.models';
15
-
16
- /**
17
- * Service to parse a FormSchema into selection/configurator tree structures,
18
- * and to rebuild a modified FormSchema from those trees.
19
- */
20
- @Injectable({ providedIn: 'root' })
21
- export class FormSchemaTreeService {
22
-
23
- // ────────────────────────────────────────────────────────────────────────────
24
- // SELECTION TREE
25
- // ────────────────────────────────────────────────────────────────────────────
26
-
27
- /**
28
- * Parse a FormSchema into SelectionGroupNodes for the field-selection UI.
29
- * Stepper forms produce one group per step; section forms produce one group.
30
- */
31
- parseSchemaToSelectionGroups(schema: FormSchema): SelectionGroupNode[] {
32
- if (schema.formType === 'STEPPER' && schema.stepperConfig?.children?.length) {
33
- return schema.stepperConfig.children
34
- .filter(child => child.type === 'GROUP')
35
- .map(groupField => this._buildGroupNode(groupField));
36
- }
37
-
38
- // SECTION form → single virtual group. This group has no backing FieldConfig of its
39
- // own (it's the schema root, not a child), so its enabled state is DERIVED from its
40
- // sections: on if at least one child section is on, off only once every child is off.
41
- // This flag is not just cosmetic — smart-form.component.html reads sectionConfig.isEnabled
42
- // to decide whether the whole form section renders for end users, so it must reflect the
43
- // real combined state of its children rather than being an independently-clicked flag.
44
- // The master toggle click itself still cascades enable/disable to all children (see
45
- // FieldSelectionService.toggleGroup); this is just what happens to the header on re-parse.
46
- if (schema.sectionConfig?.children?.length) {
47
- const sections = this._buildSectionsFromChildren(schema.sectionConfig.children);
48
- return [{
49
- label: schema.label || 'Form',
50
- groupFieldConfig: null,
51
- enabled: sections.length === 0 || sections.some(s => s.enabled),
52
- expanded: true, // Collapse by default for better UX
53
- sections,
54
- }];
55
- }
56
-
57
- return [];
58
- }
59
-
60
- /**
61
- * Rebuild a FormSchema from the selection tree, updating visible/disabled/required
62
- * flags on each FieldConfig. Does NOT mutate the original schema.
63
- */
64
- applySelectionToSchema(
65
- groups: SelectionGroupNode[],
66
- originalSchema: FormSchema,
67
- ): FormSchema {
68
- const schema: FormSchema = JSON.parse(JSON.stringify(originalSchema));
69
-
70
- if (schema.formType === 'STEPPER' && schema.stepperConfig?.children?.length) {
71
- const stepChildren = schema.stepperConfig.children.filter(c => c.type === 'GROUP');
72
- groups.forEach((group, gi) => {
73
- if (gi < stepChildren.length) {
74
- const groupField = stepChildren[gi];
75
- groupField.isEnabled = group.enabled;
76
- groupField.visible = group.enabled; // Backward compatibility
77
- groupField.disabled = !group.enabled;
78
- if (groupField.sectionConfig?.children) {
79
- this._applySectionsToChildren(group.sections, groupField.sectionConfig.children);
80
- }
81
- }
82
- });
83
- } else if (schema.sectionConfig?.children?.length && groups.length > 0) {
84
- schema.sectionConfig.isEnabled = groups[0].enabled;
85
- this._applySectionsToChildren(groups[0].sections, schema.sectionConfig.children);
86
- }
87
-
88
- return schema;
89
- }
90
-
91
- // ────────────────────────────────────────────────────────────────────────────
92
- // CONFIGURATOR TREE
93
- // ────────────────────────────────────────────────────────────────────────────
94
-
95
- /**
96
- * Parse a FormSchema into a flat ConfiguratorTreeNode[] for the left-panel tree.
97
- */
98
- parseSchemaToConfiguratorTree(schema: FormSchema): ConfiguratorTreeNode[] {
99
- if (schema.formType === 'STEPPER' && schema.stepperConfig?.children?.length) {
100
- return schema.stepperConfig.children
101
- .filter(c => c.type === 'GROUP')
102
- .map((groupField, gi) => this._buildConfiguratorGroupNode(groupField, [gi]));
103
- }
104
-
105
- if (schema.sectionConfig?.children?.length) {
106
- return this._buildConfiguratorChildNodes(schema.sectionConfig.children, []);
107
- }
108
-
109
- return [];
110
- }
111
-
112
- /**
113
- * Find a FieldConfig inside a FormSchema by its index path.
114
- */
115
- findFieldByPath(schema: FormSchema, path: number[]): FieldConfig | null {
116
- if (path.length === 0) return null;
117
-
118
- let children: FieldConfig[] | undefined;
119
- if (schema.formType === 'STEPPER') {
120
- children = schema.stepperConfig?.children;
121
- } else {
122
- children = schema.sectionConfig?.children;
123
- }
124
- if (!children) return null;
125
-
126
- let current: FieldConfig | undefined;
127
- for (let i = 0; i < path.length; i++) {
128
- const idx = path[i];
129
- if (!children || idx >= children.length) return null;
130
- current = children[idx];
131
-
132
- if (i < path.length - 1) {
133
- // Navigate deeper
134
- if (current.sectionConfig?.children) {
135
- children = current.sectionConfig.children;
136
- } else if (current.children) {
137
- children = current.children;
138
- } else {
139
- return null;
140
- }
141
- }
142
- }
143
-
144
- return current ?? null;
145
- }
146
-
147
- /**
148
- * Apply a partial patch to a FieldConfig located at the given path.
149
- * Returns a new FormSchema (does not mutate the original).
150
- */
151
- /**
152
- * Known top-level keys of FieldConfig.
153
- * Used to strip stale group-name keys (e.g. textConstraintsTextConfig) that
154
- * may have been introduced by previous incorrect patch operations.
155
- */
156
- private readonly _VALID_FIELD_KEYS = new Set([
157
- 'name', 'type', 'subType', 'label', 'placeholder', 'hint',
158
- 'required', 'disabled', 'readonly', 'isEnabled', 'visible',
159
- 'colSpan', 'defaultValue', 'prefix', 'suffix', 'className',
160
- 'payloadPath', 'errorMessage', 'visibilityExpression', 'onValidate',
161
- 'children', 'sectionConfig', 'rows',
162
- 'textConfig', 'emailConfig', 'phoneConfig', 'numberConfig',
163
- 'dateConfig', 'optionConfig', 'attachmentConfig', 'richTextConfig',
164
- 'ratingConfig', 'locationConfig', 'generatedConfig', 'rangeConfig',
165
- ]);
166
-
167
- applyFieldPatchToSchema(
168
- path: number[],
169
- patch: Partial<FieldConfig>,
170
- originalSchema: FormSchema,
171
- ): FormSchema {
172
- const schema: FormSchema = JSON.parse(JSON.stringify(originalSchema));
173
- const field = this.findFieldByPath(schema, path) as Record<string, any> | null;
174
- if (field) {
175
- // 1. Strip stale keys that don't belong to FieldConfig (e.g. old group names)
176
- for (const key of Object.keys(field)) {
177
- if (!this._VALID_FIELD_KEYS.has(key)) {
178
- delete field[key];
179
- }
180
- }
181
- // 2. Deep-merge the new patch on top of the cleaned field
182
- FormSchemaTreeService.deepMerge(field, patch as any);
183
- // 3. Clean up empty-string / null leaves from nested config objects.
184
- // e.g. user clears minDate → dateConfig.minDate becomes "" → remove it.
185
- // If the entire config object ends up empty → remove the key.
186
- FormSchemaTreeService.cleanEmptyConfigValues(field);
187
- }
188
- return schema;
189
- }
190
-
191
- /**
192
- * Remove empty-string and null values from all typed config sub-objects on a field.
193
- * If all values in a config sub-object are empty, the key is deleted entirely.
194
- */
195
- public static cleanEmptyConfigValues(field: Record<string, any>): void {
196
- const CONFIG_KEYS = [
197
- 'textConfig', 'emailConfig', 'phoneConfig', 'numberConfig',
198
- 'dateConfig', 'optionConfig', 'attachmentConfig', 'richTextConfig',
199
- 'ratingConfig', 'locationConfig', 'generatedConfig', 'rangeConfig',
200
- ];
201
- for (const key of CONFIG_KEYS) {
202
- if (field[key] && typeof field[key] === 'object' && !Array.isArray(field[key])) {
203
- field[key] = FormSchemaTreeService._removeEmptyLeaves(field[key]);
204
- if (Object.keys(field[key]).length === 0) {
205
- delete field[key];
206
- }
207
- }
208
- }
209
- }
210
-
211
- /**
212
- * Recursively strip empty-string, null, and undefined values from a plain object.
213
- * Nested objects that become empty after stripping are also removed.
214
- */
215
- private static _removeEmptyLeaves(obj: Record<string, any>): Record<string, any> {
216
- const result: Record<string, any> = {};
217
- for (const [key, val] of Object.entries(obj)) {
218
- if (val === '' || val === null || val === undefined) continue;
219
- if (typeof val === 'object' && !Array.isArray(val)) {
220
- const nested = FormSchemaTreeService._removeEmptyLeaves(val);
221
- if (Object.keys(nested).length > 0) result[key] = nested;
222
- } else {
223
- result[key] = val;
224
- }
225
- }
226
- return result;
227
- }
228
-
229
- /**
230
- * Recursively merge `source` into `target` in-place.
231
- * Objects are merged key-by-key; primitives/arrays replace the existing value.
232
- */
233
- public static deepMerge(target: Record<string, any>, source: Record<string, any>): void {
234
- for (const key of Object.keys(source)) {
235
- const srcVal = source[key];
236
- const tgtVal = target[key];
237
- if (
238
- srcVal !== null &&
239
- typeof srcVal === 'object' &&
240
- !Array.isArray(srcVal) &&
241
- tgtVal !== null &&
242
- typeof tgtVal === 'object' &&
243
- !Array.isArray(tgtVal)
244
- ) {
245
- // Both sides are plain objects — merge recursively
246
- this.deepMerge(tgtVal, srcVal);
247
- } else {
248
- target[key] = srcVal;
249
- }
250
- }
251
- }
252
-
253
- /**
254
- * Convert a flat object with dot-notation keys into a nested object.
255
- * E.g. { 'a.b.c': 1 } -> { a: { b: { c: 1 } } }
256
- */
257
- public static inflatePatch(flatPatch: Record<string, any>): Record<string, any> {
258
- const nested: Record<string, any> = {};
259
-
260
- for (const [key, value] of Object.entries(flatPatch)) {
261
- const parts = key.split('.');
262
- let current = nested;
263
-
264
- for (let i = 0; i < parts.length - 1; i++) {
265
- const part = parts[i];
266
- if (!(part in current) || typeof current[part] !== 'object' || current[part] === null) {
267
- current[part] = {};
268
- }
269
- current = current[part];
270
- }
271
-
272
- current[parts[parts.length - 1]] = value;
273
- }
274
-
275
- return nested;
276
- }
277
-
278
- /**
279
- * Convert a nested object into a flat object with dot-notation keys.
280
- * E.g. { a: { b: { c: 1 } } } -> { 'a.b.c': 1 }
281
- */
282
- public static flattenObject(obj: Record<string, any>, prefix = ''): Record<string, any> {
283
- const flat: Record<string, any> = {};
284
-
285
- for (const [key, value] of Object.entries(obj)) {
286
- const newKey = prefix ? `${prefix}.${key}` : key;
287
- if (value !== null && typeof value === 'object' && !Array.isArray(value)) {
288
- Object.assign(flat, this.flattenObject(value, newKey));
289
- } else {
290
- flat[newKey] = value;
291
- }
292
- }
293
-
294
- return flat;
295
- }
296
-
297
- // ────────────────────────────────────────────────────────────────────────────
298
- // FIELD TYPE MAPPING (FormSchema type → builder field type)
299
- // ────────────────────────────────────────────────────────────────────────────
300
-
301
- /**
302
- * Map a FormSchema FieldConfig.type to the builder fieldType key
303
- * used in field-type-schema.map.ts for config UI generation.
304
- */
305
- mapFieldTypeToBuilderType(type: string, subType?: string): string {
306
- const typeMap: Record<string, string> = {
307
- 'TEXT_INPUT': 'shortText',
308
- 'TEXT': 'shortText',
309
- 'TEXTAREA': 'longText',
310
- 'RICH_TEXT': 'richText',
311
- 'NUMBER_INPUT': 'number',
312
- 'NUMBER': 'number',
313
- 'DATE': 'date',
314
- 'TIME': 'time',
315
- 'DROPDOWN': 'dropdown',
316
- 'SELECT': 'dropdown',
317
- 'MULTI_SELECT': 'multiSelect',
318
- 'AUTOCOMPLETE': 'autocomplete',
319
- 'RADIO': 'radio',
320
- 'CHECKBOX': 'checkbox',
321
- 'SWITCH': 'toggle',
322
- 'FILE_UPLOAD': 'file',
323
- 'RATING': 'rating',
324
- 'GENERATED': 'generated',
325
- 'CHIP': 'chip',
326
- 'LOCATION': 'location',
327
- 'GROUP': 'group',
328
- 'SUBFIELDS': 'section',
329
- };
330
-
331
- // Refinement by subType
332
- if (type === 'TEXT_INPUT' && subType) {
333
- switch (subType) {
334
- case 'LONG': return 'longText';
335
- case 'EMAIL': return 'email';
336
- case 'PHONE': return 'phone';
337
- case 'PASSWORD': return 'password';
338
- default: return 'shortText';
339
- }
340
- }
341
-
342
- if (type === 'NUMBER_INPUT') {
343
- if (subType === 'DECIMAL') return 'decimal';
344
- return 'number';
345
- }
346
-
347
- if (type === 'DATE') {
348
- if (subType === 'DATETIME') return 'dateTime';
349
- return 'date';
350
- }
351
-
352
- if (type === 'CHECKBOX' && subType === 'LIST') {
353
- return 'multiCheckbox';
354
- }
355
-
356
- return typeMap[type] ?? 'shortText';
357
- }
358
-
359
- // ────────────────────────────────────────────────────────────────────────────
360
- // PRIVATE — Selection tree builders
361
- // ────────────────────────────────────────────────────────────────────────────
362
-
363
- private _buildGroupNode(groupField: FieldConfig): SelectionGroupNode {
364
- const sections: SelectionSectionNode[] = [];
365
-
366
- if (groupField.sectionConfig?.children) {
367
- const built = this._buildSectionsFromChildren(groupField.sectionConfig.children);
368
- sections.push(...built);
369
- }
370
-
371
- return {
372
- label: groupField.sectionConfig?.label || groupField.label || groupField.name || 'Group',
373
- groupFieldConfig: groupField,
374
- enabled: groupField.isEnabled ?? groupField.visible ?? true,
375
- expanded: true, // Collapse by default for better UX - user can expand as needed
376
- sections,
377
- };
378
- }
379
-
380
- /**
381
- * Build sections from a children array. Fields that are GROUP/SUBFIELDS
382
- * become sections; other leaf fields are collected into a "default" section.
383
- */
384
- private _buildSectionsFromChildren(children: FieldConfig[]): SelectionSectionNode[] {
385
- const sections: SelectionSectionNode[] = [];
386
- let leafFields: SelectionFieldNode[] = [];
387
-
388
- for (const child of children) {
389
- if (child.type === 'GROUP' || (child.type === 'SUBFIELDS') || child.sectionConfig) {
390
- // Flush any accumulated leaf fields into a default section
391
- if (leafFields.length > 0) {
392
- sections.push(this._createDefaultSection(leafFields));
393
- leafFields = [];
394
- }
395
- sections.push(this._buildSectionNode(child));
396
- } else if (child.type === 'ROW' && child.children?.length) {
397
- // ROW children are leaf fields
398
- for (const rowChild of child.children) {
399
- leafFields.push(this._buildFieldNode(rowChild));
400
- }
401
- } else {
402
- leafFields.push(this._buildFieldNode(child));
403
- }
404
- }
405
-
406
- // Flush remaining leaf fields
407
- if (leafFields.length > 0) {
408
- sections.push(this._createDefaultSection(leafFields));
409
- }
410
-
411
- return sections;
412
- }
413
-
414
- private _buildSectionNode(field: FieldConfig): SelectionSectionNode {
415
- const subsections: SelectionSectionNode[] = [];
416
- const fields: SelectionFieldNode[] = [];
417
-
418
- const children = field.sectionConfig?.children ?? field.children ?? [];
419
- for (const child of children) {
420
- if (child.type === 'GROUP' || child.sectionConfig) {
421
- subsections.push(this._buildSectionNode(child));
422
- } else if (child.type === 'ROW' && child.children?.length) {
423
- for (const rowChild of child.children) {
424
- fields.push(this._buildFieldNode(rowChild));
425
- }
426
- } else {
427
- fields.push(this._buildFieldNode(child));
428
- }
429
- }
430
-
431
- const isVisible = field.isEnabled ?? field.visible ?? true;
432
- return {
433
- label: field.sectionConfig?.label || field.label || field.name || 'Section',
434
- sectionConfig: field.sectionConfig ?? null,
435
- parentFieldConfig: field,
436
- enabled: isVisible && field.disabled !== true,
437
- expanded: false, // Collapse by default for better UX - user can expand as needed
438
- fields,
439
- subsections,
440
- };
441
- }
442
-
443
- private _createDefaultSection(fields: SelectionFieldNode[]): SelectionSectionNode {
444
- return {
445
- label: 'Fields',
446
- sectionConfig: null,
447
- parentFieldConfig: null,
448
- enabled: true,
449
- expanded: false, // Collapse by default for better UX - user can expand as needed
450
- fields,
451
- subsections: [],
452
- };
453
- }
454
-
455
- private _buildFieldNode(field: FieldConfig): SelectionFieldNode {
456
- return {
457
- fieldConfig: field,
458
- selected: field.isEnabled ?? field.visible ?? true,
459
- isLocked: field.readonly === true,
460
- };
461
- }
462
-
463
- // ────────────────────────────────────────────────────────────────────────────
464
- // PRIVATE — Apply selection back to FormSchema children
465
- // ────────────────────────────────────────────────────────────────────────────
466
-
467
- private _applySectionsToChildren(
468
- sections: SelectionSectionNode[],
469
- children: FieldConfig[],
470
- ): void {
471
- // Only sections built from an actual GROUP/section field (parentFieldConfig set) map
472
- // 1:1 to a GROUP-typed schema child here. _buildSectionsFromChildren also inserts
473
- // "default" leaf-bundle sections (parentFieldConfig: null) for stray top-level fields
474
- // that aren't wrapped in a GROUP — those don't correspond to any schema child in this
475
- // loop at all (their fields are applied via _findSelectionField below instead). Without
476
- // filtering them out, a single leading/interleaved leaf field shifts `sectionIdx` out of
477
- // alignment, silently applying one section's enabled/disabled state to the WRONG group
478
- // (e.g. toggling "Languages" off ends up disabling "Address Details" instead).
479
- const structuralSections = sections.filter(s => !!s.parentFieldConfig);
480
- let sectionIdx = 0;
481
- let fieldIdx = 0;
482
-
483
- for (const child of children) {
484
- if (child.type === 'GROUP' || child.sectionConfig) {
485
- if (sectionIdx < structuralSections.length) {
486
- const section = structuralSections[sectionIdx];
487
- child.isEnabled = section.enabled;
488
- child.visible = section.enabled; // Backward compatibility
489
- child.disabled = !section.enabled;
490
- const innerChildren = child.sectionConfig?.children ?? child.children ?? [];
491
- if (innerChildren.length > 0) {
492
- this._applySectionsToChildren(section.subsections, innerChildren);
493
- // Also apply field selections
494
- this._applyFieldsToChildren(section.fields, innerChildren);
495
- }
496
- sectionIdx++;
497
- }
498
- } else if (child.type === 'ROW' && child.children?.length) {
499
- for (const rowChild of child.children) {
500
- const matchedField = this._findSelectionField(sections, rowChild, fieldIdx);
501
- if (matchedField) {
502
- rowChild.isEnabled = matchedField.selected;
503
- rowChild.visible = matchedField.selected; // Backward compatibility
504
- fieldIdx++;
505
- }
506
- }
507
- } else {
508
- const matchedField = this._findSelectionField(sections, child, fieldIdx);
509
- if (matchedField) {
510
- child.isEnabled = matchedField.selected;
511
- child.visible = matchedField.selected; // Backward compatibility
512
- fieldIdx++;
513
- }
514
- }
515
- }
516
- }
517
-
518
- private _applyFieldsToChildren(
519
- selectionFields: SelectionFieldNode[],
520
- children: FieldConfig[],
521
- ): void {
522
- let fi = 0;
523
- for (const child of children) {
524
- if (child.type === 'GROUP' || child.sectionConfig) continue;
525
- if (child.type === 'ROW' && child.children?.length) {
526
- for (const rowChild of child.children) {
527
- if (fi < selectionFields.length) {
528
- rowChild.isEnabled = selectionFields[fi].selected;
529
- rowChild.visible = selectionFields[fi].selected; // Backward compatibility
530
- fi++;
531
- }
532
- }
533
- } else {
534
- if (fi < selectionFields.length) {
535
- child.isEnabled = selectionFields[fi].selected;
536
- child.visible = selectionFields[fi].selected; // Backward compatibility
537
- fi++;
538
- }
539
- }
540
- }
541
- }
542
-
543
- private _findSelectionField(
544
- sections: SelectionSectionNode[],
545
- _field: FieldConfig,
546
- _index: number,
547
- ): SelectionFieldNode | null {
548
- // Flatten all fields from all sections
549
- for (const section of sections) {
550
- for (const f of section.fields) {
551
- if (f.fieldConfig === _field || f.fieldConfig.name === _field.name) {
552
- return f;
553
- }
554
- }
555
- }
556
- return null;
557
- }
558
-
559
- // ────────────────────────────────────────────────────────────────────────────
560
- // PRIVATE — Configurator tree builders
561
- // ────────────────────────────────────────────────────────────────────────────
562
-
563
- private _buildConfiguratorGroupNode(
564
- groupField: FieldConfig,
565
- basePath: number[],
566
- ): ConfiguratorTreeNode {
567
- const children: ConfiguratorTreeNode[] = [];
568
- const sectionChildren = groupField.sectionConfig?.children ?? [];
569
-
570
- sectionChildren.forEach((child, ci) => {
571
- if (child.isEnabled === false || child.visible === false) return;
572
- const childPath = [...basePath, ci];
573
- if (child.type === 'GROUP' || child.type === 'SUBFIELDS' || child.subType === 'SECTION' || child.sectionConfig) {
574
- children.push(this._buildConfiguratorSectionNode(child, childPath));
575
- } else if (child.type === 'ROW' && child.children?.length) {
576
- child.children.forEach((rowChild, ri) => {
577
- if (rowChild.isEnabled !== false && rowChild.visible !== false) {
578
- children.push(this._buildConfiguratorFieldNode(rowChild, [...childPath, ri]));
579
- }
580
- });
581
- } else {
582
- children.push(this._buildConfiguratorFieldNode(child, childPath));
583
- }
584
- });
585
-
586
- return {
587
- id: groupField.name || `group-${basePath.join('-')}`,
588
- label: groupField.sectionConfig?.label || groupField.label || 'Group',
589
- type: 'group',
590
- expanded: false,
591
- fieldConfig: groupField,
592
- path: basePath,
593
- children,
594
- };
595
- }
596
-
597
- private _buildConfiguratorSectionNode(
598
- field: FieldConfig,
599
- basePath: number[],
600
- ): ConfiguratorTreeNode {
601
- const children: ConfiguratorTreeNode[] = [];
602
- const sectionChildren = field.sectionConfig?.children ?? field.children ?? [];
603
-
604
- sectionChildren.forEach((child, ci) => {
605
- if (child.isEnabled === false || child.visible === false) return;
606
- const childPath = [...basePath, ci];
607
- if (child.type === 'GROUP' || child.type === 'SUBFIELDS' || child.subType === 'SECTION' || child.sectionConfig) {
608
- children.push(this._buildConfiguratorSectionNode(child, childPath));
609
- } else if (child.type === 'ROW' && child.children?.length) {
610
- child.children.forEach((rowChild, ri) => {
611
- if (rowChild.isEnabled !== false && rowChild.visible !== false) {
612
- children.push(this._buildConfiguratorFieldNode(rowChild, [...childPath, ri]));
613
- }
614
- });
615
- } else {
616
- children.push(this._buildConfiguratorFieldNode(child, childPath));
617
- }
618
- });
619
-
620
- return {
621
- id: field.name || `section-${basePath.join('-')}`,
622
- label: field.sectionConfig?.label || field.label || 'Section',
623
- type: 'section',
624
- expanded: false,
625
- fieldConfig: field,
626
- path: basePath,
627
- children,
628
- };
629
- }
630
-
631
- private _buildConfiguratorFieldNode(
632
- field: FieldConfig,
633
- path: number[],
634
- ): ConfiguratorTreeNode {
635
- return {
636
- id: field.name || `field-${path.join('-')}`,
637
- label: field.label || field.name || 'Field',
638
- type: 'field',
639
- expanded: false,
640
- fieldConfig: field,
641
- path,
642
- children: [],
643
- };
644
- }
645
-
646
- private _buildConfiguratorChildNodes(
647
- children: FieldConfig[],
648
- basePath: number[],
649
- ): ConfiguratorTreeNode[] {
650
- const nodes: ConfiguratorTreeNode[] = [];
651
-
652
- children.forEach((child, ci) => {
653
- if (child.isEnabled === false || child.visible === false) return;
654
- const childPath = [...basePath, ci];
655
- if (child.type === 'GROUP' || child.sectionConfig) {
656
- nodes.push(this._buildConfiguratorSectionNode(child, childPath));
657
- } else if (child.type === 'ROW' && child.children?.length) {
658
- child.children.forEach((rowChild, ri) => {
659
- if (rowChild.isEnabled !== false && rowChild.visible !== false) {
660
- nodes.push(this._buildConfiguratorFieldNode(rowChild, [...childPath, ri]));
661
- }
662
- });
663
- } else {
664
- nodes.push(this._buildConfiguratorFieldNode(child, childPath));
665
- }
666
- });
667
-
668
- return nodes;
669
- }
670
- }
@@ -1,10 +0,0 @@
1
- import { InjectionToken } from '@angular/core';
2
- import { FieldTypeSchemaMap } from '../models/builder.models';
3
-
4
- /**
5
- * Optional token to override the field-type → config-schema mapping
6
- * used by the standalone FieldConfiguratorComponent.
7
- */
8
- export const BUILDER_FIELD_TYPE_SCHEMA_MAP = new InjectionToken<FieldTypeSchemaMap>(
9
- 'BUILDER_FIELD_TYPE_SCHEMA_MAP'
10
- );