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

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 (369) hide show
  1. package/README.md +222 -0
  2. package/ng-package.json +7 -0
  3. package/package.json +3 -15
  4. package/src/lib/actions/action-registry.spec.ts +52 -0
  5. package/src/lib/actions/action-registry.ts +126 -0
  6. package/src/lib/actions/action-service.spec.ts +215 -0
  7. package/src/lib/actions/action-service.ts +87 -0
  8. package/src/lib/actions/descriptors.spec.ts +155 -0
  9. package/src/lib/actions/descriptors.ts +154 -0
  10. package/src/lib/columns/column-cell.ts +33 -0
  11. package/src/lib/columns/column-defaults.spec.ts +99 -0
  12. package/src/lib/columns/column-defaults.ts +84 -0
  13. package/src/lib/columns/column-format.spec.ts +274 -0
  14. package/src/lib/columns/descriptors.ts +113 -0
  15. package/src/lib/columns/format-badge.ts +51 -0
  16. package/src/lib/columns/format-boolean.ts +58 -0
  17. package/src/lib/columns/format-currency.ts +30 -0
  18. package/src/lib/columns/format-date.ts +35 -0
  19. package/src/lib/columns/format-number.ts +32 -0
  20. package/src/lib/columns/format-text.ts +23 -0
  21. package/src/lib/columns/format-thumbnail.ts +63 -0
  22. package/src/lib/core/adapters/firebase-auth.adapter.ts +6 -0
  23. package/src/lib/core/guards/auth.guard.spec.ts +88 -0
  24. package/src/lib/core/guards/auth.guard.ts +48 -0
  25. package/src/lib/core/guards/unsaved-changes.guard.ts +16 -0
  26. package/src/lib/core/interceptors/api-error.interceptor.spec.ts +182 -0
  27. package/src/lib/core/interceptors/api-error.interceptor.ts +87 -0
  28. package/src/lib/core/models/api.model.ts +104 -0
  29. package/src/lib/core/models/schema-descriptions.ts +118 -0
  30. package/src/lib/core/models/schema.model.ts +1097 -0
  31. package/src/lib/core/registry/composition-validator.spec.ts +358 -0
  32. package/src/lib/core/registry/composition-validator.ts +270 -0
  33. package/src/lib/core/registry/field-validators.spec.ts +199 -0
  34. package/src/lib/core/registry/field-validators.ts +440 -0
  35. package/src/lib/core/registry/render-host.spec.ts +208 -0
  36. package/src/lib/core/registry/render-host.ts +646 -0
  37. package/src/lib/core/registry/render-registry.spec.ts +96 -0
  38. package/src/lib/core/registry/render-registry.ts +312 -0
  39. package/src/lib/core/registry/schema-catalog.ts +156 -0
  40. package/src/lib/core/services/api.service.spec.ts +1142 -0
  41. package/src/lib/core/services/api.service.ts +371 -0
  42. package/src/lib/core/services/auth.service.spec.ts +653 -0
  43. package/src/lib/core/services/auth.service.ts +503 -0
  44. package/src/lib/core/services/config.service.spec.ts +121 -0
  45. package/src/lib/core/services/config.service.ts +119 -0
  46. package/src/lib/core/services/data-source.service.spec.ts +179 -0
  47. package/src/lib/core/services/data-source.service.ts +142 -0
  48. package/src/lib/core/services/error-mapper.service.spec.ts +50 -0
  49. package/src/lib/core/services/error-mapper.service.ts +49 -0
  50. package/src/lib/core/services/notification.service.ts +73 -0
  51. package/src/lib/core/services/relation-drawer.service.ts +41 -0
  52. package/src/lib/core/services/theme.service.spec.ts +106 -0
  53. package/src/lib/core/services/theme.service.ts +86 -0
  54. package/src/lib/core/services/transport.spec.ts +198 -0
  55. package/src/lib/core/services/transport.ts +164 -0
  56. package/src/lib/core/services/upload.service.ts +81 -0
  57. package/src/lib/core/testing/categories.schema.ts +125 -0
  58. package/src/lib/core/testing/orders.schema.ts +372 -0
  59. package/src/lib/core/testing/products.schema.ts +258 -0
  60. package/src/lib/core/testing/site.schema.ts +195 -0
  61. package/src/lib/core/testing/test-catalog.ts +21 -0
  62. package/src/lib/core/tokens.ts +112 -0
  63. package/src/lib/core/utils/clipboard.spec.ts +55 -0
  64. package/src/lib/core/utils/clipboard.ts +90 -0
  65. package/src/lib/core/utils/context-resolver.spec.ts +95 -0
  66. package/src/lib/core/utils/context-resolver.ts +101 -0
  67. package/src/lib/core/utils/response-unwrapper.spec.ts +70 -0
  68. package/src/lib/core/utils/response-unwrapper.ts +103 -0
  69. package/src/lib/core/utils/source-options.spec.ts +96 -0
  70. package/src/lib/core/utils/source-options.ts +54 -0
  71. package/src/lib/core/utils/template-interpolator.spec.ts +59 -0
  72. package/src/lib/core/utils/template-interpolator.ts +56 -0
  73. package/src/lib/core/view-navigation/view-navigation.service.spec.ts +207 -0
  74. package/src/lib/core/view-navigation/view-navigation.service.ts +132 -0
  75. package/src/lib/fields/boolean/boolean.descriptor.ts +11 -0
  76. package/src/lib/fields/boolean/boolean.ts +40 -0
  77. package/src/lib/fields/color/color.descriptor.ts +12 -0
  78. package/src/lib/fields/color/color.ts +34 -0
  79. package/src/lib/fields/currency/currency.descriptor.ts +12 -0
  80. package/src/lib/fields/currency/currency.ts +67 -0
  81. package/src/lib/fields/date/date.descriptor.ts +12 -0
  82. package/src/lib/fields/date/date.ts +36 -0
  83. package/src/lib/fields/descriptors.ts +122 -0
  84. package/src/lib/fields/display/display-badge.ts +65 -0
  85. package/src/lib/fields/display/display-date.ts +39 -0
  86. package/src/lib/fields/display/display-defaults.ts +84 -0
  87. package/src/lib/fields/display/display-file.ts +41 -0
  88. package/src/lib/fields/display/display-image.ts +54 -0
  89. package/src/lib/fields/display/display-list.ts +107 -0
  90. package/src/lib/fields/display/display-number.ts +41 -0
  91. package/src/lib/fields/display/display-text.ts +42 -0
  92. package/src/lib/fields/display/display.spec.ts +242 -0
  93. package/src/lib/fields/dropdown/dropdown.descriptor.ts +12 -0
  94. package/src/lib/fields/dropdown/dropdown.ts +45 -0
  95. package/src/lib/fields/email/email.descriptor.ts +12 -0
  96. package/src/lib/fields/email/email.ts +28 -0
  97. package/src/lib/fields/field-aria.ts +60 -0
  98. package/src/lib/fields/field-host/field-host.spec.ts +118 -0
  99. package/src/lib/fields/field-host/field-host.ts +47 -0
  100. package/src/lib/fields/field-node.ts +88 -0
  101. package/src/lib/fields/file/file.descriptor.ts +14 -0
  102. package/src/lib/fields/file/file.spec.ts +134 -0
  103. package/src/lib/fields/file/file.ts +281 -0
  104. package/src/lib/fields/group/group.descriptor.ts +21 -0
  105. package/src/lib/fields/group/group.ts +110 -0
  106. package/src/lib/fields/image/image.descriptor.ts +12 -0
  107. package/src/lib/fields/image/image.spec.ts +117 -0
  108. package/src/lib/fields/image/image.ts +281 -0
  109. package/src/lib/fields/key-value/key-value.descriptor.ts +11 -0
  110. package/src/lib/fields/key-value/key-value.ts +283 -0
  111. package/src/lib/fields/list/list.descriptor.ts +21 -0
  112. package/src/lib/fields/list/list.ts +376 -0
  113. package/src/lib/fields/multiselect/multiselect.descriptor.ts +11 -0
  114. package/src/lib/fields/multiselect/multiselect.spec.ts +142 -0
  115. package/src/lib/fields/multiselect/multiselect.ts +152 -0
  116. package/src/lib/fields/number/number.descriptor.ts +12 -0
  117. package/src/lib/fields/number/number.ts +40 -0
  118. package/src/lib/fields/phone/phone.descriptor.ts +12 -0
  119. package/src/lib/fields/phone/phone.ts +46 -0
  120. package/src/lib/fields/readonly-text/readonly-text.descriptor.ts +12 -0
  121. package/src/lib/fields/readonly-text/readonly-text.ts +58 -0
  122. package/src/lib/fields/relation/relation.descriptor.ts +12 -0
  123. package/src/lib/fields/relation/relation.spec.ts +193 -0
  124. package/src/lib/fields/relation/relation.ts +224 -0
  125. package/src/lib/fields/rich-select/rich-select.descriptor.ts +12 -0
  126. package/src/lib/fields/rich-select/rich-select.ts +175 -0
  127. package/src/lib/fields/select/radio-mode.ts +25 -0
  128. package/src/lib/fields/select/select.descriptor.ts +12 -0
  129. package/src/lib/fields/select/select.spec.ts +162 -0
  130. package/src/lib/fields/select/select.ts +210 -0
  131. package/src/lib/fields/slug/slug.descriptor.ts +19 -0
  132. package/src/lib/fields/slug/slug.ts +67 -0
  133. package/src/lib/fields/string-list/string-list.descriptor.ts +11 -0
  134. package/src/lib/fields/string-list/string-list.ts +222 -0
  135. package/src/lib/fields/text/text.descriptor.ts +12 -0
  136. package/src/lib/fields/text/text.ts +35 -0
  137. package/src/lib/fields/textarea/textarea.descriptor.ts +12 -0
  138. package/src/lib/fields/textarea/textarea.spec.ts +117 -0
  139. package/src/lib/fields/textarea/textarea.ts +126 -0
  140. package/src/lib/fields/time/time.descriptor.ts +12 -0
  141. package/src/lib/fields/time/time.ts +28 -0
  142. package/src/lib/fields/unknown-render/unknown-render.ts +49 -0
  143. package/src/lib/fields/url/url.descriptor.ts +12 -0
  144. package/src/lib/fields/url/url.ts +53 -0
  145. package/src/lib/gas-admin-ui.spec.ts +21 -0
  146. package/src/lib/gas-admin-ui.ts +9 -0
  147. package/src/lib/layouts/descriptors.ts +9 -0
  148. package/src/lib/pages/dashboard/dashboard.ts +167 -0
  149. package/src/lib/pages/detail-view/detail-view.spec.ts +333 -0
  150. package/src/lib/pages/detail-view/detail-view.ts +570 -0
  151. package/src/lib/pages/drawer-form/drawer-form.ts +228 -0
  152. package/src/lib/pages/form-view/form-model.ts +88 -0
  153. package/src/lib/pages/form-view/form-schema.ts +255 -0
  154. package/src/lib/pages/form-view/form-view.ts +1622 -0
  155. package/src/lib/pages/list-view/list-view.formats.spec.ts +214 -0
  156. package/src/lib/pages/list-view/list-view.ts +882 -0
  157. package/src/lib/pages/login/login.spec.ts +109 -0
  158. package/src/lib/pages/login/login.ts +227 -0
  159. package/src/lib/pages/resource-page/resource-page.ts +234 -0
  160. package/src/lib/shared/components/badge/badge.ts +35 -0
  161. package/src/lib/shared/components/button/button.ts +65 -0
  162. package/src/lib/shared/components/confirm-dialog/confirm-dialog.ts +48 -0
  163. package/src/lib/shared/components/copy-button/copy-button.ts +56 -0
  164. package/src/lib/shared/components/copy-share/copy-share.spec.ts +122 -0
  165. package/src/lib/shared/components/copy-share/copy-share.ts +107 -0
  166. package/src/lib/shared/components/drawer/drawer.spec.ts +127 -0
  167. package/src/lib/shared/components/drawer/drawer.ts +172 -0
  168. package/src/lib/shared/components/empty-state/empty-state.ts +30 -0
  169. package/src/lib/shared/components/modal/modal.spec.ts +149 -0
  170. package/src/lib/shared/components/modal/modal.ts +145 -0
  171. package/src/lib/shared/components/post-create-modal/post-create-modal.spec.ts +165 -0
  172. package/src/lib/shared/components/post-create-modal/post-create-modal.ts +159 -0
  173. package/src/lib/shared/components/skeleton/skeleton.ts +31 -0
  174. package/src/lib/shared/components/toast/toast.ts +58 -0
  175. package/src/lib/shared/utils/col-span.ts +25 -0
  176. package/src/lib/shared/utils/condition-evaluator.ts +53 -0
  177. package/src/lib/shared/utils/depends-on.ts +48 -0
  178. package/src/lib/shared/utils/dialog-focus.ts +28 -0
  179. package/src/lib/shared/utils/field-path.ts +49 -0
  180. package/src/lib/shared/utils/gap-sorting.ts +144 -0
  181. package/src/lib/shared/utils/seed.spec.ts +64 -0
  182. package/src/lib/shared/utils/seed.ts +149 -0
  183. package/src/lib/shared/utils/slugify.ts +13 -0
  184. package/src/lib/shared/utils/validators.ts +41 -0
  185. package/src/lib/shell/layout/layout.ts +63 -0
  186. package/src/lib/shell/shell.routes.spec.ts +59 -0
  187. package/src/lib/shell/shell.routes.ts +122 -0
  188. package/src/lib/shell/sidebar/sidebar.ts +139 -0
  189. package/src/lib/shell/theme-toggle/theme-toggle.ts +74 -0
  190. package/src/lib/views/calendar-view/calendar-model.ts +426 -0
  191. package/src/lib/views/calendar-view/calendar-view.spec.ts +557 -0
  192. package/src/lib/views/calendar-view/calendar-view.ts +568 -0
  193. package/src/lib/views/composer/composer-host.spec.ts +301 -0
  194. package/src/lib/views/composer/composer-host.ts +248 -0
  195. package/src/lib/views/composer/composer-imports.spec.ts +54 -0
  196. package/src/lib/views/composer/view-context.spec.ts +117 -0
  197. package/src/lib/views/composer/view-context.ts +109 -0
  198. package/src/lib/views/composer/view-slot.spec.ts +130 -0
  199. package/src/lib/views/composer/view-slot.ts +178 -0
  200. package/src/lib/views/descriptors.ts +46 -0
  201. package/src/lib/views/kanban-view/kanban-model.ts +173 -0
  202. package/src/lib/views/kanban-view/kanban-view.spec.ts +540 -0
  203. package/src/lib/views/kanban-view/kanban-view.ts +327 -0
  204. package/src/lib/widgets/bar-chart/bar-chart.descriptor.ts +17 -0
  205. package/src/lib/widgets/bar-chart/bar-chart.spec.ts +66 -0
  206. package/src/lib/widgets/bar-chart/bar-chart.ts +76 -0
  207. package/src/lib/widgets/chart-line/chart-line.descriptor.ts +17 -0
  208. package/src/lib/widgets/chart-line/chart-line.spec.ts +113 -0
  209. package/src/lib/widgets/chart-line/chart-line.ts +219 -0
  210. package/src/lib/widgets/descriptors.ts +29 -0
  211. package/src/lib/widgets/metric-card/metric-card.descriptor.ts +41 -0
  212. package/src/lib/widgets/metric-card/metric-card.spec.ts +52 -0
  213. package/src/lib/widgets/metric-card/metric-card.ts +48 -0
  214. package/src/lib/widgets/quick-actions/quick-actions.descriptor.ts +13 -0
  215. package/src/lib/widgets/quick-actions/quick-actions.spec.ts +61 -0
  216. package/src/lib/widgets/quick-actions/quick-actions.ts +100 -0
  217. package/src/lib/widgets/record-list/record-list.descriptor.ts +16 -0
  218. package/src/lib/widgets/record-list/record-list.spec.ts +79 -0
  219. package/src/lib/widgets/record-list/record-list.ts +115 -0
  220. package/src/lib/widgets/series.spec.ts +42 -0
  221. package/src/lib/widgets/series.ts +56 -0
  222. package/src/lib/widgets/status-progress/status-progress.descriptor.ts +19 -0
  223. package/src/lib/widgets/status-progress/status-progress.spec.ts +63 -0
  224. package/src/lib/widgets/status-progress/status-progress.ts +104 -0
  225. package/src/lib/widgets/widget-host/widget-host.spec.ts +179 -0
  226. package/src/lib/widgets/widget-host/widget-host.ts +99 -0
  227. package/src/public-api.ts +104 -0
  228. package/tinya-code-gas-admin-ui-0.2.0-alpha.15.tgz +0 -0
  229. package/tsconfig.lib.json +13 -0
  230. package/tsconfig.lib.prod.json +11 -0
  231. package/tsconfig.spec.json +10 -0
  232. package/fesm2022/tinya-code-gas-admin-ui-badge-EeCA_l-o.mjs +0 -84
  233. package/fesm2022/tinya-code-gas-admin-ui-badge-EeCA_l-o.mjs.map +0 -1
  234. package/fesm2022/tinya-code-gas-admin-ui-bar-chart-G7sEMSBY.mjs +0 -140
  235. package/fesm2022/tinya-code-gas-admin-ui-bar-chart-G7sEMSBY.mjs.map +0 -1
  236. package/fesm2022/tinya-code-gas-admin-ui-boolean-B2ASKL0E.mjs +0 -113
  237. package/fesm2022/tinya-code-gas-admin-ui-boolean-B2ASKL0E.mjs.map +0 -1
  238. package/fesm2022/tinya-code-gas-admin-ui-button-BQjNW8KB.mjs +0 -163
  239. package/fesm2022/tinya-code-gas-admin-ui-button-BQjNW8KB.mjs.map +0 -1
  240. package/fesm2022/tinya-code-gas-admin-ui-calendar-view-DCY8bj2V.mjs +0 -1027
  241. package/fesm2022/tinya-code-gas-admin-ui-calendar-view-DCY8bj2V.mjs.map +0 -1
  242. package/fesm2022/tinya-code-gas-admin-ui-chart-line-BjdlKHoH.mjs +0 -278
  243. package/fesm2022/tinya-code-gas-admin-ui-chart-line-BjdlKHoH.mjs.map +0 -1
  244. package/fesm2022/tinya-code-gas-admin-ui-color-Dljh_By3.mjs +0 -107
  245. package/fesm2022/tinya-code-gas-admin-ui-color-Dljh_By3.mjs.map +0 -1
  246. package/fesm2022/tinya-code-gas-admin-ui-condition-evaluator-DY2k1M3C.mjs +0 -101
  247. package/fesm2022/tinya-code-gas-admin-ui-condition-evaluator-DY2k1M3C.mjs.map +0 -1
  248. package/fesm2022/tinya-code-gas-admin-ui-currency-BvuF3Z63.mjs +0 -141
  249. package/fesm2022/tinya-code-gas-admin-ui-currency-BvuF3Z63.mjs.map +0 -1
  250. package/fesm2022/tinya-code-gas-admin-ui-data-source.service-96FSbN72.mjs +0 -88
  251. package/fesm2022/tinya-code-gas-admin-ui-data-source.service-96FSbN72.mjs.map +0 -1
  252. package/fesm2022/tinya-code-gas-admin-ui-date-1SJGXZrd.mjs +0 -107
  253. package/fesm2022/tinya-code-gas-admin-ui-date-1SJGXZrd.mjs.map +0 -1
  254. package/fesm2022/tinya-code-gas-admin-ui-display-badge-fwk6sDU7.mjs +0 -140
  255. package/fesm2022/tinya-code-gas-admin-ui-display-badge-fwk6sDU7.mjs.map +0 -1
  256. package/fesm2022/tinya-code-gas-admin-ui-display-date-D7zLiDiG.mjs +0 -119
  257. package/fesm2022/tinya-code-gas-admin-ui-display-date-D7zLiDiG.mjs.map +0 -1
  258. package/fesm2022/tinya-code-gas-admin-ui-display-file-BiIhqvQC.mjs +0 -125
  259. package/fesm2022/tinya-code-gas-admin-ui-display-file-BiIhqvQC.mjs.map +0 -1
  260. package/fesm2022/tinya-code-gas-admin-ui-display-image-C1dhnZi1.mjs +0 -152
  261. package/fesm2022/tinya-code-gas-admin-ui-display-image-C1dhnZi1.mjs.map +0 -1
  262. package/fesm2022/tinya-code-gas-admin-ui-display-list-DOEuUbGe.mjs +0 -211
  263. package/fesm2022/tinya-code-gas-admin-ui-display-list-DOEuUbGe.mjs.map +0 -1
  264. package/fesm2022/tinya-code-gas-admin-ui-display-number-DDMzr4Hn.mjs +0 -116
  265. package/fesm2022/tinya-code-gas-admin-ui-display-number-DDMzr4Hn.mjs.map +0 -1
  266. package/fesm2022/tinya-code-gas-admin-ui-display-text-B8CdVNpv.mjs +0 -111
  267. package/fesm2022/tinya-code-gas-admin-ui-display-text-B8CdVNpv.mjs.map +0 -1
  268. package/fesm2022/tinya-code-gas-admin-ui-dropdown-C3blvmE1.mjs +0 -122
  269. package/fesm2022/tinya-code-gas-admin-ui-dropdown-C3blvmE1.mjs.map +0 -1
  270. package/fesm2022/tinya-code-gas-admin-ui-email-CT_O5ihA.mjs +0 -107
  271. package/fesm2022/tinya-code-gas-admin-ui-email-CT_O5ihA.mjs.map +0 -1
  272. package/fesm2022/tinya-code-gas-admin-ui-empty-state-BMc0QtoT.mjs +0 -109
  273. package/fesm2022/tinya-code-gas-admin-ui-empty-state-BMc0QtoT.mjs.map +0 -1
  274. package/fesm2022/tinya-code-gas-admin-ui-error-mapper.service-DY5y1FjE.mjs +0 -45
  275. package/fesm2022/tinya-code-gas-admin-ui-error-mapper.service-DY5y1FjE.mjs.map +0 -1
  276. package/fesm2022/tinya-code-gas-admin-ui-field-aria-BD1Wiggc.mjs +0 -50
  277. package/fesm2022/tinya-code-gas-admin-ui-field-aria-BD1Wiggc.mjs.map +0 -1
  278. package/fesm2022/tinya-code-gas-admin-ui-field-node-CIK6KNN_.mjs +0 -24
  279. package/fesm2022/tinya-code-gas-admin-ui-field-node-CIK6KNN_.mjs.map +0 -1
  280. package/fesm2022/tinya-code-gas-admin-ui-field-path-B4-FTBGZ.mjs +0 -27
  281. package/fesm2022/tinya-code-gas-admin-ui-field-path-B4-FTBGZ.mjs.map +0 -1
  282. package/fesm2022/tinya-code-gas-admin-ui-file-Dmxioog7.mjs +0 -408
  283. package/fesm2022/tinya-code-gas-admin-ui-file-Dmxioog7.mjs.map +0 -1
  284. package/fesm2022/tinya-code-gas-admin-ui-form-view-C709rc57.mjs +0 -4516
  285. package/fesm2022/tinya-code-gas-admin-ui-form-view-C709rc57.mjs.map +0 -1
  286. package/fesm2022/tinya-code-gas-admin-ui-format-badge-CK8ct5Wk.mjs +0 -82
  287. package/fesm2022/tinya-code-gas-admin-ui-format-badge-CK8ct5Wk.mjs.map +0 -1
  288. package/fesm2022/tinya-code-gas-admin-ui-format-boolean-ClzezZz-.mjs +0 -105
  289. package/fesm2022/tinya-code-gas-admin-ui-format-boolean-ClzezZz-.mjs.map +0 -1
  290. package/fesm2022/tinya-code-gas-admin-ui-format-currency-CVmniKml.mjs +0 -65
  291. package/fesm2022/tinya-code-gas-admin-ui-format-currency-CVmniKml.mjs.map +0 -1
  292. package/fesm2022/tinya-code-gas-admin-ui-format-date-Dr1YsDd_.mjs +0 -65
  293. package/fesm2022/tinya-code-gas-admin-ui-format-date-Dr1YsDd_.mjs.map +0 -1
  294. package/fesm2022/tinya-code-gas-admin-ui-format-number-CWCjpI4n.mjs +0 -65
  295. package/fesm2022/tinya-code-gas-admin-ui-format-number-CWCjpI4n.mjs.map +0 -1
  296. package/fesm2022/tinya-code-gas-admin-ui-format-text-DBOgJkH0.mjs +0 -59
  297. package/fesm2022/tinya-code-gas-admin-ui-format-text-DBOgJkH0.mjs.map +0 -1
  298. package/fesm2022/tinya-code-gas-admin-ui-format-thumbnail-PCRvxWKt.mjs +0 -94
  299. package/fesm2022/tinya-code-gas-admin-ui-format-thumbnail-PCRvxWKt.mjs.map +0 -1
  300. package/fesm2022/tinya-code-gas-admin-ui-gap-sorting-iTdy_DYG.mjs +0 -72
  301. package/fesm2022/tinya-code-gas-admin-ui-gap-sorting-iTdy_DYG.mjs.map +0 -1
  302. package/fesm2022/tinya-code-gas-admin-ui-group-h7-O8tt4.mjs +0 -238
  303. package/fesm2022/tinya-code-gas-admin-ui-group-h7-O8tt4.mjs.map +0 -1
  304. package/fesm2022/tinya-code-gas-admin-ui-image-7UhJ7nqI.mjs +0 -416
  305. package/fesm2022/tinya-code-gas-admin-ui-image-7UhJ7nqI.mjs.map +0 -1
  306. package/fesm2022/tinya-code-gas-admin-ui-kanban-view-Dl0Ol5Kb.mjs +0 -439
  307. package/fesm2022/tinya-code-gas-admin-ui-kanban-view-Dl0Ol5Kb.mjs.map +0 -1
  308. package/fesm2022/tinya-code-gas-admin-ui-key-value-nVdgg5at.mjs +0 -513
  309. package/fesm2022/tinya-code-gas-admin-ui-key-value-nVdgg5at.mjs.map +0 -1
  310. package/fesm2022/tinya-code-gas-admin-ui-list-C8ijJHAx.mjs +0 -637
  311. package/fesm2022/tinya-code-gas-admin-ui-list-C8ijJHAx.mjs.map +0 -1
  312. package/fesm2022/tinya-code-gas-admin-ui-metric-card-DnGMQL8l.mjs +0 -127
  313. package/fesm2022/tinya-code-gas-admin-ui-metric-card-DnGMQL8l.mjs.map +0 -1
  314. package/fesm2022/tinya-code-gas-admin-ui-multiselect-PB28e-jl.mjs +0 -251
  315. package/fesm2022/tinya-code-gas-admin-ui-multiselect-PB28e-jl.mjs.map +0 -1
  316. package/fesm2022/tinya-code-gas-admin-ui-notification.service-LjSULER6.mjs +0 -66
  317. package/fesm2022/tinya-code-gas-admin-ui-notification.service-LjSULER6.mjs.map +0 -1
  318. package/fesm2022/tinya-code-gas-admin-ui-number-JNr7glc8.mjs +0 -114
  319. package/fesm2022/tinya-code-gas-admin-ui-number-JNr7glc8.mjs.map +0 -1
  320. package/fesm2022/tinya-code-gas-admin-ui-phone-jR417hPf.mjs +0 -116
  321. package/fesm2022/tinya-code-gas-admin-ui-phone-jR417hPf.mjs.map +0 -1
  322. package/fesm2022/tinya-code-gas-admin-ui-quick-actions-DCQ6emmF.mjs +0 -235
  323. package/fesm2022/tinya-code-gas-admin-ui-quick-actions-DCQ6emmF.mjs.map +0 -1
  324. package/fesm2022/tinya-code-gas-admin-ui-radio-mode-DxvN07DY.mjs +0 -8
  325. package/fesm2022/tinya-code-gas-admin-ui-radio-mode-DxvN07DY.mjs.map +0 -1
  326. package/fesm2022/tinya-code-gas-admin-ui-readonly-text-BL7-4qie.mjs +0 -124
  327. package/fesm2022/tinya-code-gas-admin-ui-readonly-text-BL7-4qie.mjs.map +0 -1
  328. package/fesm2022/tinya-code-gas-admin-ui-record-list-BiZfnd_7.mjs +0 -249
  329. package/fesm2022/tinya-code-gas-admin-ui-record-list-BiZfnd_7.mjs.map +0 -1
  330. package/fesm2022/tinya-code-gas-admin-ui-relation-drawer.service-B0kT8EiW.mjs +0 -39
  331. package/fesm2022/tinya-code-gas-admin-ui-relation-drawer.service-B0kT8EiW.mjs.map +0 -1
  332. package/fesm2022/tinya-code-gas-admin-ui-relation-ykpJ3PYl.mjs +0 -309
  333. package/fesm2022/tinya-code-gas-admin-ui-relation-ykpJ3PYl.mjs.map +0 -1
  334. package/fesm2022/tinya-code-gas-admin-ui-render-registry-CULkxrSt.mjs +0 -576
  335. package/fesm2022/tinya-code-gas-admin-ui-render-registry-CULkxrSt.mjs.map +0 -1
  336. package/fesm2022/tinya-code-gas-admin-ui-rich-select-CIHaOrbU.mjs +0 -161
  337. package/fesm2022/tinya-code-gas-admin-ui-rich-select-CIHaOrbU.mjs.map +0 -1
  338. package/fesm2022/tinya-code-gas-admin-ui-rolldown-runtime-DpJrqANO.mjs +0 -11
  339. package/fesm2022/tinya-code-gas-admin-ui-schema-catalog-D0Pk0wAN.mjs +0 -685
  340. package/fesm2022/tinya-code-gas-admin-ui-schema-catalog-D0Pk0wAN.mjs.map +0 -1
  341. package/fesm2022/tinya-code-gas-admin-ui-seed-CcCA3FdQ.mjs +0 -80
  342. package/fesm2022/tinya-code-gas-admin-ui-seed-CcCA3FdQ.mjs.map +0 -1
  343. package/fesm2022/tinya-code-gas-admin-ui-select-CDwX9yNO.mjs +0 -296
  344. package/fesm2022/tinya-code-gas-admin-ui-select-CDwX9yNO.mjs.map +0 -1
  345. package/fesm2022/tinya-code-gas-admin-ui-skeleton-DnWK0tcZ.mjs +0 -119
  346. package/fesm2022/tinya-code-gas-admin-ui-skeleton-DnWK0tcZ.mjs.map +0 -1
  347. package/fesm2022/tinya-code-gas-admin-ui-slug-DU58cbiY.mjs +0 -158
  348. package/fesm2022/tinya-code-gas-admin-ui-slug-DU58cbiY.mjs.map +0 -1
  349. package/fesm2022/tinya-code-gas-admin-ui-source-options-B9R4mw8-.mjs +0 -26
  350. package/fesm2022/tinya-code-gas-admin-ui-source-options-B9R4mw8-.mjs.map +0 -1
  351. package/fesm2022/tinya-code-gas-admin-ui-status-progress-DmeG8htE.mjs +0 -205
  352. package/fesm2022/tinya-code-gas-admin-ui-status-progress-DmeG8htE.mjs.map +0 -1
  353. package/fesm2022/tinya-code-gas-admin-ui-string-list-gleasqzD.mjs +0 -432
  354. package/fesm2022/tinya-code-gas-admin-ui-string-list-gleasqzD.mjs.map +0 -1
  355. package/fesm2022/tinya-code-gas-admin-ui-template-interpolator-ewv7CkNX.mjs +0 -36
  356. package/fesm2022/tinya-code-gas-admin-ui-template-interpolator-ewv7CkNX.mjs.map +0 -1
  357. package/fesm2022/tinya-code-gas-admin-ui-text-CUPmL7W_.mjs +0 -107
  358. package/fesm2022/tinya-code-gas-admin-ui-text-CUPmL7W_.mjs.map +0 -1
  359. package/fesm2022/tinya-code-gas-admin-ui-textarea-CGLSIW13.mjs +0 -223
  360. package/fesm2022/tinya-code-gas-admin-ui-textarea-CGLSIW13.mjs.map +0 -1
  361. package/fesm2022/tinya-code-gas-admin-ui-time-BcHzsTWf.mjs +0 -107
  362. package/fesm2022/tinya-code-gas-admin-ui-time-BcHzsTWf.mjs.map +0 -1
  363. package/fesm2022/tinya-code-gas-admin-ui-upload.service-CZPEPCeN.mjs +0 -60
  364. package/fesm2022/tinya-code-gas-admin-ui-upload.service-CZPEPCeN.mjs.map +0 -1
  365. package/fesm2022/tinya-code-gas-admin-ui-url-GO4LZi__.mjs +0 -141
  366. package/fesm2022/tinya-code-gas-admin-ui-url-GO4LZi__.mjs.map +0 -1
  367. package/fesm2022/tinya-code-gas-admin-ui.mjs +0 -4599
  368. package/fesm2022/tinya-code-gas-admin-ui.mjs.map +0 -1
  369. package/types/tinya-code-gas-admin-ui.d.ts +0 -3632
