@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,149 +0,0 @@
1
- import { Component, signal } from '@angular/core';
2
- import { ComponentFixture, TestBed } from '@angular/core/testing';
3
-
4
- import { FOCUSABLE, isVisibleNow } from '../../utils/dialog-focus';
5
- import { Modal } from './modal';
6
-
7
- /**
8
- * Fase 9.3 — contrato de foco y cierre del diálogo.
9
- *
10
- * Mismo escenario que `drawer.spec.ts`: el disparador real está fuera del
11
- * diálogo, así que se puede comprobar que el foco vuelve a él — también
12
- * cuando el consumidor destruye el componente con el diálogo todavía abierto
13
- * (se monta bajo un `@if`).
14
- */
15
- @Component({
16
- template: `
17
- <button type="button" data-testid="trigger">Abrir</button>
18
- <app-modal [open]="open()" [title]="title()" (close)="open.set(false)">
19
- <button type="button" data-testid="body-action">Dentro del diálogo</button>
20
- <button type="button" data-testid="secondary-action">Cancelar</button>
21
- </app-modal>
22
- `,
23
- imports: [Modal],
24
- })
25
- class ModalHost {
26
- readonly open = signal(false);
27
- readonly title = signal('Confirmar borrado');
28
- }
29
-
30
- describe('Modal — 9.3: foco, Escape y restauración', () => {
31
- let fixture: ComponentFixture<ModalHost>;
32
-
33
- beforeEach(async () => {
34
- await TestBed.configureTestingModule({ imports: [ModalHost] }).compileComponents();
35
- fixture = TestBed.createComponent(ModalHost);
36
- fixture.detectChanges();
37
- });
38
-
39
- const dialog = (): HTMLElement | null => fixture.nativeElement.querySelector('[role="dialog"]');
40
- const trigger = (): HTMLButtonElement =>
41
- fixture.nativeElement.querySelector('[data-testid="trigger"]');
42
-
43
- const open = async (): Promise<void> => {
44
- trigger().focus();
45
- fixture.componentInstance.open.set(true);
46
- fixture.detectChanges();
47
- await fixture.whenStable();
48
- fixture.detectChanges();
49
- };
50
-
51
- it('cerrado no hay diálogo; abierto hay uno con nombre y aria-modal', async () => {
52
- expect(dialog()).toBeNull();
53
-
54
- await open();
55
-
56
- const panel = dialog();
57
- expect(panel).not.toBeNull();
58
- expect(panel!.getAttribute('aria-modal')).toBe('true');
59
- const labelledBy = panel!.getAttribute('aria-labelledby');
60
- expect(document.getElementById(labelledBy!)?.textContent).toContain('Confirmar borrado');
61
- });
62
-
63
- it('Escape y el botón ✕ piden cerrar', async () => {
64
- await open();
65
-
66
- document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }));
67
- fixture.detectChanges();
68
- expect(fixture.componentInstance.open()).toBe(false);
69
-
70
- await open();
71
- (fixture.nativeElement.querySelector('[aria-label="Cerrar"]') as HTMLElement).click();
72
- fixture.detectChanges();
73
- expect(fixture.componentInstance.open()).toBe(false);
74
- });
75
-
76
- it('el clic en el fondo pide cerrar', async () => {
77
- await open();
78
-
79
- (fixture.nativeElement.querySelector('.absolute.inset-0') as HTMLElement).click();
80
- fixture.detectChanges();
81
- expect(fixture.componentInstance.open()).toBe(false);
82
- });
83
-
84
- it('el foco entra al abrir y vuelve al disparador al cerrar', async () => {
85
- await open();
86
- expect(dialog()!.contains(document.activeElement)).toBe(true);
87
-
88
- fixture.componentInstance.open.set(false);
89
- fixture.detectChanges();
90
- await fixture.whenStable();
91
-
92
- expect(document.activeElement).toBe(trigger());
93
- });
94
-
95
- it('destruirse con el diálogo abierto devuelve el foco (no se pierde detrás del fondo)', async () => {
96
- await open();
97
- expect(document.activeElement).toBe(dialog());
98
-
99
- // Es lo que pasa cuando el consumidor lo monta bajo un `@if` y borra el
100
- // nodo sin que la señal pase por `false`: el effect no llega a correr.
101
- fixture.componentInstance.open.set(false);
102
- fixture.destroy();
103
-
104
- expect(document.activeElement).toBe(trigger());
105
- });
106
-
107
- it('el Tab queda atrapado: del último salta al primero', async () => {
108
- await open();
109
-
110
- const focusable = Array.from(
111
- dialog()!.querySelectorAll<HTMLElement>('button, [href], input, select, textarea'),
112
- );
113
- expect(focusable.length).toBeGreaterThan(1);
114
-
115
- const last = focusable[focusable.length - 1];
116
- last.focus();
117
- expect(document.activeElement).toBe(last);
118
-
119
- document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Tab', bubbles: true }));
120
- expect(document.activeElement).toBe(focusable[0]);
121
- });
122
-
123
- it('el Shift+Tab queda atrapado: del primero salta al último', async () => {
124
- await open();
125
-
126
- const focusable = Array.from(
127
- dialog()!.querySelectorAll<HTMLElement>('button, [href], input, select, textarea'),
128
- );
129
- expect(focusable.length).toBeGreaterThan(1);
130
-
131
- // Diagnóstico: la lista que ve el trap debe ser la misma que la del test
132
- // (si divergen, el selector de `FOCUSABLE` y el del test dejan de
133
- // describir el mismo conjunto de elementos).
134
- expect(
135
- Array.from(dialog()!.querySelectorAll<HTMLElement>(FOCUSABLE)).filter(isVisibleNow),
136
- 'el selector del trap difiere del del test',
137
- ).toEqual(focusable);
138
-
139
- const first = focusable[0];
140
- first.focus();
141
- expect(document.activeElement).toBe(first);
142
-
143
- document.dispatchEvent(
144
- new KeyboardEvent('keydown', { key: 'Tab', bubbles: true, shiftKey: true }),
145
- );
146
-
147
- expect(document.activeElement).toBe(focusable[focusable.length - 1]);
148
- });
149
- });
@@ -1,145 +0,0 @@
1
- import {
2
- Component,
3
- ElementRef,
4
- OnDestroy,
5
- afterRenderEffect,
6
- input,
7
- output,
8
- viewChild,
9
- } from '@angular/core';
10
- import { LucideX } from '@lucide/angular';
11
-
12
- import { FOCUSABLE, isVisibleNow } from '../../utils/dialog-focus';
13
-
14
- let titleCounter = 0;
15
-
16
- /**
17
- * Diálogo modal accesible: `aria-modal` con nombre por `aria-labelledby`,
18
- * foco al abrirse y restaurado al cerrarse — también si el consumidor lo
19
- * destruye con el diálogo todavía abierto — Escape y botón ✕ cierran.
20
- *
21
- * ATRAPA el Tab dentro del diálogo: sin eso el foco se tabula hacia la página
22
- * de atrás y se pierde detrás del fondo oscuro. Mismo contrato que `drawer`,
23
- * con el que comparte el selector de elementos focables.
24
- *
25
- * El clic en el fondo es un atajo para puntero; el teclado usa ✕ o Escape.
26
- * Componente tonto: `open`/`title` entran por `input()`, el estado vive
27
- * fuera.
28
- */
29
- @Component({
30
- selector: 'app-modal',
31
- imports: [LucideX],
32
- host: {
33
- '(document:keydown.escape)': 'onEscape()',
34
- // Angular arma la tecla CON sus modificadores y exige igualdad exacta:
35
- // sin esta segunda entrada, Shift+Tab llega como `shift.tab`, no casa con
36
- // `tab` y el foco escapa del diálogo hacia atrás.
37
- '(document:keydown.tab)': 'onTab($event)',
38
- '(document:keydown.shift.tab)': 'onTab($event)',
39
- },
40
- template: `
41
- @if (open()) {
42
- <div class="fixed inset-0 z-50 flex items-center justify-center p-4">
43
- <div class="absolute inset-0 bg-black/50" aria-hidden="true" (click)="close.emit()"></div>
44
- <div
45
- #dialog
46
- role="dialog"
47
- aria-modal="true"
48
- [attr.aria-labelledby]="titleId"
49
- tabindex="-1"
50
- class="relative w-full max-w-lg rounded-xl bg-surface-raised p-6 shadow-xl focus:outline-none"
51
- >
52
- <div class="mb-4 flex items-start justify-between gap-4">
53
- <h2 [id]="titleId" class="font-display text-section font-semibold">
54
- {{ title() }}
55
- </h2>
56
- <button
57
- type="button"
58
- class="flex min-h-11 min-w-11 items-center justify-center rounded text-neutral hover:bg-neutral/10 focus-visible:outline-2 focus-visible:outline-primary lg:min-h-0 lg:min-w-0"
59
- [attr.aria-label]="closeLabel()"
60
- (click)="close.emit()"
61
- >
62
- <svg lucideX size="18" />
63
- </button>
64
- </div>
65
- <ng-content />
66
- </div>
67
- </div>
68
- }
69
- `,
70
- })
71
- export class Modal implements OnDestroy {
72
- readonly open = input(false);
73
- readonly title = input.required<string>();
74
- readonly closeLabel = input('Cerrar');
75
- readonly close = output<void>();
76
-
77
- readonly titleId = `modal-title-${++titleCounter}`;
78
-
79
- private readonly dialogRef = viewChild<ElementRef<HTMLDivElement>>('dialog');
80
- private lastFocused: HTMLElement | null = null;
81
-
82
- private readonly focusEffect = afterRenderEffect(() => {
83
- const open = this.open();
84
- const dialog = this.dialogRef();
85
- if (open && dialog) {
86
- const active = document.activeElement;
87
- if (active !== dialog.nativeElement && this.lastFocused === null) {
88
- this.lastFocused = active instanceof HTMLElement ? active : null;
89
- }
90
- dialog.nativeElement.focus();
91
- } else if (!open && this.lastFocused !== null) {
92
- this.lastFocused.focus();
93
- this.lastFocused = null;
94
- }
95
- });
96
-
97
- /**
98
- * El consumidor puede destruir el componente con el diálogo todavía abierto
99
- * (se monta bajo un `@if`): entonces el effect nunca ve la transición a
100
- * `false` y el foco se quedaría perdido en el body.
101
- */
102
- ngOnDestroy(): void {
103
- if (this.lastFocused?.isConnected) {
104
- this.lastFocused.focus();
105
- }
106
- this.lastFocused = null;
107
- }
108
-
109
- onEscape(): void {
110
- if (this.open()) {
111
- this.close.emit();
112
- }
113
- }
114
-
115
- /**
116
- * Mantiene el Tab dentro del diálogo mientras está abierto. Recibe `Event`
117
- * porque los host listeners de Angular tipean `$event` así; el teclado se
118
- * relee acá dentro.
119
- */
120
- onTab(rawEvent: Event): void {
121
- const event = rawEvent as KeyboardEvent;
122
- const dialog = this.dialogRef()?.nativeElement;
123
- if (!this.open() || !dialog) {
124
- return;
125
- }
126
- const focusable = Array.from(dialog.querySelectorAll<HTMLElement>(FOCUSABLE)).filter(
127
- (element) => isVisibleNow(element),
128
- );
129
- if (focusable.length === 0) {
130
- event.preventDefault();
131
- dialog.focus();
132
- return;
133
- }
134
- const first = focusable[0];
135
- const last = focusable[focusable.length - 1];
136
- const active = document.activeElement;
137
- if (event.shiftKey && (active === first || active === dialog)) {
138
- event.preventDefault();
139
- last.focus();
140
- } else if (!event.shiftKey && active === last) {
141
- event.preventDefault();
142
- first.focus();
143
- }
144
- }
145
- }
@@ -1,165 +0,0 @@
1
- import { ComponentFixture, TestBed } from '@angular/core/testing';
2
- import { By } from '@angular/platform-browser';
3
- import { describe, expect, it, beforeEach } from 'vitest';
4
-
5
- import type { PostCreateSchema, ResourceSchema } from '../../../core/models/schema.model';
6
- import { CopyShare } from '../copy-share/copy-share';
7
- import { PostCreateModal } from './post-create-modal';
8
-
9
- describe('PostCreateModal', () => {
10
- let fixture: ComponentFixture<PostCreateModal>;
11
-
12
- const mockSchema: ResourceSchema = {
13
- id: 'orders',
14
- label: 'Pedido',
15
- labelPlural: 'Pedidos',
16
- kind: 'collection',
17
- endpoint: { list: '/admin/orders' },
18
- keyField: 'ref',
19
- titleField: 'customer_name',
20
- listColumns: [],
21
- fields: [
22
- { key: 'ref', type: 'text', label: 'Referencia' },
23
- { key: 'customer_name', type: 'text', label: 'Cliente' },
24
- { key: 'pickup_date', type: 'date', label: 'Fecha de Retiro' },
25
- ],
26
- };
27
-
28
- const mockConfig: PostCreateSchema = {
29
- mode: 'modal',
30
- title: '¡Pedido {ref} Creado!',
31
- description: 'El pedido de {customer_name} ya está listo para compartir.',
32
- summaryFields: ['ref', 'customer_name', 'pickup_date'],
33
- actions: [
34
- {
35
- id: 'share',
36
- type: 'copy-share',
37
- label: 'Copiar Enlace de Retiro',
38
- urlTemplate: '{public_base_url}/p/{ref}',
39
- shareTextTemplate: 'Hola {customer_name}, tu pedido {ref} está listo.',
40
- },
41
- ],
42
- };
43
-
44
- beforeEach(async () => {
45
- await TestBed.configureTestingModule({
46
- imports: [PostCreateModal],
47
- }).compileComponents();
48
- fixture = TestBed.createComponent(PostCreateModal);
49
- });
50
-
51
- it('1. interpola título y descripción con los datos del registro', () => {
52
- fixture.componentRef.setInput('schema', mockSchema);
53
- fixture.componentRef.setInput('config', mockConfig);
54
- fixture.componentRef.setInput('record', {
55
- ref: 'ORD-555',
56
- customer_name: 'Esteban Quito',
57
- pickup_date: '2026-10-10',
58
- });
59
- fixture.componentRef.setInput('configValues', {
60
- public_base_url: 'https://pickpass.app',
61
- });
62
- fixture.detectChanges();
63
-
64
- const root = fixture.nativeElement as HTMLElement;
65
- expect(root.textContent).toContain('¡Pedido ORD-555 Creado!');
66
- expect(root.textContent).toContain('El pedido de Esteban Quito ya está listo para compartir.');
67
- });
68
-
69
- it('2. renderiza los campos de resumen especificados en summaryFields', () => {
70
- fixture.componentRef.setInput('schema', mockSchema);
71
- fixture.componentRef.setInput('config', mockConfig);
72
- fixture.componentRef.setInput('record', {
73
- ref: 'ORD-555',
74
- customer_name: 'Esteban Quito',
75
- pickup_date: '2026-10-10',
76
- });
77
- fixture.detectChanges();
78
-
79
- const root = fixture.nativeElement as HTMLElement;
80
- expect(root.textContent).toContain('Referencia');
81
- expect(root.textContent).toContain('ORD-555');
82
- expect(root.textContent).toContain('Cliente');
83
- expect(root.textContent).toContain('Esteban Quito');
84
- expect(root.textContent).toContain('Fecha de Retiro');
85
- expect(root.textContent).toContain('2026-10-10');
86
- });
87
-
88
- it('3. renderiza el componente CopyShare cuando hay una acción copy-share', () => {
89
- fixture.componentRef.setInput('schema', mockSchema);
90
- fixture.componentRef.setInput('config', mockConfig);
91
- fixture.componentRef.setInput('record', {
92
- ref: 'ORD-888',
93
- customer_name: 'Lucia',
94
- });
95
- fixture.componentRef.setInput('configValues', {
96
- public_base_url: 'https://retiro.com',
97
- });
98
- fixture.detectChanges();
99
-
100
- const root = fixture.nativeElement as HTMLElement;
101
- expect(root.querySelector('app-copy-share')).not.toBeNull();
102
- expect(root.textContent).toContain('Copiar Enlace de Retiro');
103
- });
104
-
105
- it('4. emite evento closed al hacer clic en el botón Continuar', () => {
106
- let closedEmitted = false;
107
- fixture.componentInstance.closed.subscribe(() => {
108
- closedEmitted = true;
109
- });
110
-
111
- fixture.componentRef.setInput('schema', mockSchema);
112
- fixture.componentRef.setInput('config', mockConfig);
113
- fixture.componentRef.setInput('record', { ref: 'ORD-1' });
114
- fixture.detectChanges();
115
-
116
- const root = fixture.nativeElement as HTMLElement;
117
- const btns = Array.from(root.querySelectorAll<HTMLButtonElement>('button[app-button]'));
118
- const btn = btns.find((b) => b.textContent?.trim() === 'Continuar');
119
- btn?.click();
120
- fixture.detectChanges();
121
-
122
- expect(closedEmitted).toBe(true);
123
- });
124
-
125
- it('5. el enlace copiado lleva la URL pública sin que nadie pase configValues', () => {
126
- // Réplica EXACTA del binding de producción: `form-view.ts:420-425` sólo
127
- // pasa `schema`, `config`, `record` y `closed`. Nadie bindea
128
- // `[configValues]`, así que la única fuente posible de
129
- // `{public_base_url}` es `ConfigService` inyectado en el componente
130
- // (D18): antes no lo estaba y el enlace salía sin dominio.
131
- const configConUrl: PostCreateSchema = {
132
- ...mockConfig,
133
- actions: [
134
- {
135
- id: 'share',
136
- type: 'copy-share',
137
- label: 'Copiar Enlace de Retiro',
138
- urlTemplate: '{public_base_url}/p/{ref}',
139
- shareTextTemplate:
140
- 'Hola {customer_name}, puede retirar su pedido {ref} aquí: {public_base_url}/p/{ref}.',
141
- },
142
- ],
143
- };
144
-
145
- fixture.componentRef.setInput('schema', mockSchema);
146
- fixture.componentRef.setInput('config', configConUrl);
147
- fixture.componentRef.setInput('record', { ref: 'ORD-999', customer_name: 'Ana Pérez' });
148
- fixture.detectChanges();
149
-
150
- const share = fixture.debugElement.query(By.directive(CopyShare))
151
- .componentInstance as CopyShare;
152
-
153
- // Sin `configValues`, el dominio lo aporta `ConfigService` (fallback a
154
- // `window.location.origin`, config.service.ts:30).
155
- const esperado = `${window.location.origin}/p/ORD-999`;
156
- expect(share.url(), 'el enlace quedó sin dominio').toBe(esperado);
157
- expect(share.shareText(), 'el mensaje quedó con la URL rota').toContain(esperado);
158
-
159
- // Y el input sigue mandando cuando alguien lo pasa: es un override,
160
- // no la fuente principal.
161
- fixture.componentRef.setInput('configValues', { public_base_url: 'https://retiro.com' });
162
- fixture.detectChanges();
163
- expect(share.url(), 'el override dejó de aplicar').toBe('https://retiro.com/p/ORD-999');
164
- });
165
- });
@@ -1,159 +0,0 @@
1
- import { Component, computed, inject, input, output } from '@angular/core';
2
- import { LucideCheckCircle2 } from '@lucide/angular';
3
-
4
- import type {
5
- CopyShareAction,
6
- PostCreateSchema,
7
- ResourceAction,
8
- ResourceSchema,
9
- } from '../../../core/models/schema.model';
10
- import { isShareAction, resolveShare, type ResolvedShare } from '../../../actions/action-registry';
11
- import { ConfigService } from '../../../core/services/config.service';
12
- import { interpolateTemplate } from '../../../core/utils/template-interpolator';
13
- import { Button } from '../button/button';
14
- import { CopyShare } from '../copy-share/copy-share';
15
- import { Modal } from '../modal/modal';
16
-
17
- interface SummaryItem {
18
- key: string;
19
- label: string;
20
- value: string;
21
- }
22
-
23
- /**
24
- * Modal de éxito y resumen tras crear un registro.
25
- * Permite visualizar datos clave y acciones directas (como CopyShare o compartir por WhatsApp).
26
- */
27
- @Component({
28
- selector: 'app-post-create-modal',
29
- imports: [Modal, Button, CopyShare, LucideCheckCircle2],
30
- template: `
31
- <app-modal [open]="true" [title]="title()" (close)="closed.emit()">
32
- <div class="flex flex-col gap-4">
33
- <!-- Encabezado con icono de éxito -->
34
- <div class="flex items-center gap-3">
35
- <div
36
- class="flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-emerald-500/10 text-emerald-500"
37
- >
38
- <svg lucideCheckCircle2 size="22" />
39
- </div>
40
- <div>
41
- <p class="text-sm text-neutral-light">{{ description() }}</p>
42
- </div>
43
- </div>
44
-
45
- <!-- Tarjeta de campos de resumen -->
46
- @if (summaryItems().length > 0) {
47
- <div class="rounded-lg border border-neutral/15 bg-surface p-3.5">
48
- <dl class="grid grid-cols-1 gap-x-4 gap-y-2.5 sm:grid-cols-2">
49
- @for (item of summaryItems(); track item.key) {
50
- <div class="flex flex-col">
51
- <dt class="text-xs font-medium text-neutral">{{ item.label }}</dt>
52
- <dd class="text-sm font-semibold text-neutral-light truncate">
53
- {{ item.value }}
54
- </dd>
55
- </div>
56
- }
57
- </dl>
58
- </div>
59
- }
60
-
61
- <!-- Acciones declaradas (ej. CopyShare) -->
62
- @if (copyShareAction(); as action) {
63
- <div class="rounded-lg border border-primary/20 bg-primary/5 p-3.5">
64
- <p class="mb-2 text-xs font-medium text-primary">Enlace de Seguimiento</p>
65
- @let share = shareOf(action);
66
- <app-copy-share
67
- [url]="share.url"
68
- [shareText]="share.shareText"
69
- [label]="action.label"
70
- />
71
- </div>
72
- }
73
-
74
- <!-- Botón de cierre primario -->
75
- <div class="mt-2 flex justify-end">
76
- <button app-button type="button" variant="primary" (click)="closed.emit()">
77
- Continuar
78
- </button>
79
- </div>
80
- </div>
81
- </app-modal>
82
- `,
83
- })
84
- export class PostCreateModal {
85
- readonly schema = input.required<ResourceSchema>();
86
- readonly config = input.required<PostCreateSchema>();
87
- readonly record = input.required<Record<string, unknown>>();
88
-
89
- /**
90
- * Override puntual del contexto de interpolación (tests, o quien quiera
91
- * forzar un valor). **No** es la vía normal: la config global la aporta
92
- * `ConfigService`, igual que en `list-view`.
93
- */
94
- readonly configValues = input<Record<string, unknown>>({});
95
-
96
- readonly closed = output<void>();
97
-
98
- /**
99
- * Inyectado y NO opcional a propósito. El bug que motivó esto (D18): con
100
- * el input `configValues` como única fuente y nadie bindeándolo, la
101
- * plantilla salía con `{public_base_url}` vacío y el operador copiaba
102
- * `…aquí: /p/ORD-0001.` — un enlace inpegable.
103
- *
104
- * `buildInterpolationContext` mezcla config global + fila y fija
105
- * `public_base_url` (`config.service.ts:64-73`); `configValues` se aplica
106
- * encima, sólo como override.
107
- */
108
- private readonly configService = inject(ConfigService);
109
-
110
- constructor() {
111
- // El modal se abre con la sesión ya iniciada: si el load del bootstrap
112
- // falló (arranque sin sesión), éste es el momento de reintentarlo para
113
- // que el mensaje de compartir salga del singleton y no «sólo la URL».
114
- // `globalConfig` es signal: cuando llegue, el contexto y `shareOf` se
115
- // recalculan solos.
116
- void this.configService.ensureLoaded();
117
- }
118
-
119
- /** Contexto único con el que se resuelven título, descripción, URL y mensaje. */
120
- private readonly context = computed(() => ({
121
- ...this.configService.buildInterpolationContext(this.record()),
122
- ...this.configValues(),
123
- }));
124
-
125
- protected readonly title = computed(() => {
126
- const raw = this.config().title || '¡Registro Creado con Éxito!';
127
- return interpolateTemplate(raw, this.context());
128
- });
129
-
130
- protected readonly description = computed(() => {
131
- const raw =
132
- this.config().description ||
133
- 'El registro fue creado correctamente y ya se encuentra guardado en el sistema.';
134
- return interpolateTemplate(raw, this.context());
135
- });
136
-
137
- protected readonly summaryItems = computed<SummaryItem[]>(() => {
138
- const fields = this.config().summaryFields || [];
139
- const rec = this.record();
140
- const schemaFields = this.schema().fields || [];
141
-
142
- return fields.map((key) => {
143
- const fieldDef = schemaFields.find((f) => f.key === key);
144
- const label = fieldDef?.label || key.replace(/_/g, ' ');
145
- const rawVal = rec[key];
146
- const value = rawVal === null || rawVal === undefined || rawVal === '' ? '—' : String(rawVal);
147
- return { key, label, value };
148
- });
149
- });
150
-
151
- protected readonly copyShareAction = computed<CopyShareAction | null>(
152
- () => (this.config().actions || []).find(isShareAction) ?? null,
153
- );
154
-
155
- /** Enlace y mensaje, resueltos por `resolveShare` (R3.10: una sola copia). */
156
- protected shareOf(action: CopyShareAction): ResolvedShare {
157
- return resolveShare(action, this.context());
158
- }
159
- }
@@ -1,31 +0,0 @@
1
- import { Component, computed, input } from '@angular/core';
2
-
3
- /**
4
- * Bloque de carga decorativo: oculto para lectores (`aria-hidden`); la
5
- * región que lo contiene debe exponer `aria-busy="true"`.
6
- */
7
- @Component({
8
- selector: 'app-skeleton',
9
- host: { class: 'block space-y-2', 'aria-hidden': 'true' },
10
- template: `
11
- @for (line of lineCount(); track line) {
12
- <div
13
- class="animate-pulse rounded bg-neutral/15"
14
- [style.height.px]="height()"
15
- [style.width]="width()"
16
- ></div>
17
- }
18
- `,
19
- })
20
- export class Skeleton {
21
- /** Cantidad de barras (mínimo 1). */
22
- readonly lines = input(1);
23
- readonly height = input(16);
24
- readonly width = input('100%');
25
-
26
- readonly lineCount = computed(() => {
27
- const lines = Math.floor(this.lines());
28
- const count = Number.isFinite(lines) && lines > 0 ? lines : 1;
29
- return Array.from({ length: count }, (_, index) => index);
30
- });
31
- }