@gnggln/ng-ui-system 1.0.0-alpha.2 → 1.0.0-alpha.21

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 (721) hide show
  1. package/accordion/entry-accordion.d.ts +4 -0
  2. package/accordion/index.d.ts +5 -0
  3. package/accordion/lib/components/accordion/accordion.component.d.ts +125 -0
  4. package/accordion/lib/components/accordion/accordion.types.d.ts +64 -0
  5. package/accordion/lib/components/accordion/index.d.ts +2 -0
  6. package/accordion/lib/core/types/index.d.ts +133 -0
  7. package/base-layout/entry-base-layout.d.ts +4 -0
  8. package/base-layout/index.d.ts +5 -0
  9. package/base-layout/lib/components/base-layout/base-layout.component.d.ts +108 -0
  10. package/base-layout/lib/components/base-layout/base-layout.types.d.ts +40 -0
  11. package/base-layout/lib/components/base-layout/index.d.ts +13 -0
  12. package/base-layout/lib/components/blackbox/blackbox-fingerprint.service.d.ts +36 -0
  13. package/base-layout/lib/components/blackbox/blackbox-storage.service.d.ts +55 -0
  14. package/base-layout/lib/components/blackbox/blackbox.service.d.ts +144 -0
  15. package/base-layout/lib/components/blackbox/blackbox.types.d.ts +238 -0
  16. package/base-layout/lib/components/button/button-area.component.d.ts +93 -0
  17. package/base-layout/lib/components/button/button.component.d.ts +61 -0
  18. package/base-layout/lib/components/button/button.types.d.ts +75 -0
  19. package/base-layout/lib/components/page-header/breadcrumb.service.d.ts +96 -0
  20. package/base-layout/lib/components/page-header/page-header.component.d.ts +59 -0
  21. package/base-layout/lib/components/page-header/page-header.types.d.ts +96 -0
  22. package/base-layout/lib/core/types/index.d.ts +133 -0
  23. package/blackbox/entry-blackbox.d.ts +4 -0
  24. package/blackbox/index.d.ts +5 -0
  25. package/blackbox/lib/components/blackbox/blackbox-debugger.component.d.ts +80 -0
  26. package/blackbox/lib/components/blackbox/blackbox-debugger.service.d.ts +34 -0
  27. package/blackbox/lib/components/blackbox/blackbox-fingerprint.service.d.ts +36 -0
  28. package/blackbox/lib/components/blackbox/blackbox-json-viewer.component.d.ts +18 -0
  29. package/blackbox/lib/components/blackbox/blackbox-storage.service.d.ts +55 -0
  30. package/blackbox/lib/components/blackbox/blackbox.interceptor.d.ts +38 -0
  31. package/blackbox/lib/components/blackbox/blackbox.service.d.ts +144 -0
  32. package/blackbox/lib/components/blackbox/blackbox.types.d.ts +238 -0
  33. package/blackbox/lib/components/blackbox/index.d.ts +23 -0
  34. package/blackbox/lib/components/blackbox/ui-track.directive.d.ts +20 -0
  35. package/blackbox/lib/components/button/button-area.component.d.ts +93 -0
  36. package/blackbox/lib/components/button/button.component.d.ts +61 -0
  37. package/blackbox/lib/components/button/button.types.d.ts +75 -0
  38. package/blackbox/lib/components/button/index.d.ts +15 -0
  39. package/blackbox/lib/components/modal/confirm-dialog.component.d.ts +46 -0
  40. package/blackbox/lib/components/modal/index.d.ts +4 -0
  41. package/blackbox/lib/components/modal/modal.component.d.ts +44 -0
  42. package/blackbox/lib/components/modal/modal.service.d.ts +93 -0
  43. package/blackbox/lib/components/modal/modal.types.d.ts +110 -0
  44. package/blackbox/lib/core/types/index.d.ts +133 -0
  45. package/button/entry-button.d.ts +4 -0
  46. package/button/index.d.ts +5 -0
  47. package/button/lib/components/blackbox/blackbox-fingerprint.service.d.ts +36 -0
  48. package/button/lib/components/blackbox/blackbox-storage.service.d.ts +55 -0
  49. package/button/lib/components/blackbox/blackbox.service.d.ts +144 -0
  50. package/button/lib/components/blackbox/blackbox.types.d.ts +238 -0
  51. package/button/lib/components/button/button-area.component.d.ts +93 -0
  52. package/button/lib/components/button/button.component.d.ts +61 -0
  53. package/button/lib/components/button/button.types.d.ts +75 -0
  54. package/button/lib/components/button/index.d.ts +15 -0
  55. package/button/lib/core/types/index.d.ts +133 -0
  56. package/core/entry-core.d.ts +5 -0
  57. package/core/index.d.ts +5 -0
  58. package/core/lib/core/types/index.d.ts +133 -0
  59. package/core/lib/core/utils/index.d.ts +60 -0
  60. package/crud-table/entry-crud-table.d.ts +4 -0
  61. package/crud-table/index.d.ts +5 -0
  62. package/crud-table/lib/components/accordion/accordion.component.d.ts +125 -0
  63. package/crud-table/lib/components/accordion/accordion.types.d.ts +64 -0
  64. package/crud-table/lib/components/accordion/index.d.ts +2 -0
  65. package/crud-table/lib/components/blackbox/blackbox-fingerprint.service.d.ts +36 -0
  66. package/crud-table/lib/components/blackbox/blackbox-storage.service.d.ts +55 -0
  67. package/crud-table/lib/components/blackbox/blackbox.service.d.ts +144 -0
  68. package/crud-table/lib/components/blackbox/blackbox.types.d.ts +238 -0
  69. package/crud-table/lib/components/button/button-area.component.d.ts +93 -0
  70. package/crud-table/lib/components/button/button.component.d.ts +61 -0
  71. package/crud-table/lib/components/button/button.types.d.ts +75 -0
  72. package/crud-table/lib/components/button/index.d.ts +15 -0
  73. package/crud-table/lib/components/crud-table/crud-table.component.d.ts +143 -0
  74. package/crud-table/lib/components/crud-table/crud-table.types.d.ts +207 -0
  75. package/crud-table/lib/components/crud-table/index.d.ts +15 -0
  76. package/crud-table/lib/components/form-builder/adapters/it-date-adapter.d.ts +32 -0
  77. package/crud-table/lib/components/form-builder/directives/currency-input.directive.d.ts +48 -0
  78. package/crud-table/lib/components/form-builder/form-builder.component.d.ts +279 -0
  79. package/crud-table/lib/components/form-builder/services/form-condition.service.d.ts +46 -0
  80. package/crud-table/lib/components/form-builder/services/form-error-state.matcher.d.ts +9 -0
  81. package/crud-table/lib/components/form-builder/services/form-field-error.service.d.ts +38 -0
  82. package/crud-table/lib/components/form-builder/services/form-validation.service.d.ts +63 -0
  83. package/crud-table/lib/components/form-builder/services/location.service.d.ts +83 -0
  84. package/crud-table/lib/components/form-builder/services/nominatim-geocoding.service.d.ts +37 -0
  85. package/crud-table/lib/components/form-builder/sub-components/error-summary/form-error-summary.component.d.ts +31 -0
  86. package/crud-table/lib/components/form-builder/sub-components/file-input/file-input.component.d.ts +41 -0
  87. package/crud-table/lib/components/form-builder/sub-components/form-fields/form-number-field.component.d.ts +42 -0
  88. package/crud-table/lib/components/form-builder/sub-components/form-fields/form-radio-field.component.d.ts +45 -0
  89. package/crud-table/lib/components/form-builder/sub-components/form-fields/form-select-field.component.d.ts +44 -0
  90. package/crud-table/lib/components/form-builder/sub-components/form-fields/form-text-field.component.d.ts +62 -0
  91. package/crud-table/lib/components/form-builder/sub-components/form-fields/form-textarea-field.component.d.ts +39 -0
  92. package/crud-table/lib/components/form-builder/sub-components/form-fields/index.d.ts +5 -0
  93. package/crud-table/lib/components/form-builder/sub-components/location-geocoded/location-geocoded.component.d.ts +84 -0
  94. package/crud-table/lib/components/form-builder/sub-components/specifica-territoriale/specifica-territoriale.component.d.ts +145 -0
  95. package/crud-table/lib/components/form-builder/sub-components/table-territoriale/table-territoriale.component.d.ts +108 -0
  96. package/crud-table/lib/components/form-builder/types/condition.types.d.ts +51 -0
  97. package/crud-table/lib/components/form-builder/types/field.types.d.ts +330 -0
  98. package/crud-table/lib/components/form-builder/types/geocoded-location.types.d.ts +116 -0
  99. package/crud-table/lib/components/form-builder/types/schema.types.d.ts +304 -0
  100. package/crud-table/lib/components/form-builder/types/territoriale.types.d.ts +170 -0
  101. package/crud-table/lib/components/form-builder/types/validation.types.d.ts +179 -0
  102. package/crud-table/lib/components/modal/confirm-dialog.component.d.ts +46 -0
  103. package/crud-table/lib/components/modal/modal.service.d.ts +93 -0
  104. package/crud-table/lib/components/modal/modal.types.d.ts +110 -0
  105. package/crud-table/lib/core/logging/logger.config.d.ts +18 -0
  106. package/crud-table/lib/core/logging/logger.service.d.ts +75 -0
  107. package/crud-table/lib/core/logging/logger.types.d.ts +70 -0
  108. package/crud-table/lib/core/types/index.d.ts +133 -0
  109. package/esm2022/accordion/entry-accordion.mjs +5 -0
  110. package/esm2022/accordion/gnggln-ng-ui-system-accordion.mjs +5 -0
  111. package/esm2022/accordion/lib/components/accordion/accordion.component.mjs +398 -0
  112. package/esm2022/accordion/lib/components/accordion/accordion.types.mjs +6 -0
  113. package/esm2022/accordion/lib/components/accordion/index.mjs +2 -0
  114. package/esm2022/accordion/lib/core/types/index.mjs +6 -0
  115. package/esm2022/base-layout/entry-base-layout.mjs +5 -0
  116. package/esm2022/base-layout/gnggln-ng-ui-system-base-layout.mjs +5 -0
  117. package/esm2022/base-layout/lib/components/base-layout/base-layout.component.mjs +272 -0
  118. package/esm2022/base-layout/lib/components/base-layout/base-layout.types.mjs +6 -0
  119. package/esm2022/base-layout/lib/components/base-layout/index.mjs +14 -0
  120. package/esm2022/base-layout/lib/components/blackbox/blackbox-fingerprint.service.mjs +116 -0
  121. package/esm2022/base-layout/lib/components/blackbox/blackbox-storage.service.mjs +286 -0
  122. package/esm2022/base-layout/lib/components/blackbox/blackbox.service.mjs +323 -0
  123. package/esm2022/base-layout/lib/components/blackbox/blackbox.types.mjs +25 -0
  124. package/esm2022/base-layout/lib/components/button/button-area.component.mjs +210 -0
  125. package/esm2022/base-layout/lib/components/button/button.component.mjs +180 -0
  126. package/esm2022/base-layout/lib/components/button/button.types.mjs +6 -0
  127. package/esm2022/base-layout/lib/components/page-header/breadcrumb.service.mjs +243 -0
  128. package/esm2022/base-layout/lib/components/page-header/page-header.component.mjs +243 -0
  129. package/esm2022/base-layout/lib/components/page-header/page-header.types.mjs +21 -0
  130. package/esm2022/base-layout/lib/core/types/index.mjs +6 -0
  131. package/esm2022/blackbox/entry-blackbox.mjs +5 -0
  132. package/esm2022/blackbox/gnggln-ng-ui-system-blackbox.mjs +5 -0
  133. package/esm2022/blackbox/lib/components/blackbox/blackbox-debugger.component.mjs +904 -0
  134. package/esm2022/blackbox/lib/components/blackbox/blackbox-debugger.service.mjs +51 -0
  135. package/esm2022/blackbox/lib/components/blackbox/blackbox-fingerprint.service.mjs +116 -0
  136. package/esm2022/blackbox/lib/components/blackbox/blackbox-json-viewer.component.mjs +66 -0
  137. package/esm2022/blackbox/lib/components/blackbox/blackbox-storage.service.mjs +286 -0
  138. package/esm2022/blackbox/lib/components/blackbox/blackbox.interceptor.mjs +135 -0
  139. package/esm2022/blackbox/lib/components/blackbox/blackbox.service.mjs +323 -0
  140. package/esm2022/blackbox/lib/components/blackbox/blackbox.types.mjs +25 -0
  141. package/esm2022/blackbox/lib/components/blackbox/index.mjs +27 -0
  142. package/esm2022/blackbox/lib/components/blackbox/ui-track.directive.mjs +69 -0
  143. package/esm2022/blackbox/lib/components/button/button-area.component.mjs +210 -0
  144. package/esm2022/blackbox/lib/components/button/button.component.mjs +180 -0
  145. package/esm2022/blackbox/lib/components/button/button.types.mjs +6 -0
  146. package/esm2022/blackbox/lib/components/button/index.mjs +16 -0
  147. package/esm2022/blackbox/lib/components/modal/confirm-dialog.component.mjs +151 -0
  148. package/esm2022/blackbox/lib/components/modal/index.mjs +4 -0
  149. package/esm2022/blackbox/lib/components/modal/modal.component.mjs +139 -0
  150. package/esm2022/blackbox/lib/components/modal/modal.service.mjs +197 -0
  151. package/esm2022/blackbox/lib/components/modal/modal.types.mjs +6 -0
  152. package/esm2022/blackbox/lib/core/types/index.mjs +6 -0
  153. package/esm2022/button/entry-button.mjs +5 -0
  154. package/esm2022/button/gnggln-ng-ui-system-button.mjs +5 -0
  155. package/esm2022/button/lib/components/blackbox/blackbox-fingerprint.service.mjs +116 -0
  156. package/esm2022/button/lib/components/blackbox/blackbox-storage.service.mjs +286 -0
  157. package/esm2022/button/lib/components/blackbox/blackbox.service.mjs +323 -0
  158. package/esm2022/button/lib/components/blackbox/blackbox.types.mjs +25 -0
  159. package/esm2022/button/lib/components/button/button-area.component.mjs +210 -0
  160. package/esm2022/button/lib/components/button/button.component.mjs +180 -0
  161. package/esm2022/button/lib/components/button/button.types.mjs +6 -0
  162. package/esm2022/button/lib/components/button/index.mjs +16 -0
  163. package/esm2022/button/lib/core/types/index.mjs +6 -0
  164. package/esm2022/core/entry-core.mjs +6 -0
  165. package/esm2022/core/gnggln-ng-ui-system-core.mjs +5 -0
  166. package/esm2022/core/lib/core/types/index.mjs +6 -0
  167. package/esm2022/core/lib/core/utils/index.mjs +102 -0
  168. package/esm2022/crud-table/entry-crud-table.mjs +5 -0
  169. package/esm2022/crud-table/gnggln-ng-ui-system-crud-table.mjs +5 -0
  170. package/esm2022/crud-table/lib/components/accordion/accordion.component.mjs +398 -0
  171. package/esm2022/crud-table/lib/components/accordion/accordion.types.mjs +6 -0
  172. package/esm2022/crud-table/lib/components/accordion/index.mjs +2 -0
  173. package/esm2022/crud-table/lib/components/blackbox/blackbox-fingerprint.service.mjs +116 -0
  174. package/esm2022/crud-table/lib/components/blackbox/blackbox-storage.service.mjs +286 -0
  175. package/esm2022/crud-table/lib/components/blackbox/blackbox.service.mjs +323 -0
  176. package/esm2022/crud-table/lib/components/blackbox/blackbox.types.mjs +25 -0
  177. package/esm2022/crud-table/lib/components/button/button-area.component.mjs +210 -0
  178. package/esm2022/crud-table/lib/components/button/button.component.mjs +180 -0
  179. package/esm2022/crud-table/lib/components/button/button.types.mjs +6 -0
  180. package/esm2022/crud-table/lib/components/button/index.mjs +16 -0
  181. package/esm2022/crud-table/lib/components/crud-table/crud-table.component.mjs +789 -0
  182. package/esm2022/crud-table/lib/components/crud-table/crud-table.types.mjs +6 -0
  183. package/esm2022/crud-table/lib/components/crud-table/index.mjs +16 -0
  184. package/esm2022/crud-table/lib/components/form-builder/adapters/it-date-adapter.mjs +82 -0
  185. package/esm2022/crud-table/lib/components/form-builder/directives/currency-input.directive.mjs +184 -0
  186. package/esm2022/crud-table/lib/components/form-builder/form-builder.component.mjs +1351 -0
  187. package/esm2022/crud-table/lib/components/form-builder/services/form-condition.service.mjs +132 -0
  188. package/esm2022/crud-table/lib/components/form-builder/services/form-error-state.matcher.mjs +10 -0
  189. package/esm2022/crud-table/lib/components/form-builder/services/form-field-error.service.mjs +103 -0
  190. package/esm2022/crud-table/lib/components/form-builder/services/form-validation.service.mjs +381 -0
  191. package/esm2022/crud-table/lib/components/form-builder/services/location.service.mjs +141 -0
  192. package/esm2022/crud-table/lib/components/form-builder/services/nominatim-geocoding.service.mjs +120 -0
  193. package/esm2022/crud-table/lib/components/form-builder/sub-components/error-summary/form-error-summary.component.mjs +190 -0
  194. package/esm2022/crud-table/lib/components/form-builder/sub-components/file-input/file-input.component.mjs +310 -0
  195. package/esm2022/crud-table/lib/components/form-builder/sub-components/form-fields/form-number-field.component.mjs +113 -0
  196. package/esm2022/crud-table/lib/components/form-builder/sub-components/form-fields/form-radio-field.component.mjs +105 -0
  197. package/esm2022/crud-table/lib/components/form-builder/sub-components/form-fields/form-select-field.component.mjs +126 -0
  198. package/esm2022/crud-table/lib/components/form-builder/sub-components/form-fields/form-text-field.component.mjs +147 -0
  199. package/esm2022/crud-table/lib/components/form-builder/sub-components/form-fields/form-textarea-field.component.mjs +99 -0
  200. package/esm2022/crud-table/lib/components/form-builder/sub-components/form-fields/index.mjs +6 -0
  201. package/esm2022/crud-table/lib/components/form-builder/sub-components/location-geocoded/location-geocoded.component.mjs +322 -0
  202. package/esm2022/crud-table/lib/components/form-builder/sub-components/specifica-territoriale/specifica-territoriale.component.mjs +648 -0
  203. package/esm2022/crud-table/lib/components/form-builder/sub-components/table-territoriale/table-territoriale.component.mjs +432 -0
  204. package/esm2022/crud-table/lib/components/form-builder/types/condition.types.mjs +6 -0
  205. package/esm2022/crud-table/lib/components/form-builder/types/field.types.mjs +6 -0
  206. package/esm2022/crud-table/lib/components/form-builder/types/geocoded-location.types.mjs +6 -0
  207. package/esm2022/crud-table/lib/components/form-builder/types/schema.types.mjs +6 -0
  208. package/esm2022/crud-table/lib/components/form-builder/types/territoriale.types.mjs +6 -0
  209. package/esm2022/crud-table/lib/components/form-builder/types/validation.types.mjs +10 -0
  210. package/esm2022/crud-table/lib/components/modal/confirm-dialog.component.mjs +151 -0
  211. package/esm2022/crud-table/lib/components/modal/modal.service.mjs +197 -0
  212. package/esm2022/crud-table/lib/components/modal/modal.types.mjs +6 -0
  213. package/esm2022/crud-table/lib/core/logging/logger.config.mjs +18 -0
  214. package/esm2022/crud-table/lib/core/logging/logger.service.mjs +295 -0
  215. package/esm2022/crud-table/lib/core/logging/logger.types.mjs +7 -0
  216. package/esm2022/crud-table/lib/core/types/index.mjs +6 -0
  217. package/esm2022/crud-table/lib/sources/location-data.opt.json +8942 -0
  218. package/esm2022/crud-table/lib/sources/nazioni.opt.json +215 -0
  219. package/esm2022/form-builder/entry-form-builder.mjs +5 -0
  220. package/esm2022/form-builder/gnggln-ng-ui-system-form-builder.mjs +5 -0
  221. package/esm2022/form-builder/lib/components/accordion/accordion.component.mjs +398 -0
  222. package/esm2022/form-builder/lib/components/accordion/accordion.types.mjs +6 -0
  223. package/esm2022/form-builder/lib/components/accordion/index.mjs +2 -0
  224. package/esm2022/form-builder/lib/components/blackbox/blackbox-fingerprint.service.mjs +116 -0
  225. package/esm2022/form-builder/lib/components/blackbox/blackbox-storage.service.mjs +286 -0
  226. package/esm2022/form-builder/lib/components/blackbox/blackbox.service.mjs +323 -0
  227. package/esm2022/form-builder/lib/components/blackbox/blackbox.types.mjs +25 -0
  228. package/esm2022/form-builder/lib/components/button/button-area.component.mjs +210 -0
  229. package/esm2022/form-builder/lib/components/button/button.component.mjs +180 -0
  230. package/esm2022/form-builder/lib/components/button/button.types.mjs +6 -0
  231. package/esm2022/form-builder/lib/components/button/index.mjs +16 -0
  232. package/esm2022/form-builder/lib/components/form-builder/adapters/it-date-adapter.mjs +82 -0
  233. package/esm2022/form-builder/lib/components/form-builder/directives/currency-input.directive.mjs +184 -0
  234. package/esm2022/form-builder/lib/components/form-builder/form-builder.component.mjs +1351 -0
  235. package/esm2022/form-builder/lib/components/form-builder/form-wizard.component.mjs +1064 -0
  236. package/esm2022/form-builder/lib/components/form-builder/index.mjs +24 -0
  237. package/esm2022/form-builder/lib/components/form-builder/services/form-condition.service.mjs +132 -0
  238. package/esm2022/form-builder/lib/components/form-builder/services/form-error-state.matcher.mjs +10 -0
  239. package/esm2022/form-builder/lib/components/form-builder/services/form-field-error.service.mjs +103 -0
  240. package/esm2022/form-builder/lib/components/form-builder/services/form-validation.service.mjs +381 -0
  241. package/esm2022/form-builder/lib/components/form-builder/services/location.service.mjs +141 -0
  242. package/esm2022/form-builder/lib/components/form-builder/services/nominatim-geocoding.service.mjs +120 -0
  243. package/esm2022/form-builder/lib/components/form-builder/services/wizard-sync.service.mjs +84 -0
  244. package/esm2022/form-builder/lib/components/form-builder/sub-components/error-summary/form-error-summary.component.mjs +190 -0
  245. package/esm2022/form-builder/lib/components/form-builder/sub-components/file-input/file-input.component.mjs +310 -0
  246. package/esm2022/form-builder/lib/components/form-builder/sub-components/form-fields/form-number-field.component.mjs +113 -0
  247. package/esm2022/form-builder/lib/components/form-builder/sub-components/form-fields/form-radio-field.component.mjs +105 -0
  248. package/esm2022/form-builder/lib/components/form-builder/sub-components/form-fields/form-select-field.component.mjs +126 -0
  249. package/esm2022/form-builder/lib/components/form-builder/sub-components/form-fields/form-text-field.component.mjs +147 -0
  250. package/esm2022/form-builder/lib/components/form-builder/sub-components/form-fields/form-textarea-field.component.mjs +99 -0
  251. package/esm2022/form-builder/lib/components/form-builder/sub-components/form-fields/index.mjs +6 -0
  252. package/esm2022/form-builder/lib/components/form-builder/sub-components/location-geocoded/location-geocoded.component.mjs +322 -0
  253. package/esm2022/form-builder/lib/components/form-builder/sub-components/specifica-territoriale/specifica-territoriale.component.mjs +648 -0
  254. package/esm2022/form-builder/lib/components/form-builder/sub-components/table-territoriale/table-territoriale.component.mjs +432 -0
  255. package/esm2022/form-builder/lib/components/form-builder/types/condition.types.mjs +6 -0
  256. package/esm2022/form-builder/lib/components/form-builder/types/field.types.mjs +6 -0
  257. package/esm2022/form-builder/lib/components/form-builder/types/geocoded-location.types.mjs +6 -0
  258. package/esm2022/form-builder/lib/components/form-builder/types/index.mjs +3 -0
  259. package/esm2022/form-builder/lib/components/form-builder/types/schema.types.mjs +6 -0
  260. package/esm2022/form-builder/lib/components/form-builder/types/territoriale.types.mjs +6 -0
  261. package/esm2022/form-builder/lib/components/form-builder/types/validation.types.mjs +10 -0
  262. package/esm2022/form-builder/lib/core/logging/logger.config.mjs +18 -0
  263. package/esm2022/form-builder/lib/core/logging/logger.service.mjs +295 -0
  264. package/esm2022/form-builder/lib/core/logging/logger.types.mjs +7 -0
  265. package/esm2022/form-builder/lib/core/types/index.mjs +6 -0
  266. package/esm2022/form-builder/lib/sources/location-data.opt.json +8942 -0
  267. package/esm2022/form-builder/lib/sources/nazioni.opt.json +215 -0
  268. package/esm2022/form-builder-editor/entry-form-builder-editor.mjs +5 -0
  269. package/esm2022/form-builder-editor/gnggln-ng-ui-system-form-builder-editor.mjs +5 -0
  270. package/esm2022/form-builder-editor/lib/components/accordion/accordion.component.mjs +398 -0
  271. package/esm2022/form-builder-editor/lib/components/accordion/accordion.types.mjs +6 -0
  272. package/esm2022/form-builder-editor/lib/components/accordion/index.mjs +2 -0
  273. package/esm2022/form-builder-editor/lib/components/blackbox/blackbox-fingerprint.service.mjs +116 -0
  274. package/esm2022/form-builder-editor/lib/components/blackbox/blackbox-storage.service.mjs +286 -0
  275. package/esm2022/form-builder-editor/lib/components/blackbox/blackbox.service.mjs +323 -0
  276. package/esm2022/form-builder-editor/lib/components/blackbox/blackbox.types.mjs +25 -0
  277. package/esm2022/form-builder-editor/lib/components/button/button-area.component.mjs +210 -0
  278. package/esm2022/form-builder-editor/lib/components/button/button.component.mjs +180 -0
  279. package/esm2022/form-builder-editor/lib/components/button/button.types.mjs +6 -0
  280. package/esm2022/form-builder-editor/lib/components/button/index.mjs +16 -0
  281. package/esm2022/form-builder-editor/lib/components/form-builder/adapters/it-date-adapter.mjs +82 -0
  282. package/esm2022/form-builder-editor/lib/components/form-builder/directives/currency-input.directive.mjs +184 -0
  283. package/esm2022/form-builder-editor/lib/components/form-builder/form-builder.component.mjs +1351 -0
  284. package/esm2022/form-builder-editor/lib/components/form-builder/services/form-condition.service.mjs +132 -0
  285. package/esm2022/form-builder-editor/lib/components/form-builder/services/form-error-state.matcher.mjs +10 -0
  286. package/esm2022/form-builder-editor/lib/components/form-builder/services/form-field-error.service.mjs +103 -0
  287. package/esm2022/form-builder-editor/lib/components/form-builder/services/form-validation.service.mjs +381 -0
  288. package/esm2022/form-builder-editor/lib/components/form-builder/services/location.service.mjs +141 -0
  289. package/esm2022/form-builder-editor/lib/components/form-builder/services/nominatim-geocoding.service.mjs +120 -0
  290. package/esm2022/form-builder-editor/lib/components/form-builder/sub-components/error-summary/form-error-summary.component.mjs +190 -0
  291. package/esm2022/form-builder-editor/lib/components/form-builder/sub-components/file-input/file-input.component.mjs +310 -0
  292. package/esm2022/form-builder-editor/lib/components/form-builder/sub-components/form-fields/form-number-field.component.mjs +113 -0
  293. package/esm2022/form-builder-editor/lib/components/form-builder/sub-components/form-fields/form-radio-field.component.mjs +105 -0
  294. package/esm2022/form-builder-editor/lib/components/form-builder/sub-components/form-fields/form-select-field.component.mjs +126 -0
  295. package/esm2022/form-builder-editor/lib/components/form-builder/sub-components/form-fields/form-text-field.component.mjs +147 -0
  296. package/esm2022/form-builder-editor/lib/components/form-builder/sub-components/form-fields/form-textarea-field.component.mjs +99 -0
  297. package/esm2022/form-builder-editor/lib/components/form-builder/sub-components/form-fields/index.mjs +6 -0
  298. package/esm2022/form-builder-editor/lib/components/form-builder/sub-components/location-geocoded/location-geocoded.component.mjs +322 -0
  299. package/esm2022/form-builder-editor/lib/components/form-builder/sub-components/specifica-territoriale/specifica-territoriale.component.mjs +648 -0
  300. package/esm2022/form-builder-editor/lib/components/form-builder/sub-components/table-territoriale/table-territoriale.component.mjs +432 -0
  301. package/esm2022/form-builder-editor/lib/components/form-builder/types/condition.types.mjs +6 -0
  302. package/esm2022/form-builder-editor/lib/components/form-builder/types/field.types.mjs +6 -0
  303. package/esm2022/form-builder-editor/lib/components/form-builder/types/geocoded-location.types.mjs +6 -0
  304. package/esm2022/form-builder-editor/lib/components/form-builder/types/index.mjs +3 -0
  305. package/esm2022/form-builder-editor/lib/components/form-builder/types/schema.types.mjs +6 -0
  306. package/esm2022/form-builder-editor/lib/components/form-builder/types/territoriale.types.mjs +6 -0
  307. package/esm2022/form-builder-editor/lib/components/form-builder/types/validation.types.mjs +10 -0
  308. package/esm2022/form-builder-editor/lib/components/form-builder-editor/form-builder-editor.component.mjs +730 -0
  309. package/esm2022/form-builder-editor/lib/components/form-builder-editor/form-builder-editor.service.mjs +56 -0
  310. package/esm2022/form-builder-editor/lib/components/form-builder-editor/index.mjs +23 -0
  311. package/esm2022/form-builder-editor/lib/components/form-builder-editor/presets/editor-presets.mjs +395 -0
  312. package/esm2022/form-builder-editor/lib/components/form-builder-editor/services/editor-persistence.service.mjs +190 -0
  313. package/esm2022/form-builder-editor/lib/components/form-builder-editor/services/editor-state.service.mjs +324 -0
  314. package/esm2022/form-builder-editor/lib/components/form-builder-editor/services/field-factory.service.mjs +188 -0
  315. package/esm2022/form-builder-editor/lib/components/form-builder-editor/sub-components/condition-editor/condition-editor.component.mjs +667 -0
  316. package/esm2022/form-builder-editor/lib/components/form-builder-editor/sub-components/editor-toolbar/editor-toolbar.component.mjs +317 -0
  317. package/esm2022/form-builder-editor/lib/components/form-builder-editor/sub-components/field-config-panel/field-config-panel.component.mjs +611 -0
  318. package/esm2022/form-builder-editor/lib/components/form-builder-editor/sub-components/field-palette/field-palette.component.mjs +267 -0
  319. package/esm2022/form-builder-editor/lib/components/form-builder-editor/sub-components/form-values-panel/form-values-panel.component.mjs +276 -0
  320. package/esm2022/form-builder-editor/lib/components/form-builder-editor/sub-components/options-editor/options-editor.component.mjs +323 -0
  321. package/esm2022/form-builder-editor/lib/components/form-builder-editor/sub-components/preview-container/preview-container.component.mjs +238 -0
  322. package/esm2022/form-builder-editor/lib/components/form-builder-editor/sub-components/section-editor/section-editor.component.mjs +473 -0
  323. package/esm2022/form-builder-editor/lib/components/form-builder-editor/sub-components/validation-editor/validation-editor.component.mjs +473 -0
  324. package/esm2022/form-builder-editor/lib/components/form-builder-editor/types/editor.types.mjs +6 -0
  325. package/esm2022/form-builder-editor/lib/components/modal/confirm-dialog.component.mjs +151 -0
  326. package/esm2022/form-builder-editor/lib/components/modal/index.mjs +4 -0
  327. package/esm2022/form-builder-editor/lib/components/modal/modal.component.mjs +139 -0
  328. package/esm2022/form-builder-editor/lib/components/modal/modal.service.mjs +197 -0
  329. package/esm2022/form-builder-editor/lib/components/modal/modal.types.mjs +6 -0
  330. package/esm2022/form-builder-editor/lib/core/logging/logger.config.mjs +18 -0
  331. package/esm2022/form-builder-editor/lib/core/logging/logger.service.mjs +295 -0
  332. package/esm2022/form-builder-editor/lib/core/logging/logger.types.mjs +7 -0
  333. package/esm2022/form-builder-editor/lib/core/types/index.mjs +6 -0
  334. package/esm2022/form-builder-editor/lib/sources/location-data.opt.json +8942 -0
  335. package/esm2022/form-builder-editor/lib/sources/nazioni.opt.json +215 -0
  336. package/esm2022/http/entry-http.mjs +5 -0
  337. package/esm2022/http/gnggln-ng-ui-system-http.mjs +5 -0
  338. package/esm2022/http/lib/components/blackbox/blackbox-fingerprint.service.mjs +116 -0
  339. package/esm2022/http/lib/components/blackbox/blackbox-storage.service.mjs +286 -0
  340. package/esm2022/http/lib/components/blackbox/blackbox.service.mjs +323 -0
  341. package/esm2022/http/lib/components/blackbox/blackbox.types.mjs +25 -0
  342. package/esm2022/http/lib/components/http/http-message.handler.mjs +143 -0
  343. package/esm2022/http/lib/components/http/http.service.mjs +228 -0
  344. package/esm2022/http/lib/components/http/http.tokens.mjs +29 -0
  345. package/esm2022/http/lib/components/http/http.types.mjs +6 -0
  346. package/esm2022/http/lib/components/http/index.mjs +19 -0
  347. package/esm2022/http/lib/components/layout-builder/layout-builder.types.mjs +9 -0
  348. package/esm2022/http/lib/components/layout-builder/layout.service.mjs +239 -0
  349. package/esm2022/http/lib/components/toast/toast-container.component.mjs +80 -0
  350. package/esm2022/http/lib/components/toast/toast.component.mjs +151 -0
  351. package/esm2022/http/lib/components/toast/toast.service.mjs +156 -0
  352. package/esm2022/http/lib/components/toast/toast.types.mjs +12 -0
  353. package/esm2022/http/lib/core/types/index.mjs +6 -0
  354. package/esm2022/http/lib/core/utils/index.mjs +102 -0
  355. package/esm2022/layout-builder/entry-layout-builder.mjs +5 -0
  356. package/esm2022/layout-builder/gnggln-ng-ui-system-layout-builder.mjs +5 -0
  357. package/esm2022/layout-builder/lib/components/layout-builder/index.mjs +18 -0
  358. package/esm2022/layout-builder/lib/components/layout-builder/layout-builder.component.mjs +1804 -0
  359. package/esm2022/layout-builder/lib/components/layout-builder/layout-builder.types.mjs +9 -0
  360. package/esm2022/layout-builder/lib/components/layout-builder/layout.service.mjs +239 -0
  361. package/esm2022/layout-builder/lib/core/types/index.mjs +6 -0
  362. package/esm2022/lib/components/accordion/accordion.component.mjs +106 -61
  363. package/esm2022/lib/components/accordion/accordion.types.mjs +1 -1
  364. package/esm2022/lib/components/base-layout/base-layout.component.mjs +88 -34
  365. package/esm2022/lib/components/base-layout/base-layout.types.mjs +1 -1
  366. package/esm2022/lib/components/base-layout/index.mjs +1 -1
  367. package/esm2022/lib/components/blackbox/blackbox-debugger.component.mjs +904 -0
  368. package/esm2022/lib/components/blackbox/blackbox-debugger.service.mjs +51 -0
  369. package/esm2022/lib/components/blackbox/blackbox-fingerprint.service.mjs +116 -0
  370. package/esm2022/lib/components/blackbox/blackbox-json-viewer.component.mjs +66 -0
  371. package/esm2022/lib/components/blackbox/blackbox-storage.service.mjs +286 -0
  372. package/esm2022/lib/components/blackbox/blackbox.interceptor.mjs +135 -0
  373. package/esm2022/lib/components/blackbox/blackbox.service.mjs +323 -0
  374. package/esm2022/lib/components/blackbox/blackbox.types.mjs +25 -0
  375. package/esm2022/lib/components/blackbox/index.mjs +27 -0
  376. package/esm2022/lib/components/blackbox/ui-track.directive.mjs +69 -0
  377. package/esm2022/lib/components/button/button-area.component.mjs +16 -2
  378. package/esm2022/lib/components/button/button.component.mjs +23 -7
  379. package/esm2022/lib/components/button/button.types.mjs +1 -1
  380. package/esm2022/lib/components/crud-table/crud-table.component.mjs +14 -14
  381. package/esm2022/lib/components/form-builder/form-builder.component.mjs +710 -183
  382. package/esm2022/lib/components/form-builder/form-wizard.component.mjs +789 -235
  383. package/esm2022/lib/components/form-builder/index.mjs +7 -2
  384. package/esm2022/lib/components/form-builder/services/form-error-state.matcher.mjs +10 -0
  385. package/esm2022/lib/components/form-builder/services/form-field-error.service.mjs +103 -0
  386. package/esm2022/lib/components/form-builder/services/location.service.mjs +4 -3
  387. package/esm2022/lib/components/form-builder/services/nominatim-geocoding.service.mjs +120 -0
  388. package/esm2022/lib/components/form-builder/sub-components/error-summary/form-error-summary.component.mjs +142 -113
  389. package/esm2022/lib/components/form-builder/sub-components/form-fields/form-number-field.component.mjs +113 -0
  390. package/esm2022/lib/components/form-builder/sub-components/form-fields/form-radio-field.component.mjs +105 -0
  391. package/esm2022/lib/components/form-builder/sub-components/form-fields/form-select-field.component.mjs +126 -0
  392. package/esm2022/lib/components/form-builder/sub-components/form-fields/form-text-field.component.mjs +147 -0
  393. package/esm2022/lib/components/form-builder/sub-components/form-fields/form-textarea-field.component.mjs +99 -0
  394. package/esm2022/lib/components/form-builder/sub-components/form-fields/index.mjs +6 -0
  395. package/esm2022/lib/components/form-builder/sub-components/location-geocoded/location-geocoded.component.mjs +322 -0
  396. package/esm2022/lib/components/form-builder/sub-components/table-territoriale/table-territoriale.component.mjs +3 -3
  397. package/esm2022/lib/components/form-builder/types/field.types.mjs +1 -1
  398. package/esm2022/lib/components/form-builder/types/geocoded-location.types.mjs +6 -0
  399. package/esm2022/lib/components/form-builder/types/index.mjs +3 -2
  400. package/esm2022/lib/components/form-builder/types/schema.types.mjs +1 -1
  401. package/esm2022/lib/components/form-builder/types/validation.types.mjs +6 -2
  402. package/esm2022/lib/components/form-builder-editor/form-builder-editor.component.mjs +3 -3
  403. package/esm2022/lib/components/form-builder-editor/index.mjs +3 -1
  404. package/esm2022/lib/components/form-builder-editor/presets/editor-presets.mjs +395 -0
  405. package/esm2022/lib/components/form-builder-editor/sub-components/preview-container/preview-container.component.mjs +2 -2
  406. package/esm2022/lib/components/form-builder-editor/sub-components/section-editor/section-editor.component.mjs +2 -1
  407. package/esm2022/lib/components/http/http-message.handler.mjs +143 -0
  408. package/esm2022/lib/components/http/http.service.mjs +228 -0
  409. package/esm2022/lib/components/http/http.tokens.mjs +29 -0
  410. package/esm2022/lib/components/http/http.types.mjs +6 -0
  411. package/esm2022/lib/components/http/index.mjs +19 -0
  412. package/esm2022/lib/components/layout-builder/layout-builder.component.mjs +27 -15
  413. package/esm2022/lib/components/modal/confirm-dialog.component.mjs +3 -3
  414. package/esm2022/lib/components/modal/modal.service.mjs +5 -2
  415. package/esm2022/lib/components/page-header/breadcrumb.service.mjs +5 -4
  416. package/esm2022/lib/components/table/paginated-table.component.mjs +17 -3
  417. package/esm2022/lib/components/table/table.types.mjs +1 -1
  418. package/esm2022/lib/components/toast/index.mjs +18 -0
  419. package/esm2022/lib/components/toast/toast-container.component.mjs +80 -0
  420. package/esm2022/lib/components/toast/toast.component.mjs +151 -0
  421. package/esm2022/lib/components/toast/toast.service.mjs +156 -0
  422. package/esm2022/lib/components/toast/toast.types.mjs +12 -0
  423. package/esm2022/lib/core/logging/index.mjs +10 -0
  424. package/esm2022/lib/core/logging/logger.config.mjs +18 -0
  425. package/esm2022/lib/core/logging/logger.service.mjs +295 -0
  426. package/esm2022/lib/core/logging/logger.types.mjs +7 -0
  427. package/esm2022/lib/core/types/index.mjs +1 -1
  428. package/esm2022/lib/core/utils/index.mjs +50 -1
  429. package/esm2022/lib/version/ng-ui-system-version.mjs +12 -0
  430. package/esm2022/modal/entry-modal.mjs +5 -0
  431. package/esm2022/modal/gnggln-ng-ui-system-modal.mjs +5 -0
  432. package/esm2022/modal/lib/components/button/button.component.mjs +180 -0
  433. package/esm2022/modal/lib/components/button/button.types.mjs +6 -0
  434. package/esm2022/modal/lib/components/modal/confirm-dialog.component.mjs +151 -0
  435. package/esm2022/modal/lib/components/modal/index.mjs +4 -0
  436. package/esm2022/modal/lib/components/modal/modal.component.mjs +139 -0
  437. package/esm2022/modal/lib/components/modal/modal.service.mjs +197 -0
  438. package/esm2022/modal/lib/components/modal/modal.types.mjs +6 -0
  439. package/esm2022/modal/lib/core/types/index.mjs +6 -0
  440. package/esm2022/page-header/entry-page-header.mjs +5 -0
  441. package/esm2022/page-header/gnggln-ng-ui-system-page-header.mjs +5 -0
  442. package/esm2022/page-header/lib/components/page-header/breadcrumb.service.mjs +243 -0
  443. package/esm2022/page-header/lib/components/page-header/index.mjs +20 -0
  444. package/esm2022/page-header/lib/components/page-header/page-header.component.mjs +243 -0
  445. package/esm2022/page-header/lib/components/page-header/page-header.types.mjs +21 -0
  446. package/esm2022/public-api.mjs +17 -8
  447. package/esm2022/table/entry-table.mjs +5 -0
  448. package/esm2022/table/gnggln-ng-ui-system-table.mjs +5 -0
  449. package/esm2022/table/lib/components/table/index.mjs +2 -0
  450. package/esm2022/table/lib/components/table/paginated-table.component.mjs +421 -0
  451. package/esm2022/table/lib/components/table/table.types.mjs +6 -0
  452. package/esm2022/table/lib/core/utils/index.mjs +102 -0
  453. package/esm2022/toast/entry-toast.mjs +5 -0
  454. package/esm2022/toast/gnggln-ng-ui-system-toast.mjs +5 -0
  455. package/esm2022/toast/lib/components/toast/index.mjs +18 -0
  456. package/esm2022/toast/lib/components/toast/toast-container.component.mjs +80 -0
  457. package/esm2022/toast/lib/components/toast/toast.component.mjs +151 -0
  458. package/esm2022/toast/lib/components/toast/toast.service.mjs +156 -0
  459. package/esm2022/toast/lib/components/toast/toast.types.mjs +12 -0
  460. package/esm2022/toast/lib/core/types/index.mjs +6 -0
  461. package/esm2022/toast/lib/core/utils/index.mjs +102 -0
  462. package/fesm2022/gnggln-ng-ui-system-accordion.mjs +409 -0
  463. package/fesm2022/gnggln-ng-ui-system-accordion.mjs.map +1 -0
  464. package/fesm2022/gnggln-ng-ui-system-base-layout.mjs +1905 -0
  465. package/fesm2022/gnggln-ng-ui-system-base-layout.mjs.map +1 -0
  466. package/fesm2022/gnggln-ng-ui-system-blackbox.mjs +2829 -0
  467. package/fesm2022/gnggln-ng-ui-system-blackbox.mjs.map +1 -0
  468. package/fesm2022/gnggln-ng-ui-system-button.mjs +1148 -0
  469. package/fesm2022/gnggln-ng-ui-system-button.mjs.map +1 -0
  470. package/fesm2022/gnggln-ng-ui-system-core.mjs +117 -0
  471. package/fesm2022/gnggln-ng-ui-system-core.mjs.map +1 -0
  472. package/fesm2022/gnggln-ng-ui-system-crud-table.mjs +49600 -0
  473. package/fesm2022/gnggln-ng-ui-system-crud-table.mjs.map +1 -0
  474. package/fesm2022/gnggln-ng-ui-system-form-builder-editor.mjs +54332 -0
  475. package/fesm2022/gnggln-ng-ui-system-form-builder-editor.mjs.map +1 -0
  476. package/fesm2022/gnggln-ng-ui-system-form-builder.mjs +49609 -0
  477. package/fesm2022/gnggln-ng-ui-system-form-builder.mjs.map +1 -0
  478. package/fesm2022/gnggln-ng-ui-system-http.mjs +1878 -0
  479. package/fesm2022/gnggln-ng-ui-system-http.mjs.map +1 -0
  480. package/fesm2022/gnggln-ng-ui-system-layout-builder.mjs +2064 -0
  481. package/fesm2022/gnggln-ng-ui-system-layout-builder.mjs.map +1 -0
  482. package/fesm2022/gnggln-ng-ui-system-modal.mjs +664 -0
  483. package/fesm2022/gnggln-ng-ui-system-modal.mjs.map +1 -0
  484. package/fesm2022/gnggln-ng-ui-system-page-header.mjs +526 -0
  485. package/fesm2022/gnggln-ng-ui-system-page-header.mjs.map +1 -0
  486. package/fesm2022/gnggln-ng-ui-system-table.mjs +533 -0
  487. package/fesm2022/gnggln-ng-ui-system-table.mjs.map +1 -0
  488. package/fesm2022/gnggln-ng-ui-system-toast.mjs +516 -0
  489. package/fesm2022/gnggln-ng-ui-system-toast.mjs.map +1 -0
  490. package/fesm2022/gnggln-ng-ui-system.mjs +10068 -4234
  491. package/fesm2022/gnggln-ng-ui-system.mjs.map +1 -1
  492. package/form-builder/entry-form-builder.d.ts +4 -0
  493. package/form-builder/index.d.ts +5 -0
  494. package/form-builder/lib/components/accordion/accordion.component.d.ts +125 -0
  495. package/form-builder/lib/components/accordion/accordion.types.d.ts +64 -0
  496. package/form-builder/lib/components/accordion/index.d.ts +2 -0
  497. package/form-builder/lib/components/blackbox/blackbox-fingerprint.service.d.ts +36 -0
  498. package/form-builder/lib/components/blackbox/blackbox-storage.service.d.ts +55 -0
  499. package/form-builder/lib/components/blackbox/blackbox.service.d.ts +144 -0
  500. package/form-builder/lib/components/blackbox/blackbox.types.d.ts +238 -0
  501. package/form-builder/lib/components/button/button-area.component.d.ts +93 -0
  502. package/form-builder/lib/components/button/button.component.d.ts +61 -0
  503. package/form-builder/lib/components/button/button.types.d.ts +75 -0
  504. package/form-builder/lib/components/button/index.d.ts +15 -0
  505. package/form-builder/lib/components/form-builder/adapters/it-date-adapter.d.ts +32 -0
  506. package/form-builder/lib/components/form-builder/directives/currency-input.directive.d.ts +48 -0
  507. package/form-builder/lib/components/form-builder/form-builder.component.d.ts +279 -0
  508. package/form-builder/lib/components/form-builder/form-wizard.component.d.ts +172 -0
  509. package/form-builder/lib/components/form-builder/index.d.ts +19 -0
  510. package/form-builder/lib/components/form-builder/services/form-condition.service.d.ts +46 -0
  511. package/form-builder/lib/components/form-builder/services/form-error-state.matcher.d.ts +9 -0
  512. package/form-builder/lib/components/form-builder/services/form-field-error.service.d.ts +38 -0
  513. package/form-builder/lib/components/form-builder/services/form-validation.service.d.ts +63 -0
  514. package/form-builder/lib/components/form-builder/services/location.service.d.ts +83 -0
  515. package/form-builder/lib/components/form-builder/services/nominatim-geocoding.service.d.ts +37 -0
  516. package/form-builder/lib/components/form-builder/services/wizard-sync.service.d.ts +63 -0
  517. package/form-builder/lib/components/form-builder/sub-components/error-summary/form-error-summary.component.d.ts +31 -0
  518. package/form-builder/lib/components/form-builder/sub-components/file-input/file-input.component.d.ts +41 -0
  519. package/form-builder/lib/components/form-builder/sub-components/form-fields/form-number-field.component.d.ts +42 -0
  520. package/form-builder/lib/components/form-builder/sub-components/form-fields/form-radio-field.component.d.ts +45 -0
  521. package/form-builder/lib/components/form-builder/sub-components/form-fields/form-select-field.component.d.ts +44 -0
  522. package/form-builder/lib/components/form-builder/sub-components/form-fields/form-text-field.component.d.ts +62 -0
  523. package/form-builder/lib/components/form-builder/sub-components/form-fields/form-textarea-field.component.d.ts +39 -0
  524. package/form-builder/lib/components/form-builder/sub-components/form-fields/index.d.ts +5 -0
  525. package/form-builder/lib/components/form-builder/sub-components/location-geocoded/location-geocoded.component.d.ts +84 -0
  526. package/form-builder/lib/components/form-builder/sub-components/specifica-territoriale/specifica-territoriale.component.d.ts +145 -0
  527. package/form-builder/lib/components/form-builder/sub-components/table-territoriale/table-territoriale.component.d.ts +108 -0
  528. package/form-builder/lib/components/form-builder/types/condition.types.d.ts +51 -0
  529. package/form-builder/lib/components/form-builder/types/field.types.d.ts +330 -0
  530. package/form-builder/lib/components/form-builder/types/geocoded-location.types.d.ts +116 -0
  531. package/form-builder/lib/components/form-builder/types/index.d.ts +6 -0
  532. package/form-builder/lib/components/form-builder/types/schema.types.d.ts +304 -0
  533. package/form-builder/lib/components/form-builder/types/territoriale.types.d.ts +170 -0
  534. package/form-builder/lib/components/form-builder/types/validation.types.d.ts +179 -0
  535. package/form-builder/lib/core/logging/logger.config.d.ts +18 -0
  536. package/form-builder/lib/core/logging/logger.service.d.ts +75 -0
  537. package/form-builder/lib/core/logging/logger.types.d.ts +70 -0
  538. package/form-builder/lib/core/types/index.d.ts +133 -0
  539. package/form-builder-editor/entry-form-builder-editor.d.ts +4 -0
  540. package/form-builder-editor/index.d.ts +5 -0
  541. package/form-builder-editor/lib/components/accordion/accordion.component.d.ts +125 -0
  542. package/form-builder-editor/lib/components/accordion/accordion.types.d.ts +64 -0
  543. package/form-builder-editor/lib/components/accordion/index.d.ts +2 -0
  544. package/form-builder-editor/lib/components/blackbox/blackbox-fingerprint.service.d.ts +36 -0
  545. package/form-builder-editor/lib/components/blackbox/blackbox-storage.service.d.ts +55 -0
  546. package/form-builder-editor/lib/components/blackbox/blackbox.service.d.ts +144 -0
  547. package/form-builder-editor/lib/components/blackbox/blackbox.types.d.ts +238 -0
  548. package/form-builder-editor/lib/components/button/button-area.component.d.ts +93 -0
  549. package/form-builder-editor/lib/components/button/button.component.d.ts +61 -0
  550. package/form-builder-editor/lib/components/button/button.types.d.ts +75 -0
  551. package/form-builder-editor/lib/components/button/index.d.ts +15 -0
  552. package/form-builder-editor/lib/components/form-builder/adapters/it-date-adapter.d.ts +32 -0
  553. package/form-builder-editor/lib/components/form-builder/directives/currency-input.directive.d.ts +48 -0
  554. package/form-builder-editor/lib/components/form-builder/form-builder.component.d.ts +279 -0
  555. package/form-builder-editor/lib/components/form-builder/services/form-condition.service.d.ts +46 -0
  556. package/form-builder-editor/lib/components/form-builder/services/form-error-state.matcher.d.ts +9 -0
  557. package/form-builder-editor/lib/components/form-builder/services/form-field-error.service.d.ts +38 -0
  558. package/form-builder-editor/lib/components/form-builder/services/form-validation.service.d.ts +63 -0
  559. package/form-builder-editor/lib/components/form-builder/services/location.service.d.ts +83 -0
  560. package/form-builder-editor/lib/components/form-builder/services/nominatim-geocoding.service.d.ts +37 -0
  561. package/form-builder-editor/lib/components/form-builder/sub-components/error-summary/form-error-summary.component.d.ts +31 -0
  562. package/form-builder-editor/lib/components/form-builder/sub-components/file-input/file-input.component.d.ts +41 -0
  563. package/form-builder-editor/lib/components/form-builder/sub-components/form-fields/form-number-field.component.d.ts +42 -0
  564. package/form-builder-editor/lib/components/form-builder/sub-components/form-fields/form-radio-field.component.d.ts +45 -0
  565. package/form-builder-editor/lib/components/form-builder/sub-components/form-fields/form-select-field.component.d.ts +44 -0
  566. package/form-builder-editor/lib/components/form-builder/sub-components/form-fields/form-text-field.component.d.ts +62 -0
  567. package/form-builder-editor/lib/components/form-builder/sub-components/form-fields/form-textarea-field.component.d.ts +39 -0
  568. package/form-builder-editor/lib/components/form-builder/sub-components/form-fields/index.d.ts +5 -0
  569. package/form-builder-editor/lib/components/form-builder/sub-components/location-geocoded/location-geocoded.component.d.ts +84 -0
  570. package/form-builder-editor/lib/components/form-builder/sub-components/specifica-territoriale/specifica-territoriale.component.d.ts +145 -0
  571. package/form-builder-editor/lib/components/form-builder/sub-components/table-territoriale/table-territoriale.component.d.ts +108 -0
  572. package/form-builder-editor/lib/components/form-builder/types/condition.types.d.ts +51 -0
  573. package/form-builder-editor/lib/components/form-builder/types/field.types.d.ts +330 -0
  574. package/form-builder-editor/lib/components/form-builder/types/geocoded-location.types.d.ts +116 -0
  575. package/form-builder-editor/lib/components/form-builder/types/index.d.ts +6 -0
  576. package/form-builder-editor/lib/components/form-builder/types/schema.types.d.ts +304 -0
  577. package/form-builder-editor/lib/components/form-builder/types/territoriale.types.d.ts +170 -0
  578. package/form-builder-editor/lib/components/form-builder/types/validation.types.d.ts +179 -0
  579. package/form-builder-editor/lib/components/form-builder-editor/form-builder-editor.component.d.ts +117 -0
  580. package/form-builder-editor/lib/components/form-builder-editor/form-builder-editor.service.d.ts +38 -0
  581. package/form-builder-editor/lib/components/form-builder-editor/index.d.ts +17 -0
  582. package/form-builder-editor/lib/components/form-builder-editor/presets/editor-presets.d.ts +25 -0
  583. package/form-builder-editor/lib/components/form-builder-editor/services/editor-persistence.service.d.ts +42 -0
  584. package/form-builder-editor/lib/components/form-builder-editor/services/editor-state.service.d.ts +66 -0
  585. package/form-builder-editor/lib/components/form-builder-editor/services/field-factory.service.d.ts +28 -0
  586. package/form-builder-editor/lib/components/form-builder-editor/sub-components/condition-editor/condition-editor.component.d.ts +139 -0
  587. package/form-builder-editor/lib/components/form-builder-editor/sub-components/editor-toolbar/editor-toolbar.component.d.ts +43 -0
  588. package/form-builder-editor/lib/components/form-builder-editor/sub-components/field-config-panel/field-config-panel.component.d.ts +83 -0
  589. package/form-builder-editor/lib/components/form-builder-editor/sub-components/field-palette/field-palette.component.d.ts +40 -0
  590. package/form-builder-editor/lib/components/form-builder-editor/sub-components/form-values-panel/form-values-panel.component.d.ts +51 -0
  591. package/form-builder-editor/lib/components/form-builder-editor/sub-components/options-editor/options-editor.component.d.ts +63 -0
  592. package/form-builder-editor/lib/components/form-builder-editor/sub-components/preview-container/preview-container.component.d.ts +68 -0
  593. package/form-builder-editor/lib/components/form-builder-editor/sub-components/section-editor/section-editor.component.d.ts +82 -0
  594. package/form-builder-editor/lib/components/form-builder-editor/sub-components/validation-editor/validation-editor.component.d.ts +112 -0
  595. package/form-builder-editor/lib/components/form-builder-editor/types/editor.types.d.ts +124 -0
  596. package/form-builder-editor/lib/components/modal/confirm-dialog.component.d.ts +46 -0
  597. package/form-builder-editor/lib/components/modal/index.d.ts +4 -0
  598. package/form-builder-editor/lib/components/modal/modal.component.d.ts +44 -0
  599. package/form-builder-editor/lib/components/modal/modal.service.d.ts +93 -0
  600. package/form-builder-editor/lib/components/modal/modal.types.d.ts +110 -0
  601. package/form-builder-editor/lib/core/logging/logger.config.d.ts +18 -0
  602. package/form-builder-editor/lib/core/logging/logger.service.d.ts +75 -0
  603. package/form-builder-editor/lib/core/logging/logger.types.d.ts +70 -0
  604. package/form-builder-editor/lib/core/types/index.d.ts +133 -0
  605. package/http/entry-http.d.ts +4 -0
  606. package/http/index.d.ts +5 -0
  607. package/http/lib/components/blackbox/blackbox-fingerprint.service.d.ts +36 -0
  608. package/http/lib/components/blackbox/blackbox-storage.service.d.ts +55 -0
  609. package/http/lib/components/blackbox/blackbox.service.d.ts +144 -0
  610. package/http/lib/components/blackbox/blackbox.types.d.ts +238 -0
  611. package/http/lib/components/http/http-message.handler.d.ts +59 -0
  612. package/http/lib/components/http/http.service.d.ts +98 -0
  613. package/http/lib/components/http/http.tokens.d.ts +29 -0
  614. package/http/lib/components/http/http.types.d.ts +50 -0
  615. package/http/lib/components/http/index.d.ts +17 -0
  616. package/http/lib/components/layout-builder/layout-builder.types.d.ts +436 -0
  617. package/http/lib/components/layout-builder/layout.service.d.ts +100 -0
  618. package/http/lib/components/toast/toast-container.component.d.ts +27 -0
  619. package/http/lib/components/toast/toast.component.d.ts +37 -0
  620. package/http/lib/components/toast/toast.service.d.ts +39 -0
  621. package/http/lib/components/toast/toast.types.d.ts +52 -0
  622. package/http/lib/core/types/index.d.ts +133 -0
  623. package/http/lib/core/utils/index.d.ts +60 -0
  624. package/layout-builder/entry-layout-builder.d.ts +4 -0
  625. package/layout-builder/index.d.ts +5 -0
  626. package/layout-builder/lib/components/layout-builder/index.d.ts +16 -0
  627. package/layout-builder/lib/components/layout-builder/layout-builder.component.d.ts +85 -0
  628. package/layout-builder/lib/components/layout-builder/layout-builder.types.d.ts +436 -0
  629. package/layout-builder/lib/components/layout-builder/layout.service.d.ts +100 -0
  630. package/layout-builder/lib/core/types/index.d.ts +133 -0
  631. package/lib/components/accordion/accordion.component.d.ts +10 -3
  632. package/lib/components/accordion/accordion.types.d.ts +2 -0
  633. package/lib/components/base-layout/base-layout.component.d.ts +36 -11
  634. package/lib/components/base-layout/base-layout.types.d.ts +14 -0
  635. package/lib/components/base-layout/index.d.ts +1 -1
  636. package/lib/components/blackbox/blackbox-debugger.component.d.ts +80 -0
  637. package/lib/components/blackbox/blackbox-debugger.service.d.ts +34 -0
  638. package/lib/components/blackbox/blackbox-fingerprint.service.d.ts +36 -0
  639. package/lib/components/blackbox/blackbox-json-viewer.component.d.ts +18 -0
  640. package/lib/components/blackbox/blackbox-storage.service.d.ts +55 -0
  641. package/lib/components/blackbox/blackbox.interceptor.d.ts +38 -0
  642. package/lib/components/blackbox/blackbox.service.d.ts +144 -0
  643. package/lib/components/blackbox/blackbox.types.d.ts +238 -0
  644. package/lib/components/blackbox/index.d.ts +23 -0
  645. package/lib/components/blackbox/ui-track.directive.d.ts +20 -0
  646. package/lib/components/button/button-area.component.d.ts +6 -1
  647. package/lib/components/button/button.component.d.ts +8 -2
  648. package/lib/components/button/button.types.d.ts +5 -0
  649. package/lib/components/form-builder/form-builder.component.d.ts +125 -29
  650. package/lib/components/form-builder/form-wizard.component.d.ts +89 -4
  651. package/lib/components/form-builder/index.d.ts +7 -1
  652. package/lib/components/form-builder/services/form-error-state.matcher.d.ts +9 -0
  653. package/lib/components/form-builder/services/form-field-error.service.d.ts +38 -0
  654. package/lib/components/form-builder/services/nominatim-geocoding.service.d.ts +37 -0
  655. package/lib/components/form-builder/sub-components/error-summary/form-error-summary.component.d.ts +9 -6
  656. package/lib/components/form-builder/sub-components/form-fields/form-number-field.component.d.ts +42 -0
  657. package/lib/components/form-builder/sub-components/form-fields/form-radio-field.component.d.ts +45 -0
  658. package/lib/components/form-builder/sub-components/form-fields/form-select-field.component.d.ts +44 -0
  659. package/lib/components/form-builder/sub-components/form-fields/form-text-field.component.d.ts +62 -0
  660. package/lib/components/form-builder/sub-components/form-fields/form-textarea-field.component.d.ts +39 -0
  661. package/lib/components/form-builder/sub-components/form-fields/index.d.ts +5 -0
  662. package/lib/components/form-builder/sub-components/location-geocoded/location-geocoded.component.d.ts +84 -0
  663. package/lib/components/form-builder/types/field.types.d.ts +48 -6
  664. package/lib/components/form-builder/types/geocoded-location.types.d.ts +116 -0
  665. package/lib/components/form-builder/types/index.d.ts +4 -3
  666. package/lib/components/form-builder/types/schema.types.d.ts +83 -6
  667. package/lib/components/form-builder/types/validation.types.d.ts +5 -0
  668. package/lib/components/form-builder-editor/index.d.ts +2 -0
  669. package/lib/components/form-builder-editor/presets/editor-presets.d.ts +25 -0
  670. package/lib/components/http/http-message.handler.d.ts +59 -0
  671. package/lib/components/http/http.service.d.ts +98 -0
  672. package/lib/components/http/http.tokens.d.ts +29 -0
  673. package/lib/components/http/http.types.d.ts +50 -0
  674. package/lib/components/http/index.d.ts +17 -0
  675. package/lib/components/page-header/breadcrumb.service.d.ts +2 -2
  676. package/lib/components/table/table.types.d.ts +5 -0
  677. package/lib/components/toast/index.d.ts +17 -0
  678. package/lib/components/toast/toast-container.component.d.ts +27 -0
  679. package/lib/components/toast/toast.component.d.ts +37 -0
  680. package/lib/components/toast/toast.service.d.ts +39 -0
  681. package/lib/components/toast/toast.types.d.ts +52 -0
  682. package/lib/core/logging/index.d.ts +8 -0
  683. package/lib/core/logging/logger.config.d.ts +18 -0
  684. package/lib/core/logging/logger.service.d.ts +75 -0
  685. package/lib/core/logging/logger.types.d.ts +70 -0
  686. package/lib/core/types/index.d.ts +76 -0
  687. package/lib/core/utils/index.d.ts +31 -0
  688. package/lib/version/ng-ui-system-version.d.ts +9 -0
  689. package/modal/entry-modal.d.ts +4 -0
  690. package/modal/index.d.ts +5 -0
  691. package/modal/lib/components/button/button.component.d.ts +61 -0
  692. package/modal/lib/components/button/button.types.d.ts +75 -0
  693. package/modal/lib/components/modal/confirm-dialog.component.d.ts +46 -0
  694. package/modal/lib/components/modal/index.d.ts +4 -0
  695. package/modal/lib/components/modal/modal.component.d.ts +44 -0
  696. package/modal/lib/components/modal/modal.service.d.ts +93 -0
  697. package/modal/lib/components/modal/modal.types.d.ts +110 -0
  698. package/modal/lib/core/types/index.d.ts +133 -0
  699. package/package.json +93 -8
  700. package/page-header/entry-page-header.d.ts +4 -0
  701. package/page-header/index.d.ts +5 -0
  702. package/page-header/lib/components/page-header/breadcrumb.service.d.ts +96 -0
  703. package/page-header/lib/components/page-header/index.d.ts +16 -0
  704. package/page-header/lib/components/page-header/page-header.component.d.ts +59 -0
  705. package/page-header/lib/components/page-header/page-header.types.d.ts +96 -0
  706. package/public-api.d.ts +11 -6
  707. package/table/entry-table.d.ts +4 -0
  708. package/table/index.d.ts +5 -0
  709. package/table/lib/components/table/index.d.ts +2 -0
  710. package/table/lib/components/table/paginated-table.component.d.ts +85 -0
  711. package/table/lib/components/table/table.types.d.ts +86 -0
  712. package/table/lib/core/utils/index.d.ts +60 -0
  713. package/toast/entry-toast.d.ts +4 -0
  714. package/toast/index.d.ts +5 -0
  715. package/toast/lib/components/toast/index.d.ts +17 -0
  716. package/toast/lib/components/toast/toast-container.component.d.ts +27 -0
  717. package/toast/lib/components/toast/toast.component.d.ts +37 -0
  718. package/toast/lib/components/toast/toast.service.d.ts +39 -0
  719. package/toast/lib/components/toast/toast.types.d.ts +52 -0
  720. package/toast/lib/core/types/index.d.ts +133 -0
  721. package/toast/lib/core/utils/index.d.ts +60 -0
