@tinya-code/gas-admin-ui 0.2.0-alpha.15 → 0.2.0-alpha.18

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 (368) hide show
  1. package/fesm2022/tinya-code-gas-admin-ui-badge-EeCA_l-o.mjs +84 -0
  2. package/fesm2022/tinya-code-gas-admin-ui-badge-EeCA_l-o.mjs.map +1 -0
  3. package/fesm2022/tinya-code-gas-admin-ui-bar-chart-G7sEMSBY.mjs +140 -0
  4. package/fesm2022/tinya-code-gas-admin-ui-bar-chart-G7sEMSBY.mjs.map +1 -0
  5. package/fesm2022/tinya-code-gas-admin-ui-boolean-B2ASKL0E.mjs +113 -0
  6. package/fesm2022/tinya-code-gas-admin-ui-boolean-B2ASKL0E.mjs.map +1 -0
  7. package/fesm2022/tinya-code-gas-admin-ui-button-BQjNW8KB.mjs +163 -0
  8. package/fesm2022/tinya-code-gas-admin-ui-button-BQjNW8KB.mjs.map +1 -0
  9. package/fesm2022/tinya-code-gas-admin-ui-calendar-view-DCY8bj2V.mjs +1027 -0
  10. package/fesm2022/tinya-code-gas-admin-ui-calendar-view-DCY8bj2V.mjs.map +1 -0
  11. package/fesm2022/tinya-code-gas-admin-ui-chart-line-BjdlKHoH.mjs +278 -0
  12. package/fesm2022/tinya-code-gas-admin-ui-chart-line-BjdlKHoH.mjs.map +1 -0
  13. package/fesm2022/tinya-code-gas-admin-ui-color-Dljh_By3.mjs +107 -0
  14. package/fesm2022/tinya-code-gas-admin-ui-color-Dljh_By3.mjs.map +1 -0
  15. package/fesm2022/tinya-code-gas-admin-ui-condition-evaluator-DY2k1M3C.mjs +101 -0
  16. package/fesm2022/tinya-code-gas-admin-ui-condition-evaluator-DY2k1M3C.mjs.map +1 -0
  17. package/fesm2022/tinya-code-gas-admin-ui-currency-BvuF3Z63.mjs +141 -0
  18. package/fesm2022/tinya-code-gas-admin-ui-currency-BvuF3Z63.mjs.map +1 -0
  19. package/fesm2022/tinya-code-gas-admin-ui-data-source.service-96FSbN72.mjs +88 -0
  20. package/fesm2022/tinya-code-gas-admin-ui-data-source.service-96FSbN72.mjs.map +1 -0
  21. package/fesm2022/tinya-code-gas-admin-ui-date-1SJGXZrd.mjs +107 -0
  22. package/fesm2022/tinya-code-gas-admin-ui-date-1SJGXZrd.mjs.map +1 -0
  23. package/fesm2022/tinya-code-gas-admin-ui-display-badge-fwk6sDU7.mjs +140 -0
  24. package/fesm2022/tinya-code-gas-admin-ui-display-badge-fwk6sDU7.mjs.map +1 -0
  25. package/fesm2022/tinya-code-gas-admin-ui-display-date-D7zLiDiG.mjs +119 -0
  26. package/fesm2022/tinya-code-gas-admin-ui-display-date-D7zLiDiG.mjs.map +1 -0
  27. package/fesm2022/tinya-code-gas-admin-ui-display-file-BiIhqvQC.mjs +125 -0
  28. package/fesm2022/tinya-code-gas-admin-ui-display-file-BiIhqvQC.mjs.map +1 -0
  29. package/fesm2022/tinya-code-gas-admin-ui-display-image-C1dhnZi1.mjs +152 -0
  30. package/fesm2022/tinya-code-gas-admin-ui-display-image-C1dhnZi1.mjs.map +1 -0
  31. package/fesm2022/tinya-code-gas-admin-ui-display-list-DOEuUbGe.mjs +211 -0
  32. package/fesm2022/tinya-code-gas-admin-ui-display-list-DOEuUbGe.mjs.map +1 -0
  33. package/fesm2022/tinya-code-gas-admin-ui-display-number-DDMzr4Hn.mjs +116 -0
  34. package/fesm2022/tinya-code-gas-admin-ui-display-number-DDMzr4Hn.mjs.map +1 -0
  35. package/fesm2022/tinya-code-gas-admin-ui-display-text-B8CdVNpv.mjs +111 -0
  36. package/fesm2022/tinya-code-gas-admin-ui-display-text-B8CdVNpv.mjs.map +1 -0
  37. package/fesm2022/tinya-code-gas-admin-ui-dropdown-C3blvmE1.mjs +122 -0
  38. package/fesm2022/tinya-code-gas-admin-ui-dropdown-C3blvmE1.mjs.map +1 -0
  39. package/fesm2022/tinya-code-gas-admin-ui-email-CT_O5ihA.mjs +107 -0
  40. package/fesm2022/tinya-code-gas-admin-ui-email-CT_O5ihA.mjs.map +1 -0
  41. package/fesm2022/tinya-code-gas-admin-ui-empty-state-BMc0QtoT.mjs +109 -0
  42. package/fesm2022/tinya-code-gas-admin-ui-empty-state-BMc0QtoT.mjs.map +1 -0
  43. package/fesm2022/tinya-code-gas-admin-ui-error-mapper.service-DY5y1FjE.mjs +45 -0
  44. package/fesm2022/tinya-code-gas-admin-ui-error-mapper.service-DY5y1FjE.mjs.map +1 -0
  45. package/fesm2022/tinya-code-gas-admin-ui-field-aria-BD1Wiggc.mjs +50 -0
  46. package/fesm2022/tinya-code-gas-admin-ui-field-aria-BD1Wiggc.mjs.map +1 -0
  47. package/fesm2022/tinya-code-gas-admin-ui-field-node-CIK6KNN_.mjs +24 -0
  48. package/fesm2022/tinya-code-gas-admin-ui-field-node-CIK6KNN_.mjs.map +1 -0
  49. package/fesm2022/tinya-code-gas-admin-ui-field-path-B4-FTBGZ.mjs +27 -0
  50. package/fesm2022/tinya-code-gas-admin-ui-field-path-B4-FTBGZ.mjs.map +1 -0
  51. package/fesm2022/tinya-code-gas-admin-ui-file-Dmxioog7.mjs +408 -0
  52. package/fesm2022/tinya-code-gas-admin-ui-file-Dmxioog7.mjs.map +1 -0
  53. package/fesm2022/tinya-code-gas-admin-ui-form-view-CEe7aZ4m.mjs +4516 -0
  54. package/fesm2022/tinya-code-gas-admin-ui-form-view-CEe7aZ4m.mjs.map +1 -0
  55. package/fesm2022/tinya-code-gas-admin-ui-format-badge-CK8ct5Wk.mjs +82 -0
  56. package/fesm2022/tinya-code-gas-admin-ui-format-badge-CK8ct5Wk.mjs.map +1 -0
  57. package/fesm2022/tinya-code-gas-admin-ui-format-boolean-ClzezZz-.mjs +105 -0
  58. package/fesm2022/tinya-code-gas-admin-ui-format-boolean-ClzezZz-.mjs.map +1 -0
  59. package/fesm2022/tinya-code-gas-admin-ui-format-currency-CVmniKml.mjs +65 -0
  60. package/fesm2022/tinya-code-gas-admin-ui-format-currency-CVmniKml.mjs.map +1 -0
  61. package/fesm2022/tinya-code-gas-admin-ui-format-date-Dr1YsDd_.mjs +65 -0
  62. package/fesm2022/tinya-code-gas-admin-ui-format-date-Dr1YsDd_.mjs.map +1 -0
  63. package/fesm2022/tinya-code-gas-admin-ui-format-number-CWCjpI4n.mjs +65 -0
  64. package/fesm2022/tinya-code-gas-admin-ui-format-number-CWCjpI4n.mjs.map +1 -0
  65. package/fesm2022/tinya-code-gas-admin-ui-format-text-DBOgJkH0.mjs +59 -0
  66. package/fesm2022/tinya-code-gas-admin-ui-format-text-DBOgJkH0.mjs.map +1 -0
  67. package/fesm2022/tinya-code-gas-admin-ui-format-thumbnail-PCRvxWKt.mjs +94 -0
  68. package/fesm2022/tinya-code-gas-admin-ui-format-thumbnail-PCRvxWKt.mjs.map +1 -0
  69. package/fesm2022/tinya-code-gas-admin-ui-gap-sorting-iTdy_DYG.mjs +72 -0
  70. package/fesm2022/tinya-code-gas-admin-ui-gap-sorting-iTdy_DYG.mjs.map +1 -0
  71. package/fesm2022/tinya-code-gas-admin-ui-group-h7-O8tt4.mjs +238 -0
  72. package/fesm2022/tinya-code-gas-admin-ui-group-h7-O8tt4.mjs.map +1 -0
  73. package/fesm2022/tinya-code-gas-admin-ui-image-7UhJ7nqI.mjs +416 -0
  74. package/fesm2022/tinya-code-gas-admin-ui-image-7UhJ7nqI.mjs.map +1 -0
  75. package/fesm2022/tinya-code-gas-admin-ui-kanban-view-Dl0Ol5Kb.mjs +439 -0
  76. package/fesm2022/tinya-code-gas-admin-ui-kanban-view-Dl0Ol5Kb.mjs.map +1 -0
  77. package/fesm2022/tinya-code-gas-admin-ui-key-value-nVdgg5at.mjs +513 -0
  78. package/fesm2022/tinya-code-gas-admin-ui-key-value-nVdgg5at.mjs.map +1 -0
  79. package/fesm2022/tinya-code-gas-admin-ui-list-DTtCYS4d.mjs +637 -0
  80. package/fesm2022/tinya-code-gas-admin-ui-list-DTtCYS4d.mjs.map +1 -0
  81. package/fesm2022/tinya-code-gas-admin-ui-metric-card-DnGMQL8l.mjs +127 -0
  82. package/fesm2022/tinya-code-gas-admin-ui-metric-card-DnGMQL8l.mjs.map +1 -0
  83. package/fesm2022/tinya-code-gas-admin-ui-multiselect-PB28e-jl.mjs +251 -0
  84. package/fesm2022/tinya-code-gas-admin-ui-multiselect-PB28e-jl.mjs.map +1 -0
  85. package/fesm2022/tinya-code-gas-admin-ui-notification.service-LjSULER6.mjs +66 -0
  86. package/fesm2022/tinya-code-gas-admin-ui-notification.service-LjSULER6.mjs.map +1 -0
  87. package/fesm2022/tinya-code-gas-admin-ui-number-JNr7glc8.mjs +114 -0
  88. package/fesm2022/tinya-code-gas-admin-ui-number-JNr7glc8.mjs.map +1 -0
  89. package/fesm2022/tinya-code-gas-admin-ui-phone-jR417hPf.mjs +116 -0
  90. package/fesm2022/tinya-code-gas-admin-ui-phone-jR417hPf.mjs.map +1 -0
  91. package/fesm2022/tinya-code-gas-admin-ui-quick-actions-DCQ6emmF.mjs +235 -0
  92. package/fesm2022/tinya-code-gas-admin-ui-quick-actions-DCQ6emmF.mjs.map +1 -0
  93. package/fesm2022/tinya-code-gas-admin-ui-radio-mode-DxvN07DY.mjs +8 -0
  94. package/fesm2022/tinya-code-gas-admin-ui-radio-mode-DxvN07DY.mjs.map +1 -0
  95. package/fesm2022/tinya-code-gas-admin-ui-readonly-text-BL7-4qie.mjs +124 -0
  96. package/fesm2022/tinya-code-gas-admin-ui-readonly-text-BL7-4qie.mjs.map +1 -0
  97. package/fesm2022/tinya-code-gas-admin-ui-record-list-BiZfnd_7.mjs +249 -0
  98. package/fesm2022/tinya-code-gas-admin-ui-record-list-BiZfnd_7.mjs.map +1 -0
  99. package/fesm2022/tinya-code-gas-admin-ui-relation-drawer.service-B0kT8EiW.mjs +39 -0
  100. package/fesm2022/tinya-code-gas-admin-ui-relation-drawer.service-B0kT8EiW.mjs.map +1 -0
  101. package/fesm2022/tinya-code-gas-admin-ui-relation-ykpJ3PYl.mjs +309 -0
  102. package/fesm2022/tinya-code-gas-admin-ui-relation-ykpJ3PYl.mjs.map +1 -0
  103. package/fesm2022/tinya-code-gas-admin-ui-render-registry-B88Pme-y.mjs +576 -0
  104. package/fesm2022/tinya-code-gas-admin-ui-render-registry-B88Pme-y.mjs.map +1 -0
  105. package/fesm2022/tinya-code-gas-admin-ui-rich-select-CIHaOrbU.mjs +161 -0
  106. package/fesm2022/tinya-code-gas-admin-ui-rich-select-CIHaOrbU.mjs.map +1 -0
  107. package/fesm2022/tinya-code-gas-admin-ui-rolldown-runtime-DpJrqANO.mjs +11 -0
  108. package/fesm2022/tinya-code-gas-admin-ui-schema-catalog-D0Pk0wAN.mjs +685 -0
  109. package/fesm2022/tinya-code-gas-admin-ui-schema-catalog-D0Pk0wAN.mjs.map +1 -0
  110. package/fesm2022/tinya-code-gas-admin-ui-seed-DkVZbxPP.mjs +80 -0
  111. package/fesm2022/tinya-code-gas-admin-ui-seed-DkVZbxPP.mjs.map +1 -0
  112. package/fesm2022/tinya-code-gas-admin-ui-select-CDwX9yNO.mjs +296 -0
  113. package/fesm2022/tinya-code-gas-admin-ui-select-CDwX9yNO.mjs.map +1 -0
  114. package/fesm2022/tinya-code-gas-admin-ui-skeleton-DnWK0tcZ.mjs +119 -0
  115. package/fesm2022/tinya-code-gas-admin-ui-skeleton-DnWK0tcZ.mjs.map +1 -0
  116. package/fesm2022/tinya-code-gas-admin-ui-slug-DU58cbiY.mjs +158 -0
  117. package/fesm2022/tinya-code-gas-admin-ui-slug-DU58cbiY.mjs.map +1 -0
  118. package/fesm2022/tinya-code-gas-admin-ui-source-options-B9R4mw8-.mjs +26 -0
  119. package/fesm2022/tinya-code-gas-admin-ui-source-options-B9R4mw8-.mjs.map +1 -0
  120. package/fesm2022/tinya-code-gas-admin-ui-status-progress-DmeG8htE.mjs +205 -0
  121. package/fesm2022/tinya-code-gas-admin-ui-status-progress-DmeG8htE.mjs.map +1 -0
  122. package/fesm2022/tinya-code-gas-admin-ui-string-list-gleasqzD.mjs +432 -0
  123. package/fesm2022/tinya-code-gas-admin-ui-string-list-gleasqzD.mjs.map +1 -0
  124. package/fesm2022/tinya-code-gas-admin-ui-template-interpolator-ewv7CkNX.mjs +36 -0
  125. package/fesm2022/tinya-code-gas-admin-ui-template-interpolator-ewv7CkNX.mjs.map +1 -0
  126. package/fesm2022/tinya-code-gas-admin-ui-text-CUPmL7W_.mjs +107 -0
  127. package/fesm2022/tinya-code-gas-admin-ui-text-CUPmL7W_.mjs.map +1 -0
  128. package/fesm2022/tinya-code-gas-admin-ui-textarea-CGLSIW13.mjs +223 -0
  129. package/fesm2022/tinya-code-gas-admin-ui-textarea-CGLSIW13.mjs.map +1 -0
  130. package/fesm2022/tinya-code-gas-admin-ui-time-BcHzsTWf.mjs +107 -0
  131. package/fesm2022/tinya-code-gas-admin-ui-time-BcHzsTWf.mjs.map +1 -0
  132. package/fesm2022/tinya-code-gas-admin-ui-upload.service-CZPEPCeN.mjs +60 -0
  133. package/fesm2022/tinya-code-gas-admin-ui-upload.service-CZPEPCeN.mjs.map +1 -0
  134. package/fesm2022/tinya-code-gas-admin-ui-url-GO4LZi__.mjs +141 -0
  135. package/fesm2022/tinya-code-gas-admin-ui-url-GO4LZi__.mjs.map +1 -0
  136. package/fesm2022/tinya-code-gas-admin-ui.mjs +4738 -0
  137. package/fesm2022/tinya-code-gas-admin-ui.mjs.map +1 -0
  138. package/package.json +15 -3
  139. package/types/tinya-code-gas-admin-ui.d.ts +3634 -0
  140. package/ng-package.json +0 -7
  141. package/src/lib/actions/action-registry.spec.ts +0 -52
  142. package/src/lib/actions/action-registry.ts +0 -126
  143. package/src/lib/actions/action-service.spec.ts +0 -215
  144. package/src/lib/actions/action-service.ts +0 -87
  145. package/src/lib/actions/descriptors.spec.ts +0 -155
  146. package/src/lib/actions/descriptors.ts +0 -154
  147. package/src/lib/columns/column-cell.ts +0 -33
  148. package/src/lib/columns/column-defaults.spec.ts +0 -99
  149. package/src/lib/columns/column-defaults.ts +0 -84
  150. package/src/lib/columns/column-format.spec.ts +0 -274
  151. package/src/lib/columns/descriptors.ts +0 -113
  152. package/src/lib/columns/format-badge.ts +0 -51
  153. package/src/lib/columns/format-boolean.ts +0 -58
  154. package/src/lib/columns/format-currency.ts +0 -30
  155. package/src/lib/columns/format-date.ts +0 -35
  156. package/src/lib/columns/format-number.ts +0 -32
  157. package/src/lib/columns/format-text.ts +0 -23
  158. package/src/lib/columns/format-thumbnail.ts +0 -63
  159. package/src/lib/core/adapters/firebase-auth.adapter.ts +0 -6
  160. package/src/lib/core/guards/auth.guard.spec.ts +0 -88
  161. package/src/lib/core/guards/auth.guard.ts +0 -48
  162. package/src/lib/core/guards/unsaved-changes.guard.ts +0 -16
  163. package/src/lib/core/interceptors/api-error.interceptor.spec.ts +0 -182
  164. package/src/lib/core/interceptors/api-error.interceptor.ts +0 -87
  165. package/src/lib/core/models/api.model.ts +0 -104
  166. package/src/lib/core/models/schema-descriptions.ts +0 -118
  167. package/src/lib/core/models/schema.model.ts +0 -1097
  168. package/src/lib/core/registry/composition-validator.spec.ts +0 -358
  169. package/src/lib/core/registry/composition-validator.ts +0 -270
  170. package/src/lib/core/registry/field-validators.spec.ts +0 -199
  171. package/src/lib/core/registry/field-validators.ts +0 -440
  172. package/src/lib/core/registry/render-host.spec.ts +0 -208
  173. package/src/lib/core/registry/render-host.ts +0 -646
  174. package/src/lib/core/registry/render-registry.spec.ts +0 -96
  175. package/src/lib/core/registry/render-registry.ts +0 -312
  176. package/src/lib/core/registry/schema-catalog.ts +0 -156
  177. package/src/lib/core/services/api.service.spec.ts +0 -1142
  178. package/src/lib/core/services/api.service.ts +0 -371
  179. package/src/lib/core/services/auth.service.spec.ts +0 -653
  180. package/src/lib/core/services/auth.service.ts +0 -503
  181. package/src/lib/core/services/config.service.spec.ts +0 -121
  182. package/src/lib/core/services/config.service.ts +0 -119
  183. package/src/lib/core/services/data-source.service.spec.ts +0 -179
  184. package/src/lib/core/services/data-source.service.ts +0 -142
  185. package/src/lib/core/services/error-mapper.service.spec.ts +0 -50
  186. package/src/lib/core/services/error-mapper.service.ts +0 -49
  187. package/src/lib/core/services/notification.service.ts +0 -73
  188. package/src/lib/core/services/relation-drawer.service.ts +0 -41
  189. package/src/lib/core/services/theme.service.spec.ts +0 -106
  190. package/src/lib/core/services/theme.service.ts +0 -86
  191. package/src/lib/core/services/transport.spec.ts +0 -198
  192. package/src/lib/core/services/transport.ts +0 -164
  193. package/src/lib/core/services/upload.service.ts +0 -81
  194. package/src/lib/core/testing/categories.schema.ts +0 -125
  195. package/src/lib/core/testing/orders.schema.ts +0 -372
  196. package/src/lib/core/testing/products.schema.ts +0 -258
  197. package/src/lib/core/testing/site.schema.ts +0 -195
  198. package/src/lib/core/testing/test-catalog.ts +0 -21
  199. package/src/lib/core/tokens.ts +0 -112
  200. package/src/lib/core/utils/clipboard.spec.ts +0 -55
  201. package/src/lib/core/utils/clipboard.ts +0 -90
  202. package/src/lib/core/utils/context-resolver.spec.ts +0 -95
  203. package/src/lib/core/utils/context-resolver.ts +0 -101
  204. package/src/lib/core/utils/response-unwrapper.spec.ts +0 -70
  205. package/src/lib/core/utils/response-unwrapper.ts +0 -103
  206. package/src/lib/core/utils/source-options.spec.ts +0 -96
  207. package/src/lib/core/utils/source-options.ts +0 -54
  208. package/src/lib/core/utils/template-interpolator.spec.ts +0 -59
  209. package/src/lib/core/utils/template-interpolator.ts +0 -56
  210. package/src/lib/core/view-navigation/view-navigation.service.spec.ts +0 -207
  211. package/src/lib/core/view-navigation/view-navigation.service.ts +0 -132
  212. package/src/lib/fields/boolean/boolean.descriptor.ts +0 -11
  213. package/src/lib/fields/boolean/boolean.ts +0 -40
  214. package/src/lib/fields/color/color.descriptor.ts +0 -12
  215. package/src/lib/fields/color/color.ts +0 -34
  216. package/src/lib/fields/currency/currency.descriptor.ts +0 -12
  217. package/src/lib/fields/currency/currency.ts +0 -67
  218. package/src/lib/fields/date/date.descriptor.ts +0 -12
  219. package/src/lib/fields/date/date.ts +0 -36
  220. package/src/lib/fields/descriptors.ts +0 -122
  221. package/src/lib/fields/display/display-badge.ts +0 -65
  222. package/src/lib/fields/display/display-date.ts +0 -39
  223. package/src/lib/fields/display/display-defaults.ts +0 -84
  224. package/src/lib/fields/display/display-file.ts +0 -41
  225. package/src/lib/fields/display/display-image.ts +0 -54
  226. package/src/lib/fields/display/display-list.ts +0 -107
  227. package/src/lib/fields/display/display-number.ts +0 -41
  228. package/src/lib/fields/display/display-text.ts +0 -42
  229. package/src/lib/fields/display/display.spec.ts +0 -242
  230. package/src/lib/fields/dropdown/dropdown.descriptor.ts +0 -12
  231. package/src/lib/fields/dropdown/dropdown.ts +0 -45
  232. package/src/lib/fields/email/email.descriptor.ts +0 -12
  233. package/src/lib/fields/email/email.ts +0 -28
  234. package/src/lib/fields/field-aria.ts +0 -60
  235. package/src/lib/fields/field-host/field-host.spec.ts +0 -118
  236. package/src/lib/fields/field-host/field-host.ts +0 -47
  237. package/src/lib/fields/field-node.ts +0 -88
  238. package/src/lib/fields/file/file.descriptor.ts +0 -14
  239. package/src/lib/fields/file/file.spec.ts +0 -134
  240. package/src/lib/fields/file/file.ts +0 -281
  241. package/src/lib/fields/group/group.descriptor.ts +0 -21
  242. package/src/lib/fields/group/group.ts +0 -110
  243. package/src/lib/fields/image/image.descriptor.ts +0 -12
  244. package/src/lib/fields/image/image.spec.ts +0 -117
  245. package/src/lib/fields/image/image.ts +0 -281
  246. package/src/lib/fields/key-value/key-value.descriptor.ts +0 -11
  247. package/src/lib/fields/key-value/key-value.ts +0 -283
  248. package/src/lib/fields/list/list.descriptor.ts +0 -21
  249. package/src/lib/fields/list/list.ts +0 -376
  250. package/src/lib/fields/multiselect/multiselect.descriptor.ts +0 -11
  251. package/src/lib/fields/multiselect/multiselect.spec.ts +0 -142
  252. package/src/lib/fields/multiselect/multiselect.ts +0 -152
  253. package/src/lib/fields/number/number.descriptor.ts +0 -12
  254. package/src/lib/fields/number/number.ts +0 -40
  255. package/src/lib/fields/phone/phone.descriptor.ts +0 -12
  256. package/src/lib/fields/phone/phone.ts +0 -46
  257. package/src/lib/fields/readonly-text/readonly-text.descriptor.ts +0 -12
  258. package/src/lib/fields/readonly-text/readonly-text.ts +0 -58
  259. package/src/lib/fields/relation/relation.descriptor.ts +0 -12
  260. package/src/lib/fields/relation/relation.spec.ts +0 -193
  261. package/src/lib/fields/relation/relation.ts +0 -224
  262. package/src/lib/fields/rich-select/rich-select.descriptor.ts +0 -12
  263. package/src/lib/fields/rich-select/rich-select.ts +0 -175
  264. package/src/lib/fields/select/radio-mode.ts +0 -25
  265. package/src/lib/fields/select/select.descriptor.ts +0 -12
  266. package/src/lib/fields/select/select.spec.ts +0 -162
  267. package/src/lib/fields/select/select.ts +0 -210
  268. package/src/lib/fields/slug/slug.descriptor.ts +0 -19
  269. package/src/lib/fields/slug/slug.ts +0 -67
  270. package/src/lib/fields/string-list/string-list.descriptor.ts +0 -11
  271. package/src/lib/fields/string-list/string-list.ts +0 -222
  272. package/src/lib/fields/text/text.descriptor.ts +0 -12
  273. package/src/lib/fields/text/text.ts +0 -35
  274. package/src/lib/fields/textarea/textarea.descriptor.ts +0 -12
  275. package/src/lib/fields/textarea/textarea.spec.ts +0 -117
  276. package/src/lib/fields/textarea/textarea.ts +0 -126
  277. package/src/lib/fields/time/time.descriptor.ts +0 -12
  278. package/src/lib/fields/time/time.ts +0 -28
  279. package/src/lib/fields/unknown-render/unknown-render.ts +0 -49
  280. package/src/lib/fields/url/url.descriptor.ts +0 -12
  281. package/src/lib/fields/url/url.ts +0 -53
  282. package/src/lib/gas-admin-ui.spec.ts +0 -21
  283. package/src/lib/gas-admin-ui.ts +0 -9
  284. package/src/lib/layouts/descriptors.ts +0 -9
  285. package/src/lib/pages/dashboard/dashboard.ts +0 -167
  286. package/src/lib/pages/detail-view/detail-view.spec.ts +0 -333
  287. package/src/lib/pages/detail-view/detail-view.ts +0 -570
  288. package/src/lib/pages/drawer-form/drawer-form.ts +0 -228
  289. package/src/lib/pages/form-view/form-model.ts +0 -88
  290. package/src/lib/pages/form-view/form-schema.ts +0 -255
  291. package/src/lib/pages/form-view/form-view.ts +0 -1622
  292. package/src/lib/pages/list-view/list-view.formats.spec.ts +0 -214
  293. package/src/lib/pages/list-view/list-view.ts +0 -882
  294. package/src/lib/pages/login/login.spec.ts +0 -109
  295. package/src/lib/pages/login/login.ts +0 -227
  296. package/src/lib/pages/resource-page/resource-page.ts +0 -234
  297. package/src/lib/shared/components/badge/badge.ts +0 -35
  298. package/src/lib/shared/components/button/button.ts +0 -65
  299. package/src/lib/shared/components/confirm-dialog/confirm-dialog.ts +0 -48
  300. package/src/lib/shared/components/copy-button/copy-button.ts +0 -56
  301. package/src/lib/shared/components/copy-share/copy-share.spec.ts +0 -122
  302. package/src/lib/shared/components/copy-share/copy-share.ts +0 -107
  303. package/src/lib/shared/components/drawer/drawer.spec.ts +0 -127
  304. package/src/lib/shared/components/drawer/drawer.ts +0 -172
  305. package/src/lib/shared/components/empty-state/empty-state.ts +0 -30
  306. package/src/lib/shared/components/modal/modal.spec.ts +0 -149
  307. package/src/lib/shared/components/modal/modal.ts +0 -145
  308. package/src/lib/shared/components/post-create-modal/post-create-modal.spec.ts +0 -165
  309. package/src/lib/shared/components/post-create-modal/post-create-modal.ts +0 -159
  310. package/src/lib/shared/components/skeleton/skeleton.ts +0 -31
  311. package/src/lib/shared/components/toast/toast.ts +0 -58
  312. package/src/lib/shared/utils/col-span.ts +0 -25
  313. package/src/lib/shared/utils/condition-evaluator.ts +0 -53
  314. package/src/lib/shared/utils/depends-on.ts +0 -48
  315. package/src/lib/shared/utils/dialog-focus.ts +0 -28
  316. package/src/lib/shared/utils/field-path.ts +0 -49
  317. package/src/lib/shared/utils/gap-sorting.ts +0 -144
  318. package/src/lib/shared/utils/seed.spec.ts +0 -64
  319. package/src/lib/shared/utils/seed.ts +0 -149
  320. package/src/lib/shared/utils/slugify.ts +0 -13
  321. package/src/lib/shared/utils/validators.ts +0 -41
  322. package/src/lib/shell/layout/layout.ts +0 -63
  323. package/src/lib/shell/shell.routes.spec.ts +0 -59
  324. package/src/lib/shell/shell.routes.ts +0 -122
  325. package/src/lib/shell/sidebar/sidebar.ts +0 -139
  326. package/src/lib/shell/theme-toggle/theme-toggle.ts +0 -74
  327. package/src/lib/views/calendar-view/calendar-model.ts +0 -426
  328. package/src/lib/views/calendar-view/calendar-view.spec.ts +0 -557
  329. package/src/lib/views/calendar-view/calendar-view.ts +0 -568
  330. package/src/lib/views/composer/composer-host.spec.ts +0 -301
  331. package/src/lib/views/composer/composer-host.ts +0 -248
  332. package/src/lib/views/composer/composer-imports.spec.ts +0 -54
  333. package/src/lib/views/composer/view-context.spec.ts +0 -117
  334. package/src/lib/views/composer/view-context.ts +0 -109
  335. package/src/lib/views/composer/view-slot.spec.ts +0 -130
  336. package/src/lib/views/composer/view-slot.ts +0 -178
  337. package/src/lib/views/descriptors.ts +0 -46
  338. package/src/lib/views/kanban-view/kanban-model.ts +0 -173
  339. package/src/lib/views/kanban-view/kanban-view.spec.ts +0 -540
  340. package/src/lib/views/kanban-view/kanban-view.ts +0 -327
  341. package/src/lib/widgets/bar-chart/bar-chart.descriptor.ts +0 -17
  342. package/src/lib/widgets/bar-chart/bar-chart.spec.ts +0 -66
  343. package/src/lib/widgets/bar-chart/bar-chart.ts +0 -76
  344. package/src/lib/widgets/chart-line/chart-line.descriptor.ts +0 -17
  345. package/src/lib/widgets/chart-line/chart-line.spec.ts +0 -113
  346. package/src/lib/widgets/chart-line/chart-line.ts +0 -219
  347. package/src/lib/widgets/descriptors.ts +0 -29
  348. package/src/lib/widgets/metric-card/metric-card.descriptor.ts +0 -41
  349. package/src/lib/widgets/metric-card/metric-card.spec.ts +0 -52
  350. package/src/lib/widgets/metric-card/metric-card.ts +0 -48
  351. package/src/lib/widgets/quick-actions/quick-actions.descriptor.ts +0 -13
  352. package/src/lib/widgets/quick-actions/quick-actions.spec.ts +0 -61
  353. package/src/lib/widgets/quick-actions/quick-actions.ts +0 -100
  354. package/src/lib/widgets/record-list/record-list.descriptor.ts +0 -16
  355. package/src/lib/widgets/record-list/record-list.spec.ts +0 -79
  356. package/src/lib/widgets/record-list/record-list.ts +0 -115
  357. package/src/lib/widgets/series.spec.ts +0 -42
  358. package/src/lib/widgets/series.ts +0 -56
  359. package/src/lib/widgets/status-progress/status-progress.descriptor.ts +0 -19
  360. package/src/lib/widgets/status-progress/status-progress.spec.ts +0 -63
  361. package/src/lib/widgets/status-progress/status-progress.ts +0 -104
  362. package/src/lib/widgets/widget-host/widget-host.spec.ts +0 -179
  363. package/src/lib/widgets/widget-host/widget-host.ts +0 -99
  364. package/src/public-api.ts +0 -104
  365. package/tinya-code-gas-admin-ui-0.2.0-alpha.15.tgz +0 -0
  366. package/tsconfig.lib.json +0 -13
  367. package/tsconfig.lib.prod.json +0 -11
  368. package/tsconfig.spec.json +0 -10
