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,212 @@
1
+ @use 'sass:map';
2
+
3
+ // ─────────────────────────────────────────────────────────────────────────────
4
+ // Form Builder Theme
5
+ // ─────────────────────────────────────────────────────────────────────────────
6
+
7
+ $form-builder-config: (
8
+ bg: #ffffff,
9
+ border-color: #E5E7EB,
10
+ header-bg: #F9FAFB,
11
+ accent-color: #3B82F6,
12
+
13
+ // Step Indicator
14
+ step-bubble-size: 32px,
15
+ step-bubble-active-bg: #3B82F6,
16
+ step-bubble-active-color: #ffffff,
17
+ step-bubble-inactive-bg: #E5E7EB,
18
+ step-bubble-inactive-color: #6B7280,
19
+
20
+ // Sidebar / Tree
21
+ sidebar-width: 320px,
22
+ node-hover-bg: #F3F4F6,
23
+ node-selected-bg: #EFF6FF,
24
+ node-selected-border: #3B82F6,
25
+
26
+ // Config Panel (Premium Card Style)
27
+ config-panel-padding: 32px,
28
+ config-card-bg: #ffffff,
29
+ config-card-shadow: 0 1px 3px rgba(0, 0, 0, 0.05),
30
+ config-section-gap: 24px,
31
+ );
32
+
33
+ @mixin form-builder-theme($user-config: ()) {
34
+ $config: map.merge($form-builder-config, $user-config);
35
+
36
+ // Variables
37
+ --fb-bg: #{map.get($config, bg)};
38
+ --fb-border-color: #{map.get($config, border-color)};
39
+ --fb-accent: #{map.get($config, accent-color)};
40
+ --fb-font-family: 'Inter', sans-serif;
41
+
42
+ background: var(--fb-bg);
43
+ font-family: var(--fb-font-family);
44
+
45
+ // Premium Stepper (Lifecycle)
46
+ .fb-stepper {
47
+ display: flex;
48
+ align-items: center;
49
+ justify-content: center;
50
+ background: #ffffff;
51
+ padding: 1.5rem;
52
+ border-radius: 1rem;
53
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.05);
54
+ margin-bottom: 2rem;
55
+
56
+ .fb-step {
57
+ display: flex;
58
+ align-items: center;
59
+ gap: 0.75rem;
60
+ cursor: pointer;
61
+ padding: 0.5rem 1rem;
62
+ border-radius: 0.75rem;
63
+ transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
64
+
65
+ &:hover { background: #F3F4F6; }
66
+
67
+ &.active {
68
+ background: #EFF6FF;
69
+ .fb-step__icon {
70
+ background: var(--fb-accent);
71
+ color: #ffffff;
72
+ border-color: var(--fb-accent);
73
+ transform: scale(1.1);
74
+ }
75
+ .fb-step__label {
76
+ color: #111827;
77
+ font-weight: 700;
78
+ }
79
+ }
80
+
81
+ &.completed .fb-step__icon {
82
+ background: #10B981;
83
+ color: #ffffff;
84
+ border-color: #10B981;
85
+ }
86
+
87
+ &__icon {
88
+ width: 32px;
89
+ height: 32px;
90
+ border-radius: 50%;
91
+ border: 2px solid #D1D5DB;
92
+ display: flex;
93
+ align-items: center;
94
+ justify-content: center;
95
+ font-size: 14px;
96
+ font-weight: 700;
97
+ color: #6B7280;
98
+ background: #ffffff;
99
+ transition: all 0.3s;
100
+ flex-shrink: 0;
101
+ }
102
+
103
+ &__label {
104
+ font-size: 14px;
105
+ font-weight: 600;
106
+ color: #6B7280;
107
+ white-space: nowrap;
108
+ }
109
+
110
+ &__line {
111
+ width: 60px;
112
+ height: 2px;
113
+ background: #E5E7EB;
114
+ margin: 0 1rem;
115
+ flex-shrink: 0;
116
+ }
117
+ }
118
+ }
119
+
120
+ // ── Field Selection Component ───────────────────────────────────────────────
121
+ --fb-fs-padding: 16px;
122
+ --fb-fs-group-gap: 16px;
123
+ --fb-fs-group-bg: #ffffff;
124
+ --fb-fs-group-border: #e5e7eb;
125
+ --fb-fs-group-radius: 12px;
126
+ --fb-fs-header-padding: 14px 16px;
127
+ --fb-fs-header-gap: 10px;
128
+ --fb-fs-header-hover-bg: #f9fafb;
129
+ --fb-fs-chevron-color: #9ca3af;
130
+ --fb-fs-group-label-size: 14px;
131
+ --fb-fs-group-label-color: #111827;
132
+ --fb-fs-body-padding: 0 16px 16px 28px;
133
+ --fb-fs-section-gap: 12px;
134
+ --fb-fs-section-border: #e5e7eb;
135
+ --fb-fs-section-radius: 10px;
136
+ --fb-fs-section-bg: #ffffff;
137
+ --fb-fs-section-nested-border: #f3f4f6;
138
+ --fb-fs-section-nested-bg: #fafafa;
139
+ --fb-fs-section-header-padding: 10px 14px;
140
+ --fb-fs-section-header-hover: #f9fafb;
141
+ --fb-fs-section-label-size: 13px;
142
+ --fb-fs-section-label-color: #111827;
143
+ --fb-fs-section-body-padding: 4px 14px 14px 28px;
144
+ --fb-fs-field-gap: 6px;
145
+ --fb-fs-field-padding: 8px 12px;
146
+ --fb-fs-field-radius: 6px;
147
+ --fb-fs-field-bg: #ffffff;
148
+ --fb-fs-field-border: #e5e7eb;
149
+ --fb-fs-field-hover-border: #3b82f6;
150
+ --fb-fs-field-hover-bg: #f8fafc;
151
+ --fb-fs-field-selected-bg: #eff6ff;
152
+ --fb-fs-field-selected-border: #bfdbfe;
153
+ --fb-fs-field-locked-bg: #f3f4f6;
154
+ --fb-fs-field-locked-color: #6b7280;
155
+ --fb-fs-field-label-size: 13px;
156
+ --fb-fs-field-label-color: #111827;
157
+ --fb-fs-toggle-width: 36px;
158
+ --fb-fs-toggle-height: 20px;
159
+ --fb-fs-toggle-off-bg: #d1d5db;
160
+ --fb-fs-toggle-on-bg: #f5a623;
161
+ --fb-fs-toggle-thumb: #ffffff;
162
+ --fb-fs-checkbox-border: #d1d5db;
163
+ --fb-fs-checkbox-checked-bg: #3b82f6;
164
+ --fb-fs-lock-color: #9ca3af;
165
+ --fb-fs-empty-color: #9ca3af;
166
+
167
+ // ── Field Configurator Component ──────────────────────────────────────────
168
+ --fb-fc-bg: #ffffff;
169
+ --fb-fc-sidebar-width: 400px;
170
+ --fb-fc-sidebar-bg: #f9fafb;
171
+ --fb-fc-main-bg: #ffffff;
172
+ --fb-fc-border: #e5e7eb;
173
+ --fb-fc-tree-header-bg: #ffffff;
174
+ --fb-fc-tree-title-color: #111827;
175
+ --fb-fc-tree-subtitle-color: #6b7280;
176
+ --fb-fc-section-divider: #f3f4f6;
177
+ --fb-fc-section-hover: #f9fafb;
178
+ --fb-fc-chevron-color: #9ca3af;
179
+ --fb-fc-section-label-color: #111827;
180
+ --fb-fc-item-bg: #ffffff;
181
+ --fb-fc-item-border: #e5e7eb;
182
+ --fb-fc-item-hover-border: #3b82f6;
183
+ --fb-fc-item-active-border: #3b82f6;
184
+ --fb-fc-item-active-bg: #f0f7ff;
185
+ --fb-fc-drag-color: #d1d5db;
186
+ --fb-fc-item-label-color: #111827;
187
+ --fb-fc-item-type-color: #6b7280;
188
+ --fb-fc-panel-bg: #f9fafb;
189
+ --fb-fc-header-bg: #ffffff;
190
+ --fb-fc-title-color: #111827;
191
+ --fb-fc-badge-bg: #eff6ff;
192
+ --fb-fc-badge-color: #3b82f6;
193
+ --fb-fc-badge-border: #dbeafe;
194
+ --fb-fc-card-bg: #ffffff;
195
+ --fb-fc-card-border: #e5e7eb;
196
+ --fb-fc-accent: #3b82f6;
197
+ --fb-fc-empty-color: #9ca3af;
198
+ // ── Type Switcher (Standalone header select) ─────────────────────────────
199
+ --fb-fc-type-label-color: #6b7280;
200
+ --fb-fc-type-label-size: 0.75rem;
201
+ --fb-fc-type-select-height: 36px;
202
+ --fb-fc-type-select-border: #d1d5db;
203
+ --fb-fc-type-select-radius: 8px;
204
+ --fb-fc-type-select-bg: #ffffff;
205
+ --fb-fc-type-select-color: #111827;
206
+ --fb-fc-type-select-hover-border: #9ca3af;
207
+
208
+ // Shared Components Overrides
209
+ ::ng-deep lib-button button {
210
+ font-family: var(--fb-font-family) !important;
211
+ }
212
+ }
@@ -0,0 +1,9 @@
1
+ export * from './form-builder.module';
2
+ export * from './components/field-selection/field-selection.component';
3
+ export * from './components/field-configurator/field-configurator.component';
4
+ export * from './models/builder.models';
5
+ export * from './models/field-selection.models';
6
+ export * from './models/field-configurator.models';
7
+ export * from './services/field-selection.service';
8
+ export * from './services/field-configurator.service';
9
+ export * from './services/form-schema-tree.service';
@@ -0,0 +1,7 @@
1
+ import { FormSchema } from '../../../modules/smart-form/models/form-schema.model';
2
+
3
+ /**
4
+ * Maps a builder field type key to a FormSchema used to generate
5
+ * the configuration panel for that field type.
6
+ */
7
+ export type FieldTypeSchemaMap = Record<string, FormSchema>;
@@ -0,0 +1,38 @@
1
+ import { FieldConfig } from '../../smart-form/models/form-schema.model';
2
+
3
+ /**
4
+ * Metadata about the currently selected field in the configurator.
5
+ */
6
+ export interface ConfiguratorFieldInfo {
7
+ /** Reference to the FieldConfig being edited */
8
+ fieldConfig: FieldConfig;
9
+ /** Display label of the parent group */
10
+ groupLabel: string;
11
+ /** Display label of the parent section */
12
+ sectionLabel: string;
13
+ /** Index path used to locate this field inside the FormSchema tree */
14
+ path: number[];
15
+ }
16
+
17
+ /**
18
+ * A node in the configurator left-panel tree.
19
+ * Represents either a group, section, or field.
20
+ */
21
+ export type ConfiguratorNodeType = 'group' | 'section' | 'field';
22
+
23
+ export interface ConfiguratorTreeNode {
24
+ /** Unique identifier (name or generated index-based key) */
25
+ id: string;
26
+ /** Node display label */
27
+ label: string;
28
+ /** Node type */
29
+ type: ConfiguratorNodeType;
30
+ /** Whether the node is expanded (for groups/sections) */
31
+ expanded: boolean;
32
+ /** Reference to the FieldConfig (only for field nodes) */
33
+ fieldConfig: FieldConfig | null;
34
+ /** Index path to this node in FormSchema */
35
+ path: number[];
36
+ /** Child nodes */
37
+ children: ConfiguratorTreeNode[];
38
+ }
@@ -0,0 +1,51 @@
1
+ import { FieldConfig, SectionConfig } from '../../smart-form/models/form-schema.model';
2
+
3
+ /**
4
+ * Wraps a FieldConfig leaf with selection metadata for the UI tree.
5
+ */
6
+ export interface SelectionFieldNode {
7
+ /** Reference back to the original FieldConfig */
8
+ fieldConfig: FieldConfig;
9
+ /** Whether this field is selected (checkbox state) */
10
+ selected: boolean;
11
+ /** If true, the field cannot be deselected by the user */
12
+ isLocked: boolean;
13
+ }
14
+
15
+ /**
16
+ * Wraps a section (SUBFIELDS / nested sectionConfig) with toggle + tree metadata.
17
+ * Sections can recursively contain child sections.
18
+ */
19
+ export interface SelectionSectionNode {
20
+ /** Section label */
21
+ label: string;
22
+ /** The original sectionConfig reference (if applicable) */
23
+ sectionConfig: SectionConfig | null;
24
+ /** The parent FieldConfig that owns this sectionConfig (type GROUP/SUBFIELDS) */
25
+ parentFieldConfig: FieldConfig | null;
26
+ /** Whether the section toggle is ON */
27
+ enabled: boolean;
28
+ /** Whether the section is visually expanded in the tree */
29
+ expanded: boolean;
30
+ /** Leaf fields inside this section */
31
+ fields: SelectionFieldNode[];
32
+ /** Recursive child sections */
33
+ subsections: SelectionSectionNode[];
34
+ }
35
+
36
+ /**
37
+ * Top-level group node (maps to a GROUP field in stepperConfig.children
38
+ * or a top-level sectionConfig in a SECTION form).
39
+ */
40
+ export interface SelectionGroupNode {
41
+ /** Group label */
42
+ label: string;
43
+ /** The original FieldConfig of type GROUP (stepper forms) or null (section form) */
44
+ groupFieldConfig: FieldConfig | null;
45
+ /** Whether the entire group toggle is ON */
46
+ enabled: boolean;
47
+ /** Whether the group is visually expanded */
48
+ expanded: boolean;
49
+ /** Sections inside this group */
50
+ sections: SelectionSectionNode[];
51
+ }
@@ -0,0 +1,258 @@
1
+ import { Injectable, computed, signal } from '@angular/core';
2
+ import { FormSchema, FieldConfig } from '../../smart-form/models/form-schema.model';
3
+ import {
4
+ ConfiguratorTreeNode,
5
+ ConfiguratorFieldInfo,
6
+ } from '../models/field-configurator.models';
7
+ import { FormSchemaTreeService } from '../services/form-schema-tree.service';
8
+
9
+ interface FieldConfiguratorState {
10
+ tree: ConfiguratorTreeNode[];
11
+ selectedFieldPath: number[] | null;
12
+ schema: FormSchema | null;
13
+ }
14
+
15
+ /**
16
+ * Signal-based service for the field-configurator component.
17
+ * Manages the tree + selected field + config panel state.
18
+ */
19
+ @Injectable()
20
+ export class FieldConfiguratorService {
21
+ private readonly _state = signal<FieldConfiguratorState>({
22
+ tree: [],
23
+ selectedFieldPath: null,
24
+ schema: null,
25
+ });
26
+
27
+ private readonly treeService = new FormSchemaTreeService();
28
+
29
+ // ── Computed slices ─────────────────────────────────────────────
30
+ readonly tree = computed(() => this._state().tree);
31
+ readonly schema = computed(() => this._state().schema);
32
+ readonly selectedFieldPath = computed(() => this._state().selectedFieldPath);
33
+
34
+ readonly selectedField = computed<FieldConfig | null>(() => {
35
+ const { schema, selectedFieldPath } = this._state();
36
+ if (!schema || !selectedFieldPath) return null;
37
+ return this.treeService.findFieldByPath(schema, selectedFieldPath);
38
+ });
39
+
40
+ readonly selectedFieldInfo = computed<ConfiguratorFieldInfo | null>(() => {
41
+ const field = this.selectedField();
42
+ const path = this.selectedFieldPath();
43
+ if (!field || !path) return null;
44
+
45
+ // Walk the tree to find group/section labels
46
+ const labels = this._getParentLabels(this._state().tree, path);
47
+
48
+ return {
49
+ fieldConfig: field,
50
+ groupLabel: labels.groupLabel,
51
+ sectionLabel: labels.sectionLabel,
52
+ path,
53
+ };
54
+ });
55
+
56
+ /**
57
+ * Returns the builder-compatible field type string for the currently selected field.
58
+ * Used to look up the config schema from field-type-schema.map.ts.
59
+ */
60
+ readonly selectedFieldBuilderType = computed<string | null>(() => {
61
+ const field = this.selectedField();
62
+ if (!field) return null;
63
+ return this.treeService.mapFieldTypeToBuilderType(field.type, field.subType);
64
+ });
65
+
66
+ // ── Mutators ────────────────────────────────────────────────────
67
+
68
+ /**
69
+ * Initialize the store from a FormSchema.
70
+ */
71
+ loadSchema(schema: FormSchema, preserveSelection = false): void {
72
+ // If it's the exact same object reference and we are not forcing a reset, skip.
73
+ if (this._state().schema === schema && preserveSelection) return;
74
+
75
+ const tree = this.treeService.parseSchemaToConfiguratorTree(schema);
76
+
77
+ this._state.update(s => {
78
+ // If preserveSelection is truthy, we definitely keep it.
79
+ // Otherwise, we still try to keep it IF the path is still valid in the new schema.
80
+ let newPath = s.selectedFieldPath;
81
+ if (!preserveSelection && newPath) {
82
+ const stillExists = !!this.treeService.findFieldByPath(schema, newPath);
83
+ if (!stillExists) newPath = null;
84
+ }
85
+
86
+ return {
87
+ ...s,
88
+ tree,
89
+ selectedFieldPath: newPath,
90
+ schema: JSON.parse(JSON.stringify(schema)),
91
+ };
92
+ });
93
+ }
94
+
95
+ /**
96
+ * Select a field by its path. Pass null to deselect.
97
+ */
98
+ selectField(path: number[] | null): void {
99
+ this._state.update(s => ({ ...s, selectedFieldPath: path }));
100
+ }
101
+
102
+ /**
103
+ * Toggle a tree node's expanded state.
104
+ */
105
+ toggleNodeExpanded(nodeId: string): void {
106
+ this._state.update(s => ({
107
+ ...s,
108
+ tree: this._toggleExpanded(s.tree, nodeId),
109
+ }));
110
+ }
111
+
112
+ /**
113
+ * Apply a config patch to the currently selected field.
114
+ * Rebuilds the schema and tree nodes immutably.
115
+ */
116
+ patchSelectedField(patch: Partial<FieldConfig>): void {
117
+ const { schema, selectedFieldPath, tree } = this._state();
118
+ if (!schema || !selectedFieldPath) return;
119
+
120
+ const newSchema = this.treeService.applyFieldPatchToSchema(
121
+ selectedFieldPath,
122
+ patch,
123
+ schema,
124
+ );
125
+
126
+ // Rebuild the tree to reflect label changes etc.
127
+ const newTree = this.treeService.parseSchemaToConfiguratorTree(newSchema);
128
+ // Preserve expanded states from the old tree
129
+ this._restoreExpandedStates(tree, newTree);
130
+
131
+ this._state.set({
132
+ schema: newSchema,
133
+ selectedFieldPath,
134
+ tree: newTree,
135
+ });
136
+ }
137
+
138
+ /**
139
+ * Change the type (and optionally subType) of the currently selected field.
140
+ * Mapping goes from builderType keys (e.g. 'richText') → {type, subType?}.
141
+ * DROPDOWN fields cannot be changed and are guarded here as well.
142
+ */
143
+ changeFieldType(builderType: string): void {
144
+ const currentField = this.selectedField();
145
+ if (!currentField) return;
146
+ // Guard: never change a DROPDOWN-based field
147
+ const t = currentField.type?.toUpperCase();
148
+ if (t === 'DROPDOWN' || t === 'MULTI_SELECT') return;
149
+
150
+ const TYPE_MAP: Record<string, { type: string; subType?: string }> = {
151
+ shortText: { type: 'TEXT_INPUT' },
152
+ longText: { type: 'TEXT_INPUT', subType: 'LONG' },
153
+ email: { type: 'TEXT_INPUT', subType: 'EMAIL' },
154
+ phone: { type: 'TEXT_INPUT', subType: 'PHONE' },
155
+ password: { type: 'TEXT_INPUT', subType: 'PASSWORD' },
156
+ number: { type: 'NUMBER_INPUT', subType: 'INTEGER' },
157
+ decimal: { type: 'NUMBER_INPUT', subType: 'DECIMAL' },
158
+ date: { type: 'DATE', subType: 'SINGLE' },
159
+ time: { type: 'TIME', subType: 'SINGLE' },
160
+ dateTime: { type: 'DATE', subType: 'DATETIME' },
161
+ checkbox: { type: 'CHECKBOX', subType: 'BOOL' },
162
+ multiCheckbox: { type: 'CHECKBOX', subType: 'LIST' },
163
+ radio: { type: 'RADIO', subType: 'SINGLE' },
164
+ toggle: { type: 'SWITCH', subType: 'BOOL' },
165
+ chip: { type: 'CHIP', subType: 'MULTIPLE' },
166
+ richText: { type: 'RICH_TEXT' },
167
+ file: { type: 'FILE_UPLOAD', subType: 'SINGLE' },
168
+ rating: { type: 'RATING', subType: 'STAR' },
169
+ location: { type: 'LOCATION' },
170
+ generated: { type: 'GENERATED', subType: 'FORMULA' },
171
+ multiSelect: { type: 'MULTI_SELECT' },
172
+ autocomplete: { type: 'AUTOCOMPLETE', subType: 'SINGLE' },
173
+ dropdown: { type: 'DROPDOWN', subType: 'SINGLE' },
174
+ multiDropdown: { type: 'MULTI_SELECT' },
175
+ };
176
+
177
+ const mapping = TYPE_MAP[builderType];
178
+ if (!mapping) return;
179
+
180
+ const patch: Partial<FieldConfig> = { type: mapping.type };
181
+ if (mapping.subType !== undefined) {
182
+ patch.subType = mapping.subType;
183
+ } else {
184
+ // Clear stale subType from previous field type
185
+ patch.subType = undefined;
186
+ }
187
+ this.patchSelectedField(patch);
188
+ }
189
+
190
+ /**
191
+ * Get the current schema (with all applied modifications).
192
+ */
193
+ getCurrentSchema(): FormSchema | null {
194
+ return this._state().schema;
195
+ }
196
+
197
+ // ── Private helpers ─────────────────────────────────────────────
198
+
199
+ private _toggleExpanded(nodes: ConfiguratorTreeNode[], nodeId: string): ConfiguratorTreeNode[] {
200
+ return nodes.map(n => {
201
+ if (n.id === nodeId) {
202
+ return { ...n, expanded: !n.expanded };
203
+ }
204
+ if (n.children.length > 0) {
205
+ return { ...n, children: this._toggleExpanded(n.children, nodeId) };
206
+ }
207
+ return n;
208
+ });
209
+ }
210
+
211
+ private _restoreExpandedStates(
212
+ oldNodes: ConfiguratorTreeNode[],
213
+ newNodes: ConfiguratorTreeNode[],
214
+ ): void {
215
+ for (const newNode of newNodes) {
216
+ const oldNode = oldNodes.find(o => o.id === newNode.id);
217
+ if (oldNode) {
218
+ newNode.expanded = oldNode.expanded;
219
+ if (oldNode.children.length > 0 && newNode.children.length > 0) {
220
+ this._restoreExpandedStates(oldNode.children, newNode.children);
221
+ }
222
+ }
223
+ }
224
+ }
225
+
226
+ private _getParentLabels(
227
+ nodes: ConfiguratorTreeNode[],
228
+ path: number[],
229
+ ): { groupLabel: string; sectionLabel: string } {
230
+ let groupLabel = '';
231
+ let sectionLabel = '';
232
+
233
+ const findInNodes = (nodeList: ConfiguratorTreeNode[], targetPath: number[]): boolean => {
234
+ for (const node of nodeList) {
235
+ if (this._pathsEqual(node.path, targetPath)) {
236
+ return true;
237
+ }
238
+ if (node.children.length > 0) {
239
+ const found = findInNodes(node.children, targetPath);
240
+ if (found) {
241
+ if (node.type === 'group') groupLabel = node.label;
242
+ if (node.type === 'section') sectionLabel = node.label;
243
+ return true;
244
+ }
245
+ }
246
+ }
247
+ return false;
248
+ };
249
+
250
+ findInNodes(nodes, path);
251
+ return { groupLabel, sectionLabel };
252
+ }
253
+
254
+ private _pathsEqual(a: number[], b: number[]): boolean {
255
+ if (a.length !== b.length) return false;
256
+ return a.every((val, i) => val === b[i]);
257
+ }
258
+ }