@@ -0,0 +1,1905 @@
1
+ import * as i0 from '@angular/core';
2
+ import { Component, ChangeDetectionStrategy, ViewEncapsulation, Input, inject, PLATFORM_ID, Injectable, NgZone, InjectionToken, DestroyRef, ChangeDetectorRef, signal } from '@angular/core';
3
+ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
4
+ import { Router, NavigationEnd, ActivatedRoute, RouterLink } from '@angular/router';
5
+ import { filter, takeUntil, debounceTime } from 'rxjs/operators';
6
+ import * as i1 from '@angular/material/tooltip';
7
+ import { MatTooltipModule } from '@angular/material/tooltip';
8
+ import * as i2 from 'lucide-angular';
9
+ import { LucideAngularModule } from 'lucide-angular';
10
+ import { isPlatformBrowser } from '@angular/common';
11
+ import { Subject } from 'rxjs';
12
+ import { Title } from '@angular/platform-browser';
13
+
14
+ /** @internal Size-to-icon-pixel mapping for consistent icon sizing. */
15
+ const ICON_SIZE_MAP = {
16
+ xs: 14,
17
+ sm: 16,
18
+ md: 18,
19
+ lg: 20,
20
+ xl: 22,
21
+ };
22
+ /**
23
+ * Standalone button component with design-token-driven theming,
24
+ * variant/size system, Lucide icon support, loading states, and WCAG 2.1 AA accessibility.
25
+ *
26
+ * Uses native `<button>` click events — listen with `(click)` on the host element.
27
+ *
28
+ * @selector ui-button
29
+ *
30
+ * @example
31
+ * ```html
32
+ * <!-- Basic -->
33
+ * <ui-button label="Save" variant="primary" icon="save" (click)="save()" />
34
+ *
35
+ * <!-- Loading -->
36
+ * <ui-button label="Submitting..." variant="primary" [loading]="true" />
37
+ *
38
+ * <!-- Icon-only: tooltip o ariaLabel forniscono il nome accessibile -->
39
+ * <ui-button icon="trash-2" variant="warn" tooltip="Elimina" (click)="delete()" />
40
+ * ```
41
+ */
42
+ class UiButtonComponent {
43
+ constructor() {
44
+ /** Button label text. */
45
+ this.label = '';
46
+ /** Tooltip text shown on hover (uses Angular Material tooltip). */
47
+ this.tooltip = '';
48
+ /** Visual style variant. */
49
+ this.variant = 'primary';
50
+ /** Size variant. */
51
+ this.size = 'md';
52
+ /** Icon position relative to the label. */
53
+ this.iconPosition = 'trailing';
54
+ /** Whether the button is in a loading state. Disables interaction and shows spinner. */
55
+ this.loading = false;
56
+ /** Whether the button is disabled. */
57
+ this.disabled = false;
58
+ /** Expand button to full container width. */
59
+ this.fullWidth = false;
60
+ /** HTML button type attribute. */
61
+ this.type = 'button';
62
+ }
63
+ /**
64
+ * Nome accessibile risolto per il pulsante nativo.
65
+ * Usa `ariaLabel` se impostato; per pulsanti solo icona senza testo visibile
66
+ * ricade sul `tooltip` (il tooltip Material non sostituisce il nome accessibile).
67
+ */
68
+ get effectiveAriaLabel() {
69
+ const explicit = this.ariaLabel?.trim();
70
+ if (explicit)
71
+ return explicit;
72
+ if (this.label?.trim())
73
+ return undefined;
74
+ const tip = this.tooltip?.trim();
75
+ if (this.icon && tip)
76
+ return tip;
77
+ return undefined;
78
+ }
79
+ /** Computed icon pixel size based on button size. */
80
+ get iconSize() {
81
+ return ICON_SIZE_MAP[this.size] ?? 18;
82
+ }
83
+ /** Assembled CSS class string for the native button element. */
84
+ get buttonClasses() {
85
+ return [
86
+ 'ui-button',
87
+ `ui-button--${this.variant}`,
88
+ `ui-button--${this.size}`,
89
+ this.loading ? 'ui-button--loading' : '',
90
+ this.fullWidth ? 'ui-button--full-width' : '',
91
+ !this.label && this.icon ? 'ui-button--icon-only' : '',
92
+ this.customClass ?? '',
93
+ ]
94
+ .filter(Boolean)
95
+ .join(' ');
96
+ }
97
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: UiButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
98
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: UiButtonComponent, isStandalone: true, selector: "ui-button", inputs: { label: "label", tooltip: "tooltip", variant: "variant", size: "size", icon: "icon", iconPosition: "iconPosition", loading: "loading", disabled: "disabled", fullWidth: "fullWidth", type: "type", ariaLabel: "ariaLabel", customClass: "customClass" }, host: { properties: { "class.ui-button-host--full-width": "fullWidth" }, classAttribute: "ui-button-host" }, ngImport: i0, template: `
99
+ <button
100
+ [type]="type"
101
+ [class]="buttonClasses"
102
+ [disabled]="disabled || loading"
103
+ [attr.aria-label]="effectiveAriaLabel || null"
104
+ [attr.aria-busy]="loading || null"
105
+ [matTooltip]="tooltip"
106
+ >
107
+ <span class="ui-button__content" [class.ui-button__content--hidden]="loading">
108
+ @if (icon && iconPosition === 'leading') {
109
+ <lucide-icon [name]="icon!" [size]="iconSize" aria-hidden="true" />
110
+ }
111
+ @if (label) {
112
+ <span class="ui-button__label">{{ label }}</span>
113
+ }
114
+ <ng-content />
115
+ @if (icon && iconPosition === 'trailing') {
116
+ <lucide-icon [name]="icon!" [size]="iconSize" aria-hidden="true" />
117
+ }
118
+ </span>
119
+ @if (loading) {
120
+ <span class="ui-button__spinner-overlay">
121
+ <span class="ui-button__spinner" aria-hidden="true"></span>
122
+ <span class="ui-button__sr-only">Loading</span>
123
+ </span>
124
+ }
125
+ </button>
126
+ `, isInline: true, styles: [".ui-button-host{display:inline-flex}.ui-button-host--full-width{display:flex;width:100%}.ui-button{appearance:none;border:none;cursor:pointer;font-family:var(--ui-font-family);font-weight:var(--ui-font-weight-medium);letter-spacing:.01em;position:relative;display:inline-flex;align-items:center;justify-content:center;border-radius:var(--ui-radius-md);white-space:nowrap;text-decoration:none;overflow:hidden;transition:background-color var(--ui-transition-fast),color var(--ui-transition-fast),border-color var(--ui-transition-fast),box-shadow var(--ui-transition-fast),opacity var(--ui-transition-fast)}.ui-button:focus{outline:none}.ui-button:focus-visible{outline:var(--ui-focus-ring-width) solid var(--ui-focus-ring-color);outline-offset:var(--ui-focus-ring-offset)}.ui-button:disabled{opacity:.5;cursor:not-allowed}.ui-button--full-width{width:100%}.ui-button--xs{height:28px;padding:0 var(--ui-spacing-2);font-size:var(--ui-font-size-xs);border-radius:var(--ui-radius-sm);gap:var(--ui-spacing-1)}.ui-button--sm{height:32px;padding:0 var(--ui-spacing-3);font-size:var(--ui-font-size-xs);gap:6px}.ui-button--md{height:36px;padding:0 var(--ui-spacing-4);font-size:var(--ui-font-size-sm);gap:var(--ui-spacing-2)}.ui-button--lg{height:40px;padding:0 var(--ui-spacing-5);font-size:var(--ui-font-size-sm);gap:var(--ui-spacing-2)}.ui-button--xl{height:48px;padding:0 var(--ui-spacing-6);font-size:var(--ui-font-size-md);gap:var(--ui-spacing-3)}.ui-button--icon-only.ui-button--xs{width:28px;padding:0}.ui-button--icon-only.ui-button--sm{width:32px;padding:0}.ui-button--icon-only.ui-button--md{width:36px;padding:0}.ui-button--icon-only.ui-button--lg{width:40px;padding:0}.ui-button--icon-only.ui-button--xl{width:48px;padding:0}.ui-button--primary{background:var(--ui-color-primary);color:var(--ui-color-primary-contrast)}.ui-button--primary:hover:not(:disabled){background:var(--ui-color-primary-hover)}.ui-button--primary:active:not(:disabled){background:var(--ui-color-primary-active)}.ui-button--accent{background:var(--ui-color-accent);color:var(--ui-color-accent-contrast)}.ui-button--accent:hover:not(:disabled){background:var(--ui-color-accent-hover)}.ui-button--accent:active:not(:disabled){background:var(--ui-color-accent-active)}.ui-button--warn{background:var(--ui-color-warn);color:var(--ui-color-warn-contrast)}.ui-button--warn:hover:not(:disabled){background:var(--ui-color-warn-hover)}.ui-button--warn:active:not(:disabled){background:var(--ui-color-warn-active)}.ui-button--neutral{background:var(--ui-color-neutral-200);color:var(--ui-color-text)}.ui-button--neutral:hover:not(:disabled){background:var(--ui-color-neutral-300)}.ui-button--neutral:active:not(:disabled){background:var(--ui-color-neutral-400);color:var(--ui-color-text-inverse)}.ui-button--ghost{background:transparent;color:var(--ui-color-text-secondary)}.ui-button--ghost:hover:not(:disabled){background:var(--ui-color-surface-hover);color:var(--ui-color-text)}.ui-button--ghost:active:not(:disabled){background:var(--ui-color-neutral-200)}.ui-button--outline{background:transparent;color:var(--ui-color-primary);border:1.5px solid var(--ui-color-border-strong)}.ui-button--outline:hover:not(:disabled){background:var(--ui-color-primary-light);border-color:var(--ui-color-primary)}.ui-button--outline:active:not(:disabled){background:var(--ui-color-primary-light);border-color:var(--ui-color-primary-hover)}.ui-button--loading{cursor:wait;pointer-events:none}.ui-button__content{display:inline-flex;align-items:center;gap:inherit;transition:visibility var(--ui-transition-fast)}.ui-button__content--hidden{visibility:hidden}.ui-button__label{line-height:1;background-color:transparent!important}.ui-button__spinner-overlay{position:absolute;inset:0;display:flex;align-items:center;justify-content:center}.ui-button__spinner{width:1.1em;height:1.1em;border:2px solid currentColor;border-right-color:transparent;border-radius:50%;animation:ui-button-spin .6s linear infinite}@keyframes ui-button-spin{to{transform:rotate(360deg)}}.ui-button__sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}\n"], dependencies: [{ kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i1.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: LucideAngularModule }, { kind: "component", type: i2.LucideAngularComponent, selector: "lucide-angular, lucide-icon, i-lucide, span-lucide", inputs: ["class", "name", "img", "color", "absoluteStrokeWidth", "size", "strokeWidth"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
127
+ }
128
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: UiButtonComponent, decorators: [{
129
+ type: Component,
130
+ args: [{ selector: 'ui-button', standalone: true, imports: [MatTooltipModule, LucideAngularModule], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: {
131
+ class: 'ui-button-host',
132
+ '[class.ui-button-host--full-width]': 'fullWidth',
133
+ }, template: `
134
+ <button
135
+ [type]="type"
136
+ [class]="buttonClasses"
137
+ [disabled]="disabled || loading"
138
+ [attr.aria-label]="effectiveAriaLabel || null"
139
+ [attr.aria-busy]="loading || null"
140
+ [matTooltip]="tooltip"
141
+ >
142
+ <span class="ui-button__content" [class.ui-button__content--hidden]="loading">
143
+ @if (icon && iconPosition === 'leading') {
144
+ <lucide-icon [name]="icon!" [size]="iconSize" aria-hidden="true" />
145
+ }
146
+ @if (label) {
147
+ <span class="ui-button__label">{{ label }}</span>
148
+ }
149
+ <ng-content />
150
+ @if (icon && iconPosition === 'trailing') {
151
+ <lucide-icon [name]="icon!" [size]="iconSize" aria-hidden="true" />
152
+ }
153
+ </span>
154
+ @if (loading) {
155
+ <span class="ui-button__spinner-overlay">
156
+ <span class="ui-button__spinner" aria-hidden="true"></span>
157
+ <span class="ui-button__sr-only">Loading</span>
158
+ </span>
159
+ }
160
+ </button>
161
+ `, styles: [".ui-button-host{display:inline-flex}.ui-button-host--full-width{display:flex;width:100%}.ui-button{appearance:none;border:none;cursor:pointer;font-family:var(--ui-font-family);font-weight:var(--ui-font-weight-medium);letter-spacing:.01em;position:relative;display:inline-flex;align-items:center;justify-content:center;border-radius:var(--ui-radius-md);white-space:nowrap;text-decoration:none;overflow:hidden;transition:background-color var(--ui-transition-fast),color var(--ui-transition-fast),border-color var(--ui-transition-fast),box-shadow var(--ui-transition-fast),opacity var(--ui-transition-fast)}.ui-button:focus{outline:none}.ui-button:focus-visible{outline:var(--ui-focus-ring-width) solid var(--ui-focus-ring-color);outline-offset:var(--ui-focus-ring-offset)}.ui-button:disabled{opacity:.5;cursor:not-allowed}.ui-button--full-width{width:100%}.ui-button--xs{height:28px;padding:0 var(--ui-spacing-2);font-size:var(--ui-font-size-xs);border-radius:var(--ui-radius-sm);gap:var(--ui-spacing-1)}.ui-button--sm{height:32px;padding:0 var(--ui-spacing-3);font-size:var(--ui-font-size-xs);gap:6px}.ui-button--md{height:36px;padding:0 var(--ui-spacing-4);font-size:var(--ui-font-size-sm);gap:var(--ui-spacing-2)}.ui-button--lg{height:40px;padding:0 var(--ui-spacing-5);font-size:var(--ui-font-size-sm);gap:var(--ui-spacing-2)}.ui-button--xl{height:48px;padding:0 var(--ui-spacing-6);font-size:var(--ui-font-size-md);gap:var(--ui-spacing-3)}.ui-button--icon-only.ui-button--xs{width:28px;padding:0}.ui-button--icon-only.ui-button--sm{width:32px;padding:0}.ui-button--icon-only.ui-button--md{width:36px;padding:0}.ui-button--icon-only.ui-button--lg{width:40px;padding:0}.ui-button--icon-only.ui-button--xl{width:48px;padding:0}.ui-button--primary{background:var(--ui-color-primary);color:var(--ui-color-primary-contrast)}.ui-button--primary:hover:not(:disabled){background:var(--ui-color-primary-hover)}.ui-button--primary:active:not(:disabled){background:var(--ui-color-primary-active)}.ui-button--accent{background:var(--ui-color-accent);color:var(--ui-color-accent-contrast)}.ui-button--accent:hover:not(:disabled){background:var(--ui-color-accent-hover)}.ui-button--accent:active:not(:disabled){background:var(--ui-color-accent-active)}.ui-button--warn{background:var(--ui-color-warn);color:var(--ui-color-warn-contrast)}.ui-button--warn:hover:not(:disabled){background:var(--ui-color-warn-hover)}.ui-button--warn:active:not(:disabled){background:var(--ui-color-warn-active)}.ui-button--neutral{background:var(--ui-color-neutral-200);color:var(--ui-color-text)}.ui-button--neutral:hover:not(:disabled){background:var(--ui-color-neutral-300)}.ui-button--neutral:active:not(:disabled){background:var(--ui-color-neutral-400);color:var(--ui-color-text-inverse)}.ui-button--ghost{background:transparent;color:var(--ui-color-text-secondary)}.ui-button--ghost:hover:not(:disabled){background:var(--ui-color-surface-hover);color:var(--ui-color-text)}.ui-button--ghost:active:not(:disabled){background:var(--ui-color-neutral-200)}.ui-button--outline{background:transparent;color:var(--ui-color-primary);border:1.5px solid var(--ui-color-border-strong)}.ui-button--outline:hover:not(:disabled){background:var(--ui-color-primary-light);border-color:var(--ui-color-primary)}.ui-button--outline:active:not(:disabled){background:var(--ui-color-primary-light);border-color:var(--ui-color-primary-hover)}.ui-button--loading{cursor:wait;pointer-events:none}.ui-button__content{display:inline-flex;align-items:center;gap:inherit;transition:visibility var(--ui-transition-fast)}.ui-button__content--hidden{visibility:hidden}.ui-button__label{line-height:1;background-color:transparent!important}.ui-button__spinner-overlay{position:absolute;inset:0;display:flex;align-items:center;justify-content:center}.ui-button__spinner{width:1.1em;height:1.1em;border:2px solid currentColor;border-right-color:transparent;border-radius:50%;animation:ui-button-spin .6s linear infinite}@keyframes ui-button-spin{to{transform:rotate(360deg)}}.ui-button__sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}\n"] }]
162
+ }], propDecorators: { label: [{
163
+ type: Input
164
+ }], tooltip: [{
165
+ type: Input
166
+ }], variant: [{
167
+ type: Input
168
+ }], size: [{
169
+ type: Input
170
+ }], icon: [{
171
+ type: Input
172
+ }], iconPosition: [{
173
+ type: Input
174
+ }], loading: [{
175
+ type: Input
176
+ }], disabled: [{
177
+ type: Input
178
+ }], fullWidth: [{
179
+ type: Input
180
+ }], type: [{
181
+ type: Input
182
+ }], ariaLabel: [{
183
+ type: Input
184
+ }], customClass: [{
185
+ type: Input
186
+ }] } });
187
+
188
+ /**
189
+ * @module ng-ui-system/blackbox
190
+ * Types and interfaces for the BlackBox observability service.
191
+ *
192
+ * The BlackBox service acts as a "black box recorder" for user sessions,
193
+ * capturing navigation, UI interactions, form events and HTTP calls
194
+ * in a compressed, opaque format stored in IndexedDB.
195
+ */
196
+ // ─── Defaults ────────────────────────────────────────────────────────
197
+ /** Default configuration values. */
198
+ const UI_BLACKBOX_DEFAULTS = {
199
+ maxStorageMb: 50,
200
+ flushIntervalMs: 5000,
201
+ flushThreshold: 20,
202
+ bufferDebounceMs: 500,
203
+ formTracking: {
204
+ trackValues: false,
205
+ trackFocus: true,
206
+ trackBlur: true,
207
+ trackValueChanges: true,
208
+ trackValidation: true,
209
+ debounceMs: 500,
210
+ },
211
+ };
212
+
213
+ /**
214
+ * @module ng-ui-system/blackbox
215
+ * Fingerprint service — generates a stable device/browser hash
216
+ * using the open-source FingerprintJS library (MIT, no API key required).
217
+ *
218
+ * The fingerprint is computed once and cached in `localStorage` under
219
+ * the key `__ui_bb_fp` to avoid redundant recalculations.
220
+ */
221
+ /** localStorage key for the cached fingerprint. */
222
+ const FP_CACHE_KEY = '__ui_bb_fp';
223
+ /**
224
+ * Generates and caches a stable browser/device fingerprint.
225
+ *
226
+ * Uses `@fingerprintjs/fingerprintjs` (open-source, MIT) which analyses
227
+ * canvas rendering, WebGL, audio context, screen properties, timezone,
228
+ * user-agent, and other browser signals to produce a stable hash.
229
+ *
230
+ * @usageNotes
231
+ * ```typescript
232
+ * const fp = inject(UiBlackboxFingerprintService);
233
+ * const hash = await fp.getFingerprint();
234
+ * // => "a1b2c3d4e5f6..." (stable across sessions)
235
+ * ```
236
+ */
237
+ class UiBlackboxFingerprintService {
238
+ constructor() {
239
+ this.platformId = inject(PLATFORM_ID);
240
+ this.cached = null;
241
+ }
242
+ /**
243
+ * Returns the stable fingerprint for this device/browser.
244
+ *
245
+ * On first call, loads FingerprintJS dynamically, computes the hash,
246
+ * and caches it in both memory and `localStorage`.
247
+ * Subsequent calls return the cached value immediately.
248
+ */
249
+ async getFingerprint() {
250
+ // Return cached value if available
251
+ if (this.cached) {
252
+ return this.cached;
253
+ }
254
+ // SSR guard
255
+ if (!isPlatformBrowser(this.platformId)) {
256
+ return 'ssr-placeholder';
257
+ }
258
+ // Try localStorage cache first
259
+ try {
260
+ const stored = localStorage.getItem(FP_CACHE_KEY);
261
+ if (stored) {
262
+ this.cached = stored;
263
+ return stored;
264
+ }
265
+ }
266
+ catch {
267
+ // localStorage may be unavailable (privacy mode, quota exceeded)
268
+ }
269
+ // Compute fingerprint via FingerprintJS
270
+ try {
271
+ const FingerprintJS = await import('@fingerprintjs/fingerprintjs');
272
+ const agent = await FingerprintJS.load();
273
+ const result = await agent.get();
274
+ this.cached = result.visitorId;
275
+ // Persist to localStorage
276
+ try {
277
+ localStorage.setItem(FP_CACHE_KEY, this.cached);
278
+ }
279
+ catch {
280
+ // Silently ignore storage errors
281
+ }
282
+ return this.cached;
283
+ }
284
+ catch {
285
+ // Fallback: generate a pseudo-fingerprint from available signals
286
+ const fallback = this.generateFallbackFingerprint();
287
+ this.cached = fallback;
288
+ try {
289
+ localStorage.setItem(FP_CACHE_KEY, fallback);
290
+ }
291
+ catch {
292
+ // Silently ignore
293
+ }
294
+ return fallback;
295
+ }
296
+ }
297
+ /**
298
+ * Fallback fingerprint when FingerprintJS is unavailable.
299
+ * Combines basic browser signals into a hash.
300
+ * @internal
301
+ */
302
+ generateFallbackFingerprint() {
303
+ const signals = [
304
+ navigator.userAgent,
305
+ navigator.language,
306
+ screen.width + 'x' + screen.height,
307
+ screen.colorDepth?.toString() ?? '',
308
+ Intl.DateTimeFormat().resolvedOptions().timeZone,
309
+ navigator.hardwareConcurrency?.toString() ?? '',
310
+ ].join('|');
311
+ // Simple string hash (djb2)
312
+ let hash = 5381;
313
+ for (let i = 0; i < signals.length; i++) {
314
+ hash = ((hash << 5) + hash + signals.charCodeAt(i)) >>> 0;
315
+ }
316
+ return hash.toString(36).padStart(12, '0');
317
+ }
318
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: UiBlackboxFingerprintService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
319
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: UiBlackboxFingerprintService, providedIn: 'root' }); }
320
+ }
321
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: UiBlackboxFingerprintService, decorators: [{
322
+ type: Injectable,
323
+ args: [{ providedIn: 'root' }]
324
+ }] });
325
+
326
+ /**
327
+ * @module ng-ui-system/blackbox
328
+ * IndexedDB storage adapter for BlackBox sessions.
329
+ *
330
+ * Handles persistence, compression (via native CompressionStream gzip),
331
+ * quota enforcement, and JSONL export.
332
+ *
333
+ * Design notes:
334
+ * - DB name: `ui-blackbox`, object store: `sessions`
335
+ * - Each session is gzip-compressed before storage for both size
336
+ * reduction and inherent obfuscation
337
+ * - Quota enforced by total stored size; oldest sessions are pruned first
338
+ */
339
+ const DB_NAME = 'ui-blackbox';
340
+ const DB_VERSION = 1;
341
+ const STORE_NAME = 'sessions';
342
+ /**
343
+ * Low-level IndexedDB adapter for reading/writing compressed BlackBox sessions.
344
+ *
345
+ * @usageNotes
346
+ * This service is used internally by `UiBlackboxService`.
347
+ * Consumers should interact with the higher-level `UiBlackboxService` API.
348
+ */
349
+ class UiBlackboxStorageService {
350
+ constructor() {
351
+ this.platformId = inject(PLATFORM_ID);
352
+ this.db = null;
353
+ this.maxStorageMb = UI_BLACKBOX_DEFAULTS.maxStorageMb;
354
+ }
355
+ // ─── Configuration ─────────────────────────────────────────────────
356
+ /** Update the storage quota from the parent service config. */
357
+ setMaxStorageMb(mb) {
358
+ this.maxStorageMb = mb;
359
+ }
360
+ // ─── Database lifecycle ────────────────────────────────────────────
361
+ /** Open (or create) the IndexedDB database. */
362
+ async openDb() {
363
+ if (this.db)
364
+ return this.db;
365
+ if (!isPlatformBrowser(this.platformId)) {
366
+ throw new Error('IndexedDB is not available in SSR');
367
+ }
368
+ return new Promise((resolve, reject) => {
369
+ const request = indexedDB.open(DB_NAME, DB_VERSION);
370
+ request.onupgradeneeded = () => {
371
+ const db = request.result;
372
+ if (!db.objectStoreNames.contains(STORE_NAME)) {
373
+ const store = db.createObjectStore(STORE_NAME, { keyPath: 'sessionId' });
374
+ store.createIndex('fingerprint', 'fingerprint', { unique: false });
375
+ store.createIndex('startedAt', 'startedAt', { unique: false });
376
+ }
377
+ };
378
+ request.onsuccess = () => {
379
+ this.db = request.result;
380
+ resolve(this.db);
381
+ };
382
+ request.onerror = () => reject(request.error);
383
+ });
384
+ }
385
+ // ─── Compression helpers ───────────────────────────────────────────
386
+ /** Compress a string to a gzip Uint8Array using native CompressionStream. */
387
+ async compress(data) {
388
+ const encoder = new TextEncoder();
389
+ const stream = new Blob([encoder.encode(data)])
390
+ .stream()
391
+ .pipeThrough(new CompressionStream('gzip'));
392
+ const reader = stream.getReader();
393
+ const chunks = [];
394
+ let done = false;
395
+ while (!done) {
396
+ const result = await reader.read();
397
+ done = result.done;
398
+ if (result.value) {
399
+ chunks.push(result.value);
400
+ }
401
+ }
402
+ // Merge chunks into a single ArrayBuffer-backed Uint8Array
403
+ const totalLength = chunks.reduce((sum, c) => sum + c.length, 0);
404
+ const buffer = new ArrayBuffer(totalLength);
405
+ const merged = new Uint8Array(buffer);
406
+ let offset = 0;
407
+ for (const chunk of chunks) {
408
+ merged.set(chunk, offset);
409
+ offset += chunk.length;
410
+ }
411
+ return merged;
412
+ }
413
+ /** Decompress a gzip Uint8Array back to a string. */
414
+ async decompress(data) {
415
+ const stream = new Blob([data])
416
+ .stream()
417
+ .pipeThrough(new DecompressionStream('gzip'));
418
+ const reader = stream.getReader();
419
+ const decoder = new TextDecoder();
420
+ let result = '';
421
+ let done = false;
422
+ while (!done) {
423
+ const chunk = await reader.read();
424
+ done = chunk.done;
425
+ if (chunk.value) {
426
+ result += decoder.decode(chunk.value, { stream: !done });
427
+ }
428
+ }
429
+ return result;
430
+ }
431
+ // ─── CRUD ──────────────────────────────────────────────────────────
432
+ /**
433
+ * Persist a session to IndexedDB (gzip-compressed).
434
+ * Enforces quota after saving.
435
+ */
436
+ async saveSession(session) {
437
+ const db = await this.openDb();
438
+ const json = JSON.stringify(session);
439
+ const compressed = await this.compress(json);
440
+ return new Promise((resolve, reject) => {
441
+ const tx = db.transaction(STORE_NAME, 'readwrite');
442
+ const store = tx.objectStore(STORE_NAME);
443
+ // Store as { sessionId, fingerprint, startedAt, data: Uint8Array }
444
+ store.put({
445
+ sessionId: session.sessionId,
446
+ fingerprint: session.fingerprint,
447
+ startedAt: session.startedAt,
448
+ sizeBytes: compressed.byteLength,
449
+ data: compressed,
450
+ });
451
+ tx.oncomplete = () => {
452
+ this.enforceQuota().then(resolve).catch(resolve);
453
+ };
454
+ tx.onerror = () => reject(tx.error);
455
+ });
456
+ }
457
+ /**
458
+ * Read and decompress a single session by ID.
459
+ */
460
+ async getSession(sessionId) {
461
+ const db = await this.openDb();
462
+ return new Promise((resolve, reject) => {
463
+ const tx = db.transaction(STORE_NAME, 'readonly');
464
+ const store = tx.objectStore(STORE_NAME);
465
+ const req = store.get(sessionId);
466
+ req.onsuccess = async () => {
467
+ if (!req.result) {
468
+ resolve(null);
469
+ return;
470
+ }
471
+ try {
472
+ const json = await this.decompress(req.result.data);
473
+ resolve(JSON.parse(json));
474
+ }
475
+ catch (e) {
476
+ reject(e);
477
+ }
478
+ };
479
+ req.onerror = () => reject(req.error);
480
+ });
481
+ }
482
+ /**
483
+ * Get all stored sessions (decompressed).
484
+ */
485
+ async getAllSessions() {
486
+ const db = await this.openDb();
487
+ return new Promise((resolve, reject) => {
488
+ const tx = db.transaction(STORE_NAME, 'readonly');
489
+ const store = tx.objectStore(STORE_NAME);
490
+ const req = store.getAll();
491
+ req.onsuccess = async () => {
492
+ try {
493
+ const sessions = [];
494
+ for (const record of req.result) {
495
+ const json = await this.decompress(record.data);
496
+ sessions.push(JSON.parse(json));
497
+ }
498
+ resolve(sessions);
499
+ }
500
+ catch (e) {
501
+ reject(e);
502
+ }
503
+ };
504
+ req.onerror = () => reject(req.error);
505
+ });
506
+ }
507
+ /**
508
+ * Get all sessions for a given fingerprint.
509
+ */
510
+ async getSessionsByFingerprint(fingerprint) {
511
+ const db = await this.openDb();
512
+ return new Promise((resolve, reject) => {
513
+ const tx = db.transaction(STORE_NAME, 'readonly');
514
+ const store = tx.objectStore(STORE_NAME);
515
+ const index = store.index('fingerprint');
516
+ const req = index.getAll(fingerprint);
517
+ req.onsuccess = async () => {
518
+ try {
519
+ const sessions = [];
520
+ for (const record of req.result) {
521
+ const json = await this.decompress(record.data);
522
+ sessions.push(JSON.parse(json));
523
+ }
524
+ resolve(sessions);
525
+ }
526
+ catch (e) {
527
+ reject(e);
528
+ }
529
+ };
530
+ req.onerror = () => reject(req.error);
531
+ });
532
+ }
533
+ /**
534
+ * Generate a downloadable JSONL Blob of all sessions.
535
+ * Each line is one JSON-serialised session (decompressed).
536
+ */
537
+ async exportDump() {
538
+ const sessions = await this.getAllSessions();
539
+ const lines = sessions.map((s) => JSON.stringify(s)).join('\n');
540
+ return new Blob([lines], { type: 'application/x-ndjson' });
541
+ }
542
+ /**
543
+ * Delete all stored sessions.
544
+ */
545
+ async clearAll() {
546
+ const db = await this.openDb();
547
+ return new Promise((resolve, reject) => {
548
+ const tx = db.transaction(STORE_NAME, 'readwrite');
549
+ const store = tx.objectStore(STORE_NAME);
550
+ store.clear();
551
+ tx.oncomplete = () => resolve();
552
+ tx.onerror = () => reject(tx.error);
553
+ });
554
+ }
555
+ // ─── Quota enforcement ─────────────────────────────────────────────
556
+ /**
557
+ * Prune oldest sessions until total stored size is under `maxStorageMb`.
558
+ * @internal
559
+ */
560
+ async enforceQuota() {
561
+ const db = await this.openDb();
562
+ const maxBytes = this.maxStorageMb * 1024 * 1024;
563
+ return new Promise((resolve, reject) => {
564
+ const tx = db.transaction(STORE_NAME, 'readwrite');
565
+ const store = tx.objectStore(STORE_NAME);
566
+ const index = store.index('startedAt');
567
+ // Collect all records sorted by startedAt (ascending = oldest first)
568
+ const cursorReq = index.openCursor();
569
+ const records = [];
570
+ let totalSize = 0;
571
+ cursorReq.onsuccess = () => {
572
+ const cursor = cursorReq.result;
573
+ if (cursor) {
574
+ const size = cursor.value.sizeBytes || 0;
575
+ totalSize += size;
576
+ records.push({ key: cursor.primaryKey, size });
577
+ cursor.continue();
578
+ }
579
+ else {
580
+ // Cursor exhausted — prune if over quota
581
+ if (totalSize <= maxBytes) {
582
+ resolve();
583
+ return;
584
+ }
585
+ let freed = 0;
586
+ const target = totalSize - maxBytes;
587
+ for (const record of records) {
588
+ if (freed >= target)
589
+ break;
590
+ store.delete(record.key);
591
+ freed += record.size;
592
+ }
593
+ resolve();
594
+ }
595
+ };
596
+ cursorReq.onerror = () => reject(cursorReq.error);
597
+ tx.onerror = () => reject(tx.error);
598
+ });
599
+ }
600
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: UiBlackboxStorageService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
601
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: UiBlackboxStorageService, providedIn: 'root' }); }
602
+ }
603
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: UiBlackboxStorageService, decorators: [{
604
+ type: Injectable,
605
+ args: [{ providedIn: 'root' }]
606
+ }] });
607
+
608
+ /**
609
+ * @module ng-ui-system/blackbox
610
+ * Core BlackBox observability service — the main entry point for session
611
+ * recording, event buffering, and export.
612
+ *
613
+ * Architecture:
614
+ * - Root singleton (`providedIn: 'root'`)
615
+ * - On first inject: generates fingerprint, creates session, subscribes to Router events
616
+ * - Centralised in-memory buffer with periodic/threshold-based flush to IndexedDB
617
+ * - `window:beforeunload` triggers a final best-effort async flush
618
+ */
619
+ /**
620
+ * Central BlackBox observability service.
621
+ *
622
+ * Records navigation, UI interactions, form events, and HTTP calls
623
+ * into compressed sessions stored in IndexedDB.
624
+ *
625
+ * @usageNotes
626
+ * The service activates automatically when injected. Provide it at root level
627
+ * and it will start recording immediately.
628
+ *
629
+ * ```typescript
630
+ * // app.config.ts — just importing the service is enough
631
+ * import { UiBlackboxService } from '@gnggln/ng-ui-system';
632
+ *
633
+ * export const appConfig: ApplicationConfig = {
634
+ * providers: [
635
+ * // The service is providedIn: 'root', so it's auto-provided.
636
+ * // To force eager initialisation:
637
+ * { provide: APP_INITIALIZER, useFactory: () => () => inject(UiBlackboxService), multi: true },
638
+ * ],
639
+ * };
640
+ * ```
641
+ */
642
+ class UiBlackboxService {
643
+ constructor() {
644
+ this.platformId = inject(PLATFORM_ID);
645
+ this.router = inject(Router);
646
+ this.zone = inject(NgZone);
647
+ this.fingerprint = inject(UiBlackboxFingerprintService);
648
+ this.storage = inject(UiBlackboxStorageService);
649
+ this.destroy$ = new Subject();
650
+ this.config = { ...UI_BLACKBOX_DEFAULTS };
651
+ this.currentStep = null;
652
+ this.initialised = false;
653
+ // ─── Centralised event buffer ──────────────────────────────────────
654
+ this.buffer = [];
655
+ this.flushTimerId = null;
656
+ this.beforeUnloadHandler = null;
657
+ if (isPlatformBrowser(this.platformId)) {
658
+ this.init();
659
+ }
660
+ }
661
+ // ─── Initialisation ────────────────────────────────────────────────
662
+ async init() {
663
+ // Generate session ID
664
+ const sessionId = this.generateUuid();
665
+ const fp = await this.fingerprint.getFingerprint();
666
+ this.session = {
667
+ sessionId,
668
+ fingerprint: fp,
669
+ startedAt: Date.now(),
670
+ userAgent: navigator.userAgent,
671
+ steps: [],
672
+ formEvents: [],
673
+ calls: [],
674
+ };
675
+ // Create initial step from current URL
676
+ this.currentStep = {
677
+ timestamp: Date.now(),
678
+ route: this.router.url,
679
+ actions: [],
680
+ };
681
+ this.session.steps.push(this.currentStep);
682
+ // Subscribe to router navigation
683
+ this.router.events
684
+ .pipe(filter((e) => e instanceof NavigationEnd), takeUntil(this.destroy$))
685
+ .subscribe((event) => {
686
+ const previousRoute = this.currentStep?.route;
687
+ this.currentStep = {
688
+ timestamp: Date.now(),
689
+ route: event.urlAfterRedirects,
690
+ previousRoute,
691
+ actions: [],
692
+ };
693
+ this.pushBufferEvent({ kind: 'step', payload: this.currentStep });
694
+ });
695
+ // Setup periodic flush (outside Angular zone to avoid triggering CD)
696
+ this.zone.runOutsideAngular(() => {
697
+ this.flushTimerId = setInterval(() => this.flush(), this.config.flushIntervalMs);
698
+ // Best-effort flush on tab close (IndexedDB is async, no sync fallback)
699
+ this.beforeUnloadHandler = () => {
700
+ this.session.endedAt = Date.now();
701
+ void this.flush();
702
+ };
703
+ window.addEventListener('beforeunload', this.beforeUnloadHandler);
704
+ });
705
+ this.initialised = true;
706
+ }
707
+ // ─── Public API: Configuration ─────────────────────────────────────
708
+ /**
709
+ * Update the BlackBox configuration.
710
+ * Can be called at any time; changes take effect immediately.
711
+ */
712
+ configure(config) {
713
+ this.config = {
714
+ ...this.config,
715
+ ...config,
716
+ formTracking: {
717
+ ...this.config.formTracking,
718
+ ...(config.formTracking ?? {}),
719
+ },
720
+ };
721
+ this.storage.setMaxStorageMb(this.config.maxStorageMb);
722
+ // Restart flush timer with new interval
723
+ if (this.flushTimerId !== null) {
724
+ clearInterval(this.flushTimerId);
725
+ this.zone.runOutsideAngular(() => {
726
+ this.flushTimerId = setInterval(() => this.flush(), this.config.flushIntervalMs);
727
+ });
728
+ }
729
+ }
730
+ /** Returns the current configuration (readonly snapshot). */
731
+ getConfig() {
732
+ return { ...this.config };
733
+ }
734
+ // ─── Public API: Tracking ──────────────────────────────────────────
735
+ /**
736
+ * Manually track a UI action (click).
737
+ *
738
+ * Called automatically by `UiButtonAreaComponent` and the `[uiTrack]` directive.
739
+ * Can also be called programmatically for custom interactions.
740
+ *
741
+ * @param trackId - Identifier for the action (e.g. button id, link name).
742
+ * @param meta - Optional metadata: `tag`, `text`, `id` of the element.
743
+ */
744
+ trackAction(trackId, meta) {
745
+ if (!this.initialised)
746
+ return;
747
+ const action = {
748
+ timestamp: Date.now(),
749
+ type: 'click',
750
+ target: {
751
+ tag: meta?.tag ?? 'unknown',
752
+ id: meta?.id,
753
+ trackId,
754
+ text: meta?.text?.substring(0, 50),
755
+ },
756
+ };
757
+ // Add to current step immediately (for in-memory session access)
758
+ this.currentStep?.actions.push(action);
759
+ // Also push to buffer for persistence
760
+ this.pushBufferEvent({
761
+ kind: 'action',
762
+ payload: { ...action, route: this.currentStep?.route ?? this.router.url },
763
+ });
764
+ }
765
+ /**
766
+ * Track a form interaction event.
767
+ *
768
+ * Called automatically by `UiFormBuilderComponent` when the BlackBox
769
+ * service is available.
770
+ */
771
+ trackFormEvent(event) {
772
+ if (!this.initialised)
773
+ return;
774
+ this.session.formEvents.push(event);
775
+ this.pushBufferEvent({ kind: 'formEvent', payload: event });
776
+ }
777
+ /**
778
+ * Track an intercepted HTTP call.
779
+ * Called by `UiBlackboxInterceptor`.
780
+ * @internal
781
+ */
782
+ trackHttpCall(call) {
783
+ if (!this.initialised)
784
+ return;
785
+ this.session.calls.push(call);
786
+ this.pushBufferEvent({ kind: 'httpCall', payload: call });
787
+ }
788
+ // ─── Public API: Session access ────────────────────────────────────
789
+ /**
790
+ * Returns the current in-memory session (live, not yet flushed).
791
+ * Useful for debugging or real-time inspection.
792
+ */
793
+ getCurrentSession() {
794
+ return this.session;
795
+ }
796
+ /**
797
+ * Retrieve all sessions stored in IndexedDB (decompressed).
798
+ */
799
+ async getSessionHistory() {
800
+ return this.storage.getAllSessions();
801
+ }
802
+ /**
803
+ * Retrieve sessions for the current device fingerprint.
804
+ */
805
+ async getSessionsForDevice() {
806
+ const fp = await this.fingerprint.getFingerprint();
807
+ return this.storage.getSessionsByFingerprint(fp);
808
+ }
809
+ // ─── Public API: Export ────────────────────────────────────────────
810
+ /**
811
+ * Export all sessions as a downloadable JSONL Blob.
812
+ *
813
+ * @returns A Blob containing JSONL data (one session per line).
814
+ *
815
+ * @example
816
+ * ```typescript
817
+ * const blob = await blackbox.exportSessions();
818
+ * const url = URL.createObjectURL(blob);
819
+ * const a = document.createElement('a');
820
+ * a.href = url;
821
+ * a.download = 'blackbox-sessions.jsonl';
822
+ * a.click();
823
+ * ```
824
+ */
825
+ async exportSessions() {
826
+ // Flush current session first
827
+ await this.flush();
828
+ return this.storage.exportDump();
829
+ }
830
+ // ─── Public API: Lifecycle ─────────────────────────────────────────
831
+ /**
832
+ * Explicitly end the current session.
833
+ * Flushes all buffered events and marks the session as ended.
834
+ */
835
+ async endSession() {
836
+ if (!this.initialised)
837
+ return;
838
+ this.session.endedAt = Date.now();
839
+ await this.flush();
840
+ }
841
+ /**
842
+ * Clear all stored sessions from IndexedDB.
843
+ */
844
+ async clearHistory() {
845
+ return this.storage.clearAll();
846
+ }
847
+ // ─── Buffer management ─────────────────────────────────────────────
848
+ /**
849
+ * Push an event into the centralised buffer.
850
+ * Triggers an immediate flush if the buffer exceeds the threshold.
851
+ * @internal
852
+ */
853
+ pushBufferEvent(event) {
854
+ this.buffer.push(event);
855
+ if (this.buffer.length >= this.config.flushThreshold) {
856
+ this.flush();
857
+ }
858
+ }
859
+ /**
860
+ * Flush buffered events to IndexedDB asynchronously.
861
+ * @internal
862
+ */
863
+ async flush() {
864
+ if (!this.initialised || this.buffer.length === 0)
865
+ return;
866
+ // Drain buffer
867
+ const events = this.buffer.splice(0);
868
+ // Apply step events to the session
869
+ for (const event of events) {
870
+ if (event.kind === 'step') {
871
+ // Steps are already pushed in real-time; ensure they're in the session
872
+ if (!this.session.steps.includes(event.payload)) {
873
+ this.session.steps.push(event.payload);
874
+ }
875
+ }
876
+ // Actions, formEvents, httpCalls are already pushed in real-time
877
+ // to the in-memory session by trackAction/trackFormEvent/trackHttpCall
878
+ }
879
+ // Save the full session snapshot
880
+ try {
881
+ await this.storage.saveSession(this.session);
882
+ }
883
+ catch (e) {
884
+ // storage error — re-enqueue events for next flush
885
+ console.warn('[UiBlackbox] Storage flush failed:', e);
886
+ }
887
+ }
888
+ // ─── Utilities ─────────────────────────────────────────────────────
889
+ /** Generate a UUID v4. */
890
+ generateUuid() {
891
+ if (typeof crypto !== 'undefined' && crypto.randomUUID) {
892
+ return crypto.randomUUID();
893
+ }
894
+ // Fallback for older browsers
895
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
896
+ const r = (Math.random() * 16) | 0;
897
+ const v = c === 'x' ? r : (r & 0x3) | 0x8;
898
+ return v.toString(16);
899
+ });
900
+ }
901
+ // ─── Cleanup ───────────────────────────────────────────────────────
902
+ ngOnDestroy() {
903
+ this.destroy$.next();
904
+ this.destroy$.complete();
905
+ if (this.flushTimerId !== null) {
906
+ clearInterval(this.flushTimerId);
907
+ }
908
+ if (this.beforeUnloadHandler) {
909
+ window.removeEventListener('beforeunload', this.beforeUnloadHandler);
910
+ }
911
+ // Final flush
912
+ void this.flush();
913
+ }
914
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: UiBlackboxService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
915
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: UiBlackboxService, providedIn: 'root' }); }
916
+ }
917
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: UiBlackboxService, decorators: [{
918
+ type: Injectable,
919
+ args: [{ providedIn: 'root' }]
920
+ }], ctorParameters: () => [] });
921
+
922
+ /**
923
+ * Standalone button-group component driven by a `UiButtonDescriptor[]` configuration.
924
+ *
925
+ * Renders a group of `UiButton` instances from declarative descriptors.
926
+ * Supports per-button loading/disabled states, dynamic visibility,
927
+ * alignment control, and optional navigation via Angular Router.
928
+ *
929
+ * When the `UiBlackboxService` is provided, button clicks are
930
+ * automatically tracked in the active session.
931
+ *
932
+ * @selector ui-button-area
933
+ *
934
+ * @example
935
+ * ```html
936
+ * <ui-button-area
937
+ * [buttons]="actions"
938
+ * align="end"
939
+ * gap="sm"
940
+ * [loadingIds]="currentlyLoading"
941
+ * />
942
+ * ```
943
+ *
944
+ * @example
945
+ * ```typescript
946
+ * // Dynamic configuration
947
+ * actions: UiButtonDescriptor[] = [
948
+ * { id: 'export', label: 'Export Excel', icon: 'file-spreadsheet', variant: 'primary',
949
+ * action: () => this.exportExcel() },
950
+ * { id: 'delete', label: 'Delete', icon: 'trash-2', variant: 'warn',
951
+ * action: () => this.deleteSelected(), hidden: !this.hasSelection },
952
+ * ];
953
+ *
954
+ * // Set loading state from outside:
955
+ * currentlyLoading: string | string[] | null = 'export';
956
+ * ```
957
+ */
958
+ class UiButtonAreaComponent {
959
+ constructor() {
960
+ /**
961
+ * Array of button descriptors to render.
962
+ * Buttons with `hidden: true` are filtered out.
963
+ */
964
+ this.buttons = [];
965
+ /** Horizontal alignment of the button group. */
966
+ this.align = 'end';
967
+ /** Accessible group label for screen readers. */
968
+ this.ariaLabel = 'Actions';
969
+ /** Gap between buttons (maps to design token spacing). */
970
+ this.gap = 'sm';
971
+ /** Stack buttons vertically on mobile viewports (<600px). */
972
+ this.stackOnMobile = true;
973
+ /**
974
+ * When `true`, all buttons are disabled while any button is in a loading state.
975
+ * Useful to prevent double-actions during async operations.
976
+ */
977
+ this.disableWhileLoading = false;
978
+ /** @internal */
979
+ this._loadingIds = new Set();
980
+ /** @internal Optional router for href navigation. */
981
+ this.router = inject(Router, { optional: true });
982
+ /** @internal Optional BlackBox service — auto-tracks button clicks when available. */
983
+ this.blackbox = inject(UiBlackboxService, { optional: true });
984
+ }
985
+ /**
986
+ * Set one or more buttons to a loading state by their `id`.
987
+ * Accepts a single string, an array of strings, or `null` to clear.
988
+ *
989
+ * @example
990
+ * ```html
991
+ * <!-- Single -->
992
+ * <ui-button-area [loadingIds]="'save'" />
993
+ *
994
+ * <!-- Multiple -->
995
+ * <ui-button-area [loadingIds]="['save', 'export']" />
996
+ * ```
997
+ */
998
+ set loadingIds(value) {
999
+ if (value === null || value === undefined) {
1000
+ this._loadingIds = new Set();
1001
+ }
1002
+ else if (Array.isArray(value)) {
1003
+ this._loadingIds = new Set(value);
1004
+ }
1005
+ else {
1006
+ this._loadingIds = new Set([value]);
1007
+ }
1008
+ }
1009
+ /** Buttons filtered to visible (non-hidden) entries. */
1010
+ get visibleButtons() {
1011
+ return this.buttons.filter((b) => !b.hidden);
1012
+ }
1013
+ /** Assembled CSS class string for the button area container. */
1014
+ get areaClasses() {
1015
+ return [
1016
+ 'ui-button-area',
1017
+ `ui-button-area--align-${this.align}`,
1018
+ `ui-button-area--gap-${this.gap}`,
1019
+ this.stackOnMobile ? 'ui-button-area--stack-mobile' : '',
1020
+ ]
1021
+ .filter(Boolean)
1022
+ .join(' ');
1023
+ }
1024
+ /** @internal Track function for @for loop. */
1025
+ trackButton(index, button) {
1026
+ return button.id ?? `idx-${index}`;
1027
+ }
1028
+ /** Whether a specific button is in a loading state. */
1029
+ isButtonLoading(button) {
1030
+ return !!button.loading || (!!button.id && this._loadingIds.has(button.id));
1031
+ }
1032
+ /** Whether a specific button is disabled (includes loading logic). */
1033
+ isButtonDisabled(button) {
1034
+ if (button.disabled)
1035
+ return true;
1036
+ if (this.isButtonLoading(button))
1037
+ return true;
1038
+ if (this.disableWhileLoading && this._loadingIds.size > 0)
1039
+ return true;
1040
+ return false;
1041
+ }
1042
+ /** @internal Handles button click: tracks action, calls callback and/or navigates. */
1043
+ handleButtonClick(button, event) {
1044
+ // BlackBox auto-tracking (no-op if service is not provided)
1045
+ this.blackbox?.trackAction(button.id ?? button.label, {
1046
+ tag: 'ui-button',
1047
+ id: button.id,
1048
+ text: button.label,
1049
+ });
1050
+ if (button.action) {
1051
+ button.action(event);
1052
+ }
1053
+ if (button.href && this.router) {
1054
+ this.router.navigateByUrl(button.href);
1055
+ }
1056
+ }
1057
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: UiButtonAreaComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1058
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: UiButtonAreaComponent, isStandalone: true, selector: "ui-button-area", inputs: { buttons: "buttons", align: "align", ariaLabel: "ariaLabel", gap: "gap", stackOnMobile: "stackOnMobile", disableWhileLoading: "disableWhileLoading", loadingIds: "loadingIds" }, host: { classAttribute: "ui-button-area-host" }, ngImport: i0, template: `
1059
+ <div
1060
+ [class]="areaClasses"
1061
+ role="group"
1062
+ [attr.aria-label]="ariaLabel"
1063
+ >
1064
+ @for (button of visibleButtons; track trackButton($index, button)) {
1065
+ <ui-button
1066
+ [attr.data-button-id]="button.id || null"
1067
+ [label]="button.label"
1068
+ [tooltip]="button.tooltip ?? ''"
1069
+ [ariaLabel]="button.ariaLabel"
1070
+ [icon]="button.icon"
1071
+ [iconPosition]="button.iconPosition ?? 'trailing'"
1072
+ [variant]="button.variant ?? 'primary'"
1073
+ [size]="button.size ?? 'md'"
1074
+ [loading]="isButtonLoading(button)"
1075
+ [disabled]="isButtonDisabled(button)"
1076
+ [customClass]="button.customClass"
1077
+ (click)="handleButtonClick(button, $event)"
1078
+ />
1079
+ }
1080
+ </div>
1081
+ `, isInline: true, styles: [".ui-button-area-host{display:block}@media (max-width: 767.98px){.ui-button-area-host{width:100%}}.ui-button-area{display:flex;flex-wrap:wrap;align-items:center}.ui-button-area--gap-xs{gap:var(--ui-spacing-1)}.ui-button-area--gap-sm{gap:var(--ui-spacing-2)}.ui-button-area--gap-md{gap:var(--ui-spacing-3)}.ui-button-area--gap-lg{gap:var(--ui-spacing-4)}.ui-button-area--gap-xl{gap:var(--ui-spacing-5)}.ui-button-area--align-start{justify-content:flex-start}.ui-button-area--align-center{justify-content:center}.ui-button-area--align-end{justify-content:flex-end}.ui-button-area--align-between{justify-content:space-between}@media (max-width: 767.98px){.ui-button-area--stack-mobile{flex-direction:column;width:100%}.ui-button-area--stack-mobile .ui-button-host{display:flex;width:100%}.ui-button-area--stack-mobile .ui-button{width:100%}}\n"], dependencies: [{ kind: "component", type: UiButtonComponent, selector: "ui-button", inputs: ["label", "tooltip", "variant", "size", "icon", "iconPosition", "loading", "disabled", "fullWidth", "type", "ariaLabel", "customClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
1082
+ }
1083
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: UiButtonAreaComponent, decorators: [{
1084
+ type: Component,
1085
+ args: [{ selector: 'ui-button-area', standalone: true, imports: [UiButtonComponent], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: {
1086
+ class: 'ui-button-area-host',
1087
+ }, template: `
1088
+ <div
1089
+ [class]="areaClasses"
1090
+ role="group"
1091
+ [attr.aria-label]="ariaLabel"
1092
+ >
1093
+ @for (button of visibleButtons; track trackButton($index, button)) {
1094
+ <ui-button
1095
+ [attr.data-button-id]="button.id || null"
1096
+ [label]="button.label"
1097
+ [tooltip]="button.tooltip ?? ''"
1098
+ [ariaLabel]="button.ariaLabel"
1099
+ [icon]="button.icon"
1100
+ [iconPosition]="button.iconPosition ?? 'trailing'"
1101
+ [variant]="button.variant ?? 'primary'"
1102
+ [size]="button.size ?? 'md'"
1103
+ [loading]="isButtonLoading(button)"
1104
+ [disabled]="isButtonDisabled(button)"
1105
+ [customClass]="button.customClass"
1106
+ (click)="handleButtonClick(button, $event)"
1107
+ />
1108
+ }
1109
+ </div>
1110
+ `, styles: [".ui-button-area-host{display:block}@media (max-width: 767.98px){.ui-button-area-host{width:100%}}.ui-button-area{display:flex;flex-wrap:wrap;align-items:center}.ui-button-area--gap-xs{gap:var(--ui-spacing-1)}.ui-button-area--gap-sm{gap:var(--ui-spacing-2)}.ui-button-area--gap-md{gap:var(--ui-spacing-3)}.ui-button-area--gap-lg{gap:var(--ui-spacing-4)}.ui-button-area--gap-xl{gap:var(--ui-spacing-5)}.ui-button-area--align-start{justify-content:flex-start}.ui-button-area--align-center{justify-content:center}.ui-button-area--align-end{justify-content:flex-end}.ui-button-area--align-between{justify-content:space-between}@media (max-width: 767.98px){.ui-button-area--stack-mobile{flex-direction:column;width:100%}.ui-button-area--stack-mobile .ui-button-host{display:flex;width:100%}.ui-button-area--stack-mobile .ui-button{width:100%}}\n"] }]
1111
+ }], propDecorators: { buttons: [{
1112
+ type: Input
1113
+ }], align: [{
1114
+ type: Input
1115
+ }], ariaLabel: [{
1116
+ type: Input
1117
+ }], gap: [{
1118
+ type: Input
1119
+ }], stackOnMobile: [{
1120
+ type: Input
1121
+ }], disableWhileLoading: [{
1122
+ type: Input
1123
+ }], loadingIds: [{
1124
+ type: Input
1125
+ }] } });
1126
+
1127
+ /**
1128
+ * @module ng-ui-system/page-header
1129
+ * Types and interfaces for UiPageHeader and UiBreadcrumbService.
1130
+ */
1131
+ /**
1132
+ * Injection token for providing a custom label resolver to UiBreadcrumbService.
1133
+ *
1134
+ * When not provided, parameters are displayed as-is (identity function).
1135
+ *
1136
+ * @example
1137
+ * ```typescript
1138
+ * // In your app.config.ts or module providers:
1139
+ * { provide: UI_BREADCRUMB_LABEL_RESOLVER, useValue: myLabelResolver }
1140
+ * ```
1141
+ */
1142
+ const UI_BREADCRUMB_LABEL_RESOLVER = new InjectionToken('UI_BREADCRUMB_LABEL_RESOLVER', {
1143
+ providedIn: 'root',
1144
+ factory: () => (_name, value) => value,
1145
+ });
1146
+
1147
+ /** biome-ignore-all lint/complexity/useLiteralKeys: <explanation> */
1148
+ /**
1149
+ * Service that builds a nested breadcrumb trail from Angular route configuration.
1150
+ *
1151
+ * Routes must define `data.id`, `data.title`, and optionally `data.breadcrumbs`
1152
+ * (an array of parent route IDs) for the chain to resolve correctly.
1153
+ *
1154
+ * Supports lazy-loaded routes: the internal route map is rebuilt automatically
1155
+ * whenever new routes are loaded via `NavigationEnd`.
1156
+ *
1157
+ * Label resolution for route parameters (`:param`) is delegated to an injectable
1158
+ * `UiLabelResolverFn` via the `UI_BREADCRUMB_LABEL_RESOLVER` token.
1159
+ *
1160
+ * @usageNotes
1161
+ * ### Route configuration
1162
+ * ```typescript
1163
+ * const routes: Routes = [
1164
+ * {
1165
+ * path: 'users',
1166
+ * data: { id: 'users', title: 'Utenti' },
1167
+ * children: [
1168
+ * {
1169
+ * path: ':userId',
1170
+ * data: { id: 'user-detail', title: ':userId', breadcrumbs: ['users'] },
1171
+ * component: UserDetailComponent,
1172
+ * },
1173
+ * ],
1174
+ * },
1175
+ * ];
1176
+ * ```
1177
+ *
1178
+ * ### Custom label resolver
1179
+ * ```typescript
1180
+ * providers: [
1181
+ * {
1182
+ * provide: UI_BREADCRUMB_LABEL_RESOLVER,
1183
+ * useValue: (name: string, value: string) =>
1184
+ * name === 'userId' ? `User #${value}` : value,
1185
+ * },
1186
+ * ]
1187
+ * ```
1188
+ */
1189
+ class UiBreadcrumbService {
1190
+ constructor() {
1191
+ this.router = inject(Router);
1192
+ this.labelResolver = inject(UI_BREADCRUMB_LABEL_RESOLVER);
1193
+ /** @internal Map of route ID → breadcrumb configuration. */
1194
+ this.breadcrumbMap = new Map();
1195
+ /** @internal Tracks route count to detect lazy-loaded route additions. */
1196
+ this.lastRouteConfigLength = 0;
1197
+ /** @internal Last computed breadcrumbs for navigateBack. */
1198
+ this.lastBreadcrumbs = [];
1199
+ this.rebuildRouteMap();
1200
+ this.router.events
1201
+ .pipe(filter((event) => event instanceof NavigationEnd))
1202
+ .subscribe(() => this.rebuildRouteMapIfNeeded());
1203
+ }
1204
+ /**
1205
+ * Computes the breadcrumb trail for the currently active route.
1206
+ *
1207
+ * @param route - The root `ActivatedRoute` (typically injected in the component).
1208
+ * @returns Ordered array of breadcrumb items from root to current route.
1209
+ */
1210
+ getBreadcrumbsForRoute(route) {
1211
+ let deepestRoute = route;
1212
+ while (deepestRoute.firstChild) {
1213
+ deepestRoute = deepestRoute.firstChild;
1214
+ }
1215
+ let routeWithId = deepestRoute;
1216
+ while (routeWithId && !routeWithId.snapshot.data['id']) {
1217
+ routeWithId = routeWithId.parent;
1218
+ }
1219
+ const routeId = routeWithId?.snapshot.data['id'];
1220
+ if (!routeId) {
1221
+ this.lastBreadcrumbs = [];
1222
+ return [];
1223
+ }
1224
+ const params = this.collectParamsFromPath(deepestRoute);
1225
+ const breadcrumbs = this.buildBreadcrumbChain(routeId, params);
1226
+ this.lastBreadcrumbs = breadcrumbs;
1227
+ return breadcrumbs;
1228
+ }
1229
+ /**
1230
+ * Navigates to the previous breadcrumb (parent route).
1231
+ * Falls back to `fallbackUrl` (default: `/`) when no parent exists.
1232
+ */
1233
+ navigateBack(fallbackUrl = '/') {
1234
+ const prev = this.lastBreadcrumbs.length > 1 ? this.lastBreadcrumbs[this.lastBreadcrumbs.length - 2] : null;
1235
+ const target = prev?.url ?? fallbackUrl;
1236
+ this.router.navigateByUrl(target);
1237
+ }
1238
+ /** @internal Collects all route params from the full path (including parents). */
1239
+ collectParamsFromPath(route) {
1240
+ const params = {};
1241
+ for (const r of route.pathFromRoot) {
1242
+ Object.assign(params, r.snapshot.params);
1243
+ }
1244
+ return params;
1245
+ }
1246
+ // ─── Private helpers ─────────────────────────────────────────────
1247
+ /** @internal Rebuilds the map only when new lazy routes appear. */
1248
+ rebuildRouteMapIfNeeded() {
1249
+ const currentLength = this.countRoutes(this.router.config);
1250
+ if (currentLength !== this.lastRouteConfigLength) {
1251
+ this.rebuildRouteMap();
1252
+ }
1253
+ }
1254
+ /** @internal Recursively counts routes including lazy-loaded children. */
1255
+ countRoutes(routes) {
1256
+ let count = routes.length;
1257
+ for (const route of routes) {
1258
+ if (route.children) {
1259
+ count += this.countRoutes(route.children);
1260
+ }
1261
+ if (route._loadedRoutes) {
1262
+ count += this.countRoutes(route._loadedRoutes);
1263
+ }
1264
+ }
1265
+ return count;
1266
+ }
1267
+ /** @internal Clears and rebuilds the full route → breadcrumb map. */
1268
+ rebuildRouteMap() {
1269
+ this.breadcrumbMap.clear();
1270
+ this.buildRouteMap(this.router.config);
1271
+ this.lastRouteConfigLength = this.countRoutes(this.router.config);
1272
+ }
1273
+ /** @internal Recursively walks route tree to build the breadcrumb map. */
1274
+ buildRouteMap(routes, parentPath = '') {
1275
+ for (const route of routes) {
1276
+ const currentPath = `${parentPath}/${route.path || ''}`;
1277
+ if (route.data?.['id']) {
1278
+ const fullPath = this.normalizePath(currentPath);
1279
+ this.breadcrumbMap.set(route.data['id'], {
1280
+ id: route.data['id'],
1281
+ path: fullPath,
1282
+ label: route.data['title'] || route.path || route.data['id'],
1283
+ parentIds: route.data['breadcrumbs'] || [],
1284
+ metadata: route.data,
1285
+ });
1286
+ }
1287
+ if (route.children) {
1288
+ this.buildRouteMap(route.children, currentPath);
1289
+ }
1290
+ if (route._loadedRoutes) {
1291
+ this.buildRouteMap(route._loadedRoutes, currentPath);
1292
+ }
1293
+ }
1294
+ }
1295
+ /** @internal Builds the full breadcrumb chain for a route by its ID. */
1296
+ buildBreadcrumbChain(routeId, params) {
1297
+ const config = this.breadcrumbMap.get(routeId);
1298
+ if (!config)
1299
+ return [];
1300
+ this.saveFullPath(routeId, this.router.url);
1301
+ const parentChain = this.getParentChain(config.parentIds, params);
1302
+ const breadcrumbs = [...parentChain];
1303
+ breadcrumbs.push({
1304
+ label: this.resolveLabel(config.label, params),
1305
+ url: this.stripQueryParams(this.router.url),
1306
+ isLast: true,
1307
+ });
1308
+ return breadcrumbs;
1309
+ }
1310
+ /** @internal Resolves parent breadcrumbs from ordered parent IDs. */
1311
+ getParentChain(parentIds, params) {
1312
+ if (!parentIds?.length)
1313
+ return [];
1314
+ return parentIds
1315
+ .map((id) => {
1316
+ const config = this.breadcrumbMap.get(id);
1317
+ if (!config)
1318
+ return null;
1319
+ return {
1320
+ label: this.resolveLabel(config.label, params),
1321
+ url: this.resolveUrl(config.path, params),
1322
+ isLast: false,
1323
+ };
1324
+ })
1325
+ .filter(Boolean);
1326
+ }
1327
+ /**
1328
+ * @internal Resolves `:param` placeholders in a label using
1329
+ * the injected label resolver function.
1330
+ */
1331
+ resolveLabel(label, params) {
1332
+ if (!label.includes(':'))
1333
+ return label;
1334
+ let resolved = label;
1335
+ for (const [key, value] of Object.entries(params)) {
1336
+ const readableValue = this.labelResolver(key, value);
1337
+ resolved = resolved.replace(`:${key}`, readableValue);
1338
+ }
1339
+ return resolved;
1340
+ }
1341
+ /** @internal Resolves `:param` placeholders in a path and creates a URL. */
1342
+ resolveUrl(path, params) {
1343
+ let processedPath = path;
1344
+ if (path.includes(':')) {
1345
+ const segments = path.split('/');
1346
+ const processedSegments = segments.map((segment) => {
1347
+ if (segment.startsWith(':')) {
1348
+ const paramName = segment.substring(1);
1349
+ return params[paramName] || segment;
1350
+ }
1351
+ return segment;
1352
+ });
1353
+ processedPath = processedSegments.join('/');
1354
+ }
1355
+ try {
1356
+ return this.router.createUrlTree([processedPath]).toString();
1357
+ }
1358
+ catch {
1359
+ return processedPath;
1360
+ }
1361
+ }
1362
+ /** @internal Normalizes path by collapsing double slashes and trimming trailing slash. */
1363
+ normalizePath(path) {
1364
+ return path.replace(/\/+/g, '/').replace(/\/$/, '');
1365
+ }
1366
+ /** @internal Removes query parameters from a URL. */
1367
+ stripQueryParams(url) {
1368
+ return url.split('?')[0];
1369
+ }
1370
+ /** @internal Caches the fully resolved URL for a route ID. */
1371
+ saveFullPath(routeId, fullPath) {
1372
+ const config = this.breadcrumbMap.get(routeId);
1373
+ if (config) {
1374
+ config.fullPath = this.stripQueryParams(fullPath);
1375
+ }
1376
+ }
1377
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: UiBreadcrumbService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1378
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: UiBreadcrumbService, providedIn: 'root' }); }
1379
+ }
1380
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: UiBreadcrumbService, decorators: [{
1381
+ type: Injectable,
1382
+ args: [{ providedIn: 'root' }]
1383
+ }], ctorParameters: () => [] });
1384
+
1385
+ /**
1386
+ * Page header component that renders a breadcrumb navigation trail
1387
+ * and a page title. Integrates with `UiBreadcrumbService` to
1388
+ * automatically derive breadcrumbs from Angular route configuration.
1389
+ *
1390
+ * The breadcrumb trail is generated from route `data` properties:
1391
+ * - `data.id` — unique route identifier
1392
+ * - `data.title` — display label
1393
+ * - `data.breadcrumbs` — ordered array of parent route IDs
1394
+ *
1395
+ * @selector ui-page-header
1396
+ *
1397
+ * @example
1398
+ * ```html
1399
+ * <!-- Auto breadcrumbs from route data -->
1400
+ * <ui-page-header />
1401
+ *
1402
+ * <!-- With explicit title override -->
1403
+ * <ui-page-header title="Custom Title" />
1404
+ *
1405
+ * <!-- With document title update -->
1406
+ * <ui-page-header [updateDocumentTitle]="true" titleSuffix=" | My App" />
1407
+ * ```
1408
+ */
1409
+ class UiPageHeaderComponent {
1410
+ constructor() {
1411
+ /** Override the auto-detected page title. When empty, title is derived from the last breadcrumb. */
1412
+ this.title = '';
1413
+ /** Route path for the Home breadcrumb link. */
1414
+ this.homeRoute = '/';
1415
+ /** Whether to display the Home link at the start of the trail. */
1416
+ this.showHome = true;
1417
+ /** When `true`, updates `document.title` on each navigation. */
1418
+ this.updateDocumentTitle = false;
1419
+ /** Suffix appended to `document.title` (e.g. `' | My App'`). Only used when `updateDocumentTitle` is `true`. */
1420
+ this.titleSuffix = '';
1421
+ /** @internal */
1422
+ this.breadcrumbs = [];
1423
+ this.router = inject(Router);
1424
+ this.activatedRoute = inject(ActivatedRoute);
1425
+ this.titleService = inject(Title);
1426
+ this.breadcrumbService = inject(UiBreadcrumbService);
1427
+ this.destroyRef = inject(DestroyRef);
1428
+ this.cdr = inject(ChangeDetectorRef);
1429
+ }
1430
+ /** Resolved page title: explicit `title` input wins, otherwise last breadcrumb label. */
1431
+ get displayTitle() {
1432
+ if (this.title)
1433
+ return this.title;
1434
+ if (this.breadcrumbs.length > 0) {
1435
+ return this.breadcrumbs[this.breadcrumbs.length - 1].label;
1436
+ }
1437
+ return '';
1438
+ }
1439
+ ngOnInit() {
1440
+ this.refresh();
1441
+ this.router.events
1442
+ .pipe(filter((event) => event instanceof NavigationEnd), takeUntilDestroyed(this.destroyRef))
1443
+ .subscribe(() => this.refresh());
1444
+ }
1445
+ /**
1446
+ * Navigates to the previous breadcrumb (parent route).
1447
+ * @param fallbackUrl - URL to navigate to when no parent exists (default: homeRoute).
1448
+ */
1449
+ navigateBack(fallbackUrl) {
1450
+ this.breadcrumbService.navigateBack(fallbackUrl ?? this.homeRoute);
1451
+ }
1452
+ /** @internal */
1453
+ refresh() {
1454
+ this.breadcrumbs = this.breadcrumbService.getBreadcrumbsForRoute(this.activatedRoute);
1455
+ if (this.updateDocumentTitle) {
1456
+ const title = this.displayTitle;
1457
+ if (title) {
1458
+ this.titleService.setTitle(`${title}${this.titleSuffix}`);
1459
+ }
1460
+ }
1461
+ this.cdr.markForCheck();
1462
+ }
1463
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: UiPageHeaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1464
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: UiPageHeaderComponent, isStandalone: true, selector: "ui-page-header", inputs: { title: "title", homeRoute: "homeRoute", showHome: "showHome", updateDocumentTitle: "updateDocumentTitle", titleSuffix: "titleSuffix" }, host: { classAttribute: "ui-page-header-host" }, ngImport: i0, template: `
1465
+ <header class="ui-page-header">
1466
+ <nav aria-label="Breadcrumb" class="ui-page-header__nav">
1467
+ <ol
1468
+ class="ui-page-header__breadcrumb"
1469
+ itemscope
1470
+ itemtype="https://schema.org/BreadcrumbList"
1471
+ >
1472
+ @if (showHome) {
1473
+ <li
1474
+ class="ui-page-header__item"
1475
+ itemprop="itemListElement"
1476
+ itemscope
1477
+ itemtype="https://schema.org/ListItem"
1478
+ >
1479
+ <a
1480
+ itemprop="item"
1481
+ [routerLink]="homeRoute"
1482
+ class="ui-page-header__link"
1483
+ aria-label="Home"
1484
+ >
1485
+ <lucide-icon name="home" [size]="14" aria-hidden="true" />
1486
+ <span itemprop="name" class="ui-page-header__text">Home</span>
1487
+ </a>
1488
+ <meta itemprop="position" content="1" />
1489
+ <span class="ui-page-header__separator" aria-hidden="true">
1490
+ <lucide-icon name="chevron-right" [size]="14" />
1491
+ </span>
1492
+ </li>
1493
+ }
1494
+ @for (crumb of breadcrumbs; track crumb.url; let i = $index) {
1495
+ <li
1496
+ class="ui-page-header__item"
1497
+ [class.ui-page-header__item--current]="crumb.isLast"
1498
+ itemprop="itemListElement"
1499
+ itemscope
1500
+ itemtype="https://schema.org/ListItem"
1501
+ >
1502
+ @if (!crumb.isLast) {
1503
+ <a
1504
+ itemprop="item"
1505
+ [routerLink]="crumb.url"
1506
+ class="ui-page-header__link"
1507
+ >
1508
+ <span itemprop="name" class="ui-page-header__text">{{ crumb.label }}</span>
1509
+ </a>
1510
+ <span class="ui-page-header__separator" aria-hidden="true">
1511
+ <lucide-icon name="chevron-right" [size]="14" />
1512
+ </span>
1513
+ } @else {
1514
+ <span
1515
+ itemprop="name"
1516
+ class="ui-page-header__text ui-page-header__text--current"
1517
+ aria-current="page"
1518
+ >
1519
+ {{ crumb.label }}
1520
+ </span>
1521
+ }
1522
+ <meta itemprop="position" [attr.content]="showHome ? i + 2 : i + 1" />
1523
+ </li>
1524
+ }
1525
+ </ol>
1526
+ </nav>
1527
+
1528
+ <h1 class="ui-page-header__title" id="page-title">
1529
+ {{ displayTitle }}
1530
+ </h1>
1531
+ </header>
1532
+ `, isInline: true, styles: [".ui-page-header-host{display:block}.ui-page-header{margin-bottom:var(--ui-spacing-5)}.ui-page-header__nav{margin-bottom:var(--ui-spacing-2)}.ui-page-header__breadcrumb{display:flex;flex-wrap:wrap;align-items:center;list-style:none;margin:0;padding:0;font-family:var(--ui-font-family);font-size:var(--ui-font-size-sm);line-height:var(--ui-line-height-normal);gap:var(--ui-spacing-1)}.ui-page-header__item{display:inline-flex;align-items:center;gap:var(--ui-spacing-1)}a.ui-page-header__link lucide-icon{transform:translateY(2px)!important}span.ui-page-header__separator lucide-icon{transform:translateY(3px)!important}.ui-page-header__link{display:inline-flex;align-items:center;gap:4px;text-decoration:none;color:var(--ui-color-primary);border-radius:var(--ui-radius-sm);padding:2px 4px;margin:-2px -4px;transition:color var(--ui-transition-fast),background-color var(--ui-transition-fast)}.ui-page-header__link:hover{color:var(--ui-color-primary-hover);text-decoration:underline}.ui-page-header__link:focus{outline:none}.ui-page-header__link:focus-visible{outline:var(--ui-focus-ring-width) solid var(--ui-focus-ring-color);outline-offset:var(--ui-focus-ring-offset)}.ui-page-header__text{white-space:nowrap}.ui-page-header__text--current{font-weight:var(--ui-font-weight-medium);color:var(--ui-color-text)}.ui-page-header__separator{display:inline-flex;align-items:center;color:var(--ui-color-text-muted);flex-shrink:0}.ui-page-header__title{margin:0;font-family:var(--ui-font-family);font-size:var(--ui-font-size-2xl);font-weight:var(--ui-font-weight-bold);color:var(--ui-color-text);line-height:var(--ui-line-height-tight)}.ui-page-header__title:focus{outline:none}@media (min-width: 640px){.ui-page-header__title{font-size:var(--ui-font-size-xl)}.ui-page-header__breadcrumb{font-size:var(--ui-font-size-xs)}}\n"], dependencies: [{ kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "ngmodule", type: LucideAngularModule }, { kind: "component", type: i2.LucideAngularComponent, selector: "lucide-angular, lucide-icon, i-lucide, span-lucide", inputs: ["class", "name", "img", "color", "absoluteStrokeWidth", "size", "strokeWidth"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
1533
+ }
1534
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: UiPageHeaderComponent, decorators: [{
1535
+ type: Component,
1536
+ args: [{ selector: 'ui-page-header', standalone: true, imports: [RouterLink, LucideAngularModule], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: {
1537
+ class: 'ui-page-header-host',
1538
+ }, template: `
1539
+ <header class="ui-page-header">
1540
+ <nav aria-label="Breadcrumb" class="ui-page-header__nav">
1541
+ <ol
1542
+ class="ui-page-header__breadcrumb"
1543
+ itemscope
1544
+ itemtype="https://schema.org/BreadcrumbList"
1545
+ >
1546
+ @if (showHome) {
1547
+ <li
1548
+ class="ui-page-header__item"
1549
+ itemprop="itemListElement"
1550
+ itemscope
1551
+ itemtype="https://schema.org/ListItem"
1552
+ >
1553
+ <a
1554
+ itemprop="item"
1555
+ [routerLink]="homeRoute"
1556
+ class="ui-page-header__link"
1557
+ aria-label="Home"
1558
+ >
1559
+ <lucide-icon name="home" [size]="14" aria-hidden="true" />
1560
+ <span itemprop="name" class="ui-page-header__text">Home</span>
1561
+ </a>
1562
+ <meta itemprop="position" content="1" />
1563
+ <span class="ui-page-header__separator" aria-hidden="true">
1564
+ <lucide-icon name="chevron-right" [size]="14" />
1565
+ </span>
1566
+ </li>
1567
+ }
1568
+ @for (crumb of breadcrumbs; track crumb.url; let i = $index) {
1569
+ <li
1570
+ class="ui-page-header__item"
1571
+ [class.ui-page-header__item--current]="crumb.isLast"
1572
+ itemprop="itemListElement"
1573
+ itemscope
1574
+ itemtype="https://schema.org/ListItem"
1575
+ >
1576
+ @if (!crumb.isLast) {
1577
+ <a
1578
+ itemprop="item"
1579
+ [routerLink]="crumb.url"
1580
+ class="ui-page-header__link"
1581
+ >
1582
+ <span itemprop="name" class="ui-page-header__text">{{ crumb.label }}</span>
1583
+ </a>
1584
+ <span class="ui-page-header__separator" aria-hidden="true">
1585
+ <lucide-icon name="chevron-right" [size]="14" />
1586
+ </span>
1587
+ } @else {
1588
+ <span
1589
+ itemprop="name"
1590
+ class="ui-page-header__text ui-page-header__text--current"
1591
+ aria-current="page"
1592
+ >
1593
+ {{ crumb.label }}
1594
+ </span>
1595
+ }
1596
+ <meta itemprop="position" [attr.content]="showHome ? i + 2 : i + 1" />
1597
+ </li>
1598
+ }
1599
+ </ol>
1600
+ </nav>
1601
+
1602
+ <h1 class="ui-page-header__title" id="page-title">
1603
+ {{ displayTitle }}
1604
+ </h1>
1605
+ </header>
1606
+ `, styles: [".ui-page-header-host{display:block}.ui-page-header{margin-bottom:var(--ui-spacing-5)}.ui-page-header__nav{margin-bottom:var(--ui-spacing-2)}.ui-page-header__breadcrumb{display:flex;flex-wrap:wrap;align-items:center;list-style:none;margin:0;padding:0;font-family:var(--ui-font-family);font-size:var(--ui-font-size-sm);line-height:var(--ui-line-height-normal);gap:var(--ui-spacing-1)}.ui-page-header__item{display:inline-flex;align-items:center;gap:var(--ui-spacing-1)}a.ui-page-header__link lucide-icon{transform:translateY(2px)!important}span.ui-page-header__separator lucide-icon{transform:translateY(3px)!important}.ui-page-header__link{display:inline-flex;align-items:center;gap:4px;text-decoration:none;color:var(--ui-color-primary);border-radius:var(--ui-radius-sm);padding:2px 4px;margin:-2px -4px;transition:color var(--ui-transition-fast),background-color var(--ui-transition-fast)}.ui-page-header__link:hover{color:var(--ui-color-primary-hover);text-decoration:underline}.ui-page-header__link:focus{outline:none}.ui-page-header__link:focus-visible{outline:var(--ui-focus-ring-width) solid var(--ui-focus-ring-color);outline-offset:var(--ui-focus-ring-offset)}.ui-page-header__text{white-space:nowrap}.ui-page-header__text--current{font-weight:var(--ui-font-weight-medium);color:var(--ui-color-text)}.ui-page-header__separator{display:inline-flex;align-items:center;color:var(--ui-color-text-muted);flex-shrink:0}.ui-page-header__title{margin:0;font-family:var(--ui-font-family);font-size:var(--ui-font-size-2xl);font-weight:var(--ui-font-weight-bold);color:var(--ui-color-text);line-height:var(--ui-line-height-tight)}.ui-page-header__title:focus{outline:none}@media (min-width: 640px){.ui-page-header__title{font-size:var(--ui-font-size-xl)}.ui-page-header__breadcrumb{font-size:var(--ui-font-size-xs)}}\n"] }]
1607
+ }], propDecorators: { title: [{
1608
+ type: Input
1609
+ }], homeRoute: [{
1610
+ type: Input
1611
+ }], showHome: [{
1612
+ type: Input
1613
+ }], updateDocumentTitle: [{
1614
+ type: Input
1615
+ }], titleSuffix: [{
1616
+ type: Input
1617
+ }] } });
1618
+
1619
+ /**
1620
+ * Full-page layout component that combines a page header (breadcrumbs + title),
1621
+ * a main content area via `<ng-content>`, and a sticky footer action bar
1622
+ * powered by `UiButtonAreaComponent`.
1623
+ *
1624
+ * Optionally renders an automatic "back" button in the footer, derived from
1625
+ * the breadcrumb trail (navigates to the parent breadcrumb).
1626
+ *
1627
+ * ### Route `data`
1628
+ *
1629
+ * Sulla rotta attiva (foglia) puoi impostare:
1630
+ *
1631
+ * - `breadcrumbOff: true` — nasconde `ui-page-header`
1632
+ * - `footerNavOff: true` — nasconde `ui-base-layout__footer`
1633
+ * - `id: string` — valorizza `data-route-id` sul contenitore `.ui-base-layout`
1634
+ *
1635
+ * @selector ui-base-layout
1636
+ *
1637
+ * @example
1638
+ * ```html
1639
+ * <ui-base-layout [actions]="pageActions" footerAlign="end">
1640
+ * <p>Your page content here</p>
1641
+ * </ui-base-layout>
1642
+ * ```
1643
+ *
1644
+ * @example
1645
+ * ```html
1646
+ * <!-- With back button and custom title -->
1647
+ * <ui-base-layout
1648
+ * title="Dettaglio utente"
1649
+ * [showBackButton]="true"
1650
+ * [actions]="[
1651
+ * { id: 'save', label: 'Salva', variant: 'primary', icon: 'save', action: save },
1652
+ * ]"
1653
+ * >
1654
+ * <app-user-detail />
1655
+ * </ui-base-layout>
1656
+ * ```
1657
+ */
1658
+ class UiBaseLayoutComponent {
1659
+ constructor() {
1660
+ /** Whether to display the page header (breadcrumbs + title). */
1661
+ this.showHeader = true;
1662
+ /** Override the auto-detected page title. Passed through to `ui-page-header`. */
1663
+ this.title = '';
1664
+ /** Route path for the Home breadcrumb link. */
1665
+ this.homeRoute = '/';
1666
+ /** Whether to display the Home link in the breadcrumb trail. */
1667
+ this.showHome = true;
1668
+ /** When `true`, updates `document.title` on navigation. */
1669
+ this.updateDocumentTitle = false;
1670
+ /** Suffix appended to `document.title`. */
1671
+ this.titleSuffix = '';
1672
+ /** Whether to show an automatic "back" button based on breadcrumbs. */
1673
+ this.showBackButton = true;
1674
+ /** Configuration overrides for the automatic back button. */
1675
+ this.backButtonConfig = {};
1676
+ /** Array of button descriptors for the footer action area. */
1677
+ this.actions = [];
1678
+ /** Horizontal alignment of the footer button area. */
1679
+ this.footerAlign = 'start';
1680
+ /** Gap size between footer buttons. */
1681
+ this.footerGap = 'sm';
1682
+ this.router = inject(Router);
1683
+ this.activatedRoute = inject(ActivatedRoute);
1684
+ this.breadcrumbService = inject(UiBreadcrumbService);
1685
+ this.destroyRef = inject(DestroyRef);
1686
+ /**
1687
+ * Flag derivati dalla catena attiva (`breadcrumbOff`, `footerNavOff`, `id`).
1688
+ * Aggiornati a ogni `NavigationEnd`.
1689
+ */
1690
+ this.routeSnapshotFlags = signal({
1691
+ breadcrumbOff: false,
1692
+ footerNavOff: false,
1693
+ routeId: null,
1694
+ });
1695
+ /** Header visibile se abilitato da input e non disattivato da `data.breadcrumbOff`. */
1696
+ this.effectiveShowHeader = () => this.showHeader && !this.routeSnapshotFlags().breadcrumbOff;
1697
+ /** Footer azioni visibile se ci sono azioni visibili e non disattivato da `data.footerNavOff`. */
1698
+ this.effectiveShowFooterNav = () => !this.routeSnapshotFlags().footerNavOff && this.hasVisibleActions;
1699
+ }
1700
+ /**
1701
+ * Merged action list (back button + consumer actions).
1702
+ * Computed on every change-detection check so it stays in sync
1703
+ * with both navigation state (breadcrumbs) and input changes.
1704
+ */
1705
+ get mergedActions() {
1706
+ const result = [];
1707
+ if (this.showBackButton) {
1708
+ result.push({
1709
+ id: '__ui-back',
1710
+ label: this.backButtonConfig.label ?? 'Indietro',
1711
+ icon: this.backButtonConfig.icon ?? 'arrow-left',
1712
+ iconPosition: 'leading',
1713
+ variant: this.backButtonConfig.variant ?? 'outline',
1714
+ hidden: this.shouldHideBackButton(),
1715
+ action: () => this.navigateBack(),
1716
+ });
1717
+ }
1718
+ result.push(...this.actions);
1719
+ return result;
1720
+ }
1721
+ /** Whether the footer should render (at least one non-hidden action exists). */
1722
+ get hasVisibleActions() {
1723
+ return this.mergedActions.some((a) => !a.hidden);
1724
+ }
1725
+ ngOnInit() {
1726
+ this.syncFromActivatedRoute();
1727
+ this.router.events
1728
+ .pipe(filter((event) => event instanceof NavigationEnd), debounceTime(50), takeUntilDestroyed(this.destroyRef))
1729
+ .subscribe(() => this.syncFromActivatedRoute());
1730
+ }
1731
+ /** @internal Allinea breadcrumb service e flag layout alla rotta corrente. */
1732
+ syncFromActivatedRoute() {
1733
+ this.refreshRouteSnapshotFlags();
1734
+ this.breadcrumbService.getBreadcrumbsForRoute(this.activatedRoute);
1735
+ }
1736
+ /** @internal Legge `breadcrumbOff`, `footerNavOff`, `id` dalla catena `pathFromRoot` / foglia. */
1737
+ refreshRouteSnapshotFlags() {
1738
+ const deepest = this.deepestChildRoute(this.activatedRoute);
1739
+ let breadcrumbOff = false;
1740
+ let footerNavOff = false;
1741
+ for (const seg of deepest.pathFromRoot) {
1742
+ const d = seg.snapshot.data;
1743
+ if (!d)
1744
+ continue;
1745
+ // biome-ignore lint/complexity/useLiteralKeys: chiavi documentate in UiBaseLayoutRouteData
1746
+ if (d['breadcrumbOff'] === true)
1747
+ breadcrumbOff = true;
1748
+ // biome-ignore lint/complexity/useLiteralKeys: chiavi documentate in UiBaseLayoutRouteData
1749
+ if (d['footerNavOff'] === true)
1750
+ footerNavOff = true;
1751
+ }
1752
+ let routeId = null;
1753
+ let cursor = deepest;
1754
+ while (cursor) {
1755
+ const raw = cursor.snapshot.data?.['id'];
1756
+ if (typeof raw === 'string' && raw.length > 0) {
1757
+ routeId = raw;
1758
+ break;
1759
+ }
1760
+ cursor = cursor.parent;
1761
+ }
1762
+ this.routeSnapshotFlags.set({ breadcrumbOff, footerNavOff, routeId });
1763
+ }
1764
+ /** @internal Percorre fino al `ActivatedRoute` foglia sotto il punto di iniezione. */
1765
+ deepestChildRoute(route) {
1766
+ let deepest = route;
1767
+ while (deepest.firstChild) {
1768
+ deepest = deepest.firstChild;
1769
+ }
1770
+ return deepest;
1771
+ }
1772
+ /** @internal Determina se il back button deve essere nascosto per la rotta corrente. */
1773
+ shouldHideBackButton() {
1774
+ const currentPath = this.router.url.split('?')[0].split('#')[0];
1775
+ if (currentPath === this.homeRoute) {
1776
+ return true;
1777
+ }
1778
+ const deepestRoute = this.deepestChildRoute(this.activatedRoute);
1779
+ // biome-ignore lint/complexity/useLiteralKeys: <explanation>
1780
+ if (deepestRoute.snapshot.data?.['hideBackButton'] === true) {
1781
+ return true;
1782
+ }
1783
+ return false;
1784
+ }
1785
+ /** @internal Naviga al breadcrumb genitore o esegue il fallback alla home route. */
1786
+ navigateBack() {
1787
+ this.breadcrumbService.navigateBack(this.homeRoute);
1788
+ }
1789
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: UiBaseLayoutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1790
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: UiBaseLayoutComponent, isStandalone: true, selector: "ui-base-layout", inputs: { showHeader: "showHeader", title: "title", homeRoute: "homeRoute", showHome: "showHome", updateDocumentTitle: "updateDocumentTitle", titleSuffix: "titleSuffix", showBackButton: "showBackButton", backButtonConfig: "backButtonConfig", actions: "actions", footerAlign: "footerAlign", footerGap: "footerGap" }, host: { classAttribute: "ui-base-layout-host" }, ngImport: i0, template: `
1791
+ <div class="ui-base-layout" [attr.data-route-id]="routeSnapshotFlags().routeId">
1792
+ @if (effectiveShowHeader()) {
1793
+ <ui-page-header
1794
+ [title]="title"
1795
+ [homeRoute]="homeRoute"
1796
+ [showHome]="showHome"
1797
+ [updateDocumentTitle]="updateDocumentTitle"
1798
+ [titleSuffix]="titleSuffix"
1799
+ />
1800
+ }
1801
+
1802
+ <main class="ui-base-layout__content">
1803
+ <ng-content />
1804
+ </main>
1805
+
1806
+ @if (effectiveShowFooterNav()) {
1807
+ <aside
1808
+ class="ui-base-layout__footer"
1809
+ aria-label="Page actions"
1810
+ >
1811
+ <ui-button-area
1812
+ [buttons]="mergedActions"
1813
+ [align]="footerAlign"
1814
+ [gap]="footerGap"
1815
+ [stackOnMobile]="true"
1816
+ ariaLabel="Page actions"
1817
+ />
1818
+ </aside>
1819
+ }
1820
+ </div>
1821
+ `, isInline: true, styles: [".ui-base-layout-host{display:block;min-height:100%}.ui-base-layout{display:flex;flex-direction:column;min-height:100%;font-family:var(--ui-font-family);padding:var(--ui-spacing-6)}.ui-base-layout__content{flex:1 1 auto}.ui-base-layout__footer{position:sticky;bottom:0;z-index:var(--ui-z-sticky, 100);padding:var(--ui-spacing-4) 0;margin-top:var(--ui-spacing-6);background:var(--ui-color-surface);border-top:1px solid var(--ui-color-border)}@media (min-width: 640px){.ui-base-layout__footer{padding:var(--ui-spacing-3) 0}}\n"], dependencies: [{ kind: "component", type: UiPageHeaderComponent, selector: "ui-page-header", inputs: ["title", "homeRoute", "showHome", "updateDocumentTitle", "titleSuffix"] }, { kind: "component", type: UiButtonAreaComponent, selector: "ui-button-area", inputs: ["buttons", "align", "ariaLabel", "gap", "stackOnMobile", "disableWhileLoading", "loadingIds"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
1822
+ }
1823
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: UiBaseLayoutComponent, decorators: [{
1824
+ type: Component,
1825
+ args: [{ selector: 'ui-base-layout', standalone: true, imports: [UiPageHeaderComponent, UiButtonAreaComponent], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: {
1826
+ class: 'ui-base-layout-host',
1827
+ }, template: `
1828
+ <div class="ui-base-layout" [attr.data-route-id]="routeSnapshotFlags().routeId">
1829
+ @if (effectiveShowHeader()) {
1830
+ <ui-page-header
1831
+ [title]="title"
1832
+ [homeRoute]="homeRoute"
1833
+ [showHome]="showHome"
1834
+ [updateDocumentTitle]="updateDocumentTitle"
1835
+ [titleSuffix]="titleSuffix"
1836
+ />
1837
+ }
1838
+
1839
+ <main class="ui-base-layout__content">
1840
+ <ng-content />
1841
+ </main>
1842
+
1843
+ @if (effectiveShowFooterNav()) {
1844
+ <aside
1845
+ class="ui-base-layout__footer"
1846
+ aria-label="Page actions"
1847
+ >
1848
+ <ui-button-area
1849
+ [buttons]="mergedActions"
1850
+ [align]="footerAlign"
1851
+ [gap]="footerGap"
1852
+ [stackOnMobile]="true"
1853
+ ariaLabel="Page actions"
1854
+ />
1855
+ </aside>
1856
+ }
1857
+ </div>
1858
+ `, styles: [".ui-base-layout-host{display:block;min-height:100%}.ui-base-layout{display:flex;flex-direction:column;min-height:100%;font-family:var(--ui-font-family);padding:var(--ui-spacing-6)}.ui-base-layout__content{flex:1 1 auto}.ui-base-layout__footer{position:sticky;bottom:0;z-index:var(--ui-z-sticky, 100);padding:var(--ui-spacing-4) 0;margin-top:var(--ui-spacing-6);background:var(--ui-color-surface);border-top:1px solid var(--ui-color-border)}@media (min-width: 640px){.ui-base-layout__footer{padding:var(--ui-spacing-3) 0}}\n"] }]
1859
+ }], propDecorators: { showHeader: [{
1860
+ type: Input
1861
+ }], title: [{
1862
+ type: Input
1863
+ }], homeRoute: [{
1864
+ type: Input
1865
+ }], showHome: [{
1866
+ type: Input
1867
+ }], updateDocumentTitle: [{
1868
+ type: Input
1869
+ }], titleSuffix: [{
1870
+ type: Input
1871
+ }], showBackButton: [{
1872
+ type: Input
1873
+ }], backButtonConfig: [{
1874
+ type: Input
1875
+ }], actions: [{
1876
+ type: Input
1877
+ }], footerAlign: [{
1878
+ type: Input
1879
+ }], footerGap: [{
1880
+ type: Input
1881
+ }] } });
1882
+
1883
+ /**
1884
+ * ng-ui-system — Base Layout entry point.
1885
+ *
1886
+ * @example
1887
+ * ```typescript
1888
+ * import {
1889
+ * UiBaseLayoutComponent,
1890
+ * UiBackButtonConfig,
1891
+ * } from 'ng-ui-system';
1892
+ * ```
1893
+ */
1894
+ // Components
1895
+
1896
+ /**
1897
+ * Bootstrap del secondary entry `@gnggln/ng-ui-system/base-layout`. Base Layout.
1898
+ */
1899
+
1900
+ /**
1901
+ * Generated bundle index. Do not edit.
1902
+ */
1903
+
1904
+ export { UiBaseLayoutComponent };
1905
+ //# sourceMappingURL=gnggln-ng-ui-system-base-layout.mjs.map