@@ -1,242 +0,0 @@
1
- import { Component, input } from '@angular/core';
2
- import { TestBed } from '@angular/core/testing';
3
- import { beforeEach, describe, expect, it } from 'vitest';
4
-
5
- import type { FieldSchema, SelectField } from '../../core/models/schema.model';
6
- import { SUPPORTED_FIELD_TYPE_LIST } from '../descriptors';
7
- import { RenderHost } from '../../core/registry/render-host';
8
- import { displayLoader } from './display-defaults';
9
-
10
- /**
11
- * Paridad del modo `display` (R4.1 · R4.2).
12
- *
13
- * Cada caso es una fila de la tabla vieja `formatValue` de `detail-view`:
14
- * si un tipo pinta distinto de lo que pintaba antes de R4.2, este test se
15
- * pone rojo. Se monta por `RenderHost` y no por el componente suelto, para
16
- * que la prueba cubra también la rama de display del host (vacío, tabla y
17
- * degradación), no sólo el componente.
18
- */
19
- @Component({
20
- selector: 'spec-display-host',
21
- imports: [RenderHost],
22
- template: `
23
- <app-render-host
24
- [type]="type()"
25
- [config]="campo()"
26
- mode="display"
27
- [value]="valor()"
28
- [chip]="chip()"
29
- />
30
- `,
31
- })
32
- class Host {
33
- readonly type = input.required<string>();
34
- readonly campo = input.required<FieldSchema>();
35
- readonly valor = input<unknown>(null);
36
- readonly chip = input(false);
37
- }
38
-
39
- describe('R4.1 — display por defecto según tipo', () => {
40
- beforeEach(async () => {
41
- await TestBed.configureTestingModule({ imports: [Host] }).compileComponents();
42
- });
43
-
44
- /**
45
- * Monta el host y espera el `load()` perezoso del display.
46
- *
47
- * `whenStable()` no cubre el `import()` dinámico (promesa ajena al rastreo
48
- * de Angular), así que se espera acotadamente mientras quede `<app-skeleton>`;
49
- * si el componente nunca monta, la espera se agota y falla la aserción.
50
- */
51
- async function pintar(campo: FieldSchema, valor: unknown, chip = false): Promise<HTMLElement> {
52
- const fixture = TestBed.createComponent(Host);
53
- fixture.componentRef.setInput('type', campo.type);
54
- fixture.componentRef.setInput('campo', campo);
55
- fixture.componentRef.setInput('valor', valor);
56
- fixture.componentRef.setInput('chip', chip);
57
- fixture.detectChanges();
58
- await fixture.whenStable();
59
- for (
60
- let intento = 0;
61
- intento < 100 && fixture.nativeElement.querySelector('app-skeleton');
62
- intento++
63
- ) {
64
- fixture.detectChanges();
65
- await new Promise((resolve) => setTimeout(resolve, 1));
66
- }
67
- fixture.detectChanges();
68
- return fixture.nativeElement as HTMLElement;
69
- }
70
-
71
- const texto: FieldSchema = { key: 'nota', label: 'Nota', type: 'text' };
72
- const fecha: FieldSchema = { key: 'fecha', label: 'Fecha', type: 'date' };
73
- const numero: FieldSchema = { key: 'total', label: 'Total', type: 'number' };
74
- const moneda: FieldSchema = { key: 'precio', label: 'Precio', type: 'currency' };
75
- const booleano: FieldSchema = { key: 'activo', label: 'Activo', type: 'boolean' };
76
- const estado: SelectField = {
77
- key: 'status',
78
- label: 'Estado',
79
- type: 'select',
80
- options: [
81
- { value: 'PENDIENTE', label: 'Pendiente' },
82
- { value: 'ENTREGADO', label: 'Entregado' },
83
- ],
84
- };
85
- const imagen: FieldSchema = { key: 'foto', label: 'Foto', type: 'image' };
86
- const historial: FieldSchema = {
87
- key: 'history',
88
- label: 'Historial',
89
- type: 'list',
90
- itemFields: [{ key: 'action', label: 'Acción', type: 'text' }],
91
- };
92
-
93
- it('los 21 tipos de la unión tienen display en la tabla', () => {
94
- // Tripwire de la tabla: `Record<FieldType, …>` ya no compila si falta
95
- // uno, pero el acceso en runtime pasa por `displayLoader()` con un
96
- // `string` (un schema puede escribir cualquier cosa), y ahí sólo este
97
- // test vigila que el string válido no caiga en `undefined`.
98
- const sinDisplay = SUPPORTED_FIELD_TYPE_LIST.filter((type) => !displayLoader(type));
99
- expect(sinDisplay).toEqual([]);
100
- });
101
-
102
- it('un type fuera de la unión degrada a control desconocido, no a pantalla roja', async () => {
103
- const inventado = { key: 'x', label: 'X', type: 'wat' } as unknown as FieldSchema;
104
- const nodo = await pintar(inventado, 'valor');
105
- expect(nodo.querySelector('app-unknown-render'), 'debe pintarse la degradación').not.toBeNull();
106
- expect(nodo.textContent).toContain('wat');
107
- });
108
-
109
- describe('vacío', () => {
110
- // El criterio no cambia: `null`, `undefined` y `''` son vacío; `false`,
111
- // `0` y `[]` no lo son.
112
- for (const [nombre, valor] of [
113
- ['null', null],
114
- ['undefined', undefined],
115
- ['cadena vacía', ''],
116
- ] as const) {
117
- it(`${nombre} pinta — y no monta componente`, async () => {
118
- const nodo = await pintar(texto, valor);
119
- expect(nodo.textContent).toContain('—');
120
- expect(nodo.querySelector('app-field-display-text')).toBeNull();
121
- });
122
- }
123
-
124
- it('false, 0 y [] sí se pintan', async () => {
125
- expect((await pintar(booleano, false)).textContent).toContain('No');
126
- expect((await pintar(numero, 0)).textContent).toContain('0');
127
- expect((await pintar(historial, [])).textContent).toContain('historial');
128
- });
129
- });
130
-
131
- describe('texto crudo', () => {
132
- it('un string sale tal cual', async () => {
133
- expect((await pintar(texto, 'ORD-42')).textContent).toContain('ORD-42');
134
- });
135
-
136
- it('un array sale unido por comas (String(raw), como antes)', async () => {
137
- expect((await pintar(texto, ['a', 'b'])).textContent).toContain('a,b');
138
- });
139
-
140
- it('un objeto sale [object Object] (degradación heredada)', async () => {
141
- expect((await pintar(texto, { a: 1 })).textContent).toContain('[object Object]');
142
- });
143
- });
144
-
145
- it('date: es-PE, medium y UTC', async () => {
146
- const nodo = await pintar(fecha, '2026-10-10');
147
- // El mismo formato que usaba `formatValue`: sin UTC se correría un día.
148
- expect(nodo.textContent).toContain('10 oct. 2026');
149
- });
150
-
151
- it('date no parseable se pinta crudo', async () => {
152
- expect((await pintar(fecha, 'no-es-fecha')).textContent).toContain('no-es-fecha');
153
- });
154
-
155
- it('number y currency comparten formato es-PE', async () => {
156
- expect((await pintar(numero, 1234567.5)).textContent).toContain('1,234,567.5');
157
- expect((await pintar(moneda, 1234567.5)).textContent).toContain('1,234,567.5');
158
- });
159
-
160
- it('number no numérico se pinta crudo', async () => {
161
- expect((await pintar(numero, 'muchos')).textContent).toContain('muchos');
162
- });
163
-
164
- describe('boolean', () => {
165
- it('true → «Sí» en success', async () => {
166
- const nodo = await pintar(booleano, true);
167
- expect(nodo.textContent).toContain('Sí');
168
- expect(nodo.querySelector('app-badge')?.className).toContain('bg-success');
169
- });
170
-
171
- it('false → «No» en neutral', async () => {
172
- const nodo = await pintar(booleano, false);
173
- expect(nodo.textContent).toContain('No');
174
- expect(nodo.querySelector('app-badge')?.className).toContain('bg-neutral');
175
- });
176
- });
177
-
178
- describe('select', () => {
179
- it('el valor se traduce a la etiqueta de la opción', async () => {
180
- const nodo = await pintar(estado, 'PENDIENTE');
181
- expect(nodo.textContent).toContain('Pendiente');
182
- expect(nodo.querySelector('app-badge')?.className).toContain('bg-accent/20');
183
- });
184
-
185
- it('un valor sin opción se pinta crudo con su clase de estado', async () => {
186
- const nodo = await pintar(estado, 'DESCONOCIDO');
187
- expect(nodo.textContent).toContain('DESCONOCIDO');
188
- expect(nodo.querySelector('app-badge')?.className).toContain('bg-neutral');
189
- });
190
-
191
- it('ENTREGADO sigue siendo success (vocabulario heredado)', async () => {
192
- const nodo = await pintar(estado, 'ENTREGADO');
193
- expect(nodo.textContent).toContain('Entregado');
194
- expect(nodo.querySelector('app-badge')?.className).toContain('bg-success');
195
- });
196
- });
197
-
198
- it('image: miniatura enlazada con alt de la etiqueta', async () => {
199
- const nodo = await pintar(imagen, 'https://x.test/a.png');
200
- const img = nodo.querySelector('img');
201
- expect(img?.getAttribute('src')).toBe('https://x.test/a.png');
202
- expect(img?.getAttribute('alt')).toBe('Foto');
203
- expect(nodo.querySelector('a')?.getAttribute('href')).toBe('https://x.test/a.png');
204
- });
205
-
206
- it('list: timeline con acción, fecha y detalle', async () => {
207
- const nodo = await pintar(historial, [
208
- { action: 'PEDIDO_CREADO', at: '2026-10-10T15:30:00Z', detail: 'Pedido registrado' },
209
- ]);
210
- expect(nodo.textContent).toContain('PEDIDO CREADO');
211
- expect(nodo.textContent).toContain('Pedido registrado');
212
- expect(nodo.textContent).toContain('10 oct. 2026');
213
- });
214
-
215
- it('list vacío sigue diciendo que no hay registros', async () => {
216
- expect((await pintar(historial, [])).textContent).toContain(
217
- 'No hay registros en el historial.',
218
- );
219
- });
220
-
221
- describe('chip de cabecera', () => {
222
- it('un texto con chip sale como badge', async () => {
223
- const nodo = await pintar(texto, 'ORD-42', true);
224
- expect(nodo.querySelector('app-badge')?.textContent?.trim()).toBe('ORD-42');
225
- });
226
-
227
- it('una fecha con chip sale como badge con la fecha formateada', async () => {
228
- const nodo = await pintar(fecha, '2026-10-10', true);
229
- expect(nodo.querySelector('app-badge')?.textContent?.trim()).toBe('10 oct. 2026');
230
- });
231
-
232
- it('una lista con chip resume en «N elementos»', async () => {
233
- const nodo = await pintar(historial, [{ action: 'X' }], true);
234
- expect(nodo.querySelector('app-badge')?.textContent?.trim()).toBe('1 elementos');
235
- });
236
-
237
- it('un select con chip conserva la clase de estado', async () => {
238
- const nodo = await pintar(estado, 'PENDIENTE', true);
239
- expect(nodo.querySelector('app-badge')?.className).toContain('bg-accent/20');
240
- });
241
- });
242
- });
@@ -1,12 +0,0 @@
1
- import type { RenderDescriptor } from '../../core/registry/render-registry';
2
-
3
- /** Descriptor del campo `dropdown` (desplegable nativo siempre). */
4
- export const descriptor: RenderDescriptor = {
5
- kind: 'field',
6
- type: 'dropdown',
7
- since: '1.0',
8
- load: () => import('./dropdown').then((module) => module.FieldDropdown),
9
- // Nace como cadena: el valor seleccionado es un string.
10
- seed: 'string',
11
- surfaces: ['form', 'display'],
12
- };
@@ -1,45 +0,0 @@
1
- import { Component, computed, input } from '@angular/core';
2
- import { FormField } from '@angular/forms/signals';
3
-
4
- import type { DropdownField } from '../../core/models/schema.model';
5
- import { FieldAria } from '../field-aria';
6
- import { childTree, type RootTree } from '../field-node';
7
-
8
- /**
9
- * Desplegable nativo (`<select>`) que SIEMPRE se renderiza como lista
10
- * desplegable, independientemente de cuántas opciones tenga.
11
- *
12
- * A diferencia de `select` (que usa radio buttons para 2–4 opciones
13
- * estáticas por la guía de control §1), este tipo nunca muta a radios.
14
- * Úsalo cuando necesites un dropdown verdadero aunque tenga pocas opciones.
15
- */
16
- @Component({
17
- selector: 'app-field-dropdown',
18
- imports: [FieldAria, FormField],
19
- template: `
20
- <select
21
- class="field-input"
22
- [id]="state().name()"
23
- [formField]="node()"
24
- >
25
- @if (!field().required) {
26
- <option value="">{{ field().placeholder ?? '— Seleccionar —' }}</option>
27
- }
28
- @for (option of options(); track option.value) {
29
- <option [value]="option.value" [disabled]="option.disabled ?? false">
30
- {{ option.label }}
31
- </option>
32
- }
33
- </select>
34
- `,
35
- })
36
- export class FieldDropdown {
37
- readonly field = input.required<DropdownField>();
38
- readonly tree = input.required<RootTree>();
39
-
40
- protected readonly node = computed(() => childTree<string>(this.tree(), this.field().key));
41
- protected readonly state = computed(() => this.node()());
42
-
43
- /** Opciones estáticas del schema (dropdown no soporta `source`). */
44
- protected readonly options = computed(() => this.field().options);
45
- }
@@ -1,12 +0,0 @@
1
- import type { RenderDescriptor } from '../../core/registry/render-registry';
2
-
3
- /** Descriptor del campo `email` (R3.3). */
4
- export const descriptor: RenderDescriptor = {
5
- kind: 'field',
6
- type: 'email',
7
- since: '1.0',
8
- load: () => import('./email').then((module) => module.FieldEmail),
9
- // Nace como cadena: los textos, fechas, urls, selects y relacionales.
10
- seed: 'string',
11
- surfaces: ['form', 'display'],
12
- };
@@ -1,28 +0,0 @@
1
- import { Component, computed, input } from '@angular/core';
2
- import { FormField } from '@angular/forms/signals';
3
-
4
- import type { EmailField } from '../../core/models/schema.model';
5
- import { FieldAria } from '../field-aria';
6
- import { childTree, type RootTree } from '../field-node';
7
-
8
- /** Input de correo (base.md §5.1); la validación `email()` llega en Fase 10. */
9
- @Component({
10
- selector: 'app-field-email',
11
- imports: [FieldAria, FormField],
12
- template: `
13
- <input
14
- type="email"
15
- class="field-input"
16
- [id]="state().name()"
17
- [formField]="node()"
18
- [placeholder]="field().placeholder ?? ''"
19
- />
20
- `,
21
- })
22
- export class FieldEmail {
23
- readonly field = input.required<EmailField>();
24
- readonly tree = input.required<RootTree>();
25
-
26
- protected readonly node = computed(() => childTree<string>(this.tree(), this.field().key));
27
- protected readonly state = computed(() => this.node()());
28
- }
@@ -1,60 +0,0 @@
1
- import { Directive, InjectionToken, computed, inject, type Signal } from '@angular/core';
2
-
3
- /**
4
- * Contexto de accesibilidad que `app-field-host` expone a los controles.
5
- *
6
- * El host conoce la ayuda y el error (ambos viven en SU plantilla), pero el
7
- * `<input>` real vive dentro de un componente hijo distinto por cada tipo de
8
- * campo. En lugar de pasar dos inputs por cada uno de los 14 controles, el
9
- * host provee este contexto y cada control importa `FieldAria`, que lo lee
10
- * por DI y lo vuelca en el elemento.
11
- *
12
- * Selector por `[id]`: casa sólo con el elemento que ya recibe el `for` de la
13
- * etiqueta, así el mismo id es ancla de label y de `aria-describedby`. Los
14
- * controles fuera de un `app-field-host` inyectan `null` y no emiten nada.
15
- */
16
- export interface FieldAriaContext {
17
- /** `id` del texto de ayuda y/o del error, separados por espacio. */
18
- readonly describedBy: Signal<string | null>;
19
- /** `true` cuando el campo muestra error visible (mismo criterio que el mensaje). */
20
- readonly invalid: Signal<boolean>;
21
- /**
22
- * Requerido por schema. Necesario porque la marca visual `*` desaparece en
23
- * los recursos donde mandan los `(opcional)` (§2): sin este atributo el
24
- * requerimiento quedaría sólo en pantalla.
25
- */
26
- readonly required: Signal<boolean>;
27
- }
28
-
29
- export const FIELD_ARIA = new InjectionToken<FieldAriaContext>('FIELD_ARIA');
30
-
31
- /**
32
- * Vincula `aria-invalid` y `aria-describedby` a un control de formulario.
33
- *
34
- * `aria-invalid` se emite SIEMPRE (`"true"`/`"false"`, nunca ausente) para
35
- * que el atributo sea inspeccionable en cualquier estado; `aria-describedby`
36
- * se omite cuando no hay ni ayuda ni error, que es el caso por defecto.
37
- * `aria-required` sigue la misma regla que `aria-invalid`.
38
- *
39
- * Convención con `role="alert"` en el mensaje de error: el `alert` anuncia el
40
- * error en el momento en que aparece (fallo de submit), mientras que
41
- * `aria-describedby` lo lee al enfocar el campo. Son momentos distintos; no
42
- * compiten.
43
- */
44
- @Directive({
45
- selector: 'input[id], select[id], textarea[id], output[id]',
46
- host: {
47
- '[attr.aria-invalid]': 'ariaInvalid()',
48
- '[attr.aria-required]': 'ariaRequired()',
49
- '[attr.aria-describedby]': 'ariaDescribedBy()',
50
- },
51
- })
52
- export class FieldAria {
53
- private readonly ctx = inject(FIELD_ARIA, { optional: true });
54
-
55
- protected readonly ariaInvalid = computed(() => (this.ctx ? String(this.ctx.invalid()) : null));
56
-
57
- protected readonly ariaRequired = computed(() => (this.ctx ? String(this.ctx.required()) : null));
58
-
59
- protected readonly ariaDescribedBy = computed(() => this.ctx?.describedBy() ?? null);
60
- }
@@ -1,118 +0,0 @@
1
- import { Component, EnvironmentInjector, input, signal } from '@angular/core';
2
- import { TestBed } from '@angular/core/testing';
3
- import { By } from '@angular/platform-browser';
4
- import { form } from '@angular/forms/signals';
5
- import { of } from 'rxjs';
6
- import { describe, expect, it } from 'vitest';
7
-
8
- import type { FieldSchema, ResourceSchema } from '../../core/models/schema.model';
9
- import type { ApiService } from '../../core/services/api.service';
10
- import { seedModel } from '../../pages/form-view/form-model';
11
- import { buildFormSchema } from '../../pages/form-view/form-schema';
12
- import { childTree, type RootTree } from '../field-node';
13
- import { UnknownRender } from '../unknown-render/unknown-render';
14
- import { FieldHost } from './field-host';
15
-
16
- /**
17
- * R1.10 — degradación controlada de un tipo de campo sin renderizador.
18
- *
19
- * El `@switch` del host NO tiene `@default`, así que un `type` fuera del
20
- * catálogo no revienta el template: no dibuja nada. Eso cumple «nunca
21
- * pantalla rota», pero deja un hueco mudo donde el operador no distingue
22
- * «me falta un campo» de «lo escribí mal». El aviso existe sólo en dev
23
- * (`isDevMode`); en producción se omite y queda un `console.warn`.
24
- *
25
- * **Por qué el cast:** `FieldSchema.type` es unión, así que `tsc` no deja
26
- * declarar un tipo desconocido — eso lo garantiza el tripwire de R1.7. Este
27
- * test simula el estado en runtime que el compilador impide llegar a
28
- * producción (schema versionado a mano, instancia con un registro viejo,
29
- * `record` de un repo de schemas externo), que es exactamente lo que la
30
- * degradación tiene que tolerar.
31
- */
32
- @Component({
33
- template: ` <app-field-host [field]="field()" [tree]="tree()" /> `,
34
- imports: [FieldHost],
35
- })
36
- class Host {
37
- readonly field = input.required<FieldSchema>();
38
- readonly tree = input.required<RootTree>();
39
- }
40
-
41
- describe('FieldHost — tipo de campo sin renderizador', () => {
42
- const API = { list: () => of([]) } as unknown as ApiService;
43
-
44
- /** Árbol real, con las mismas reglas que usa `FormView` (para `hidden`). */
45
- function treeFor(schema: ResourceSchema): RootTree {
46
- const model = signal(seedModel(schema));
47
- return form(model, buildFormSchema(schema, API), {
48
- injector: TestBed.inject(EnvironmentInjector),
49
- }) as unknown as RootTree;
50
- }
51
-
52
- function schemaWith(field: Partial<FieldSchema>): ResourceSchema {
53
- return {
54
- id: '__unknown__',
55
- label: 'Prueba',
56
- labelPlural: 'Pruebas',
57
- kind: 'collection',
58
- endpoint: { list: '/admin/__unknown__' },
59
- keyField: 'marca',
60
- titleField: 'marca',
61
- listColumns: [],
62
- fields: [{ key: 'marca', type: 'text', label: 'Marca' }, { ...field } as FieldSchema],
63
- } as ResourceSchema;
64
- }
65
-
66
- async function render(field: Partial<FieldSchema>, schema?: ResourceSchema) {
67
- await TestBed.configureTestingModule({ imports: [Host] }).compileComponents();
68
- const s = schema ?? schemaWith(field);
69
- const fixture = TestBed.createComponent(Host);
70
- fixture.componentRef.setInput('field', field as FieldSchema);
71
- fixture.componentRef.setInput('tree', treeFor(s));
72
- fixture.detectChanges();
73
- await fixture.whenStable();
74
- fixture.detectChanges();
75
- return fixture;
76
- }
77
-
78
- const desconocido = { key: 'gorro', type: 'sombrero', label: 'Talla' } as unknown as FieldSchema;
79
-
80
- it('un tipo fuera del catálogo dibuja el aviso en vez de dejar un hueco', async () => {
81
- const fixture = await render(desconocido, schemaWith(desconocido));
82
-
83
- const aviso = fixture.debugElement.query(By.directive(UnknownRender));
84
- expect(aviso, 'debería renderizar app-unknown-render').not.toBeNull();
85
- expect(aviso.nativeElement.textContent).toContain('sombrero');
86
- expect(aviso.nativeElement.textContent).toContain('Talla');
87
-
88
- // Y no intenta dibujar un control que no sabe armar.
89
- expect(fixture.nativeElement.querySelector('input, textarea, select')).toBeNull();
90
- });
91
-
92
- it('un tipo del catálogo NO muestra el aviso', async () => {
93
- const fixture = await render({ key: 'gorro', type: 'text', label: 'Gorro' });
94
-
95
- expect(fixture.debugElement.query(By.directive(UnknownRender))).toBeNull();
96
- expect(fixture.nativeElement.querySelector('input')).not.toBeNull();
97
- });
98
-
99
- it('un campo oculto (tipo soportado) cae en el mismo @else pero NO avisa', async () => {
100
- // La rama `@else` del host cubre DOS motivos: «fuera de catálogo» y
101
- // «oculto por hiddenOn». Sin el chequeo `unsupported()`, un campo
102
- // legítimamente oculto expondría un aviso ruidoso.
103
- //
104
- // (La recíproca —un tipo desconocido Y oculto— no es alcanzable: al
105
- // siembrarse `undefined` no tiene nodo, así que tampoco tiene regla de
106
- // `hidden`; lo cubre el docblock de `unsupported`.)
107
- const oculto = {
108
- key: 'gorro',
109
- type: 'text',
110
- label: 'Talla',
111
- hiddenOn: 'always',
112
- } as FieldSchema;
113
-
114
- const fixture = await render(oculto, schemaWith(oculto));
115
- expect(fixture.debugElement.query(By.directive(UnknownRender))).toBeNull();
116
- expect(fixture.nativeElement.querySelector('input')).toBeNull();
117
- });
118
- });
@@ -1,47 +0,0 @@
1
- import { Component, computed, input } from '@angular/core';
2
-
3
- import type { FieldSchema } from '../../core/models/schema.model';
4
- import { RenderHost, type RenderContext } from '../../core/registry/render-host';
5
- import type { RootTree } from '../field-node';
6
-
7
- /**
8
- * Entrada estable de los formularios (base.md §5).
9
- *
10
- * **R3.5 · ya no despacha.** Este host redujo sus 493 líneas —el `@switch`
11
- * de 20 ramas, los 21 imports a mano y el envoltorio de label/errores— a un
12
- * adaptador que traduce su API histórica (`field` + `tree` + `pathPrefix` …)
13
- * al `RenderContext` que espera `<app-render-host>`, el motor único de
14
- * render (F1 · `refactormotor.md`).
15
- *
16
- * El rótulo, las marcas required/opcional, el error, la ayuda,
17
- * `FIELD_ARIA` y la **recursión de `group`/`list`** (los `ng-template` con
18
- * `ngTemplateOutlet` y `ListChildContext`) viven ahora en `RenderHost`, que
19
- * se auto-importa para instanciar sus propios hijos.
20
- *
21
- * Rutas del backend: `pathPrefix` encadena el prefijo del contenedor
22
- * (`address.`, `faq[2].`) y `serverErrors` lleva el mapa completo; el error
23
- * propio de este campo se resuelve como `serverErrors[prefix + key]`.
24
- */
25
- @Component({
26
- selector: 'app-field-host',
27
- imports: [RenderHost],
28
- template: `
29
- <app-render-host kind="field" [type]="field().type" [config]="field()" [ctx]="ctx()" />
30
- `,
31
- })
32
- export class FieldHost {
33
- readonly field = input.required<FieldSchema>();
34
- readonly tree = input.required<RootTree>();
35
- readonly exists = input(false);
36
- readonly serverErrors = input<Record<string, string>>({});
37
- readonly pathPrefix = input('');
38
- readonly resource = input('');
39
-
40
- protected readonly ctx = computed<RenderContext>(() => ({
41
- tree: this.tree(),
42
- serverErrors: this.serverErrors(),
43
- pathPrefix: this.pathPrefix(),
44
- exists: this.exists(),
45
- resource: this.resource(),
46
- }));
47
- }
@@ -1,88 +0,0 @@
1
- /**
2
- * Acceso dinámico a los subárboles de un formulario cuyo modelo es
3
- * `Record<string, unknown>` (decisión Fase 10: el tipado del modelo como
4
- * Record permite indexar con cualquier clave, pero el acceso se centraliza
5
- * aquí porque devuelve `undefined` en el tipo).
6
- *
7
- * Fase 11: los contenedores (`group`, `list`) se resuelven igual, más los
8
- * índices de las listas (`itemTree`).
9
- */
10
-
11
- import type { FieldTree } from '@angular/forms/signals';
12
-
13
- import type { FieldSchema } from '../core/models/schema.model';
14
-
15
- /** Árbol de un formulario con modelo dinámico. */
16
- export type RootTree = FieldTree<Record<string, unknown>>;
17
-
18
- /**
19
- * Contexto que el `ng-template` del `list` recibe por `ngTemplateOutlet`
20
- * para renderizar los campos de un ítem. El template vive en el despachador
21
- * (`field-host`) porque es el único que puede instanciar `app-field-host`;
22
- * el list lo instancia una vez por ítem con este contexto.
23
- */
24
- export interface ListChildContext {
25
- fields: readonly FieldSchema[];
26
- tree: RootTree;
27
- /** Prefijo de ruta de los errores del backend para este nivel (`faq[2].`). */
28
- prefix: string;
29
- errors: Record<string, string>;
30
- exists: boolean;
31
- /** `itemDisplay: 'row'` → los campos van en flujo compacto, no en grilla. */
32
- row: boolean;
33
- /** Clase `sm:col-span-*` de un campo (literal: Tailwind v4 es JIT). */
34
- colSpan: (width?: number) => string;
35
- }
36
-
37
- /** Subárbol del hijo directo bajo `key`. Lanza un error claro si el modelo no
38
- * contiene la clave (los modelos se siembran con los `default` del schema
39
- * antes de llamar a `form()`).
40
- */
41
- export function childTree<T>(parent: RootTree, key: string): FieldTree<T> {
42
- const child = (parent as unknown as Record<string, FieldTree<T> | undefined>)[key];
43
- if (child === undefined) {
44
- throw new Error(`El formulario no contiene el campo "${key}".`);
45
- }
46
- return child;
47
- }
48
-
49
- /** Subárbol de un campo `list`/`group` cuyo valor es un objeto. */
50
- export function groupTree(parent: RootTree, key: string): RootTree {
51
- return childTree<Record<string, unknown>>(parent, key);
52
- }
53
-
54
- /** Subárbol de un campo `list` (los ítems se acceden por índice). */
55
- export function listTree<T>(parent: RootTree, key: string): FieldTree<T[]> {
56
- return childTree<T[]>(parent, key);
57
- }
58
-
59
- /**
60
- * Ítem de una lista como árbol navegable.
61
- *
62
- * **Los nodos de ítem se atan a la identidad del elemento**, no al índice:
63
- * tras un cambio del arreglo el nodo viejo queda huérfano y leerlo lanza
64
- * `NG01904 «Orphan field»`. Por eso este helper se llama SIEMPRE fresco, en
65
- * cada render/computed — nunca se cachea un nodo entre mutaciones.
66
- *
67
- * El `as unknown` es porque `FieldTree<Item, number>` no es assignable a
68
- * `RootTree` (le falta el index signature de `string`), pero se navega igual.
69
- */
70
- export function itemTree<T>(items: FieldTree<T[]>, index: number): RootTree {
71
- const item = items[index];
72
- if (item === undefined) {
73
- throw new Error(`La lista no contiene el índice ${index}.`);
74
- }
75
- return item as unknown as RootTree;
76
- }
77
-
78
- /**
79
- * Ítem escalar de un `string-list` como nodo (`FieldTree<string>`), listo
80
- * para `[formField]`. Mismo criterio de frescura que `itemTree`.
81
- */
82
- export function stringItemTree(items: FieldTree<string[]>, index: number): FieldTree<string> {
83
- const item = items[index] as FieldTree<string> | undefined;
84
- if (item === undefined) {
85
- throw new Error(`La lista no contiene el índice ${index}.`);
86
- }
87
- return item;
88
- }
@@ -1,14 +0,0 @@
1
- import type { RenderDescriptor } from '../../core/registry/render-registry';
2
-
3
- /** Descriptor del campo `file` (R3.3 · R9.5.3). */
4
- export const descriptor: RenderDescriptor = {
5
- kind: 'field',
6
- type: 'file',
7
- since: '9.5',
8
- load: () => import('./file').then((module) => module.FieldFile),
9
- // Nace como cadena: la URL pública es el valor, igual que en `image`.
10
- seed: 'string',
11
- surfaces: ['form', 'display'],
12
- // Como `image` (D27): control propio cuya sincronización con Signal Forms
13
- // vive en ɵɵcontrol, así que el host lo declara a mano con `[formField]`.
14
- };