@@ -0,0 +1,426 @@
1
+ import { InjectionToken } from '@angular/core';
2
+ import type { CalendarViewConfig, FieldSchema } from '../../core/models/schema.model';
3
+ import type { SourceRow } from '../../core/services/data-source.service';
4
+
5
+ /**
6
+ * Pure date + event-mapping model for the generic calendar view (R9.8.3).
7
+ *
8
+ * Date model (decided): backend `date` fields are ISO civil dates
9
+ * `YYYY-MM-DD` treated as CALENDAR DAYS — never shifted through the browser
10
+ * timezone. Every parse goes through `Date.UTC` on the literal parts, never
11
+ * `new Date('YYYY-MM-DD')` in local time (that lands on the previous day
12
+ * west of Greenwich).
13
+ */
14
+
15
+ /** Milliseconds in one civil day — every day-step of the model uses this. */
16
+ export const DAY_MS = 86_400_000;
17
+
18
+ /** Visible modes of the calendar. */
19
+ export type CalendarMode = 'month' | 'week' | 'day' | 'agenda';
20
+
21
+ /** Inclusive pair of civil days (`YYYY-MM-DD`) that the view paints. */
22
+ export interface CivilRange {
23
+ desde: string;
24
+ hasta: string;
25
+ }
26
+
27
+ /** One event painted from a source row. */
28
+ export interface CalEvent {
29
+ key: string;
30
+ title: string;
31
+ /** True first day (`YYYY-MM-DD`), before any clamp to the visible range. */
32
+ startDay: string;
33
+ /** True last day, inclusive. Equals `startDay` for single-day events. */
34
+ endDay: string;
35
+ color?: string;
36
+ row: SourceRow;
37
+ }
38
+
39
+ /** A row excluded from the grid because its interval is inconsistent. */
40
+ export interface CalendarProblem {
41
+ row: SourceRow;
42
+ reason: string;
43
+ }
44
+
45
+ /** Result of mapping raw rows onto calendar events (R9.8.3). */
46
+ export interface CalendarMapping {
47
+ events: CalEvent[];
48
+ /** Rows whose `startField` is empty or not a valid civil date. */
49
+ undated: SourceRow[];
50
+ /** Rows whose `endField` makes the interval impossible. */
51
+ invalid: CalendarProblem[];
52
+ }
53
+
54
+ /** Spanish reasons shown next to problem records (UI copy). */
55
+ export const REASON_UNDATED = 'Sin fecha de inicio válida';
56
+ export const REASON_INVALID_END = 'Fecha de fin inválida';
57
+ export const REASON_END_BEFORE_START = 'El fin es anterior al inicio';
58
+
59
+ const MONTHS = [
60
+ 'enero',
61
+ 'febrero',
62
+ 'marzo',
63
+ 'abril',
64
+ 'mayo',
65
+ 'junio',
66
+ 'julio',
67
+ 'agosto',
68
+ 'septiembre',
69
+ 'octubre',
70
+ 'noviembre',
71
+ 'diciembre',
72
+ ];
73
+
74
+ const MONTHS_SHORT = [
75
+ 'ene',
76
+ 'feb',
77
+ 'mar',
78
+ 'abr',
79
+ 'may',
80
+ 'jun',
81
+ 'jul',
82
+ 'ago',
83
+ 'sep',
84
+ 'oct',
85
+ 'nov',
86
+ 'dic',
87
+ ];
88
+
89
+ /** Weekday names Monday-first (the calendar's week start, decided). */
90
+ const WEEKDAYS_SHORT = ['lun', 'mar', 'mié', 'jue', 'vie', 'sáb', 'dom'];
91
+ const WEEKDAYS = ['lunes', 'martes', 'miércoles', 'jueves', 'viernes', 'sábado', 'domingo'];
92
+
93
+ /** Weekday headings of the Monday-first grid, in display order. */
94
+ export const WEEKDAY_HEADINGS: readonly string[] = WEEKDAYS_SHORT;
95
+
96
+ const DAY_PATTERN = /^(\d{4})-(\d{2})-(\d{2})$/;
97
+
98
+ /**
99
+ * `YYYY-MM-DD` → UTC milliseconds at midnight of that civil day.
100
+ *
101
+ * Strict: the string must be exactly three zero-padded parts and name a real
102
+ * calendar day (`2026-02-30` is rejected, not rolled into March). Empty,
103
+ * malformed or non-string input → `null` (the caller decides whether that
104
+ * means "undated" or "invalid").
105
+ */
106
+ export function parseDay(value: unknown): number | null {
107
+ if (typeof value !== 'string') return null;
108
+ const match = DAY_PATTERN.exec(value.trim());
109
+ if (match === null) return null;
110
+ const year = Number(match[1]);
111
+ const month = Number(match[2]);
112
+ const day = Number(match[3]);
113
+ const ms = Date.UTC(year, month - 1, day);
114
+ const back = new Date(ms);
115
+ if (
116
+ back.getUTCFullYear() !== year ||
117
+ back.getUTCMonth() !== month - 1 ||
118
+ back.getUTCDate() !== day
119
+ ) {
120
+ return null;
121
+ }
122
+ return ms;
123
+ }
124
+
125
+ /** UTC milliseconds at midnight → `YYYY-MM-DD` (inverse of `parseDay`). */
126
+ export function formatDay(ms: number): string {
127
+ const date = new Date(ms);
128
+ const month = String(date.getUTCMonth() + 1).padStart(2, '0');
129
+ const day = String(date.getUTCDate()).padStart(2, '0');
130
+ return `${date.getUTCFullYear()}-${month}-${day}`;
131
+ }
132
+
133
+ /**
134
+ * Today as a civil day, in the USER's local calendar date — the local parts
135
+ * are read off `new Date()` and formatted manually, so no timezone shift can
136
+ * sneak in through a round-trip.
137
+ */
138
+ export function todayCivil(): string {
139
+ const now = new Date();
140
+ const month = String(now.getMonth() + 1).padStart(2, '0');
141
+ const day = String(now.getDate()).padStart(2, '0');
142
+ return `${now.getFullYear()}-${month}-${day}`;
143
+ }
144
+
145
+ /**
146
+ * Token inyectable para "hoy" (YYYY-MM-DD). Permite a los tests fijar la
147
+ * fecha del sistema sin depender del reloj real (evita flakiness por mes).
148
+ * Por defecto usa `todayCivil()` (fecha real del sistema).
149
+ */
150
+ export const CALENDAR_TODAY = new InjectionToken<() => string>(
151
+ 'gas.admin.calendarToday',
152
+ { providedIn: 'root', factory: () => todayCivil },
153
+ );
154
+
155
+ /** Day-step on civil days (safe: every `ms` is a UTC midnight). */
156
+ export function addDays(ms: number, days: number): number {
157
+ return ms + days * DAY_MS;
158
+ }
159
+
160
+ /** 0 = Monday … 6 = Sunday (the calendar's Monday-first convention). */
161
+ export function dayOfWeekMon0(ms: number): number {
162
+ return (new Date(ms).getUTCDay() + 6) % 7;
163
+ }
164
+
165
+ /**
166
+ * Move a civil day by whole months, clamping the day-of-month to the target
167
+ * month's length (Jan 31 + 1 month → Feb 28).
168
+ */
169
+ export function shiftMonths(ms: number, months: number): number {
170
+ const date = new Date(ms);
171
+ const target = new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth() + months, 1));
172
+ const lastDay = new Date(
173
+ Date.UTC(target.getUTCFullYear(), target.getUTCMonth() + 1, 0),
174
+ ).getUTCDate();
175
+ return Date.UTC(
176
+ target.getUTCFullYear(),
177
+ target.getUTCMonth(),
178
+ Math.min(date.getUTCDate(), lastDay),
179
+ );
180
+ }
181
+
182
+ /** Monday of the 6-week (42-day) grid that shows the cursor's month. */
183
+ function monthGridStartMs(cursorMs: number): number {
184
+ const date = new Date(cursorMs);
185
+ const firstOfMonth = Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), 1);
186
+ return addDays(firstOfMonth, -dayOfWeekMon0(firstOfMonth));
187
+ }
188
+
189
+ /**
190
+ * The 42 civil days of the month grid (6 Monday-first weeks), so the grid
191
+ * always has the same shape and the de-emphasized edge days are complete.
192
+ */
193
+ export function monthGridDays(cursorDay: string): string[] {
194
+ const cursor = parseDay(cursorDay);
195
+ if (cursor === null) return [];
196
+ const start = monthGridStartMs(cursor);
197
+ return Array.from({ length: 42 }, (_, index) => formatDay(addDays(start, index)));
198
+ }
199
+
200
+ /** The 7 civil days of the Monday-first week containing the cursor. */
201
+ export function weekDays(cursorDay: string): string[] {
202
+ const cursor = parseDay(cursorDay);
203
+ if (cursor === null) return [];
204
+ const start = addDays(cursor, -dayOfWeekMon0(cursor));
205
+ return Array.from({ length: 7 }, (_, index) => formatDay(addDays(start, index)));
206
+ }
207
+
208
+ /** Every civil day of an inclusive range (empty when the range is invalid). */
209
+ export function daysInRange(range: CivilRange): string[] {
210
+ const from = parseDay(range.desde);
211
+ const to = parseDay(range.hasta);
212
+ if (from === null || to === null || to < from) return [];
213
+ const days: string[] = [];
214
+ for (let ms = from; ms <= to; ms = addDays(ms, 1)) {
215
+ days.push(formatDay(ms));
216
+ }
217
+ return days;
218
+ }
219
+
220
+ /**
221
+ * Visible `{desde, hasta}` for a mode + cursor.
222
+ *
223
+ * - `month`: the 6-week grid range (superset of the month) — with the
224
+ * backend-range optimization the fetch already covers the edge weeks.
225
+ * - `week`: the Monday-first week of the cursor.
226
+ * - `day`: the cursor itself.
227
+ * - `agenda`: a fixed 30-day window from the cursor.
228
+ */
229
+ export function visibleRangeFor(mode: CalendarMode, cursorDay: string): CivilRange {
230
+ const cursor = parseDay(cursorDay);
231
+ if (cursor === null) return { desde: '', hasta: '' };
232
+ switch (mode) {
233
+ case 'month': {
234
+ const start = monthGridStartMs(cursor);
235
+ return { desde: formatDay(start), hasta: formatDay(addDays(start, 41)) };
236
+ }
237
+ case 'week': {
238
+ const start = addDays(cursor, -dayOfWeekMon0(cursor));
239
+ return { desde: formatDay(start), hasta: formatDay(addDays(start, 6)) };
240
+ }
241
+ case 'day':
242
+ return { desde: formatDay(cursor), hasta: formatDay(cursor) };
243
+ case 'agenda':
244
+ return { desde: formatDay(cursor), hasta: formatDay(addDays(cursor, 29)) };
245
+ }
246
+ }
247
+
248
+ /** Move the cursor one step of the current mode (agenda steps 30 days). */
249
+ export function shiftCursor(mode: CalendarMode, cursorDay: string, delta: 1 | -1): string {
250
+ const cursor = parseDay(cursorDay) ?? parseDay(todayCivil()) ?? Date.UTC(1970, 0, 1);
251
+ switch (mode) {
252
+ case 'month':
253
+ return formatDay(shiftMonths(cursor, delta));
254
+ case 'week':
255
+ return formatDay(addDays(cursor, 7 * delta));
256
+ case 'day':
257
+ return formatDay(addDays(cursor, delta));
258
+ case 'agenda':
259
+ return formatDay(addDays(cursor, 30 * delta));
260
+ }
261
+ }
262
+
263
+ /** True when both civil days fall in the same year+month. */
264
+ export function sameMonth(a: string, b: string): boolean {
265
+ const msA = parseDay(a);
266
+ const msB = parseDay(b);
267
+ if (msA === null || msB === null) return false;
268
+ const dateA = new Date(msA);
269
+ const dateB = new Date(msB);
270
+ return (
271
+ dateA.getUTCFullYear() === dateB.getUTCFullYear() && dateA.getUTCMonth() === dateB.getUTCMonth()
272
+ );
273
+ }
274
+
275
+ /** Depth-first lookup of a field by key through `group`/`list` nesting. */
276
+ export function findFieldByKey(
277
+ fields: readonly FieldSchema[],
278
+ key: string,
279
+ ): FieldSchema | undefined {
280
+ for (const field of fields) {
281
+ if (field.key === key) return field;
282
+ if (field.type === 'group') {
283
+ const hit = findFieldByKey(field.fields, key);
284
+ if (hit !== undefined) return hit;
285
+ } else if (field.type === 'list') {
286
+ const hit = findFieldByKey(field.itemFields, key);
287
+ if (hit !== undefined) return hit;
288
+ }
289
+ }
290
+ return undefined;
291
+ }
292
+
293
+ /**
294
+ * Pure row → event mapping (R9.8.3): the single place that decides what is a
295
+ * paintable event, what is undated and what is an impossible interval.
296
+ *
297
+ * - Empty/invalid `startField` → `undated` (surfaced, never hidden).
298
+ * - `endField` of type `time` → same civil day as the start (time-of-day
299
+ * within the start day; it never spans days).
300
+ * - Empty `endField` (date) → single-day event on the start.
301
+ * - `end < start` → `invalid` with a visible reason; not painted at all.
302
+ */
303
+ export function mapCalendarRows(
304
+ rows: readonly SourceRow[],
305
+ config: CalendarViewConfig,
306
+ options: { keyField: string; endFieldType?: string },
307
+ ): CalendarMapping {
308
+ const events: CalEvent[] = [];
309
+ const undated: SourceRow[] = [];
310
+ const invalid: CalendarProblem[] = [];
311
+
312
+ for (const row of rows) {
313
+ const startMs = parseDay(row[config.startField]);
314
+ if (startMs === null) {
315
+ undated.push(row);
316
+ continue;
317
+ }
318
+ let endMs = startMs;
319
+ if (config.endField !== undefined && options.endFieldType !== 'time') {
320
+ const rawEnd = row[config.endField];
321
+ const empty = rawEnd === null || rawEnd === undefined || rawEnd === '';
322
+ if (!empty) {
323
+ const parsedEnd = parseDay(rawEnd);
324
+ if (parsedEnd === null) {
325
+ invalid.push({ row, reason: REASON_INVALID_END });
326
+ continue;
327
+ }
328
+ if (parsedEnd < startMs) {
329
+ invalid.push({ row, reason: REASON_END_BEFORE_START });
330
+ continue;
331
+ }
332
+ endMs = parsedEnd;
333
+ }
334
+ }
335
+ const key = String(row[options.keyField] ?? '');
336
+ const title = String(row[config.titleField] ?? '').trim() || key;
337
+ const rawColor = config.colorField !== undefined ? row[config.colorField] : undefined;
338
+ const color = typeof rawColor === 'string' && rawColor !== '' ? rawColor : undefined;
339
+ events.push({ key, title, startDay: formatDay(startMs), endDay: formatDay(endMs), color, row });
340
+ }
341
+
342
+ return { events, undated, invalid };
343
+ }
344
+
345
+ /**
346
+ * Bucket events per civil day inside the visible range.
347
+ *
348
+ * A multi-day event appears under EVERY day it touches; the painted span is
349
+ * clamped to the range (the event keeps its true `startDay`/`endDay` — only
350
+ * the buckets are limited), which also keeps long intervals cheap.
351
+ */
352
+ export function eventsByDay(
353
+ events: readonly CalEvent[],
354
+ range: CivilRange,
355
+ ): Map<string, CalEvent[]> {
356
+ const byDay = new Map<string, CalEvent[]>();
357
+ const from = parseDay(range.desde);
358
+ const to = parseDay(range.hasta);
359
+ if (from === null || to === null || to < from) return byDay;
360
+ for (const event of events) {
361
+ const start = parseDay(event.startDay);
362
+ const end = parseDay(event.endDay);
363
+ if (start === null || end === null) continue;
364
+ const paintFrom = Math.max(start, from);
365
+ const paintTo = Math.min(end, to);
366
+ for (let ms = paintFrom; ms <= paintTo; ms = addDays(ms, 1)) {
367
+ const day = formatDay(ms);
368
+ const bucket = byDay.get(day);
369
+ if (bucket === undefined) byDay.set(day, [event]);
370
+ else bucket.push(event);
371
+ }
372
+ }
373
+ return byDay;
374
+ }
375
+
376
+ /** "12 de octubre de 2026" — civil parts, UTC-based (no TZ shift). */
377
+ export function dayLabel(day: string): string {
378
+ const ms = parseDay(day);
379
+ if (ms === null) return day;
380
+ const date = new Date(ms);
381
+ return `${date.getUTCDate()} de ${MONTHS[date.getUTCMonth()]} de ${date.getUTCFullYear()}`;
382
+ }
383
+
384
+ /** Short weekday of a civil day, Monday-first ("lunes" → "lun"). */
385
+ export function weekdayShort(day: string): string {
386
+ const ms = parseDay(day);
387
+ if (ms === null) return '';
388
+ return WEEKDAYS_SHORT[dayOfWeekMon0(ms)];
389
+ }
390
+
391
+ /** Full weekday of a civil day ("lunes"). */
392
+ export function weekdayFull(day: string): string {
393
+ const ms = parseDay(day);
394
+ if (ms === null) return '';
395
+ return WEEKDAYS[dayOfWeekMon0(ms)];
396
+ }
397
+
398
+ /** "lunes, 12 de octubre de 2026" — agenda/day heading. */
399
+ export function agendaDayLabel(day: string): string {
400
+ const weekday = weekdayFull(day);
401
+ return weekday !== '' ? `${weekday}, ${dayLabel(day)}` : dayLabel(day);
402
+ }
403
+
404
+ /**
405
+ * Header label for the visible range, built from civil parts with a fixed
406
+ * Spanish vocabulary (deterministic regardless of the runtime locale).
407
+ */
408
+ export function rangeLabelFor(mode: CalendarMode, cursorDay: string): string {
409
+ const cursor = parseDay(cursorDay);
410
+ if (cursor === null) return '';
411
+ const date = new Date(cursor);
412
+ if (mode === 'month') {
413
+ return `${MONTHS[date.getUTCMonth()]} de ${date.getUTCFullYear()}`;
414
+ }
415
+ const range = visibleRangeFor(mode, cursorDay);
416
+ const desde = parseDay(range.desde);
417
+ const hasta = parseDay(range.hasta);
418
+ if (desde === null || hasta === null) return '';
419
+ const startDate = new Date(desde);
420
+ const endDate = new Date(hasta);
421
+ const sameYear = startDate.getUTCFullYear() === endDate.getUTCFullYear();
422
+ const left = `${startDate.getUTCDate()} ${MONTHS_SHORT[startDate.getUTCMonth()]}${
423
+ sameYear ? '' : ` ${startDate.getUTCFullYear()}`
424
+ }`;
425
+ return `${left} – ${endDate.getUTCDate()} ${MONTHS_SHORT[endDate.getUTCMonth()]} ${endDate.getUTCFullYear()}`;
426
+ }