@stackcraftmx/calcita 0.47.0 → 0.51.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (488) hide show
  1. package/README.md +173 -12
  2. package/cli/calcita.js +15 -0
  3. package/cli/checkTexts.js +209 -0
  4. package/cli/packageVersions.js +6 -1
  5. package/cli/projectFiles.js +4 -2
  6. package/cli/templates/project/README.md.tpl +21 -1
  7. package/cli/templates/project/eslint.config.js.tpl +27 -0
  8. package/cli/templates/project/src/app/appTexts.js.tpl +2 -1
  9. package/cli/templates/project/src/core/publicPaths.js.tpl +10 -2
  10. package/cli/templates/project/vite.config.js.tpl +8 -1
  11. package/dist/DataTable/AuditTrailDialog.js +3 -2
  12. package/dist/DataTable/AuditTrailDialog.js.map +1 -1
  13. package/dist/DataTable/ColumnFilters/HeaderFilterPopover.js +3 -2
  14. package/dist/DataTable/ColumnFilters/HeaderFilterPopover.js.map +1 -1
  15. package/dist/DataTable/ColumnFilters/MultiSelectColumnFilter.js +3 -2
  16. package/dist/DataTable/ColumnFilters/MultiSelectColumnFilter.js.map +1 -1
  17. package/dist/DataTable/ColumnFilters/SortableFilterHeader.js +3 -2
  18. package/dist/DataTable/ColumnFilters/SortableFilterHeader.js.map +1 -1
  19. package/dist/DataTable/EmptyState.js +3 -2
  20. package/dist/DataTable/EmptyState.js.map +1 -1
  21. package/dist/DataTable/FilterChips.js +3 -2
  22. package/dist/DataTable/FilterChips.js.map +1 -1
  23. package/dist/DataTable/GoToPage.js +3 -2
  24. package/dist/DataTable/GoToPage.js.map +1 -1
  25. package/dist/DataTable/ServerTable.js +95 -28
  26. package/dist/DataTable/ServerTable.js.map +1 -1
  27. package/dist/DataTable/ServerTableFilterDrawer.js +8 -3
  28. package/dist/DataTable/ServerTableFilterDrawer.js.map +1 -1
  29. package/dist/DataTable/StackedCell.js +60 -0
  30. package/dist/DataTable/StackedCell.js.map +1 -0
  31. package/dist/DataTable/TableCardsView.js +88 -0
  32. package/dist/DataTable/TableCardsView.js.map +1 -0
  33. package/dist/DataTable/columnWidths.js +30 -0
  34. package/dist/DataTable/columnWidths.js.map +1 -0
  35. package/dist/DataTable/columns.js +47 -1
  36. package/dist/DataTable/columns.js.map +1 -1
  37. package/dist/DataTable/fixedColumns.js +24 -0
  38. package/dist/DataTable/fixedColumns.js.map +1 -0
  39. package/dist/DataTable/useTableView.js +29 -0
  40. package/dist/DataTable/useTableView.js.map +1 -0
  41. package/dist/access/PermissionMatrix.js +3 -2
  42. package/dist/access/PermissionMatrix.js.map +1 -1
  43. package/dist/account/AccountProvider.js +1 -1
  44. package/dist/account/AccountSecuritySection.js +3 -2
  45. package/dist/account/AccountSecuritySection.js.map +1 -1
  46. package/dist/account/DemoTotpCodeButton.js +3 -2
  47. package/dist/account/DemoTotpCodeButton.js.map +1 -1
  48. package/dist/account/ProfileScreen.js +3 -2
  49. package/dist/account/ProfileScreen.js.map +1 -1
  50. package/dist/account/SignInScreen.js +3 -2
  51. package/dist/account/SignInScreen.js.map +1 -1
  52. package/dist/appShell/AccountMenu.js +3 -2
  53. package/dist/appShell/AccountMenu.js.map +1 -1
  54. package/dist/appShell/AppLayout.js +3 -2
  55. package/dist/appShell/AppLayout.js.map +1 -1
  56. package/dist/appShell/AppearanceSettings.js +3 -2
  57. package/dist/appShell/AppearanceSettings.js.map +1 -1
  58. package/dist/appShell/AuthLayout.js +3 -2
  59. package/dist/appShell/AuthLayout.js.map +1 -1
  60. package/dist/appShell/BarActionButton.js +11 -4
  61. package/dist/appShell/BarActionButton.js.map +1 -1
  62. package/dist/appShell/BarActions.js +3 -2
  63. package/dist/appShell/BarActions.js.map +1 -1
  64. package/dist/appShell/BarCapsule.js +3 -2
  65. package/dist/appShell/BarCapsule.js.map +1 -1
  66. package/dist/appShell/BarSearch.js +3 -2
  67. package/dist/appShell/BarSearch.js.map +1 -1
  68. package/dist/appShell/HeaderTools.js +3 -2
  69. package/dist/appShell/HeaderTools.js.map +1 -1
  70. package/dist/appShell/MobileTabBar.js +3 -2
  71. package/dist/appShell/MobileTabBar.js.map +1 -1
  72. package/dist/appShell/SettingsMenu.js +3 -2
  73. package/dist/appShell/SettingsMenu.js.map +1 -1
  74. package/dist/appShell/SideMenu.js +3 -2
  75. package/dist/appShell/SideMenu.js.map +1 -1
  76. package/dist/appShell/SideMenuEntry.js +3 -2
  77. package/dist/appShell/SideMenuEntry.js.map +1 -1
  78. package/dist/appShell/SubmenuActionsMenu.js +3 -2
  79. package/dist/appShell/SubmenuActionsMenu.js.map +1 -1
  80. package/dist/appShell/TabBarEditor.js +3 -2
  81. package/dist/appShell/TabBarEditor.js.map +1 -1
  82. package/dist/appShell/TopMenu.js +3 -2
  83. package/dist/appShell/TopMenu.js.map +1 -1
  84. package/dist/appShell/Wordmark.js +3 -2
  85. package/dist/appShell/Wordmark.js.map +1 -1
  86. package/dist/auth/PasswordChecklist.js +3 -2
  87. package/dist/auth/PasswordChecklist.js.map +1 -1
  88. package/dist/calendar/EventCalendar.js +3 -2
  89. package/dist/calendar/EventCalendar.js.map +1 -1
  90. package/dist/calendar/EventDetails.js +3 -2
  91. package/dist/calendar/EventDetails.js.map +1 -1
  92. package/dist/datePickers/DateInput.js +28 -22
  93. package/dist/datePickers/DateInput.js.map +1 -1
  94. package/dist/datePickers/DateTimeInput.js +33 -27
  95. package/dist/datePickers/DateTimeInput.js.map +1 -1
  96. package/dist/datePickers/MonthInput.js +27 -21
  97. package/dist/datePickers/MonthInput.js.map +1 -1
  98. package/dist/datePickers/TimeInput.js +26 -20
  99. package/dist/datePickers/TimeInput.js.map +1 -1
  100. package/dist/datePickers/usePickerField.js +5 -4
  101. package/dist/datePickers/usePickerField.js.map +1 -1
  102. package/dist/downloads/DownloadManager.js +3 -2
  103. package/dist/downloads/DownloadManager.js.map +1 -1
  104. package/dist/feedback/ConfirmDialog.js +3 -2
  105. package/dist/feedback/ConfirmDialog.js.map +1 -1
  106. package/dist/feedback/ModalWaiting.js +3 -2
  107. package/dist/feedback/ModalWaiting.js.map +1 -1
  108. package/dist/feedback/NewBuildNotice.js +3 -2
  109. package/dist/feedback/NewBuildNotice.js.map +1 -1
  110. package/dist/filepond/FileDropzone.js +3 -2
  111. package/dist/filepond/FileDropzone.js.map +1 -1
  112. package/dist/forms/FormProblemAlert.js +3 -2
  113. package/dist/forms/FormProblemAlert.js.map +1 -1
  114. package/dist/forms/SubmitButton.js +7 -2
  115. package/dist/forms/SubmitButton.js.map +1 -1
  116. package/dist/forms/auth/SignInForm.js +3 -2
  117. package/dist/forms/auth/SignInForm.js.map +1 -1
  118. package/dist/forms/fieldRules.js +30 -0
  119. package/dist/forms/fieldRules.js.map +1 -0
  120. package/dist/forms/security/SecondStepForm.js +3 -2
  121. package/dist/forms/security/SecondStepForm.js.map +1 -1
  122. package/dist/forms/security/TwoStepVerificationCard.js +3 -2
  123. package/dist/forms/security/TwoStepVerificationCard.js.map +1 -1
  124. package/dist/forms/useValidationText.js +18 -0
  125. package/dist/forms/useValidationText.js.map +1 -0
  126. package/dist/forms/validation.js +35 -31
  127. package/dist/forms/validation.js.map +1 -1
  128. package/dist/forms/validationMessages.js +64 -7
  129. package/dist/forms/validationMessages.js.map +1 -1
  130. package/dist/forms.js +3 -0
  131. package/dist/forms.js.map +1 -1
  132. package/dist/hookForm/FormProblemAlert.js +3 -2
  133. package/dist/hookForm/FormProblemAlert.js.map +1 -1
  134. package/dist/hookForm/SubmitButton.js +7 -2
  135. package/dist/hookForm/SubmitButton.js.map +1 -1
  136. package/dist/inbox/InboxLayout.js +3 -2
  137. package/dist/inbox/InboxLayout.js.map +1 -1
  138. package/dist/inbox/MessageList.js +3 -2
  139. package/dist/inbox/MessageList.js.map +1 -1
  140. package/dist/inbox/MessageView.js +3 -2
  141. package/dist/inbox/MessageView.js.map +1 -1
  142. package/dist/index.js +186 -163
  143. package/dist/index.js.map +1 -1
  144. package/dist/inputs/CatalogInput.js +32 -25
  145. package/dist/inputs/CatalogInput.js.map +1 -1
  146. package/dist/inputs/CheckboxGroupInput.js +8 -5
  147. package/dist/inputs/CheckboxGroupInput.js.map +1 -1
  148. package/dist/inputs/ColorInput.js +7 -4
  149. package/dist/inputs/ColorInput.js.map +1 -1
  150. package/dist/inputs/FieldFrame.js +10 -4
  151. package/dist/inputs/FieldFrame.js.map +1 -1
  152. package/dist/inputs/FormSection.js +1 -1
  153. package/dist/inputs/MaskedInput.js +1 -0
  154. package/dist/inputs/MaskedInput.js.map +1 -1
  155. package/dist/inputs/NumberInput.js +29 -24
  156. package/dist/inputs/NumberInput.js.map +1 -1
  157. package/dist/inputs/RepeatingFields.js +8 -5
  158. package/dist/inputs/RepeatingFields.js.map +1 -1
  159. package/dist/inputs/SelectInput.js +8 -5
  160. package/dist/inputs/SelectInput.js.map +1 -1
  161. package/dist/inputs/TextInput.js +5 -3
  162. package/dist/inputs/TextInput.js.map +1 -1
  163. package/dist/inputs/TransferListInput.js +8 -5
  164. package/dist/inputs/TransferListInput.js.map +1 -1
  165. package/dist/inputs/WizardLayout.js +3 -2
  166. package/dist/inputs/WizardLayout.js.map +1 -1
  167. package/dist/kanban/KanbanBoard.js +3 -2
  168. package/dist/kanban/KanbanBoard.js.map +1 -1
  169. package/dist/legal/CookieNotice.js +3 -2
  170. package/dist/legal/CookieNotice.js.map +1 -1
  171. package/dist/legal/TermsAcceptanceDialog.js +3 -2
  172. package/dist/legal/TermsAcceptanceDialog.js.map +1 -1
  173. package/dist/locales/en.js +24 -0
  174. package/dist/locales/en.js.map +1 -1
  175. package/dist/locales/es.js +24 -0
  176. package/dist/locales/es.js.map +1 -1
  177. package/dist/maps/MapView.js +3 -2
  178. package/dist/maps/MapView.js.map +1 -1
  179. package/dist/mexico/CfdiSummary.js +3 -2
  180. package/dist/mexico/CfdiSummary.js.map +1 -1
  181. package/dist/mexico/EfirmaFields.js +3 -2
  182. package/dist/mexico/EfirmaFields.js.map +1 -1
  183. package/dist/mexico/mexicoIdentifiers.js +5 -0
  184. package/dist/mexico/mexicoIdentifiers.js.map +1 -1
  185. package/dist/mexico/mexicoRules.js +9 -4
  186. package/dist/mexico/mexicoRules.js.map +1 -1
  187. package/dist/mexico.js +4 -2
  188. package/dist/pwa/InstallAppSetting.js +3 -2
  189. package/dist/pwa/InstallAppSetting.js.map +1 -1
  190. package/dist/pwa/InstallInstructionsDialog.js +3 -2
  191. package/dist/pwa/InstallInstructionsDialog.js.map +1 -1
  192. package/dist/pwa/InstallPromptBanner.js +3 -2
  193. package/dist/pwa/InstallPromptBanner.js.map +1 -1
  194. package/dist/react-hook-form.js +3 -0
  195. package/dist/react-hook-form.js.map +1 -1
  196. package/dist/richText/RichTextEditor.js +7 -4
  197. package/dist/richText/RichTextEditor.js.map +1 -1
  198. package/dist/richText/RichTextView.js +3 -2
  199. package/dist/richText/RichTextView.js.map +1 -1
  200. package/dist/security/ActivityLog.js +3 -2
  201. package/dist/security/ActivityLog.js.map +1 -1
  202. package/dist/security/RecoveryCodesDialog.js +3 -2
  203. package/dist/security/RecoveryCodesDialog.js.map +1 -1
  204. package/dist/security/SessionsCard.js +3 -2
  205. package/dist/security/SessionsCard.js.map +1 -1
  206. package/dist/table.js +21 -2
  207. package/dist/table.js.map +1 -1
  208. package/dist/theme/themePieces.js +70 -4
  209. package/dist/theme/themePieces.js.map +1 -1
  210. package/dist/toolkit/ToolkitProvider.js +8 -1
  211. package/dist/toolkit/ToolkitProvider.js.map +1 -1
  212. package/dist/toolkit/browserNavigation.js +19 -4
  213. package/dist/toolkit/browserNavigation.js.map +1 -1
  214. package/dist/toolkit/combineTexts.js +32 -0
  215. package/dist/toolkit/combineTexts.js.map +1 -0
  216. package/dist/toolkit/hashNavigation.js +17 -3
  217. package/dist/toolkit/hashNavigation.js.map +1 -1
  218. package/dist/toolkit/navigationPaths.js +15 -0
  219. package/dist/toolkit/navigationPaths.js.map +1 -1
  220. package/dist/toolkit/pathIndex.js +66 -0
  221. package/dist/toolkit/pathIndex.js.map +1 -0
  222. package/dist/toolkit/toolkitSettings.js +19 -1
  223. package/dist/toolkit/toolkitSettings.js.map +1 -1
  224. package/dist/types/DataTable/AuditTrailDialog.d.ts +6 -17
  225. package/dist/types/DataTable/ColumnFilters/HeaderFilterPopover.d.ts +6 -5
  226. package/dist/types/DataTable/ColumnFilters/MultiSelectColumnFilter.d.ts +6 -9
  227. package/dist/types/DataTable/ColumnFilters/SortableFilterHeader.d.ts +6 -14
  228. package/dist/types/DataTable/EmptyState.d.ts +6 -9
  229. package/dist/types/DataTable/FilterChips.d.ts +6 -11
  230. package/dist/types/DataTable/GoToPage.d.ts +6 -9
  231. package/dist/types/DataTable/ServerTable.d.ts +16 -80
  232. package/dist/types/DataTable/ServerTableFilterDrawer.d.ts +6 -13
  233. package/dist/types/DataTable/StackedCell.d.ts +12 -0
  234. package/dist/types/DataTable/TableCardsView.d.ts +27 -0
  235. package/dist/types/DataTable/columnWidths.d.ts +21 -0
  236. package/dist/types/DataTable/columns.d.ts +111 -0
  237. package/dist/types/DataTable/fixedColumns.d.ts +29 -0
  238. package/dist/types/DataTable/index.d.ts +6 -1
  239. package/dist/types/DataTable/useTableView.d.ts +22 -0
  240. package/dist/types/access/PermissionMatrix.d.ts +6 -10
  241. package/dist/types/account/AccountSecuritySection.d.ts +6 -7
  242. package/dist/types/account/DemoTotpCodeButton.d.ts +6 -5
  243. package/dist/types/account/ProfileScreen.d.ts +6 -18
  244. package/dist/types/account/SignInScreen.d.ts +6 -13
  245. package/dist/types/appShell/AccountMenu.d.ts +6 -11
  246. package/dist/types/appShell/AppLayout.d.ts +3 -40
  247. package/dist/types/appShell/AppearanceSettings.d.ts +6 -12
  248. package/dist/types/appShell/AuthLayout.d.ts +3 -11
  249. package/dist/types/appShell/BarActionButton.d.ts +6 -10
  250. package/dist/types/appShell/BarActions.d.ts +6 -15
  251. package/dist/types/appShell/BarCapsule.d.ts +6 -9
  252. package/dist/types/appShell/BarSearch.d.ts +6 -15
  253. package/dist/types/appShell/HeaderTools.d.ts +6 -16
  254. package/dist/types/appShell/MobileTabBar.d.ts +6 -13
  255. package/dist/types/appShell/SettingsMenu.d.ts +6 -10
  256. package/dist/types/appShell/SideMenu.d.ts +6 -20
  257. package/dist/types/appShell/SideMenuEntry.d.ts +6 -11
  258. package/dist/types/appShell/SubmenuActionsMenu.d.ts +6 -12
  259. package/dist/types/appShell/TabBarEditor.d.ts +6 -9
  260. package/dist/types/appShell/TopMenu.d.ts +6 -5
  261. package/dist/types/appShell/Wordmark.d.ts +6 -7
  262. package/dist/types/auth/PasswordChecklist.d.ts +6 -9
  263. package/dist/types/calendar/EventCalendar.d.ts +6 -23
  264. package/dist/types/calendar/EventDetails.d.ts +6 -10
  265. package/dist/types/datePickers/DateInput.d.ts +7 -22
  266. package/dist/types/datePickers/DateTimeInput.d.ts +7 -27
  267. package/dist/types/datePickers/MonthInput.d.ts +7 -21
  268. package/dist/types/datePickers/TimeInput.d.ts +7 -21
  269. package/dist/types/datePickers/usePickerField.d.ts +5 -1
  270. package/dist/types/downloads/DownloadManager.d.ts +6 -6
  271. package/dist/types/feedback/ConfirmDialog.d.ts +6 -18
  272. package/dist/types/feedback/ModalWaiting.d.ts +6 -9
  273. package/dist/types/feedback/NewBuildNotice.d.ts +6 -10
  274. package/dist/types/filepond/FileDropzone.d.ts +6 -29
  275. package/dist/types/forms/FormProblemAlert.d.ts +6 -5
  276. package/dist/types/forms/SubmitButton.d.ts +6 -6
  277. package/dist/types/forms/auth/SignInForm.d.ts +6 -11
  278. package/dist/types/forms/fieldRules.d.ts +44 -0
  279. package/dist/types/forms/index.d.ts +1 -0
  280. package/dist/types/forms/security/SecondStepForm.d.ts +6 -14
  281. package/dist/types/forms/security/TwoStepVerificationCard.d.ts +6 -21
  282. package/dist/types/forms/useValidationText.d.ts +12 -0
  283. package/dist/types/forms/validation.d.ts +117 -174
  284. package/dist/types/forms/validationMessages.d.ts +54 -6
  285. package/dist/types/forms.d.ts +1 -1
  286. package/dist/types/hookForm/FormProblemAlert.d.ts +6 -5
  287. package/dist/types/hookForm/SubmitButton.d.ts +6 -13
  288. package/dist/types/inbox/InboxLayout.d.ts +6 -17
  289. package/dist/types/inbox/MessageList.d.ts +6 -18
  290. package/dist/types/inbox/MessageView.d.ts +6 -14
  291. package/dist/types/index.d.ts +8 -1
  292. package/dist/types/inputs/CatalogInput.d.ts +7 -24
  293. package/dist/types/inputs/CheckboxGroupInput.d.ts +7 -18
  294. package/dist/types/inputs/ColorInput.d.ts +7 -16
  295. package/dist/types/inputs/FieldFrame.d.ts +6 -10
  296. package/dist/types/inputs/MaskedInput.d.ts +3 -0
  297. package/dist/types/inputs/NumberInput.d.ts +7 -20
  298. package/dist/types/inputs/RepeatingFields.d.ts +7 -28
  299. package/dist/types/inputs/SelectInput.d.ts +7 -20
  300. package/dist/types/inputs/TextInput.d.ts +3 -0
  301. package/dist/types/inputs/TransferListInput.d.ts +7 -20
  302. package/dist/types/inputs/WizardLayout.d.ts +6 -19
  303. package/dist/types/kanban/KanbanBoard.d.ts +6 -25
  304. package/dist/types/legal/CookieNotice.d.ts +6 -16
  305. package/dist/types/legal/TermsAcceptanceDialog.d.ts +6 -18
  306. package/dist/types/locales/en.d.ts +24 -0
  307. package/dist/types/locales/es.d.ts +24 -0
  308. package/dist/types/maps/MapView.d.ts +6 -17
  309. package/dist/types/mexico/CfdiSummary.d.ts +6 -11
  310. package/dist/types/mexico/EfirmaFields.d.ts +6 -16
  311. package/dist/types/mexico/mexicoIdentifiers.d.ts +7 -0
  312. package/dist/types/mexico/mexicoRules.d.ts +19 -3
  313. package/dist/types/mexico.d.ts +2 -2
  314. package/dist/types/pwa/InstallAppSetting.d.ts +6 -6
  315. package/dist/types/pwa/InstallInstructionsDialog.d.ts +6 -9
  316. package/dist/types/pwa/InstallPromptBanner.d.ts +6 -11
  317. package/dist/types/react-hook-form.d.ts +1 -0
  318. package/dist/types/richText/RichTextEditor.d.ts +7 -22
  319. package/dist/types/richText/RichTextView.d.ts +6 -9
  320. package/dist/types/security/ActivityLog.d.ts +6 -9
  321. package/dist/types/security/RecoveryCodesDialog.d.ts +6 -11
  322. package/dist/types/security/SessionsCard.d.ts +6 -11
  323. package/dist/types/table.d.ts +3 -1
  324. package/dist/types/theme/themePieces.d.ts +55 -3
  325. package/dist/types/toolkit/ToolkitProvider.d.ts +13 -1
  326. package/dist/types/toolkit/browserNavigation.d.ts +7 -3
  327. package/dist/types/toolkit/combineTexts.d.ts +6 -0
  328. package/dist/types/toolkit/hashNavigation.d.ts +4 -2
  329. package/dist/types/toolkit/navigationPaths.d.ts +35 -0
  330. package/dist/types/toolkit/pathIndex.d.ts +27 -0
  331. package/dist/types/toolkit/toolkitSettings.d.ts +7 -4
  332. package/dist/types/ui/actions/ActionsMenu.d.ts +9 -11
  333. package/dist/types/ui/actions/CopyButton.d.ts +6 -12
  334. package/dist/types/ui/actions/DownloadMenu.d.ts +6 -29
  335. package/dist/types/ui/actions/SecretField.d.ts +6 -11
  336. package/dist/types/ui/actions/SelectionActions.d.ts +6 -13
  337. package/dist/types/ui/cards/RecordCard.d.ts +6 -31
  338. package/dist/types/ui/cards/RecordCardSkeleton.d.ts +6 -11
  339. package/dist/types/ui/countdown/Countdown.d.ts +6 -15
  340. package/dist/types/ui/documents/PdfViewerDialog.d.ts +6 -13
  341. package/dist/types/ui/filters/DateRangeFilter.d.ts +6 -10
  342. package/dist/types/ui/filters/FilterDrawer.d.ts +6 -17
  343. package/dist/types/ui/filters/PeriodRangeSelector.d.ts +6 -13
  344. package/dist/types/ui/filters/QuickFilters.d.ts +6 -12
  345. package/dist/types/ui/help/HelpButton.d.ts +6 -10
  346. package/dist/types/ui/help/HelpCarouselDialog.d.ts +6 -14
  347. package/dist/types/ui/labels/MarkedText.d.ts +10 -0
  348. package/dist/types/ui/labels/Tag.d.ts +6 -12
  349. package/dist/types/ui/labels/markedTextPieces.d.ts +22 -0
  350. package/dist/types/ui/layout/CollapsibleSection.d.ts +6 -12
  351. package/dist/types/ui/layout/ContentDialog.d.ts +6 -10
  352. package/dist/types/ui/layout/DefinitionList.d.ts +6 -9
  353. package/dist/types/ui/layout/DetailHeader.d.ts +6 -10
  354. package/dist/types/ui/layout/ErrorPage.d.ts +6 -17
  355. package/dist/types/ui/layout/FullPageLoader.d.ts +6 -6
  356. package/dist/types/ui/layout/GlassPanel.d.ts +6 -8
  357. package/dist/types/ui/layout/PageHeader.d.ts +6 -10
  358. package/dist/types/ui/layout/PageHeading.d.ts +6 -11
  359. package/dist/types/ui/layout/ProfileHeader.d.ts +6 -11
  360. package/dist/types/ui/layout/ScrollableRow.d.ts +6 -13
  361. package/dist/types/ui/layout/SectionCard.d.ts +6 -8
  362. package/dist/types/ui/metrics/BarList.d.ts +6 -12
  363. package/dist/types/ui/metrics/CalendarHeatmap.d.ts +6 -19
  364. package/dist/types/ui/metrics/ChartTooltip.d.ts +6 -6
  365. package/dist/types/ui/metrics/ColumnChart.d.ts +6 -25
  366. package/dist/types/ui/metrics/LineChart.d.ts +6 -20
  367. package/dist/types/ui/metrics/MetricCard.d.ts +6 -17
  368. package/dist/types/ui/metrics/TableToggle.d.ts +6 -6
  369. package/dist/types/ui/metrics/chartParts.d.ts +15 -30
  370. package/dist/types/ui/navigation/BackButton.d.ts +6 -9
  371. package/dist/types/ui/navigation/ColorSchemeToggle.d.ts +6 -9
  372. package/dist/types/ui/navigation/FontSizeToggle.d.ts +6 -8
  373. package/dist/types/ui/navigation/LanguageToggle.d.ts +6 -8
  374. package/dist/types/ui/navigation/PageBreadcrumbs.d.ts +6 -7
  375. package/dist/types/ui/navigation/RouteTabs.d.ts +7 -12
  376. package/dist/types/ui/timeline/GroupedTimeline.d.ts +6 -23
  377. package/dist/types/upload/AttachmentsInput.d.ts +11 -1
  378. package/dist/types/upload/FileDropzone.d.ts +6 -21
  379. package/dist/types/upload/FileInput.d.ts +7 -24
  380. package/dist/types/upload/FileUploadInput.d.ts +7 -31
  381. package/dist/types/upload/ImageInput.d.ts +7 -25
  382. package/dist/types/upload/TemplateDownloadButton.d.ts +6 -18
  383. package/dist/ui/actions/ActionsMenu.js +14 -5
  384. package/dist/ui/actions/ActionsMenu.js.map +1 -1
  385. package/dist/ui/actions/CopyButton.js +8 -3
  386. package/dist/ui/actions/CopyButton.js.map +1 -1
  387. package/dist/ui/actions/DownloadMenu.js +3 -2
  388. package/dist/ui/actions/DownloadMenu.js.map +1 -1
  389. package/dist/ui/actions/SecretField.js +8 -3
  390. package/dist/ui/actions/SecretField.js.map +1 -1
  391. package/dist/ui/actions/SelectionActions.js +3 -2
  392. package/dist/ui/actions/SelectionActions.js.map +1 -1
  393. package/dist/ui/cards/RecordCard.js +4 -3
  394. package/dist/ui/cards/RecordCard.js.map +1 -1
  395. package/dist/ui/cards/RecordCardSkeleton.js +8 -3
  396. package/dist/ui/cards/RecordCardSkeleton.js.map +1 -1
  397. package/dist/ui/countdown/Countdown.js +3 -2
  398. package/dist/ui/countdown/Countdown.js.map +1 -1
  399. package/dist/ui/documents/PdfViewerDialog.js +3 -2
  400. package/dist/ui/documents/PdfViewerDialog.js.map +1 -1
  401. package/dist/ui/filters/DateRangeFilter.js +3 -2
  402. package/dist/ui/filters/DateRangeFilter.js.map +1 -1
  403. package/dist/ui/filters/FilterDrawer.js +3 -2
  404. package/dist/ui/filters/FilterDrawer.js.map +1 -1
  405. package/dist/ui/filters/PeriodRangeSelector.js +3 -2
  406. package/dist/ui/filters/PeriodRangeSelector.js.map +1 -1
  407. package/dist/ui/filters/QuickFilters.js +3 -2
  408. package/dist/ui/filters/QuickFilters.js.map +1 -1
  409. package/dist/ui/help/HelpButton.js +8 -3
  410. package/dist/ui/help/HelpButton.js.map +1 -1
  411. package/dist/ui/help/HelpCarouselDialog.js +3 -2
  412. package/dist/ui/help/HelpCarouselDialog.js.map +1 -1
  413. package/dist/ui/labels/MarkedText.js +31 -0
  414. package/dist/ui/labels/MarkedText.js.map +1 -0
  415. package/dist/ui/labels/Tag.js +3 -2
  416. package/dist/ui/labels/Tag.js.map +1 -1
  417. package/dist/ui/labels/markedTextPieces.js +64 -0
  418. package/dist/ui/labels/markedTextPieces.js.map +1 -0
  419. package/dist/ui/layout/CollapsibleSection.js +3 -2
  420. package/dist/ui/layout/CollapsibleSection.js.map +1 -1
  421. package/dist/ui/layout/ContentDialog.js +3 -2
  422. package/dist/ui/layout/ContentDialog.js.map +1 -1
  423. package/dist/ui/layout/DefinitionList.js +3 -2
  424. package/dist/ui/layout/DefinitionList.js.map +1 -1
  425. package/dist/ui/layout/DetailHeader.js +3 -2
  426. package/dist/ui/layout/DetailHeader.js.map +1 -1
  427. package/dist/ui/layout/ErrorPage.js +3 -2
  428. package/dist/ui/layout/ErrorPage.js.map +1 -1
  429. package/dist/ui/layout/FullPageLoader.js +3 -2
  430. package/dist/ui/layout/FullPageLoader.js.map +1 -1
  431. package/dist/ui/layout/GlassPanel.js +3 -2
  432. package/dist/ui/layout/GlassPanel.js.map +1 -1
  433. package/dist/ui/layout/PageHeader.js +3 -2
  434. package/dist/ui/layout/PageHeader.js.map +1 -1
  435. package/dist/ui/layout/PageHeading.js +3 -2
  436. package/dist/ui/layout/PageHeading.js.map +1 -1
  437. package/dist/ui/layout/ProfileHeader.js +3 -2
  438. package/dist/ui/layout/ProfileHeader.js.map +1 -1
  439. package/dist/ui/layout/ScrollableRow.js +3 -2
  440. package/dist/ui/layout/ScrollableRow.js.map +1 -1
  441. package/dist/ui/layout/SectionCard.js +3 -2
  442. package/dist/ui/layout/SectionCard.js.map +1 -1
  443. package/dist/ui/metrics/BarList.js +3 -2
  444. package/dist/ui/metrics/BarList.js.map +1 -1
  445. package/dist/ui/metrics/CalendarHeatmap.js +3 -2
  446. package/dist/ui/metrics/CalendarHeatmap.js.map +1 -1
  447. package/dist/ui/metrics/ChartTooltip.js +3 -2
  448. package/dist/ui/metrics/ChartTooltip.js.map +1 -1
  449. package/dist/ui/metrics/ColumnChart.js +3 -2
  450. package/dist/ui/metrics/ColumnChart.js.map +1 -1
  451. package/dist/ui/metrics/LineChart.js +3 -2
  452. package/dist/ui/metrics/LineChart.js.map +1 -1
  453. package/dist/ui/metrics/MetricCard.js +3 -2
  454. package/dist/ui/metrics/MetricCard.js.map +1 -1
  455. package/dist/ui/metrics/TableToggle.js +3 -2
  456. package/dist/ui/metrics/TableToggle.js.map +1 -1
  457. package/dist/ui/metrics/chartParts.js +7 -4
  458. package/dist/ui/metrics/chartParts.js.map +1 -1
  459. package/dist/ui/navigation/BackButton.js +7 -2
  460. package/dist/ui/navigation/BackButton.js.map +1 -1
  461. package/dist/ui/navigation/ColorSchemeToggle.js +3 -2
  462. package/dist/ui/navigation/ColorSchemeToggle.js.map +1 -1
  463. package/dist/ui/navigation/FontSizeToggle.js +3 -2
  464. package/dist/ui/navigation/FontSizeToggle.js.map +1 -1
  465. package/dist/ui/navigation/LanguageToggle.js +3 -2
  466. package/dist/ui/navigation/LanguageToggle.js.map +1 -1
  467. package/dist/ui/navigation/PageBreadcrumbs.js +3 -2
  468. package/dist/ui/navigation/PageBreadcrumbs.js.map +1 -1
  469. package/dist/ui/navigation/RouteTabs.js +8 -4
  470. package/dist/ui/navigation/RouteTabs.js.map +1 -1
  471. package/dist/ui/timeline/GroupedTimeline.js +3 -2
  472. package/dist/ui/timeline/GroupedTimeline.js.map +1 -1
  473. package/dist/upload/AttachmentsInput.js +9 -6
  474. package/dist/upload/AttachmentsInput.js.map +1 -1
  475. package/dist/upload/FileChip.js +2 -1
  476. package/dist/upload/FileChip.js.map +1 -1
  477. package/dist/upload/FileDropzone.js +5 -4
  478. package/dist/upload/FileDropzone.js.map +1 -1
  479. package/dist/upload/FileInput.js +9 -6
  480. package/dist/upload/FileInput.js.map +1 -1
  481. package/dist/upload/FileUploadInput.js +9 -6
  482. package/dist/upload/FileUploadInput.js.map +1 -1
  483. package/dist/upload/ImageInput.js +8 -5
  484. package/dist/upload/ImageInput.js.map +1 -1
  485. package/dist/upload/TemplateDownloadButton.js +3 -2
  486. package/dist/upload/TemplateDownloadButton.js.map +1 -1
  487. package/package.json +1 -1
  488. package/cli/templates/project/src/app/combineTexts.js.tpl +0 -31
@@ -6,12 +6,12 @@ import Stack from "@mui/material/Stack";
6
6
  import Typography from "@mui/material/Typography";
7
7
  import ScienceOutlinedIcon from "@mui/icons-material/ScienceOutlined";
8
8
  import { useToolkitTranslation } from "../toolkit/useToolkitTranslation.js";
9
- import { piecePart, usePieceProps } from "../theme/themePieces.js";
9
+ import { piecePart, withPieceSlots, usePieceProps } from "../theme/themePieces.js";
10
10
  import { warnUnknownProps } from "../toolkit/unknownProps.js";
11
11
  const THEME_NAME = "CalcitaDemoTotpCode";
12
12
  const TotpRoot = piecePart(THEME_NAME, "Root", Stack);
13
13
  const TotpCode = piecePart(THEME_NAME, "Code", Typography);
14
- function DemoTotpCodeButton(props) {
14
+ function DemoTotpCodeButtonContent(props) {
15
15
  const { loadCode, ...unknownProps } = usePieceProps(props, THEME_NAME);
16
16
  warnUnknownProps(THEME_NAME, unknownProps);
17
17
  const { t } = useToolkitTranslation("account");
@@ -27,6 +27,7 @@ function DemoTotpCodeButton(props) {
27
27
  /* @__PURE__ */ jsx(TotpCode, { variant: "caption", color: "text.secondary", ownSx: { textAlign: "center" }, children: t("demo.totpCodeHelp") })
28
28
  ] });
29
29
  }
30
+ const DemoTotpCodeButton = withPieceSlots(DemoTotpCodeButtonContent, THEME_NAME);
30
31
  export {
31
32
  DemoTotpCodeButton as default
32
33
  };
@@ -1 +1 @@
1
- {"version":3,"file":"DemoTotpCodeButton.js","sources":["../../src/account/DemoTotpCodeButton.jsx"],"sourcesContent":["// El atajo de la DEMOSTRACIÓN para la app autenticadora: llena el campo «code» del formulario con el código que enseñaría\n// la app ahorita. Para quien prueba sin la app en su teléfono (y para las pruebas automáticas, que no escanean QR). Solo\n// sale cuando el conector trae demoTotpCode: con un backend de verdad no existe (el código solo lo conoce la app).\n//\n// Va dentro del formulario de formik (abajo del segundo paso o en el diálogo de activar la app).\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaDemoTotpCode con defaultProps y\n// styleOverrides de sus partes: root, code.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useFormikContext} from 'formik';\nimport Button from '@mui/material/Button';\nimport Stack from '@mui/material/Stack';\nimport Typography from '@mui/material/Typography';\nimport ScienceOutlinedIcon from '@mui/icons-material/ScienceOutlined';\n\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport {piecePart, usePieceProps} from '@/theme/themePieces.js';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaDemoTotpCode)\nconst THEME_NAME = 'CalcitaDemoTotpCode';\nconst TotpRoot = piecePart(THEME_NAME, 'Root', Stack);\nconst TotpCode = piecePart(THEME_NAME, 'Code', Typography);\n\n/**\n * @param {{loadCode: () => Promise<string|null>}} props\n */\nexport default function DemoTotpCodeButton(props) {\n // lo que el proyecto puso en su tema (components.CalcitaDemoTotpCode.defaultProps) y encima lo que llega aquí\n const {loadCode, ...unknownProps} = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n const {t} = useToolkitTranslation('account');\n const {setFieldValue} = useFormikContext();\n\n const fillCode = async () => {\n const code = await loadCode();\n if (code) {\n setFieldValue('code', code);\n }\n };\n\n return (\n <TotpRoot spacing={0.5} ownSx={{alignItems: 'center'}}>\n <Button size=\"small\" startIcon={<ScienceOutlinedIcon />} onClick={fillCode}>{t('demo.totpCode')}</Button>\n <TotpCode variant=\"caption\" color=\"text.secondary\" ownSx={{textAlign: 'center'}}>{t('demo.totpCodeHelp')}</TotpCode>\n </TotpRoot>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;AAqBA,MAAM,aAAa;AACnB,MAAM,WAAW,UAAU,YAAY,QAAQ,KAAK;AACpD,MAAM,WAAW,UAAU,YAAY,QAAQ,UAAU;AAKzD,SAAwB,mBAAmB,OAAO;AAE9C,QAAM,EAAC,UAAU,GAAG,iBAAgB,cAAc,OAAO,UAAU;AACnE,mBAAiB,YAAY,YAAY;AACzC,QAAM,EAAC,EAAA,IAAK,sBAAsB,SAAS;AAC3C,QAAM,EAAC,cAAA,IAAiB,iBAAA;AAExB,QAAM,WAAW,YAAY;AACzB,UAAM,OAAO,MAAM,SAAA;AACnB,QAAI,MAAM;AACN,oBAAc,QAAQ,IAAI;AAAA,IAC9B;AAAA,EACJ;AAEA,SACI,qBAAC,YAAS,SAAS,KAAK,OAAO,EAAC,YAAY,YACxC,UAAA;AAAA,IAAA,oBAAC,QAAA,EAAO,MAAK,SAAQ,WAAW,oBAAC,qBAAA,CAAA,CAAoB,GAAI,SAAS,UAAW,UAAA,EAAE,eAAe,GAAE;AAAA,IAChG,oBAAC,UAAA,EAAS,SAAQ,WAAU,OAAM,kBAAiB,OAAO,EAAC,WAAW,SAAA,GAAY,UAAA,EAAE,mBAAmB,EAAA,CAAE;AAAA,EAAA,GAC7G;AAER;"}
1
+ {"version":3,"file":"DemoTotpCodeButton.js","sources":["../../src/account/DemoTotpCodeButton.jsx"],"sourcesContent":["// El atajo de la DEMOSTRACIÓN para la app autenticadora: llena el campo «code» del formulario con el código que enseñaría\n// la app ahorita. Para quien prueba sin la app en su teléfono (y para las pruebas automáticas, que no escanean QR). Solo\n// sale cuando el conector trae demoTotpCode: con un backend de verdad no existe (el código solo lo conoce la app).\n//\n// Va dentro del formulario de formik (abajo del segundo paso o en el diálogo de activar la app).\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaDemoTotpCode con defaultProps y\n// styleOverrides de sus partes: root, code.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useFormikContext} from 'formik';\nimport Button from '@mui/material/Button';\nimport Stack from '@mui/material/Stack';\nimport Typography from '@mui/material/Typography';\nimport ScienceOutlinedIcon from '@mui/icons-material/ScienceOutlined';\n\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport {piecePart, usePieceProps, withPieceSlots} from '@/theme/themePieces.js';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaDemoTotpCode)\nconst THEME_NAME = 'CalcitaDemoTotpCode';\nconst TotpRoot = piecePart(THEME_NAME, 'Root', Stack);\nconst TotpCode = piecePart(THEME_NAME, 'Code', Typography);\n\n/**\n * @param {{loadCode: () => Promise<string|null>}} props\n */\nfunction DemoTotpCodeButtonContent(props) {\n // lo que el proyecto puso en su tema (components.CalcitaDemoTotpCode.defaultProps) y encima lo que llega aquí\n const {loadCode, ...unknownProps} = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n const {t} = useToolkitTranslation('account');\n const {setFieldValue} = useFormikContext();\n\n const fillCode = async () => {\n const code = await loadCode();\n if (code) {\n setFieldValue('code', code);\n }\n };\n\n return (\n <TotpRoot spacing={0.5} ownSx={{alignItems: 'center'}}>\n <Button size=\"small\" startIcon={<ScienceOutlinedIcon />} onClick={fillCode}>{t('demo.totpCode')}</Button>\n <TotpCode variant=\"caption\" color=\"text.secondary\" ownSx={{textAlign: 'center'}}>{t('demo.totpCodeHelp')}</TotpCode>\n </TotpRoot>\n );\n}\n\n// lo que se exporta: la pieza con slots y slotProps para cambiar sus partes (themePieces.js)\nconst DemoTotpCodeButton = withPieceSlots(DemoTotpCodeButtonContent, THEME_NAME);\nexport default DemoTotpCodeButton;\n"],"names":[],"mappings":";;;;;;;;;;AAqBA,MAAM,aAAa;AACnB,MAAM,WAAW,UAAU,YAAY,QAAQ,KAAK;AACpD,MAAM,WAAW,UAAU,YAAY,QAAQ,UAAU;AAKzD,SAAS,0BAA0B,OAAO;AAEtC,QAAM,EAAC,UAAU,GAAG,iBAAgB,cAAc,OAAO,UAAU;AACnE,mBAAiB,YAAY,YAAY;AACzC,QAAM,EAAC,EAAA,IAAK,sBAAsB,SAAS;AAC3C,QAAM,EAAC,cAAA,IAAiB,iBAAA;AAExB,QAAM,WAAW,YAAY;AACzB,UAAM,OAAO,MAAM,SAAA;AACnB,QAAI,MAAM;AACN,oBAAc,QAAQ,IAAI;AAAA,IAC9B;AAAA,EACJ;AAEA,SACI,qBAAC,YAAS,SAAS,KAAK,OAAO,EAAC,YAAY,YACxC,UAAA;AAAA,IAAA,oBAAC,QAAA,EAAO,MAAK,SAAQ,WAAW,oBAAC,qBAAA,CAAA,CAAoB,GAAI,SAAS,UAAW,UAAA,EAAE,eAAe,GAAE;AAAA,IAChG,oBAAC,UAAA,EAAS,SAAQ,WAAU,OAAM,kBAAiB,OAAO,EAAC,WAAW,SAAA,GAAY,UAAA,EAAE,mBAAmB,EAAA,CAAE;AAAA,EAAA,GAC7G;AAER;AAGA,MAAM,qBAAqB,eAAe,2BAA2B,UAAU;"}
@@ -20,7 +20,7 @@ import { useToolkitNavigation } from "../toolkit/toolkitContext.js";
20
20
  import { useToolkitTranslation } from "../toolkit/useToolkitTranslation.js";
21
21
  import ProfileHeader from "../ui/layout/ProfileHeader.js";
22
22
  import SectionCard from "../ui/layout/SectionCard.js";
23
- import { piecePart, usePieceProps } from "../theme/themePieces.js";
23
+ import { piecePart, withPieceSlots, usePieceProps } from "../theme/themePieces.js";
24
24
  import { warnUnknownProps } from "../toolkit/unknownProps.js";
25
25
  const THEME_NAME = "CalcitaProfileScreen";
26
26
  const ProfileScreenSectionTitle = piecePart(THEME_NAME, "SectionTitle", Typography);
@@ -74,7 +74,7 @@ function ProfileDataSection({ extraFields, onProfileSaved, texts }) {
74
74
  ] }) }) })
75
75
  ] });
76
76
  }
77
- function ProfileScreen(props) {
77
+ function ProfileScreenContent(props) {
78
78
  const {
79
79
  showColorScheme = true,
80
80
  extraFields,
@@ -136,6 +136,7 @@ function ProfileScreen(props) {
136
136
  activeExtraTab?.content
137
137
  ] });
138
138
  }
139
+ const ProfileScreen = withPieceSlots(ProfileScreenContent, THEME_NAME);
139
140
  export {
140
141
  PROFILE_TAB,
141
142
  ProfileScreen as default
@@ -1 +1 @@
1
- {"version":3,"file":"ProfileScreen.js","sources":["../../src/account/ProfileScreen.jsx"],"sourcesContent":["// Mi perfil, completo: quién está dentro (ProfileHeader con sus perfiles como chips) y tres pestañas:\n// - Sus datos: nombre y teléfono (el correo se ve pero no se cambia aquí); al guardar se vuelve a leer la sesión, así la\n// barra y el menú de la cuenta ya dicen el nombre nuevo;\n// - Seguridad: AccountSecuritySection (contraseña, dos pasos, sesiones y bitácora);\n// - Preferencias: AppearanceSettings (tamaño de letra, idioma y modo de color).\n// La pestaña abierta va en la dirección (?tab=): se puede compartir o recargar sin perderla. Lo del servidor sale del\n// conector de la cuenta.\n//\n// Se extiende sin tocar el framework (cada proyecto tiene su perfil «especial»):\n// - extraFields: campos propios en «Sus datos» (el área, el número de empleado…), con su valor de inicio sacado del usuario\n// de la sesión, sus reglas de yup y sus campos. Al guardar viajan a connector.updateProfile junto con name y phone: un\n// backend que ya existe recibe lo suyo con sus nombres;\n// - extraTabs: pestañas propias después de las de la casa (facturación, notificaciones…); hiddenTabs esconde las de la casa;\n// - eventos: onTabChange y onProfileSaved (lo guardado y lo que contestó el servidor);\n// - texts: cualquier texto, con la forma de `account` en los textos del paquete.\n//\n// <ProfileScreen />\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaProfileScreen con defaultProps y\n// styleOverrides de sus partes: sectionTitle, form, preferences.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useMemo} from 'react';\nimport {Form, Formik} from 'formik';\nimport Stack from '@mui/material/Stack';\nimport Tab from '@mui/material/Tab';\nimport Tabs from '@mui/material/Tabs';\nimport Typography from '@mui/material/Typography';\n\nimport AccountSecuritySection from '@/account/AccountSecuritySection.jsx';\nimport {useAccount} from '@/account/AccountProvider.jsx';\nimport AppearanceSettings from '@/appShell/AppearanceSettings.jsx';\nimport {toastSuccess} from '@/feedback/toast.jsx';\nimport FormProblemAlert from '@/forms/FormProblemAlert.jsx';\nimport FormTextField from '@/forms/FormTextField.jsx';\nimport SubmitButton from '@/forms/SubmitButton.jsx';\nimport {applyServerProblem} from '@/forms/applyServerProblem.js';\nimport {Yup} from '@/forms/validation.js';\nimport TextInput from '@/inputs/TextInput.jsx';\nimport {useToolkitNavigation} from '@/toolkit/toolkitContext.js';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport ProfileHeader from '@/ui/layout/ProfileHeader.jsx';\nimport SectionCard from '@/ui/layout/SectionCard.jsx';\nimport {piecePart, usePieceProps} from '@/theme/themePieces.js';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaProfileScreen)\nconst THEME_NAME = 'CalcitaProfileScreen';\nconst ProfileScreenSectionTitle = piecePart(THEME_NAME, 'SectionTitle', Typography);\nconst ProfileScreenForm = piecePart(THEME_NAME, 'Form', Stack);\nconst ProfileScreenPreferences = piecePart(THEME_NAME, 'Preferences', Stack);\n\n/** Las pestañas, en el orden en que se pintan. */\nexport const PROFILE_TAB = Object.freeze({data: 'data', security: 'security', preferences: 'preferences'});\nconst TAB_PARAM = 'tab';\n// el teléfono: dígitos, con + opcional al inicio (formato internacional); lo largo que permite el plan de numeración\nconst PHONE_PATTERN = /^\\+?\\d{7,15}$/;\n// lo ancho de los formularios: un renglón cómodo, no toda la pantalla\nconst FORM_MAX_WIDTH = 520;\n\n/**\n * Sus datos: nombre, teléfono y los campos propios del proyecto (extraFields).\n *\n * @param {object} props\n * @param {object} [props.extraFields]\n * @param {Function} [props.onProfileSaved]\n * @param {object} [props.texts]\n */\nfunction ProfileDataSection({extraFields, onProfileSaved, texts}) {\n const {t} = useToolkitTranslation('account', texts);\n const {connector, session, refreshSession} = useAccount();\n const extraRules = extraFields?.rules;\n // el esquema se arma al pintar: yup toma sus mensajes al armarlo. Las reglas propias se suman a las de la casa\n const schema = useMemo(() => Yup.object({\n name: Yup.string().trim().required(),\n phone: Yup.string().trim().matches(PHONE_PATTERN, {message: {key: 'account:profile.data.phoneInvalid'}, excludeEmptyString: true}),\n ...extraRules,\n }), [extraRules]);\n const initialValues = {name: session.user.name ?? '', phone: session.user.phone ?? '', ...extraFields?.initialValues?.(session.user)};\n\n const save = async (values, formikHelpers) => {\n // lo de la casa limpio de espacios; lo propio, tal como lo dejaron sus campos\n const profile = {...values, name: values.name.trim(), phone: values.phone.trim()};\n try {\n const response = await connector.updateProfile(profile);\n await refreshSession();\n toastSuccess(response?.message ?? t('profile.data.saved'));\n onProfileSaved?.({values: profile, response});\n } catch (error) {\n applyServerProblem(error, {...formikHelpers, values});\n }\n };\n\n return (\n <SectionCard title={t('profile.data.title')}>\n <ProfileScreenSectionTitle variant=\"body2\" color=\"text.secondary\" ownSx={{mb: 2}}>{t('profile.data.text')}</ProfileScreenSectionTitle>\n <Formik initialValues={initialValues} validationSchema={schema} onSubmit={save}>\n <Form noValidate>\n <ProfileScreenForm spacing={2} ownSx={{maxWidth: FORM_MAX_WIDTH}}>\n <FormProblemAlert />\n <FormTextField name=\"name\" label={t('profile.data.name')} autoComplete=\"name\" />\n {/* el correo se ve con el mismo estilo de los demás campos, pero no se cambia aquí */}\n <TextInput name=\"email\" label={t('profile.data.email')} value={session.user.email} onChange={() => {}}\n helperText={t('profile.data.emailHelp')} disabled />\n <FormTextField name=\"phone\" label={t('profile.data.phone')} type=\"tel\" autoComplete=\"tel\" inputMode=\"tel\" />\n {extraFields?.fields}\n <SubmitButton sx={{alignSelf: 'flex-start'}}>{t('profile.data.save')}</SubmitButton>\n </ProfileScreenForm>\n </Form>\n </Formik>\n </SectionCard>\n );\n}\n\n/** @typedef {import('@/account/accountConnector.js').AccountUser} AccountUser */\n\n/**\n * @param {object} props\n * @param {boolean} [props.showColorScheme] el ajuste de claro u oscuro en Preferencias; sin modo oscuro, false\n * @param {{initialValues?: (user: AccountUser & Record<string, any>) => Record<string, any>, rules?: Record<string, any>, fields: import('react').ReactNode}} [props.extraFields]\n * campos propios en «Sus datos», debajo del teléfono: sus valores de inicio salen del usuario de la sesión (lo que su\n * conector ponga en session.user), sus reglas de yup y sus campos (FormTextField, FormSelectField… de /forms). Al guardar\n * viajan a connector.updateProfile junto con name y phone\n * @param {Array<{key: string, label: string, content: import('react').ReactNode}>} [props.extraTabs] pestañas propias,\n * después de las de la casa; label ya traducido\n * @param {Array<'data'|'security'|'preferences'>} [props.hiddenTabs] pestañas de la casa que no se ven (PROFILE_TAB)\n * @param {(tab: string) => void} [props.onTabChange] cada que se cambia de pestaña\n * @param {(saved: {values: Record<string, any>, response: unknown}) => void} [props.onProfileSaved] después de guardar «Sus datos»\n * @param {object} [props.texts] los textos que cambian, con la forma de `account` en los textos del paquete:\n * {profile: {tabs: {data: 'Mis datos'}}}\n */\nexport default function ProfileScreen(props) {\n // lo que el proyecto puso en su tema (components.CalcitaProfileScreen.defaultProps) y encima lo que llega aquí\n const {\n showColorScheme = true, extraFields, extraTabs = [], hiddenTabs = [], onTabChange, onProfileSaved, texts,\n ...unknownProps\n} = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n const {t} = useToolkitTranslation('account', texts);\n const {session} = useAccount();\n const {useNavigate, useLocation} = useToolkitNavigation();\n const navigate = useNavigate();\n const {pathname, search} = useLocation();\n // las pestañas que se ven: las de la casa que no se escondieron y luego las del proyecto\n const tabs = [\n ...Object.values(PROFILE_TAB).filter((tab) => !hiddenTabs.includes(tab)).map((tab) => ({key: tab, label: t(`profile.tabs.${tab}`)})),\n ...extraTabs.map(({key, label}) => ({key, label})),\n ];\n const requestedTab = new URLSearchParams(search).get(TAB_PARAM);\n const activeTab = tabs.some((tab) => tab.key === requestedTab) ? requestedTab : tabs[0]?.key;\n const activeExtraTab = extraTabs.find((tab) => tab.key === activeTab);\n const changeTab = (tab) => {\n navigate(`${pathname}?${TAB_PARAM}=${tab}`, {replace: true});\n onTabChange?.(tab);\n };\n\n // guard clause: sin sesión no hay perfil que enseñar (el marco de la app ya lleva a entrar)\n if (!session) {\n return null;\n }\n\n return (\n <Stack spacing={2}>\n <ProfileHeader name={session.user.name} email={session.user.email} subtitle={session.user.subtitle} avatarUrl={session.user.avatarUrl}\n chips={session.labels ?? []} />\n <Tabs value={activeTab} onChange={(event, tab) => changeTab(tab)} aria-label={t('profile.tabs.label')}\n variant=\"scrollable\" allowScrollButtonsMobile>\n {tabs.map((tab) => <Tab key={tab.key} value={tab.key} label={tab.label} />)}\n </Tabs>\n {activeTab === PROFILE_TAB.data && <ProfileDataSection extraFields={extraFields} onProfileSaved={onProfileSaved} texts={texts} />}\n {activeTab === PROFILE_TAB.security && <AccountSecuritySection />}\n {activeTab === PROFILE_TAB.preferences && (\n <SectionCard title={t('profile.preferences.title')}>\n <ProfileScreenSectionTitle variant=\"body2\" color=\"text.secondary\" ownSx={{mb: 1}}>{t('profile.preferences.text')}</ProfileScreenSectionTitle>\n <ProfileScreenPreferences ownSx={{maxWidth: FORM_MAX_WIDTH, mx: -1}}>\n <AppearanceSettings showColorScheme={showColorScheme} />\n </ProfileScreenPreferences>\n </SectionCard>\n )}\n {activeExtraTab?.content}\n </Stack>\n );\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ProfileScreen.js","sources":["../../src/account/ProfileScreen.jsx"],"sourcesContent":["// Mi perfil, completo: quién está dentro (ProfileHeader con sus perfiles como chips) y tres pestañas:\n// - Sus datos: nombre y teléfono (el correo se ve pero no se cambia aquí); al guardar se vuelve a leer la sesión, así la\n// barra y el menú de la cuenta ya dicen el nombre nuevo;\n// - Seguridad: AccountSecuritySection (contraseña, dos pasos, sesiones y bitácora);\n// - Preferencias: AppearanceSettings (tamaño de letra, idioma y modo de color).\n// La pestaña abierta va en la dirección (?tab=): se puede compartir o recargar sin perderla. Lo del servidor sale del\n// conector de la cuenta.\n//\n// Se extiende sin tocar el framework (cada proyecto tiene su perfil «especial»):\n// - extraFields: campos propios en «Sus datos» (el área, el número de empleado…), con su valor de inicio sacado del usuario\n// de la sesión, sus reglas de yup y sus campos. Al guardar viajan a connector.updateProfile junto con name y phone: un\n// backend que ya existe recibe lo suyo con sus nombres;\n// - extraTabs: pestañas propias después de las de la casa (facturación, notificaciones…); hiddenTabs esconde las de la casa;\n// - eventos: onTabChange y onProfileSaved (lo guardado y lo que contestó el servidor);\n// - texts: cualquier texto, con la forma de `account` en los textos del paquete.\n//\n// <ProfileScreen />\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaProfileScreen con defaultProps y\n// styleOverrides de sus partes: sectionTitle, form, preferences.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useMemo} from 'react';\nimport {Form, Formik} from 'formik';\nimport Stack from '@mui/material/Stack';\nimport Tab from '@mui/material/Tab';\nimport Tabs from '@mui/material/Tabs';\nimport Typography from '@mui/material/Typography';\n\nimport AccountSecuritySection from '@/account/AccountSecuritySection.jsx';\nimport {useAccount} from '@/account/AccountProvider.jsx';\nimport AppearanceSettings from '@/appShell/AppearanceSettings.jsx';\nimport {toastSuccess} from '@/feedback/toast.jsx';\nimport FormProblemAlert from '@/forms/FormProblemAlert.jsx';\nimport FormTextField from '@/forms/FormTextField.jsx';\nimport SubmitButton from '@/forms/SubmitButton.jsx';\nimport {applyServerProblem} from '@/forms/applyServerProblem.js';\nimport {Yup} from '@/forms/validation.js';\nimport TextInput from '@/inputs/TextInput.jsx';\nimport {useToolkitNavigation} from '@/toolkit/toolkitContext.js';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport ProfileHeader from '@/ui/layout/ProfileHeader.jsx';\nimport SectionCard from '@/ui/layout/SectionCard.jsx';\nimport {piecePart, usePieceProps, withPieceSlots} from '@/theme/themePieces.js';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaProfileScreen)\nconst THEME_NAME = 'CalcitaProfileScreen';\nconst ProfileScreenSectionTitle = piecePart(THEME_NAME, 'SectionTitle', Typography);\nconst ProfileScreenForm = piecePart(THEME_NAME, 'Form', Stack);\nconst ProfileScreenPreferences = piecePart(THEME_NAME, 'Preferences', Stack);\n\n/** Las pestañas, en el orden en que se pintan. */\nexport const PROFILE_TAB = Object.freeze({data: 'data', security: 'security', preferences: 'preferences'});\nconst TAB_PARAM = 'tab';\n// el teléfono: dígitos, con + opcional al inicio (formato internacional); lo largo que permite el plan de numeración\nconst PHONE_PATTERN = /^\\+?\\d{7,15}$/;\n// lo ancho de los formularios: un renglón cómodo, no toda la pantalla\nconst FORM_MAX_WIDTH = 520;\n\n/**\n * Sus datos: nombre, teléfono y los campos propios del proyecto (extraFields).\n *\n * @param {object} props\n * @param {object} [props.extraFields]\n * @param {Function} [props.onProfileSaved]\n * @param {object} [props.texts]\n */\nfunction ProfileDataSection({extraFields, onProfileSaved, texts}) {\n const {t} = useToolkitTranslation('account', texts);\n const {connector, session, refreshSession} = useAccount();\n const extraRules = extraFields?.rules;\n // el esquema se arma al pintar: yup toma sus mensajes al armarlo. Las reglas propias se suman a las de la casa\n const schema = useMemo(() => Yup.object({\n name: Yup.string().trim().required(),\n phone: Yup.string().trim().matches(PHONE_PATTERN, {message: {key: 'account:profile.data.phoneInvalid'}, excludeEmptyString: true}),\n ...extraRules,\n }), [extraRules]);\n const initialValues = {name: session.user.name ?? '', phone: session.user.phone ?? '', ...extraFields?.initialValues?.(session.user)};\n\n const save = async (values, formikHelpers) => {\n // lo de la casa limpio de espacios; lo propio, tal como lo dejaron sus campos\n const profile = {...values, name: values.name.trim(), phone: values.phone.trim()};\n try {\n const response = await connector.updateProfile(profile);\n await refreshSession();\n toastSuccess(response?.message ?? t('profile.data.saved'));\n onProfileSaved?.({values: profile, response});\n } catch (error) {\n applyServerProblem(error, {...formikHelpers, values});\n }\n };\n\n return (\n <SectionCard title={t('profile.data.title')}>\n <ProfileScreenSectionTitle variant=\"body2\" color=\"text.secondary\" ownSx={{mb: 2}}>{t('profile.data.text')}</ProfileScreenSectionTitle>\n <Formik initialValues={initialValues} validationSchema={schema} onSubmit={save}>\n <Form noValidate>\n <ProfileScreenForm spacing={2} ownSx={{maxWidth: FORM_MAX_WIDTH}}>\n <FormProblemAlert />\n <FormTextField name=\"name\" label={t('profile.data.name')} autoComplete=\"name\" />\n {/* el correo se ve con el mismo estilo de los demás campos, pero no se cambia aquí */}\n <TextInput name=\"email\" label={t('profile.data.email')} value={session.user.email} onChange={() => {}}\n helperText={t('profile.data.emailHelp')} disabled />\n <FormTextField name=\"phone\" label={t('profile.data.phone')} type=\"tel\" autoComplete=\"tel\" inputMode=\"tel\" />\n {extraFields?.fields}\n <SubmitButton sx={{alignSelf: 'flex-start'}}>{t('profile.data.save')}</SubmitButton>\n </ProfileScreenForm>\n </Form>\n </Formik>\n </SectionCard>\n );\n}\n\n/** @typedef {import('@/account/accountConnector.js').AccountUser} AccountUser */\n\n/**\n * @param {object} props\n * @param {boolean} [props.showColorScheme] el ajuste de claro u oscuro en Preferencias; sin modo oscuro, false\n * @param {{initialValues?: (user: AccountUser & Record<string, any>) => Record<string, any>, rules?: Record<string, any>, fields: import('react').ReactNode}} [props.extraFields]\n * campos propios en «Sus datos», debajo del teléfono: sus valores de inicio salen del usuario de la sesión (lo que su\n * conector ponga en session.user), sus reglas de yup y sus campos (FormTextField, FormSelectField… de /forms). Al guardar\n * viajan a connector.updateProfile junto con name y phone\n * @param {Array<{key: string, label: string, content: import('react').ReactNode}>} [props.extraTabs] pestañas propias,\n * después de las de la casa; label ya traducido\n * @param {Array<'data'|'security'|'preferences'>} [props.hiddenTabs] pestañas de la casa que no se ven (PROFILE_TAB)\n * @param {(tab: string) => void} [props.onTabChange] cada que se cambia de pestaña\n * @param {(saved: {values: Record<string, any>, response: unknown}) => void} [props.onProfileSaved] después de guardar «Sus datos»\n * @param {object} [props.texts] los textos que cambian, con la forma de `account` en los textos del paquete:\n * {profile: {tabs: {data: 'Mis datos'}}}\n */\nfunction ProfileScreenContent(props) {\n // lo que el proyecto puso en su tema (components.CalcitaProfileScreen.defaultProps) y encima lo que llega aquí\n const {\n showColorScheme = true, extraFields, extraTabs = [], hiddenTabs = [], onTabChange, onProfileSaved, texts,\n ...unknownProps\n} = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n const {t} = useToolkitTranslation('account', texts);\n const {session} = useAccount();\n const {useNavigate, useLocation} = useToolkitNavigation();\n const navigate = useNavigate();\n const {pathname, search} = useLocation();\n // las pestañas que se ven: las de la casa que no se escondieron y luego las del proyecto\n const tabs = [\n ...Object.values(PROFILE_TAB).filter((tab) => !hiddenTabs.includes(tab)).map((tab) => ({key: tab, label: t(`profile.tabs.${tab}`)})),\n ...extraTabs.map(({key, label}) => ({key, label})),\n ];\n const requestedTab = new URLSearchParams(search).get(TAB_PARAM);\n const activeTab = tabs.some((tab) => tab.key === requestedTab) ? requestedTab : tabs[0]?.key;\n const activeExtraTab = extraTabs.find((tab) => tab.key === activeTab);\n const changeTab = (tab) => {\n navigate(`${pathname}?${TAB_PARAM}=${tab}`, {replace: true});\n onTabChange?.(tab);\n };\n\n // guard clause: sin sesión no hay perfil que enseñar (el marco de la app ya lleva a entrar)\n if (!session) {\n return null;\n }\n\n return (\n <Stack spacing={2}>\n <ProfileHeader name={session.user.name} email={session.user.email} subtitle={session.user.subtitle} avatarUrl={session.user.avatarUrl}\n chips={session.labels ?? []} />\n <Tabs value={activeTab} onChange={(event, tab) => changeTab(tab)} aria-label={t('profile.tabs.label')}\n variant=\"scrollable\" allowScrollButtonsMobile>\n {tabs.map((tab) => <Tab key={tab.key} value={tab.key} label={tab.label} />)}\n </Tabs>\n {activeTab === PROFILE_TAB.data && <ProfileDataSection extraFields={extraFields} onProfileSaved={onProfileSaved} texts={texts} />}\n {activeTab === PROFILE_TAB.security && <AccountSecuritySection />}\n {activeTab === PROFILE_TAB.preferences && (\n <SectionCard title={t('profile.preferences.title')}>\n <ProfileScreenSectionTitle variant=\"body2\" color=\"text.secondary\" ownSx={{mb: 1}}>{t('profile.preferences.text')}</ProfileScreenSectionTitle>\n <ProfileScreenPreferences ownSx={{maxWidth: FORM_MAX_WIDTH, mx: -1}}>\n <AppearanceSettings showColorScheme={showColorScheme} />\n </ProfileScreenPreferences>\n </SectionCard>\n )}\n {activeExtraTab?.content}\n </Stack>\n );\n}\n\n// lo que se exporta: la pieza con slots y slotProps para cambiar sus partes (themePieces.js)\nconst ProfileScreen = withPieceSlots(ProfileScreenContent, THEME_NAME);\nexport default ProfileScreen;\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AA+CA,MAAM,aAAa;AACnB,MAAM,4BAA4B,UAAU,YAAY,gBAAgB,UAAU;AAClF,MAAM,oBAAoB,UAAU,YAAY,QAAQ,KAAK;AAC7D,MAAM,2BAA2B,UAAU,YAAY,eAAe,KAAK;AAGpE,MAAM,cAAc,OAAO,OAAO,EAAC,MAAM,QAAQ,UAAU,YAAY,aAAa,cAAA,CAAc;AACzG,MAAM,YAAY;AAElB,MAAM,gBAAgB;AAEtB,MAAM,iBAAiB;AAUvB,SAAS,mBAAmB,EAAC,aAAa,gBAAgB,SAAQ;AAC9D,QAAM,EAAC,EAAA,IAAK,sBAAsB,WAAW,KAAK;AAClD,QAAM,EAAC,WAAW,SAAS,eAAA,IAAkB,WAAA;AAC7C,QAAM,aAAa,aAAa;AAEhC,QAAM,SAAS,QAAQ,MAAM,IAAI,OAAO;AAAA,IACpC,MAAM,IAAI,OAAA,EAAS,KAAA,EAAO,SAAA;AAAA,IAC1B,OAAO,IAAI,OAAA,EAAS,KAAA,EAAO,QAAQ,eAAe,EAAC,SAAS,EAAC,KAAK,oCAAA,GAAsC,oBAAoB,MAAK;AAAA,IACjI,GAAG;AAAA,EAAA,CACN,GAAG,CAAC,UAAU,CAAC;AAChB,QAAM,gBAAgB,EAAC,MAAM,QAAQ,KAAK,QAAQ,IAAI,OAAO,QAAQ,KAAK,SAAS,IAAI,GAAG,aAAa,gBAAgB,QAAQ,IAAI,EAAA;AAEnI,QAAM,OAAO,OAAO,QAAQ,kBAAkB;AAE1C,UAAM,UAAU,EAAC,GAAG,QAAQ,MAAM,OAAO,KAAK,KAAA,GAAQ,OAAO,OAAO,MAAM,OAAK;AAC/E,QAAI;AACA,YAAM,WAAW,MAAM,UAAU,cAAc,OAAO;AACtD,YAAM,eAAA;AACN,mBAAa,UAAU,WAAW,EAAE,oBAAoB,CAAC;AACzD,uBAAiB,EAAC,QAAQ,SAAS,SAAA,CAAS;AAAA,IAChD,SAAS,OAAO;AACZ,yBAAmB,OAAO,EAAC,GAAG,eAAe,QAAO;AAAA,IACxD;AAAA,EACJ;AAEA,SACI,qBAAC,aAAA,EAAY,OAAO,EAAE,oBAAoB,GACtC,UAAA;AAAA,IAAA,oBAAC,2BAAA,EAA0B,SAAQ,SAAQ,OAAM,kBAAiB,OAAO,EAAC,IAAI,EAAA,GAAK,UAAA,EAAE,mBAAmB,EAAA,CAAE;AAAA,wBACzG,QAAA,EAAO,eAA8B,kBAAkB,QAAQ,UAAU,MACtE,UAAA,oBAAC,MAAA,EAAK,YAAU,MACZ,UAAA,qBAAC,qBAAkB,SAAS,GAAG,OAAO,EAAC,UAAU,kBAC7C,UAAA;AAAA,MAAA,oBAAC,kBAAA,EAAiB;AAAA,MAClB,oBAAC,iBAAc,MAAK,QAAO,OAAO,EAAE,mBAAmB,GAAG,cAAa,QAAO;AAAA,MAE9E;AAAA,QAAC;AAAA,QAAA;AAAA,UAAU,MAAK;AAAA,UAAQ,OAAO,EAAE,oBAAoB;AAAA,UAAG,OAAO,QAAQ,KAAK;AAAA,UAAO,UAAU,MAAM;AAAA,UAAC;AAAA,UACzF,YAAY,EAAE,wBAAwB;AAAA,UAAG,UAAQ;AAAA,QAAA;AAAA,MAAA;AAAA,MAC5D,oBAAC,eAAA,EAAc,MAAK,SAAQ,OAAO,EAAE,oBAAoB,GAAG,MAAK,OAAM,cAAa,OAAM,WAAU,MAAA,CAAM;AAAA,MACzG,aAAa;AAAA,MACd,oBAAC,gBAAa,IAAI,EAAC,WAAW,aAAA,GAAgB,UAAA,EAAE,mBAAmB,EAAA,CAAE;AAAA,IAAA,EAAA,CACzE,GACJ,EAAA,CACJ;AAAA,EAAA,GACJ;AAER;AAmBA,SAAS,qBAAqB,OAAO;AAEjC,QAAM;AAAA,IACN,kBAAkB;AAAA,IAAM;AAAA,IAAa,YAAY,CAAA;AAAA,IAAI,aAAa,CAAA;AAAA,IAAI;AAAA,IAAa;AAAA,IAAgB;AAAA,IACnG,GAAG;AAAA,EAAA,IACH,cAAc,OAAO,UAAU;AAC/B,mBAAiB,YAAY,YAAY;AACzC,QAAM,EAAC,EAAA,IAAK,sBAAsB,WAAW,KAAK;AAClD,QAAM,EAAC,QAAA,IAAW,WAAA;AAClB,QAAM,EAAC,aAAa,YAAA,IAAe,qBAAA;AACnC,QAAM,WAAW,YAAA;AACjB,QAAM,EAAC,UAAU,OAAA,IAAU,YAAA;AAE3B,QAAM,OAAO;AAAA,IACT,GAAG,OAAO,OAAO,WAAW,EAAE,OAAO,CAAC,QAAQ,CAAC,WAAW,SAAS,GAAG,CAAC,EAAE,IAAI,CAAC,SAAS,EAAC,KAAK,KAAK,OAAO,EAAE,gBAAgB,GAAG,EAAE,EAAA,EAAG;AAAA,IACnI,GAAG,UAAU,IAAI,CAAC,EAAC,KAAK,aAAY,EAAC,KAAK,QAAO;AAAA,EAAA;AAErD,QAAM,eAAe,IAAI,gBAAgB,MAAM,EAAE,IAAI,SAAS;AAC9D,QAAM,YAAY,KAAK,KAAK,CAAC,QAAQ,IAAI,QAAQ,YAAY,IAAI,eAAe,KAAK,CAAC,GAAG;AACzF,QAAM,iBAAiB,UAAU,KAAK,CAAC,QAAQ,IAAI,QAAQ,SAAS;AACpE,QAAM,YAAY,CAAC,QAAQ;AACvB,aAAS,GAAG,QAAQ,IAAI,SAAS,IAAI,GAAG,IAAI,EAAC,SAAS,KAAA,CAAK;AAC3D,kBAAc,GAAG;AAAA,EACrB;AAGA,MAAI,CAAC,SAAS;AACV,WAAO;AAAA,EACX;AAEA,SACI,qBAAC,OAAA,EAAM,SAAS,GACZ,UAAA;AAAA,IAAA;AAAA,MAAC;AAAA,MAAA;AAAA,QAAc,MAAM,QAAQ,KAAK;AAAA,QAAM,OAAO,QAAQ,KAAK;AAAA,QAAO,UAAU,QAAQ,KAAK;AAAA,QAAU,WAAW,QAAQ,KAAK;AAAA,QAC7G,OAAO,QAAQ,UAAU,CAAA;AAAA,MAAC;AAAA,IAAA;AAAA,IACzC;AAAA,MAAC;AAAA,MAAA;AAAA,QAAK,OAAO;AAAA,QAAW,UAAU,CAAC,OAAO,QAAQ,UAAU,GAAG;AAAA,QAAG,cAAY,EAAE,oBAAoB;AAAA,QAC9F,SAAQ;AAAA,QAAa,0BAAwB;AAAA,QAC9C,UAAA,KAAK,IAAI,CAAC,4BAAS,KAAA,EAAkB,OAAO,IAAI,KAAK,OAAO,IAAI,MAAA,GAApC,IAAI,GAAuC,CAAE;AAAA,MAAA;AAAA,IAAA;AAAA,IAE7E,cAAc,YAAY,4BAAS,oBAAA,EAAmB,aAA0B,gBAAgC,OAAc;AAAA,IAC9H,cAAc,YAAY,YAAY,oBAAC,wBAAA,CAAA,CAAuB;AAAA,IAC9D,cAAc,YAAY,eACvB,qBAAC,eAAY,OAAO,EAAE,2BAA2B,GAC7C,UAAA;AAAA,MAAA,oBAAC,2BAAA,EAA0B,SAAQ,SAAQ,OAAM,kBAAiB,OAAO,EAAC,IAAI,EAAA,GAAK,UAAA,EAAE,0BAA0B,EAAA,CAAE;AAAA,MACjH,oBAAC,0BAAA,EAAyB,OAAO,EAAC,UAAU,gBAAgB,IAAI,GAAA,GAC5D,UAAA,oBAAC,oBAAA,EAAmB,gBAAA,CAAkC,EAAA,CAC1D;AAAA,IAAA,GACJ;AAAA,IAEH,gBAAgB;AAAA,EAAA,GACrB;AAER;AAGA,MAAM,gBAAgB,eAAe,sBAAsB,UAAU;"}
@@ -12,11 +12,11 @@ import { signWithPasskey, passkeysSupported } from "../security/passkeys.js";
12
12
  import { useToolkitNavigation } from "../toolkit/toolkitContext.js";
13
13
  import { useToolkitTranslation } from "../toolkit/useToolkitTranslation.js";
14
14
  import ComponentTexts from "../toolkit/ComponentTexts.js";
15
- import { piecePart, usePieceProps } from "../theme/themePieces.js";
15
+ import { piecePart, withPieceSlots, usePieceProps } from "../theme/themePieces.js";
16
16
  import { warnUnknownProps } from "../toolkit/unknownProps.js";
17
17
  const THEME_NAME = "CalcitaSignInScreen";
18
18
  const SignInAlert = piecePart(THEME_NAME, "Alert", Alert);
19
- function SignInScreen(props) {
19
+ function SignInScreenContent(props) {
20
20
  const { homePath = "/", forgotPasswordPath, logo, brandName, footer, showLanguageToggle = true, showColorSchemeToggle = true, texts, ...unknownProps } = usePieceProps(props, THEME_NAME);
21
21
  warnUnknownProps(THEME_NAME, unknownProps);
22
22
  const { t } = useToolkitTranslation("auth", texts);
@@ -102,6 +102,7 @@ function SignInScreen(props) {
102
102
  }
103
103
  ) });
104
104
  }
105
+ const SignInScreen = withPieceSlots(SignInScreenContent, THEME_NAME);
105
106
  export {
106
107
  SignInScreen as default
107
108
  };
@@ -1 +1 @@
1
- {"version":3,"file":"SignInScreen.js","sources":["../../src/account/SignInScreen.jsx"],"sourcesContent":["// Entrar, completo: la contraseña (SignInForm) y, si la cuenta tiene verificación en dos pasos, el segundo paso\n// (SecondStepForm: la llave de acceso, el código de la app o uno de recuperación). Al terminar se vuelve a leer la sesión y\n// se va a la pantalla que se quería abrir (readRedirectParam: solo si es de esta app) o al inicio.\n//\n// Lo del servidor sale del conector de la cuenta (useAccount): en el proyecto la pantalla solo se pone en su ruta.\n//\n// <SignInScreen forgotPasswordPath=\"/forgot-password\" logo={<AppLogo />} />\n//\n// footer va abajo de la tarjeta. Si es una función, recibe signIn para entrar desde un botón propio (p. ej. «Entrar con la\n// cuenta de ejemplo»), con el mismo segundo paso; si falla, el motivo sale arriba del formulario.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaSignInScreen con defaultProps y\n// styleOverrides de sus partes: alert.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useEffect, useState} from 'react';\nimport Alert from '@mui/material/Alert';\n\nimport {useAccount} from '@/account/AccountProvider.jsx';\nimport DemoTotpCodeButton from '@/account/DemoTotpCodeButton.jsx';\nimport {AuthLayout} from '@/appShell/AuthLayout.jsx';\nimport SignInForm from '@/forms/auth/SignInForm.jsx';\nimport SecondStepForm, {SECOND_STEP_METHOD} from '@/forms/security/SecondStepForm.jsx';\nimport {readRedirectParam} from '@/navigation.js';\nimport {passkeysSupported, signWithPasskey} from '@/security/passkeys.js';\nimport {useToolkitNavigation} from '@/toolkit/toolkitContext.js';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport ComponentTexts from '@/toolkit/ComponentTexts.jsx';\nimport {piecePart, usePieceProps} from '@/theme/themePieces.js';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaSignInScreen)\nconst THEME_NAME = 'CalcitaSignInScreen';\nconst SignInAlert = piecePart(THEME_NAME, 'Alert', Alert);\n\n/**\n * @param {object} props\n * @param {string} [props.homePath] a dónde ir si no se quería abrir otra pantalla; por omisión '/'\n * @param {string} [props.forgotPasswordPath] sin ella no sale «¿Olvidó su contraseña?»\n * @param {import('react').ReactNode} [props.logo]\n * @param {string} [props.brandName] por omisión el appName de ToolkitProvider\n * @param {import('react').ReactNode | ((helpers: {signIn: (credentials: {email: string, password: string, remember?: boolean}) => Promise<void>}) => import('react').ReactNode)} [props.footer]\n * @param {boolean} [props.showLanguageToggle] por omisión sí\n * @param {boolean} [props.showColorSchemeToggle] por omisión sí\n * @param {object} [props.texts] los textos que cambian, con la forma de `auth` en los textos del paquete\n */\nexport default function SignInScreen(props) {\n // lo que el proyecto puso en su tema (components.CalcitaSignInScreen.defaultProps) y encima lo que llega aquí\n const {homePath = '/', forgotPasswordPath, logo, brandName, footer, showLanguageToggle = true, showColorSchemeToggle = true, texts, ...unknownProps} = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n const {t} = useToolkitTranslation('auth', texts);\n const {connector, session, refreshSession} = useAccount();\n const {useNavigate, useLocation} = useToolkitNavigation();\n const navigate = useNavigate();\n const {search} = useLocation();\n // con verificación en dos pasos: los métodos del segundo paso (la contraseña ya fue correcta)\n const [secondStep, setSecondStep] = useState(null);\n const [notice, setNotice] = useState(null);\n const destination = readRedirectParam(search) ?? homePath;\n\n // ya hay sesión (acaba de entrar, o abrió esta pantalla estando dentro): a donde iba\n useEffect(() => {\n if (session) {\n navigate(destination, {replace: true});\n }\n }, [session, destination, navigate]);\n\n // después de la contraseña: el segundo paso si lo pide el servidor; si no, ya está dentro\n const signIn = async (credentials) => {\n setNotice(null);\n const result = await connector.signIn({remember: false, ...credentials});\n if (result?.secondStep) {\n setSecondStep(result.secondStep);\n return;\n }\n await refreshSession();\n };\n // desde un botón propio del footer: el error no tiene formulario donde salir, sale arriba\n const signInFromFooter = async (credentials) => {\n try {\n await signIn(credentials);\n } catch (error) {\n setNotice(error?.message ?? null);\n }\n };\n // se acabaron los intentos o se venció el tiempo: de regreso a la contraseña, con el motivo\n const backToPassword = (message) => {\n setSecondStep(null);\n setNotice(message);\n };\n\n if (session) {\n return null;\n }\n\n if (secondStep) {\n const showsDemoCode = typeof connector.demoTotpCode === 'function' && secondStep.methods.includes(SECOND_STEP_METHOD.totp);\n return (\n <ComponentTexts namespace=\"auth\" texts={texts}>\n <AuthLayout logo={logo} brandName={brandName} title={t('security:twoStep.title')}\n showLanguageToggle={showLanguageToggle} showColorSchemeToggle={showColorSchemeToggle}>\n <SecondStepForm methods={secondStep.methods} canUsePasskeys={passkeysSupported()}\n onUsePasskey={async () => {\n await connector.signInWithPasskey(await signWithPasskey(await connector.secondStepPasskeyOptions()));\n await refreshSession();\n }}\n onSubmitCode={async ({method, code}) => {\n await connector.signInSecondStep({method, code});\n await refreshSession();\n }}\n onCancel={backToPassword}\n footer={showsDemoCode && <DemoTotpCodeButton loadCode={connector.demoTotpCode} />} />\n </AuthLayout>\n </ComponentTexts>\n );\n }\n\n return (\n <ComponentTexts namespace=\"auth\" texts={texts}>\n <AuthLayout logo={logo} brandName={brandName} title={t('signIn.title')} description={t('signIn.subtitle')}\n showLanguageToggle={showLanguageToggle} showColorSchemeToggle={showColorSchemeToggle}\n footer={typeof footer === 'function' ? footer({signIn: signInFromFooter}) : footer}>\n {notice && <SignInAlert severity=\"warning\" ownSx={{mb: 2}}>{notice}</SignInAlert>}\n <SignInForm onSubmit={signIn} forgotPasswordPath={forgotPasswordPath} />\n </AuthLayout>\n </ComponentTexts>\n );\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"SignInScreen.js","sources":["../../src/account/SignInScreen.jsx"],"sourcesContent":["// Entrar, completo: la contraseña (SignInForm) y, si la cuenta tiene verificación en dos pasos, el segundo paso\n// (SecondStepForm: la llave de acceso, el código de la app o uno de recuperación). Al terminar se vuelve a leer la sesión y\n// se va a la pantalla que se quería abrir (readRedirectParam: solo si es de esta app) o al inicio.\n//\n// Lo del servidor sale del conector de la cuenta (useAccount): en el proyecto la pantalla solo se pone en su ruta.\n//\n// <SignInScreen forgotPasswordPath=\"/forgot-password\" logo={<AppLogo />} />\n//\n// footer va abajo de la tarjeta. Si es una función, recibe signIn para entrar desde un botón propio (p. ej. «Entrar con la\n// cuenta de ejemplo»), con el mismo segundo paso; si falla, el motivo sale arriba del formulario.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaSignInScreen con defaultProps y\n// styleOverrides de sus partes: alert.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useEffect, useState} from 'react';\nimport Alert from '@mui/material/Alert';\n\nimport {useAccount} from '@/account/AccountProvider.jsx';\nimport DemoTotpCodeButton from '@/account/DemoTotpCodeButton.jsx';\nimport {AuthLayout} from '@/appShell/AuthLayout.jsx';\nimport SignInForm from '@/forms/auth/SignInForm.jsx';\nimport SecondStepForm, {SECOND_STEP_METHOD} from '@/forms/security/SecondStepForm.jsx';\nimport {readRedirectParam} from '@/navigation.js';\nimport {passkeysSupported, signWithPasskey} from '@/security/passkeys.js';\nimport {useToolkitNavigation} from '@/toolkit/toolkitContext.js';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport ComponentTexts from '@/toolkit/ComponentTexts.jsx';\nimport {piecePart, usePieceProps, withPieceSlots} from '@/theme/themePieces.js';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaSignInScreen)\nconst THEME_NAME = 'CalcitaSignInScreen';\nconst SignInAlert = piecePart(THEME_NAME, 'Alert', Alert);\n\n/**\n * @param {object} props\n * @param {string} [props.homePath] a dónde ir si no se quería abrir otra pantalla; por omisión '/'\n * @param {string} [props.forgotPasswordPath] sin ella no sale «¿Olvidó su contraseña?»\n * @param {import('react').ReactNode} [props.logo]\n * @param {string} [props.brandName] por omisión el appName de ToolkitProvider\n * @param {import('react').ReactNode | ((helpers: {signIn: (credentials: {email: string, password: string, remember?: boolean}) => Promise<void>}) => import('react').ReactNode)} [props.footer]\n * @param {boolean} [props.showLanguageToggle] por omisión sí\n * @param {boolean} [props.showColorSchemeToggle] por omisión sí\n * @param {object} [props.texts] los textos que cambian, con la forma de `auth` en los textos del paquete\n */\nfunction SignInScreenContent(props) {\n // lo que el proyecto puso en su tema (components.CalcitaSignInScreen.defaultProps) y encima lo que llega aquí\n const {homePath = '/', forgotPasswordPath, logo, brandName, footer, showLanguageToggle = true, showColorSchemeToggle = true, texts, ...unknownProps} = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n const {t} = useToolkitTranslation('auth', texts);\n const {connector, session, refreshSession} = useAccount();\n const {useNavigate, useLocation} = useToolkitNavigation();\n const navigate = useNavigate();\n const {search} = useLocation();\n // con verificación en dos pasos: los métodos del segundo paso (la contraseña ya fue correcta)\n const [secondStep, setSecondStep] = useState(null);\n const [notice, setNotice] = useState(null);\n const destination = readRedirectParam(search) ?? homePath;\n\n // ya hay sesión (acaba de entrar, o abrió esta pantalla estando dentro): a donde iba\n useEffect(() => {\n if (session) {\n navigate(destination, {replace: true});\n }\n }, [session, destination, navigate]);\n\n // después de la contraseña: el segundo paso si lo pide el servidor; si no, ya está dentro\n const signIn = async (credentials) => {\n setNotice(null);\n const result = await connector.signIn({remember: false, ...credentials});\n if (result?.secondStep) {\n setSecondStep(result.secondStep);\n return;\n }\n await refreshSession();\n };\n // desde un botón propio del footer: el error no tiene formulario donde salir, sale arriba\n const signInFromFooter = async (credentials) => {\n try {\n await signIn(credentials);\n } catch (error) {\n setNotice(error?.message ?? null);\n }\n };\n // se acabaron los intentos o se venció el tiempo: de regreso a la contraseña, con el motivo\n const backToPassword = (message) => {\n setSecondStep(null);\n setNotice(message);\n };\n\n if (session) {\n return null;\n }\n\n if (secondStep) {\n const showsDemoCode = typeof connector.demoTotpCode === 'function' && secondStep.methods.includes(SECOND_STEP_METHOD.totp);\n return (\n <ComponentTexts namespace=\"auth\" texts={texts}>\n <AuthLayout logo={logo} brandName={brandName} title={t('security:twoStep.title')}\n showLanguageToggle={showLanguageToggle} showColorSchemeToggle={showColorSchemeToggle}>\n <SecondStepForm methods={secondStep.methods} canUsePasskeys={passkeysSupported()}\n onUsePasskey={async () => {\n await connector.signInWithPasskey(await signWithPasskey(await connector.secondStepPasskeyOptions()));\n await refreshSession();\n }}\n onSubmitCode={async ({method, code}) => {\n await connector.signInSecondStep({method, code});\n await refreshSession();\n }}\n onCancel={backToPassword}\n footer={showsDemoCode && <DemoTotpCodeButton loadCode={connector.demoTotpCode} />} />\n </AuthLayout>\n </ComponentTexts>\n );\n }\n\n return (\n <ComponentTexts namespace=\"auth\" texts={texts}>\n <AuthLayout logo={logo} brandName={brandName} title={t('signIn.title')} description={t('signIn.subtitle')}\n showLanguageToggle={showLanguageToggle} showColorSchemeToggle={showColorSchemeToggle}\n footer={typeof footer === 'function' ? footer({signIn: signInFromFooter}) : footer}>\n {notice && <SignInAlert severity=\"warning\" ownSx={{mb: 2}}>{notice}</SignInAlert>}\n <SignInForm onSubmit={signIn} forgotPasswordPath={forgotPasswordPath} />\n </AuthLayout>\n </ComponentTexts>\n );\n}\n\n// lo que se exporta: la pieza con slots y slotProps para cambiar sus partes (themePieces.js)\nconst SignInScreen = withPieceSlots(SignInScreenContent, THEME_NAME);\nexport default SignInScreen;\n"],"names":[],"mappings":"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"}
@@ -19,7 +19,7 @@ import { barMenuPlacementOf } from "./barMenuPlacement.js";
19
19
  import MenuLinks from "./MenuLinks.js";
20
20
  import { WHITE_LABEL, MONOGRAM_GRAY } from "../theme/components/glassComponents.js";
21
21
  import { isGlassTheme } from "../theme/glassSurface.js";
22
- import { piecePart, usePieceProps } from "../theme/themePieces.js";
22
+ import { piecePart, withPieceSlots, usePieceProps } from "../theme/themePieces.js";
23
23
  import { warnUnknownProps } from "../toolkit/unknownProps.js";
24
24
  const THEME_NAME = "CalcitaAccountMenu";
25
25
  const AccountButton = piecePart(THEME_NAME, "Button", IconButton);
@@ -27,7 +27,7 @@ const AccountAvatar = piecePart(THEME_NAME, "Avatar", Avatar);
27
27
  const AccountHeader = piecePart(THEME_NAME, "Header", Box);
28
28
  const AccountName = piecePart(THEME_NAME, "Name", Typography);
29
29
  const AccountSettings = piecePart(THEME_NAME, "Settings", Box);
30
- function AccountMenu(props) {
30
+ function AccountMenuContent(props) {
31
31
  const { user, profilePath, accountMenuItems = [], onSignOut, isSigningOut = false, settings, ...unknownProps } = usePieceProps(props, THEME_NAME);
32
32
  warnUnknownProps(THEME_NAME, unknownProps);
33
33
  const { t } = useToolkitTranslation("layout");
@@ -82,6 +82,7 @@ function AccountMenu(props) {
82
82
  )
83
83
  ] });
84
84
  }
85
+ const AccountMenu = withPieceSlots(AccountMenuContent, THEME_NAME);
85
86
  export {
86
87
  AccountMenu as default
87
88
  };
@@ -1 +1 @@
1
- {"version":3,"file":"AccountMenu.js","sources":["../../src/appShell/AccountMenu.jsx"],"sourcesContent":["// La cuenta de quien está dentro, arriba a la derecha (como en las plantillas de MUI): un avatar con sus iniciales (o su\n// foto) que abre un menú con su nombre y correo, Mi perfil, lo que el proyecto agregue (accountMenuItems: Facturación,\n// Mis llaves…) y Salir.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaAccountMenu con defaultProps y\n// styleOverrides de sus partes: button, avatar, header, name, settings.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useState} from 'react';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport Avatar from '@mui/material/Avatar';\nimport Box from '@mui/material/Box';\nimport Divider from '@mui/material/Divider';\nimport IconButton from '@mui/material/IconButton';\nimport ListItemIcon from '@mui/material/ListItemIcon';\nimport ListItemText from '@mui/material/ListItemText';\nimport Menu from '@mui/material/Menu';\nimport MenuItem from '@mui/material/MenuItem';\nimport Tooltip from '@mui/material/Tooltip';\nimport Typography from '@mui/material/Typography';\nimport LogoutIcon from '@mui/icons-material/Logout';\nimport PersonOutlineIcon from '@mui/icons-material/PersonOutline';\n\nimport {initialsOf} from '@/appShell/menuItemText.js';\nimport {barMenuPlacementOf} from '@/appShell/barMenuPlacement.js';\nimport MenuLinks from '@/appShell/MenuLinks.jsx';\nimport {MONOGRAM_GRAY, WHITE_LABEL} from '@/theme/components/glassComponents.js';\nimport {isGlassTheme} from '@/theme/glassSurface.js';\nimport {piecePart, usePieceProps} from '@/theme/themePieces.js';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaAccountMenu)\nconst THEME_NAME = 'CalcitaAccountMenu';\nconst AccountButton = piecePart(THEME_NAME, 'Button', IconButton);\nconst AccountAvatar = piecePart(THEME_NAME, 'Avatar', Avatar);\nconst AccountHeader = piecePart(THEME_NAME, 'Header', Box);\nconst AccountName = piecePart(THEME_NAME, 'Name', Typography);\nconst AccountSettings = piecePart(THEME_NAME, 'Settings', Box);\n\n/**\n * @param {object} props\n * @param {{name: string, email?: string, subtitle?: string, avatarUrl?: string}} props.user\n * @param {string} [props.profilePath] sin ella no sale «Mi perfil»\n * @param {Array<{to?: string, onClick?: Function, label?: string, labelKey?: string, Icon?: import('react').ElementType}>} [props.accountMenuItems]\n * @param {() => void} [props.onSignOut] sin él no sale «Salir»\n * @param {boolean} [props.isSigningOut]\n * @param {import('react').ReactNode} [props.settings] los ajustes de la app, entre los datos de la persona y sus ligas\n */\nexport default function AccountMenu(props) {\n // lo que el proyecto puso en su tema (components.CalcitaAccountMenu.defaultProps) y encima lo que llega aquí\n const {user, profilePath, accountMenuItems = [], onSignOut, isSigningOut = false, settings, ...unknownProps} = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n const {t} = useToolkitTranslation('layout');\n const [anchorElement, setAnchorElement] = useState(null);\n const closeMenu = () => setAnchorElement(null);\n const menuLinks = [\n ...(profilePath ? [{to: profilePath, labelKey: 'layout:account.myProfile', Icon: PersonOutlineIcon}] : []),\n ...accountMenuItems,\n ];\n\n // hacia arriba si la barra está abajo (teléfono con vidrio)\n const placement = barMenuPlacementOf(anchorElement);\n\n const signOut = () => {\n closeMenu();\n onSignOut();\n };\n\n return (\n <>\n <Tooltip title={t('account.open')}>\n <AccountButton size=\"small\" aria-label={t('account.open')} aria-haspopup=\"menu\" onClick={(event) => setAnchorElement(event.currentTarget)} ownSx={{p: 0.5}}>\n <AccountAvatar src={user.avatarUrl} alt=\"\" ownSx={(theme) => ({\n width: 32, height: 32, fontSize: '0.875rem', bgcolor: 'secondary.main', color: 'secondary.contrastText',\n // con vidrio, en oscuro el monograma de Apple (gris oscuro con letra blanca), el que se aprobó. Antes lo\n // ponía el tema porque su regla de oscuro le ganaba a este sx; ahora el sx gana en los dos modos\n ...(isGlassTheme(theme) && theme.applyStyles('dark', {bgcolor: MONOGRAM_GRAY.dark, color: WHITE_LABEL})),\n })}>\n {initialsOf(user.name)}\n </AccountAvatar>\n </AccountButton>\n </Tooltip>\n <Menu anchorEl={anchorElement} open={Boolean(anchorElement)} onClose={closeMenu}\n anchorOrigin={placement.anchorOrigin} transformOrigin={placement.transformOrigin}\n slotProps={{paper: {sx: {minWidth: settings ? 300 : 240, maxWidth: 360, ...placement.gapSx}}}}>\n <AccountHeader ownSx={{px: 2, py: 1.25}}>\n <AccountName variant=\"subtitle2\" noWrap ownSx={{fontWeight: 600}}>{user.name}</AccountName>\n {user.email && <Typography variant=\"body2\" color=\"text.secondary\" noWrap>{user.email}</Typography>}\n {user.subtitle && <Typography variant=\"caption\" color=\"text.secondary\" component=\"p\" noWrap>{user.subtitle}</Typography>}\n </AccountHeader>\n {/* los ajustes de la app (letra, idioma, claro u oscuro y los del proyecto): en la cuenta y no sueltos en la barra */}\n {settings && <Divider />}\n {settings && <AccountSettings ownSx={{py: 0.5}}>{settings}</AccountSettings>}\n {menuLinks.length > 0 && <Divider />}\n <MenuLinks links={menuLinks} onClose={closeMenu} />\n {onSignOut && <Divider />}\n {onSignOut && (\n <MenuItem onClick={signOut} disabled={isSigningOut}>\n <ListItemIcon><LogoutIcon fontSize=\"small\" /></ListItemIcon>\n <ListItemText primary={t('signOut')} />\n </MenuItem>\n )}\n </Menu>\n </>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAgCA,MAAM,aAAa;AACnB,MAAM,gBAAgB,UAAU,YAAY,UAAU,UAAU;AAChE,MAAM,gBAAgB,UAAU,YAAY,UAAU,MAAM;AAC5D,MAAM,gBAAgB,UAAU,YAAY,UAAU,GAAG;AACzD,MAAM,cAAc,UAAU,YAAY,QAAQ,UAAU;AAC5D,MAAM,kBAAkB,UAAU,YAAY,YAAY,GAAG;AAW7D,SAAwB,YAAY,OAAO;AAEvC,QAAM,EAAC,MAAM,aAAa,mBAAmB,CAAA,GAAI,WAAW,eAAe,OAAO,UAAU,GAAG,aAAA,IAAgB,cAAc,OAAO,UAAU;AAC9I,mBAAiB,YAAY,YAAY;AACzC,QAAM,EAAC,EAAA,IAAK,sBAAsB,QAAQ;AAC1C,QAAM,CAAC,eAAe,gBAAgB,IAAI,SAAS,IAAI;AACvD,QAAM,YAAY,MAAM,iBAAiB,IAAI;AAC7C,QAAM,YAAY;AAAA,IACd,GAAI,cAAc,CAAC,EAAC,IAAI,aAAa,UAAU,4BAA4B,MAAM,kBAAA,CAAkB,IAAI,CAAA;AAAA,IACvG,GAAG;AAAA,EAAA;AAIP,QAAM,YAAY,mBAAmB,aAAa;AAElD,QAAM,UAAU,MAAM;AAClB,cAAA;AACA,cAAA;AAAA,EACJ;AAEA,SACI,qBAAA,UAAA,EACI,UAAA;AAAA,IAAA,oBAAC,WAAQ,OAAO,EAAE,cAAc,GAC5B,8BAAC,eAAA,EAAc,MAAK,SAAQ,cAAY,EAAE,cAAc,GAAG,iBAAc,QAAO,SAAS,CAAC,UAAU,iBAAiB,MAAM,aAAa,GAAG,OAAO,EAAC,GAAG,OAClJ,UAAA,oBAAC,eAAA,EAAc,KAAK,KAAK,WAAW,KAAI,IAAG,OAAO,CAAC,WAAW;AAAA,MAC1D,OAAO;AAAA,MAAI,QAAQ;AAAA,MAAI,UAAU;AAAA,MAAY,SAAS;AAAA,MAAkB,OAAO;AAAA;AAAA;AAAA,MAG/E,GAAI,aAAa,KAAK,KAAK,MAAM,YAAY,QAAQ,EAAC,SAAS,cAAc,MAAM,OAAO,aAAY;AAAA,IAAA,IAErG,UAAA,WAAW,KAAK,IAAI,EAAA,CACzB,GACJ,GACJ;AAAA,IACA;AAAA,MAAC;AAAA,MAAA;AAAA,QAAK,UAAU;AAAA,QAAe,MAAM,QAAQ,aAAa;AAAA,QAAG,SAAS;AAAA,QAChE,cAAc,UAAU;AAAA,QAAc,iBAAiB,UAAU;AAAA,QACjE,WAAW,EAAC,OAAO,EAAC,IAAI,EAAC,UAAU,WAAW,MAAM,KAAK,UAAU,KAAK,GAAG,UAAU,MAAA,IAAM;AAAA,QAC7F,UAAA;AAAA,UAAA,qBAAC,iBAAc,OAAO,EAAC,IAAI,GAAG,IAAI,QAC9B,UAAA;AAAA,YAAA,oBAAC,aAAA,EAAY,SAAQ,aAAY,QAAM,MAAC,OAAO,EAAC,YAAY,IAAA,GAAO,UAAA,KAAK,KAAA,CAAK;AAAA,YAC5E,KAAK,SAAS,oBAAC,YAAA,EAAW,SAAQ,SAAQ,OAAM,kBAAiB,QAAM,MAAE,UAAA,KAAK,MAAA,CAAM;AAAA,YACpF,KAAK,YAAY,oBAAC,YAAA,EAAW,SAAQ,WAAU,OAAM,kBAAiB,WAAU,KAAI,QAAM,MAAE,eAAK,SAAA,CAAS;AAAA,UAAA,GAC/G;AAAA,UAEC,gCAAa,SAAA,EAAQ;AAAA,UACrB,gCAAa,iBAAA,EAAgB,OAAO,EAAC,IAAI,IAAA,GAAO,UAAA,UAAS;AAAA,UACzD,UAAU,SAAS,KAAK,oBAAC,SAAA,CAAA,CAAQ;AAAA,UAClC,oBAAC,WAAA,EAAU,OAAO,WAAW,SAAS,WAAW;AAAA,UAChD,iCAAc,SAAA,EAAQ;AAAA,UACtB,aACG,qBAAC,UAAA,EAAS,SAAS,SAAS,UAAU,cAClC,UAAA;AAAA,YAAA,oBAAC,cAAA,EAAa,UAAA,oBAAC,YAAA,EAAW,UAAS,SAAQ,GAAE;AAAA,YAC7C,oBAAC,cAAA,EAAa,SAAS,EAAE,SAAS,EAAA,CAAG;AAAA,UAAA,EAAA,CACzC;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA;AAAA,EAER,GACJ;AAER;"}
1
+ {"version":3,"file":"AccountMenu.js","sources":["../../src/appShell/AccountMenu.jsx"],"sourcesContent":["// La cuenta de quien está dentro, arriba a la derecha (como en las plantillas de MUI): un avatar con sus iniciales (o su\n// foto) que abre un menú con su nombre y correo, Mi perfil, lo que el proyecto agregue (accountMenuItems: Facturación,\n// Mis llaves…) y Salir.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaAccountMenu con defaultProps y\n// styleOverrides de sus partes: button, avatar, header, name, settings.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useState} from 'react';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport Avatar from '@mui/material/Avatar';\nimport Box from '@mui/material/Box';\nimport Divider from '@mui/material/Divider';\nimport IconButton from '@mui/material/IconButton';\nimport ListItemIcon from '@mui/material/ListItemIcon';\nimport ListItemText from '@mui/material/ListItemText';\nimport Menu from '@mui/material/Menu';\nimport MenuItem from '@mui/material/MenuItem';\nimport Tooltip from '@mui/material/Tooltip';\nimport Typography from '@mui/material/Typography';\nimport LogoutIcon from '@mui/icons-material/Logout';\nimport PersonOutlineIcon from '@mui/icons-material/PersonOutline';\n\nimport {initialsOf} from '@/appShell/menuItemText.js';\nimport {barMenuPlacementOf} from '@/appShell/barMenuPlacement.js';\nimport MenuLinks from '@/appShell/MenuLinks.jsx';\nimport {MONOGRAM_GRAY, WHITE_LABEL} from '@/theme/components/glassComponents.js';\nimport {isGlassTheme} from '@/theme/glassSurface.js';\nimport {piecePart, usePieceProps, withPieceSlots} from '@/theme/themePieces.js';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaAccountMenu)\nconst THEME_NAME = 'CalcitaAccountMenu';\nconst AccountButton = piecePart(THEME_NAME, 'Button', IconButton);\nconst AccountAvatar = piecePart(THEME_NAME, 'Avatar', Avatar);\nconst AccountHeader = piecePart(THEME_NAME, 'Header', Box);\nconst AccountName = piecePart(THEME_NAME, 'Name', Typography);\nconst AccountSettings = piecePart(THEME_NAME, 'Settings', Box);\n\n/**\n * @param {object} props\n * @param {{name: string, email?: string, subtitle?: string, avatarUrl?: string}} props.user\n * @param {string} [props.profilePath] sin ella no sale «Mi perfil»\n * @param {Array<{to?: string, onClick?: Function, label?: string, labelKey?: string, Icon?: import('react').ElementType}>} [props.accountMenuItems]\n * @param {() => void} [props.onSignOut] sin él no sale «Salir»\n * @param {boolean} [props.isSigningOut]\n * @param {import('react').ReactNode} [props.settings] los ajustes de la app, entre los datos de la persona y sus ligas\n */\nfunction AccountMenuContent(props) {\n // lo que el proyecto puso en su tema (components.CalcitaAccountMenu.defaultProps) y encima lo que llega aquí\n const {user, profilePath, accountMenuItems = [], onSignOut, isSigningOut = false, settings, ...unknownProps} = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n const {t} = useToolkitTranslation('layout');\n const [anchorElement, setAnchorElement] = useState(null);\n const closeMenu = () => setAnchorElement(null);\n const menuLinks = [\n ...(profilePath ? [{to: profilePath, labelKey: 'layout:account.myProfile', Icon: PersonOutlineIcon}] : []),\n ...accountMenuItems,\n ];\n\n // hacia arriba si la barra está abajo (teléfono con vidrio)\n const placement = barMenuPlacementOf(anchorElement);\n\n const signOut = () => {\n closeMenu();\n onSignOut();\n };\n\n return (\n <>\n <Tooltip title={t('account.open')}>\n <AccountButton size=\"small\" aria-label={t('account.open')} aria-haspopup=\"menu\" onClick={(event) => setAnchorElement(event.currentTarget)} ownSx={{p: 0.5}}>\n <AccountAvatar src={user.avatarUrl} alt=\"\" ownSx={(theme) => ({\n width: 32, height: 32, fontSize: '0.875rem', bgcolor: 'secondary.main', color: 'secondary.contrastText',\n // con vidrio, en oscuro el monograma de Apple (gris oscuro con letra blanca), el que se aprobó. Antes lo\n // ponía el tema porque su regla de oscuro le ganaba a este sx; ahora el sx gana en los dos modos\n ...(isGlassTheme(theme) && theme.applyStyles('dark', {bgcolor: MONOGRAM_GRAY.dark, color: WHITE_LABEL})),\n })}>\n {initialsOf(user.name)}\n </AccountAvatar>\n </AccountButton>\n </Tooltip>\n <Menu anchorEl={anchorElement} open={Boolean(anchorElement)} onClose={closeMenu}\n anchorOrigin={placement.anchorOrigin} transformOrigin={placement.transformOrigin}\n slotProps={{paper: {sx: {minWidth: settings ? 300 : 240, maxWidth: 360, ...placement.gapSx}}}}>\n <AccountHeader ownSx={{px: 2, py: 1.25}}>\n <AccountName variant=\"subtitle2\" noWrap ownSx={{fontWeight: 600}}>{user.name}</AccountName>\n {user.email && <Typography variant=\"body2\" color=\"text.secondary\" noWrap>{user.email}</Typography>}\n {user.subtitle && <Typography variant=\"caption\" color=\"text.secondary\" component=\"p\" noWrap>{user.subtitle}</Typography>}\n </AccountHeader>\n {/* los ajustes de la app (letra, idioma, claro u oscuro y los del proyecto): en la cuenta y no sueltos en la barra */}\n {settings && <Divider />}\n {settings && <AccountSettings ownSx={{py: 0.5}}>{settings}</AccountSettings>}\n {menuLinks.length > 0 && <Divider />}\n <MenuLinks links={menuLinks} onClose={closeMenu} />\n {onSignOut && <Divider />}\n {onSignOut && (\n <MenuItem onClick={signOut} disabled={isSigningOut}>\n <ListItemIcon><LogoutIcon fontSize=\"small\" /></ListItemIcon>\n <ListItemText primary={t('signOut')} />\n </MenuItem>\n )}\n </Menu>\n </>\n );\n}\n\n// lo que se exporta: la pieza con slots y slotProps para cambiar sus partes (themePieces.js)\nconst AccountMenu = withPieceSlots(AccountMenuContent, THEME_NAME);\nexport default AccountMenu;\n"],"names":[],"mappings":"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"}
@@ -37,7 +37,7 @@ import { THEME_LOOK, TOP_BAR } from "../theme/createToolkitTheme.js";
37
37
  import { isGlassTheme, ambientBackgroundOf, scrollEdgeStylesOf, PANEL_RADIUS } from "../theme/glassSurface.js";
38
38
  import GlassLensFilter from "../ui/layout/GlassLensFilter.js";
39
39
  import { useAppBarHeightPublisher, APP_BAR_HEIGHT } from "../ui/layout/appBarHeight.js";
40
- import { piecePart, usePieceProps } from "../theme/themePieces.js";
40
+ import { piecePart, withPieceSlots, usePieceProps } from "../theme/themePieces.js";
41
41
  import { warnUnknownProps } from "../toolkit/unknownProps.js";
42
42
  const THEME_NAME = "CalcitaAppLayout";
43
43
  const LayoutSkipLink = piecePart(THEME_NAME, "SkipLink", Link);
@@ -474,7 +474,7 @@ const AppLayoutFrame = ({
474
474
  )
475
475
  ] }) });
476
476
  };
477
- const AppLayout = (props) => {
477
+ const AppLayoutContent = (props) => {
478
478
  const {
479
479
  logo,
480
480
  wordmark,
@@ -545,6 +545,7 @@ const AppLayout = (props) => {
545
545
  }
546
546
  ) }) }) });
547
547
  };
548
+ const AppLayout = withPieceSlots(AppLayoutContent, THEME_NAME);
548
549
  export {
549
550
  AppLayout,
550
551
  MENU_POSITION
@@ -1 +1 @@
1
- {"version":3,"file":"AppLayout.js","sources":["../../src/appShell/AppLayout.jsx"],"sourcesContent":["// El marco de las pantallas con sesión, al estilo de las plantillas de MUI (y del marco de walk-ot). Dos estilos de\n// barra con las mismas props, para que el proyecto (o el `init` del CLI) solo elija:\n//\n// menuPosition=\"side\" (por omisión) menuPosition=\"top\" (apps de pocos módulos)\n// ┌──────────────────────────────────────────┐ ┌──────────────────────────────────────────┐\n// │ ☰ Logo Nombre · Título al deslizar · ⚙ (A)│ │ Logo · Inicio Pedidos Clientes ▾ · ⚙ (A) │\n// ├────────┬─────────────────────────────────┤ ├──────────────────────────────────────────┤\n// │ Menú │ contenido │ │ contenido │\n// │ por │ │ │ │\n// │ secc. │ │ │ │\n// └────────┴─────────────────────────────────┘ └──────────────────────────────────────────┘\n//\n// En el teléfono los dos son iguales: hamburguesa, título y ajustes en la barra; el menú sale en un cajón con el logo.\n//\n// Lo que trae, con su porqué:\n// - La barra va a todo lo ancho, con el logo y el nombre de la app a la izquierda, y el menú lateral debajo de ella\n// (como el DashboardLayout de MUI). La ☰ de la barra encoge el menú a solo íconos y lo recuerda (useDrawerCollapsed);\n// antes era un botón montado en la orilla del menú y se encimaba con él.\n// - El título de la página sube a la barra cuando su título grande sale de la vista (pageTitle.jsx).\n// - Escritorio y teléfono se eligen con CSS, no con useMediaQuery: el servidor (Next.js) ya pinta lo correcto.\n// - Dentro de la barra, para que se queden pegados al deslizar: los avisos del proyecto (ribbons), el de versión nueva\n// (NewBuildNotice; con vidrio flota aparte en su cápsula, ver NewBuildNotice.jsx) y la rayita de «cargando la pantalla»\n// (isNavigating). La barra publica su alto real, y el menú lateral empieza justo debajo de ella aunque crezca con un aviso.\n// - Con vidrio, en el teléfono la barra flota ABAJO en una cápsula, como la de Safari en el iPhone; y en escritorio, con\n// el menú encogido, la barra desaparece y se funde con el menú (☰ y logo arriba, ajustes y cuenta abajo).\n// - El primer Tab lleva a «Saltar al contenido» (WCAG 2.4.1) y el contenido es <main>. Respeta el área segura del\n// iPhone (la muesca) cuando la app corre instalada.\n// - Huecos para extender sin tocar el framework: headerActions, sidebarFooter, accountMenuItems, accountSettings, ribbons.\n// - Los ajustes de la app (letra, idioma, claro u oscuro y los del proyecto) van DENTRO del menú de la cuenta, no sueltos\n// en la barra (HeaderTools).\n// - El menú queda al alcance de las páginas (appMenuContext): PageHeading arma sus migas sola.\n// - Con el vidrio del tema (createToolkitTheme({glass: true})): el lienzo lleva manchas de color, y en escritorio la\n// barra y el menú lateral flotan a 8 px de la orilla y entre ellos, con esquinas redondas, para que el contenido pase\n// por detrás y se vea desenfocado; encogido, el menú es una cápsula. En el teléfono la barra sigue de orilla a orilla\n// (como en iOS). Sin vidrio, todo igual que siempre: el marco lo sabe por el tema (isGlassTheme), sin otra prop.\n// - Con vidrio y con el minimalista la barra no lleva franja, como las ventanas de macOS Tahoe (TOP_BAR.capsules, lo de\n// omisión): la ☰ con el nombre, el menú de arriba y la cuenta van cada uno en su cápsula, y el título queda suelto.\n// Con vidrio las cápsulas son de vidrio y el contenido pasa por debajo, desenfocado en la orilla (scrollEdgeStylesOf);\n// con el minimalista son bloques del tono de las tarjetas sobre la barra del color del fondo, también en el teléfono.\n// Con cápsulas el menú encogido ya no se funde con la barra: la cuenta y los ajustes se quedan arriba. Con\n// bar: TOP_BAR.band, la franja de lado a lado. Mismo alto y mismo lugar las dos: el menú lateral y las páginas no se\n// mueven.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaAppLayout con defaultProps y\n// styleOverrides de sus partes: skipLink, brand, brandLogo, brandText, brandName, brandCaption, titleArea, phoneTitle,\n// desktopTitle, railBrand, railLogo, collapseButton, root, scrollEdge, bar, toolbar, menuButton, spacer, tools,\n// progress, body, drawer, main, phoneSlot, content, phoneDrawer.\n//\n// Lo renderiza la app: arrow (regla de la casa).\nimport {useMemo, useState} from 'react';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport {useToolkitNavigation, useToolkitSettings} from '@/toolkit/toolkitContext.js';\nimport AppBar from '@mui/material/AppBar';\nimport Box from '@mui/material/Box';\nimport ButtonBase from '@mui/material/ButtonBase';\nimport Drawer from '@mui/material/Drawer';\nimport Fade from '@mui/material/Fade';\nimport IconButton from '@mui/material/IconButton';\nimport LinearProgress from '@mui/material/LinearProgress';\nimport Link from '@mui/material/Link';\nimport Toolbar from '@mui/material/Toolbar';\nimport Tooltip from '@mui/material/Tooltip';\nimport Typography from '@mui/material/Typography';\nimport {useTheme} from '@mui/material/styles';\nimport MenuIcon from '@mui/icons-material/Menu';\nimport MenuOpenIcon from '@mui/icons-material/MenuOpen';\n\nimport {AppMenuContext} from '@/appShell/appMenuContext.js';\nimport BarCapsule from '@/appShell/BarCapsule.jsx';\nimport {BarActionsSlotContext} from '@/appShell/barActionsSlot.js';\nimport HeaderTools from '@/appShell/HeaderTools.jsx';\nimport MobileTabBar from '@/appShell/MobileTabBar.jsx';\nimport Wordmark from '@/appShell/Wordmark.jsx';\nimport {PageTitleProvider, usePageTitle} from '@/appShell/pageTitle.jsx';\nimport {\n APP_BAR_HEIGHT_PIXELS, DESKTOP_MEDIA_QUERY, DRAWER_WIDTH_COLLAPSED, DRAWER_WIDTH_EXPANDED, GLASS_PANEL_GAP_PIXELS, MAIN_CONTENT_ID,\n FLOATING_BOTTOM_SPACE_CSS_VARIABLE, MOBILE_TAB_BAR_HEIGHT_PIXELS, PHONE_MEDIA_QUERY, drawerTransitionOf,\n} from '@/appShell/shellSizes.js';\nimport SideMenu from '@/appShell/SideMenu.jsx';\nimport {usesMobileTabBar} from '@/appShell/tabBarRule.js';\nimport TopMenu from '@/appShell/TopMenu.jsx';\nimport {useDrawerCollapsed} from '@/appShell/useDrawerCollapsed.js';\nimport ComponentTexts from '@/toolkit/ComponentTexts.jsx';\nimport NewBuildNotice, {NEW_BUILD_NOTICE_VARIANT} from '@/feedback/NewBuildNotice.jsx';\nimport {activeMenuItemOf, menuItemsWithIconsOf} from '@/navigation/appMenu.js';\nimport {useNavigationTrail} from '@/navigationTrail.js';\nimport {THEME_LOOK, TOP_BAR} from '@/theme/createToolkitTheme.js';\nimport {PANEL_RADIUS, ambientBackgroundOf, isGlassTheme, scrollEdgeStylesOf} from '@/theme/glassSurface.js';\nimport GlassLensFilter from '@/ui/layout/GlassLensFilter.jsx';\nimport {APP_BAR_HEIGHT, useAppBarHeightPublisher} from '@/ui/layout/appBarHeight.js';\nimport {piecePart, usePieceProps} from '@/theme/themePieces.js';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaAppLayout)\nconst THEME_NAME = 'CalcitaAppLayout';\nconst LayoutSkipLink = piecePart(THEME_NAME, 'SkipLink', Link);\nconst LayoutBrand = piecePart(THEME_NAME, 'Brand', ButtonBase);\nconst LayoutBrandLogo = piecePart(THEME_NAME, 'BrandLogo', Box);\nconst LayoutBrandText = piecePart(THEME_NAME, 'BrandText', Box);\nconst LayoutBrandName = piecePart(THEME_NAME, 'BrandName', Typography);\nconst LayoutBrandCaption = piecePart(THEME_NAME, 'BrandCaption', Typography);\nconst LayoutTitleArea = piecePart(THEME_NAME, 'TitleArea', Box);\nconst LayoutPhoneTitle = piecePart(THEME_NAME, 'PhoneTitle', Typography);\nconst LayoutDesktopTitle = piecePart(THEME_NAME, 'DesktopTitle', Typography);\nconst LayoutRailBrand = piecePart(THEME_NAME, 'RailBrand', ButtonBase);\nconst LayoutRailLogo = piecePart(THEME_NAME, 'RailLogo', Box);\nconst LayoutCollapseButton = piecePart(THEME_NAME, 'CollapseButton', IconButton);\nconst LayoutRoot = piecePart(THEME_NAME, 'Root', Box);\nconst LayoutScrollEdge = piecePart(THEME_NAME, 'ScrollEdge', Box);\nconst LayoutBar = piecePart(THEME_NAME, 'Bar', AppBar);\nconst LayoutToolbar = piecePart(THEME_NAME, 'Toolbar', Toolbar);\nconst LayoutMenuButton = piecePart(THEME_NAME, 'MenuButton', IconButton);\nconst LayoutSpacer = piecePart(THEME_NAME, 'Spacer', Box);\nconst LayoutTools = piecePart(THEME_NAME, 'Tools', Box);\nconst LayoutProgress = piecePart(THEME_NAME, 'Progress', LinearProgress);\nconst LayoutBody = piecePart(THEME_NAME, 'Body', Box);\nconst LayoutDrawer = piecePart(THEME_NAME, 'Drawer', Drawer);\nconst LayoutMain = piecePart(THEME_NAME, 'Main', Box);\nconst LayoutPhoneSlot = piecePart(THEME_NAME, 'PhoneSlot', Box);\nconst LayoutContent = piecePart(THEME_NAME, 'Content', Box);\nconst LayoutPhoneDrawer = piecePart(THEME_NAME, 'PhoneDrawer', Drawer);\n\n/** Los dos estilos de barra. */\nexport const MENU_POSITION = Object.freeze({side: 'side', top: 'top'});\n\nconst NAVIGATING_BAR_PIXELS = 2;\n\n/**\n * Un grupo de la barra: con la barra en cápsulas, su cápsula (BarCapsule: de vidrio, o con el minimalista un bloque del\n * tono de las tarjetas); con la franja, sus piezas tal cual (sin caja de más, para que la franja se quede idéntica).\n */\nconst BarGroup = ({isCapsule, sx, children}) => {\n if (!isCapsule) {\n return children;\n }\n // presentation: lo de adentro (la ☰, el nombre, la cuenta) ya se anuncia solo; el grupo es solo la forma\n return <BarCapsule role=\"presentation\" sx={sx}>{children}</BarCapsule>;\n};\n\n/** «Saltar al contenido»: escondido arriba hasta que llega el foco del teclado. */\nconst SkipToContentLink = () => {\n const {t} = useToolkitTranslation('layout');\n return (\n <LayoutSkipLink href={`#${MAIN_CONTENT_ID}`} ownSx={{\n position: 'absolute', left: 8, top: -48, zIndex: (theme) => theme.zIndex.tooltip + 1, bgcolor: 'background.paper',\n px: 1.5, py: 0.75, borderRadius: 1, boxShadow: 3, '&:focus': {top: 8},\n }}>\n {t('skipToContent')}\n </LayoutSkipLink>\n );\n};\n\n/** El logo y el nombre de la app en la barra (con su renglón chico, si lo hay), o el logo ancho; lleva al inicio. */\nconst BarBrand = ({logo, wordmark, brandName, brandCaption, homePath, sx}) => {\n const {Link: RouterLink} = useToolkitNavigation();\n return (\n <LayoutBrand component={RouterLink} to={homePath} aria-label={wordmark ? brandName : undefined}\n ownSx={[{alignItems: 'center', gap: 1.25, borderRadius: 1, flexShrink: 0, minWidth: 0, pr: 1, textAlign: 'left'}, sx]}>\n {wordmark ? <Wordmark>{wordmark}</Wordmark> : (\n <>\n {logo && <LayoutBrandLogo ownSx={{width: 28, height: 28, flex: '0 0 auto', display: 'flex', alignItems: 'center', justifyContent: 'center'}}>{logo}</LayoutBrandLogo>}\n <LayoutBrandText ownSx={{minWidth: 0}}>\n <LayoutBrandName variant=\"subtitle2\" component=\"span\" noWrap ownSx={{display: 'block', fontWeight: 600, lineHeight: 1.3}}>{brandName}</LayoutBrandName>\n {/* el renglón chico hereda el color de la barra (sobre el naranja, el gris del texto secundario no se leía) */}\n {brandCaption && <LayoutBrandCaption variant=\"caption\" component=\"span\" noWrap ownSx={{display: 'block', lineHeight: 1.3, opacity: 0.8}}>{brandCaption}</LayoutBrandCaption>}\n </LayoutBrandText>\n </>\n )}\n </LayoutBrand>\n );\n};\n\n/**\n * El título en la barra: en escritorio, después del nombre de la app y solo cuando el título grande ya no se ve; en el\n * teléfono siempre (o el nombre de la app).\n */\nconst BarTitle = ({brandName}) => {\n const {title, isTitleVisible} = usePageTitle();\n return (\n <LayoutTitleArea ownSx={{flexGrow: 1, minWidth: 0}}>\n <LayoutPhoneTitle variant=\"subtitle1\" component=\"p\" noWrap ownSx={{display: 'block', [DESKTOP_MEDIA_QUERY]: {display: 'none'}, fontWeight: 600}}>{title ?? brandName}</LayoutPhoneTitle>\n <Fade in={Boolean(title) && !isTitleVisible}>\n <LayoutDesktopTitle variant=\"subtitle1\" component=\"p\" noWrap\n ownSx={{display: 'none', [DESKTOP_MEDIA_QUERY]: {display: 'block'}, fontWeight: 600, ml: 1, pl: 2, borderLeft: '1px solid color-mix(in srgb, currentColor 30%, transparent)'}}>\n {title}\n </LayoutDesktopTitle>\n </Fade>\n </LayoutTitleArea>\n );\n};\n\n/** El logo solo, arriba del menú encogido que hace de barra; lleva al inicio. */\nconst RailBrand = ({logo, brandName, homePath}) => {\n const {Link: RouterLink} = useToolkitNavigation();\n return (\n <Tooltip title={brandName} placement=\"right\">\n <LayoutRailBrand component={RouterLink} to={homePath} aria-label={brandName}\n ownSx={{width: 44, height: 44, borderRadius: '10px', display: 'flex', alignItems: 'center', justifyContent: 'center'}}>\n <LayoutRailLogo ownSx={{width: 28, height: 28, display: 'flex', alignItems: 'center', justifyContent: 'center'}}>{logo}</LayoutRailLogo>\n </LayoutRailBrand>\n </Tooltip>\n );\n};\n\n/** La ☰ de escritorio: encoge el menú lateral a solo íconos o lo vuelve a abrir. */\nconst CollapseMenuButton = ({collapsed, onToggle}) => {\n const {t} = useToolkitTranslation('layout');\n const label = collapsed ? t('drawer.expand') : t('drawer.collapse');\n return (\n <Tooltip title={label}>\n <LayoutCollapseButton aria-label={label} aria-expanded={!collapsed} onClick={onToggle} ownSx={{display: 'none', [DESKTOP_MEDIA_QUERY]: {display: 'inline-flex'}, color: 'inherit'}}>\n {collapsed ? <MenuIcon /> : <MenuOpenIcon />}\n </LayoutCollapseButton>\n </Tooltip>\n );\n};\n\nconst AppLayoutFrame = ({\n logo, wordmark, brandName, brandCaption, homePath, menuItems, menuPosition, user, profilePath, accountMenuItems, onSignOut, isSigningOut, headerActions,\n accountSettings, menuBadges, sidebarFooter, showFontSizeToggle, showLanguageToggle, showColorSchemeToggle, ribbons, isNavigating, defaultCollapsed, minimizeTabBarOnScroll, contentMaxWidth,\n onMenuCollapse, onMobileMenuChange, onMobileTabsChange, children,\n}) => {\n const {t} = useToolkitTranslation('layout');\n const {useLocation} = useToolkitNavigation();\n const {pathname} = useLocation();\n const {collapsed, toggle} = useDrawerCollapsed(defaultCollapsed);\n const [isMobileMenuOpen, setIsMobileMenuOpenState] = useState(false);\n // cada cambio del menú también sale afuera (para medir, o para que el proyecto guarde la preferencia en su servidor)\n const toggleCollapsed = () => {\n toggle();\n onMenuCollapse?.(!collapsed);\n };\n const setIsMobileMenuOpen = (isOpen) => {\n setIsMobileMenuOpenState(isOpen);\n onMobileMenuChange?.(isOpen);\n };\n const appBarRef = useAppBarHeightPublisher();\n useNavigationTrail();\n\n const theme = useTheme();\n const isGlass = isGlassTheme(theme);\n // la barra de pestañas del teléfono (estilo Apple): con vidrio, y con el minimalista en cápsulas (usesMobileTabBar);\n // sin vidrio, o con el minimalista en franja, se queda la barra de MUI arriba con su cajón\n const usesTabBar = usesMobileTabBar(theme);\n\n const isSideMenu = menuPosition !== MENU_POSITION.top;\n // con vidrio y el menú encogido, en escritorio la barra de arriba desaparece y se funde con el menú: la ☰ y el logo van\n // arriba del menú y los ajustes y la cuenta abajo (lo pidió el autor). Si el proyecto trae avisos en la barra (ribbons),\n // la barra se queda: los avisos no tendrían dónde ir\n // la barra sin franja, en cápsulas (lo de omisión con vidrio y con el minimalista; TOP_BAR.band pide la franja). El\n // estilo de Stackcraft sin vidrio se queda con su barra de siempre\n const isMinimalLook = theme.toolkit?.look === THEME_LOOK.minimal;\n const usesBarCapsules = (isGlass || isMinimalLook) && theme.toolkit?.bar === TOP_BAR.capsules;\n // con vidrio, o con cápsulas, la barra y el menú lateral van a GLASS_PANEL_GAP_PIXELS de la orilla: la columna del menú\n // mide eso de más. OJO: con el minimalista en cápsulas era 0 y las cápsulas quedaban pegadas arriba (a 4 px) y el menú\n // pegado a la izquierda (lo reportó el autor; medido en Chrome)\n const panelGap = isGlass || usesBarCapsules ? GLASS_PANEL_GAP_PIXELS : 0;\n // con cápsulas no se funde: no hay franja que esconder, y la cuenta y los ajustes se quedan arriba en su cápsula en\n // lugar de bajar al pie del menú encogido (lo pidió el autor)\n const isBarMerged = isGlass && isSideMenu && collapsed && !ribbons && !usesBarCapsules;\n const drawerWidth = collapsed ? DRAWER_WIDTH_COLLAPSED : DRAWER_WIDTH_EXPANDED;\n const activeItem = activeMenuItemOf(menuItems, pathname);\n const sideMenuProps = {logo, wordmark, brandName, brandCaption, homePath, menuItems, activeItem, menuBadges, footer: sidebarFooter};\n // el lugar de la barra donde caen las acciones de cada pantalla (BarActions); con la barra fundida con el menú no hay\n // barra en escritorio y se quedan en la pantalla\n const [barActionsSlot, setBarActionsSlot] = useState(null);\n // en el teléfono con cápsulas no hay barra de arriba (la de pestañas va abajo): las acciones flotan arriba a la derecha\n const usesPhoneFloatingActions = usesTabBar && usesBarCapsules;\n const [phoneBarActionsSlot, setPhoneBarActionsSlot] = useState(null);\n const barActions = useMemo(() => ({\n slot: isBarMerged ? null : barActionsSlot,\n phoneSlot: usesPhoneFloatingActions ? phoneBarActionsSlot : null,\n usesCapsules: usesBarCapsules,\n }), [isBarMerged, barActionsSlot, usesPhoneFloatingActions, phoneBarActionsSlot, usesBarCapsules]);\n\n return (\n <BarActionsSlotContext.Provider value={barActions}>\n <LayoutRoot ownSx={[{display: 'flex', flexDirection: 'column', minHeight: '100vh', bgcolor: 'background.default'}, isGlass && ambientBackgroundOf]}>\n <SkipToContentLink />\n <GlassLensFilter />\n\n {/* en cápsulas, lo que pasa por debajo de la barra se desenfoca en la orilla: debajo del menú lateral, que sigue nítido */}\n {isGlass && usesBarCapsules && (\n <LayoutScrollEdge aria-hidden=\"true\"\n ownSx={(theme) => ({\n ...scrollEdgeStylesOf(theme), display: 'none', [DESKTOP_MEDIA_QUERY]: {display: 'block'},\n position: 'fixed', top: 0, left: 0, right: 0, height: `calc(${APP_BAR_HEIGHT} + ${panelGap}px)`,\n zIndex: theme.zIndex.drawer - 1, pointerEvents: 'none',\n })} />\n )}\n {/* en cápsulas con vidrio la barra va transparente (color=\"transparent\": el tema no le pone vidrio) y cada grupo\n lleva el suyo; con el minimalista se queda del color del fondo, que tapa lo que pasa por debajo */}\n <LayoutBar ref={appBarRef} position=\"sticky\" color={isGlass && usesBarCapsules ? 'transparent' : undefined}\n ownSx={(theme) => ({\n pt: 'env(safe-area-inset-top)',\n // encima del menú lateral, como en el DashboardLayout de MUI\n zIndex: theme.zIndex.drawer + 1,\n // con vidrio flota: en escritorio arriba, separada de las orillas; en el teléfono ABAJO, en una cápsula,\n // como la barra de Safari en el iPhone (en el teléfono se veía cuadrada y pegada arriba; lo reportaron).\n // Abajo se suma la zona del gesto de inicio del iPhone (safe-area) a la separación\n ...(isGlass && {\n // en cápsulas no se recorta: la sombra de cada cápsula se saldría cortada\n overflow: usesBarCapsules ? 'visible' : 'hidden',\n [DESKTOP_MEDIA_QUERY]: {\n top: panelGap, mt: `${panelGap}px`, mx: `${panelGap}px`, width: 'auto',\n borderRadius: PANEL_RADIUS,\n // sin la raya de abajo de la barra fija: no hay franja que separar\n ...(usesBarCapsules && {borderBottom: 0, boxShadow: 'none'}),\n ...(isBarMerged && {display: 'none'}),\n },\n }),\n // el minimalista en cápsulas no flota (su barra es del color del fondo y tapa lo que pasa por debajo):\n // la separación de las orillas va por dentro, para que las cápsulas queden donde las del vidrio\n ...(!isGlass && usesBarCapsules && {\n [DESKTOP_MEDIA_QUERY]: {pt: `calc(env(safe-area-inset-top) + ${panelGap}px)`, px: `${panelGap}px`},\n }),\n // en el teléfono la barra de pestañas (MobileTabBar) la reemplaza: con ella van el menú y la cuenta\n ...(usesTabBar && {[PHONE_MEDIA_QUERY]: {display: 'none'}}),\n })}>\n {/* a la izquierda, la ☰ queda alineada con los íconos del menú lateral (los dos a 32 px de su orilla) */}\n <LayoutToolbar disableGutters ownSx={{minHeight: {xs: APP_BAR_HEIGHT_PIXELS, sm: APP_BAR_HEIGHT_PIXELS}, gap: 1, pl: {xs: 1.5, md: isSideMenu ? 1.5 : 3}, pr: {xs: 1.5, md: 3}}}>\n {/* la ☰ del teléfono va en la primera cápsula (en escritorio la de encoger el menú y el nombre). OJO: dentro de\n una cápsula, sin el margen negativo de «orilla de inicio» de MUI (-12 px): el botón quedaba pegado a la\n curva. Así su círculo queda concéntrico con la cápsula */}\n <BarGroup isCapsule={usesBarCapsules}>\n <LayoutMenuButton edge=\"start\" aria-label={t('drawer.open')} aria-expanded={isMobileMenuOpen} onClick={() => setIsMobileMenuOpen(true)}\n ownSx={{display: 'inline-flex', [DESKTOP_MEDIA_QUERY]: {display: 'none'}, color: 'inherit', ...((isGlass || usesBarCapsules) && {ml: 0})}}>\n <MenuIcon />\n </LayoutMenuButton>\n {isSideMenu && <CollapseMenuButton collapsed={collapsed} onToggle={toggleCollapsed} />}\n <BarBrand logo={logo} wordmark={wordmark} brandName={brandName} brandCaption={brandCaption} homePath={homePath}\n sx={isSideMenu ? {display: 'none', [DESKTOP_MEDIA_QUERY]: {display: 'flex'}} : {display: 'flex'}} />\n </BarGroup>\n {isSideMenu ? (\n <BarTitle brandName={brandName} />\n ) : (\n <>\n {/* el menú de arriba no sale en el teléfono: su cápsula tampoco (vacía se vería) */}\n <BarGroup isCapsule={usesBarCapsules} sx={{display: 'none', [DESKTOP_MEDIA_QUERY]: {display: 'flex'}}}>\n <TopMenu menuItems={menuItems} activeItem={activeItem} />\n </BarGroup>\n <LayoutSpacer ownSx={{flexGrow: 1}} />\n </>\n )}\n {/* las acciones de la pantalla abierta (BarActions, y las de PageHeading con cápsulas): cada grupo cae aquí,\n antes de la cuenta. Solo en escritorio: en el teléfono flotan arriba (phoneBarActionsSlot, en el contenido) */}\n <LayoutTools ref={setBarActionsSlot} ownSx={{display: 'none', [DESKTOP_MEDIA_QUERY]: {display: 'flex'}, alignItems: 'center', gap: 1, minWidth: 0}} />\n <BarGroup isCapsule={usesBarCapsules}>\n <HeaderTools headerActions={headerActions} accountSettings={accountSettings} showFontSizeToggle={showFontSizeToggle} showLanguageToggle={showLanguageToggle}\n showColorSchemeToggle={showColorSchemeToggle} user={user} profilePath={profilePath} accountMenuItems={accountMenuItems}\n onSignOut={onSignOut} isSigningOut={isSigningOut} />\n </BarGroup>\n </LayoutToolbar>\n {ribbons}\n {/* con la barra de pestañas el aviso de versión nueva flota aparte, en su cápsula (en el teléfono esta barra no\n se ve); sin ella, franja dentro de la barra */}\n {!usesTabBar && <NewBuildNotice />}\n {isNavigating && (\n <LayoutProgress aria-label={t('navigating')} color=\"inherit\"\n ownSx={{position: 'absolute', bottom: 0, left: 0, right: 0, height: NAVIGATING_BAR_PIXELS}} />\n )}\n </LayoutBar>\n {usesTabBar && <NewBuildNotice variant={NEW_BUILD_NOTICE_VARIANT.floating} />}\n {usesTabBar && (\n <MobileTabBar menuItems={menuItems} activeItem={activeItem} menuBadges={menuBadges} moreFooter={sidebarFooter} minimizeOnScroll={minimizeTabBarOnScroll}\n onPinnedTabsChange={onMobileTabsChange}\n account={(\n <HeaderTools headerActions={headerActions} accountSettings={accountSettings} showFontSizeToggle={showFontSizeToggle}\n showLanguageToggle={showLanguageToggle} showColorSchemeToggle={showColorSchemeToggle} user={user}\n profilePath={profilePath} accountMenuItems={accountMenuItems} onSignOut={onSignOut} isSigningOut={isSigningOut} />\n )} />\n )}\n\n <LayoutBody ownSx={{display: 'flex', flexGrow: 1, minWidth: 0}}>\n {isSideMenu && (\n <LayoutDrawer variant=\"permanent\"\n ownSx={(theme) => ({\n display: 'none', [DESKTOP_MEDIA_QUERY]: {display: 'block'}, width: drawerWidth + panelGap, flexShrink: 0, whiteSpace: 'nowrap',\n transition: drawerTransitionOf(theme),\n '& .MuiDrawer-paper': {\n width: drawerWidth, left: panelGap, boxSizing: 'border-box', overflowX: 'hidden', transition: drawerTransitionOf(theme, ['width']),\n // justo debajo de la barra (su alto real, con avisos o sin ellos) y hasta abajo; si la barra se\n // fundió con el menú, de arriba a abajo\n ...(isBarMerged\n ? {top: panelGap, height: `calc(100% - ${panelGap * 2}px)`}\n : {top: `calc(${APP_BAR_HEIGHT} + ${panelGap}px)`, height: `calc(100% - ${APP_BAR_HEIGHT} - ${panelGap * 2}px)`}),\n // el panel flotante: separado de las orillas y sin la línea de la derecha (lo separa su brillo).\n // Encogido es una cápsula (radio de la mitad de su ancho), como las barras de pestañas de vidrio\n ...(isGlass && {\n border: 0,\n borderRadius: PANEL_RADIUS,\n }),\n },\n })}>\n <SideMenu {...sideMenuProps} showBrand={false} collapsed={collapsed}\n railTop={isBarMerged ? (\n <>\n <CollapseMenuButton collapsed={collapsed} onToggle={toggleCollapsed} />\n {logo && <RailBrand logo={logo} brandName={brandName} homePath={homePath} />}\n </>\n ) : undefined}\n railBottom={isBarMerged ? (\n <HeaderTools vertical headerActions={headerActions} accountSettings={accountSettings} showFontSizeToggle={showFontSizeToggle}\n showLanguageToggle={showLanguageToggle} showColorSchemeToggle={showColorSchemeToggle} user={user}\n profilePath={profilePath} accountMenuItems={accountMenuItems} onSignOut={onSignOut}\n isSigningOut={isSigningOut} />\n ) : undefined} />\n </LayoutDrawer>\n )}\n\n <LayoutMain component=\"main\" id={MAIN_CONTENT_ID} tabIndex={-1}\n ownSx={(theme) => ({\n flexGrow: 1, minWidth: 0, outline: 'none', px: {xs: 2, md: 3, lg: 4}, pt: 3, pb: 6,\n // con la barra de pestañas abajo (teléfono): arriba, lugar para la hora y la cámara del iPhone; abajo,\n // lugar para que la barra (que flota a GLASS_PANEL_GAP_PIXELS) no tape el final de la página\n ...(usesTabBar && {\n [PHONE_MEDIA_QUERY]: {\n pt: `calc(${theme.spacing(3)} + env(safe-area-inset-top))`,\n pb: `calc(${MOBILE_TAB_BAR_HEIGHT_PIXELS.portrait + GLASS_PANEL_GAP_PIXELS * 2}px + env(safe-area-inset-bottom) + ${theme.spacing(3)} + var(${FLOATING_BOTTOM_SPACE_CSS_VARIABLE}, 0px))`,\n },\n }),\n })}>\n {/* teléfono con cápsulas: el renglón de las acciones de la pantalla, arriba a la derecha. Va pegado (sticky)\n y no fijo: así ocupa su lugar arriba de la página (no tapa las migas ni el título) y al bajar se queda\n flotando. Vacío no se ve. Solo las cápsulas reciben clics: el hueco de la izquierda deja pasar el dedo\n a lo de abajo */}\n {usesPhoneFloatingActions && (\n <LayoutPhoneSlot ref={setPhoneBarActionsSlot} data-phone-bar-actions=\"\"\n ownSx={(theme) => ({\n display: 'none',\n [PHONE_MEDIA_QUERY]: {\n display: 'flex', '&:empty': {display: 'none'},\n position: 'sticky', top: `calc(env(safe-area-inset-top) + ${GLASS_PANEL_GAP_PIXELS}px)`, zIndex: theme.zIndex.appBar,\n justifyContent: 'flex-end', alignItems: 'center', gap: 1, mb: 2,\n pointerEvents: 'none', '& > *': {pointerEvents: 'auto'},\n },\n })} />\n )}\n <LayoutContent ownSx={{maxWidth: contentMaxWidth, mx: 'auto'}}>{children}</LayoutContent>\n </LayoutMain>\n </LayoutBody>\n\n {/* el cajón del teléfono (los dos estilos): con el logo arriba, se cierra al elegir una pantalla */}\n <LayoutPhoneDrawer variant=\"temporary\" open={isMobileMenuOpen} onClose={() => setIsMobileMenuOpen(false)} ModalProps={{keepMounted: true}}\n ownSx={{[DESKTOP_MEDIA_QUERY]: {display: 'none'}}}\n slotProps={{paper: {sx: {width: DRAWER_WIDTH_EXPANDED, boxSizing: 'border-box', pt: 'env(safe-area-inset-top)', pb: 'env(safe-area-inset-bottom)'}}}}>\n <SideMenu {...sideMenuProps} collapsed={false} onNavigate={() => setIsMobileMenuOpen(false)} />\n </LayoutPhoneDrawer>\n </LayoutRoot>\n </BarActionsSlotContext.Provider>\n );\n};\n\n/**\n * @param {object} props\n * @param {import('react').ReactNode} [props.logo] el logo chico (28 px), en la barra junto al nombre y en el cajón del teléfono\n * @param {import('react').ReactNode | {light?: import('react').ReactNode, dark?: import('react').ReactNode}} [props.wordmark] el logo\n * ancho, la marca con su nombre en una sola imagen (como el de muchas empresas), o uno para cada modo ({light, dark}: el de\n * color en claro y el blanco en oscuro): va en lugar del logo y el nombre en la barra y arriba del menú del teléfono, a 24 px de alto. Con el menú\n * encogido se queda el logo chico (logo), si lo hay. brandName sigue siendo su nombre para el lector de pantalla\n * @param {string} [props.brandName] el nombre de la app; por omisión el appName de ToolkitProvider\n * @param {string} [props.brandCaption] el renglón chico debajo del nombre («Panel de administración»)\n * @param {string} [props.homePath] por omisión '/'\n * @param {object[]} [props.menuItems] lo que regresa composeMenu\n * @param {'side'|'top'} [props.menuPosition] por omisión 'side' (MENU_POSITION)\n * @param {{name: string, email?: string, subtitle?: string, avatarUrl?: string}|null} [props.user] quién está dentro\n * @param {string} [props.profilePath] la ruta de Mi perfil\n * @param {object[]} [props.accountMenuItems] renglones propios en el menú de la cuenta ({to | onClick, label | labelKey, Icon})\n * @param {() => void} [props.onSignOut] sin él no sale «Salir» (una app sin sesión)\n * @param {boolean} [props.isSigningOut]\n * @param {import('react').ReactNode} [props.headerActions] botones propios en la barra, antes de la cuenta\n * @param {Record<string, number>} [props.menuBadges] los conteos del servidor por badgeKey de cada entrada del menú\n * (useMenuBadges): lo pendiente de cada pantalla, como numerito\n * @param {import('react').ReactNode} [props.accountSettings] ajustes propios del proyecto dentro del menú de la cuenta, debajo de\n * letra, idioma y claro u oscuro (con SettingSection, para que se vean igual)\n * @param {import('react').ReactNode} [props.sidebarFooter] lo de abajo del menú lateral (una tarjeta de ayuda…)\n * @param {boolean} [props.showFontSizeToggle] por omisión sí\n * @param {boolean} [props.showLanguageToggle] por omisión sí\n * @param {boolean} [props.showColorSchemeToggle] por omisión sí\n * @param {import('react').ReactNode} [props.ribbons] avisos propios dentro de la barra\n * @param {boolean} [props.isNavigating] la pantalla siguiente se está descargando (react-router: useIsNavigating)\n * @param {boolean} [props.defaultCollapsed] el menú lateral empieza encogido (la persona lo cambia y se recuerda)\n * @param {boolean} [props.minimizeTabBarOnScroll] en el teléfono con vidrio, la barra de pestañas se encoge al leer hacia\n * abajo y regresa al subir (como iOS 26); por omisión sí\n * @param {number|string} [props.contentMaxWidth] por omisión 1400\n * @param {(collapsed: boolean) => void} [props.onMenuCollapse] la persona encogió (true) o abrió (false) el menú lateral\n * @param {(isOpen: boolean) => void} [props.onMobileMenuChange] se abrió o se cerró el menú del teléfono (el cajón)\n * @param {(keys: string[]|null) => void} [props.onMobileTabsChange] la persona eligió sus pestañas del teléfono (las llaves\n * de menuItemKeyOf; null: regresó a las de omisión). Se recuerdan en el navegador; con esto el proyecto las puede guardar\n * en su servidor\n * @param {object} [props.texts] los textos que cambian, con la forma de `layout` en los textos del paquete (para todo el marco)\n * @param {import('react').ReactNode} props.children el contenido\n */\nexport const AppLayout = (props) => {\n // lo que el proyecto puso en su tema (components.CalcitaAppLayout.defaultProps) y encima lo que llega aquí\n const {\n logo, wordmark, brandName, brandCaption, homePath = '/', menuItems = [], menuPosition = MENU_POSITION.side, user = null, profilePath, accountMenuItems = [], onSignOut,\n isSigningOut = false, headerActions, accountSettings, menuBadges, sidebarFooter, showFontSizeToggle = true, showLanguageToggle = true, showColorSchemeToggle = true, ribbons,\n isNavigating = false, defaultCollapsed = false, minimizeTabBarOnScroll = true, contentMaxWidth = 1400, onMenuCollapse, onMobileMenuChange, onMobileTabsChange,\n texts, children,\n ...unknownProps\n} = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n const {appName} = useToolkitSettings();\n // un ícono ya pintado (icon) se vuelve componente aquí, una vez: las piezas del menú pintan siempre Icon\n const shownMenuItems = useMemo(() => menuItemsWithIconsOf(menuItems), [menuItems]);\n const appMenu = useMemo(() => ({menuItems: shownMenuItems}), [shownMenuItems]);\n // los textos del marco llegan a todas sus piezas (la cuenta, el menú, las pestañas del teléfono), cada una lee los suyos\n return (\n <ComponentTexts namespace=\"layout\" texts={texts}>\n <PageTitleProvider>\n <AppMenuContext.Provider value={appMenu}>\n <AppLayoutFrame logo={logo} wordmark={wordmark} brandName={brandName ?? appName} brandCaption={brandCaption} homePath={homePath} menuItems={shownMenuItems} menuPosition={menuPosition}\n user={user} profilePath={profilePath} accountMenuItems={accountMenuItems} onSignOut={onSignOut} isSigningOut={isSigningOut}\n headerActions={headerActions} accountSettings={accountSettings} menuBadges={menuBadges} sidebarFooter={sidebarFooter} showFontSizeToggle={showFontSizeToggle}\n showLanguageToggle={showLanguageToggle} showColorSchemeToggle={showColorSchemeToggle} ribbons={ribbons}\n isNavigating={isNavigating} defaultCollapsed={defaultCollapsed} minimizeTabBarOnScroll={minimizeTabBarOnScroll}\n contentMaxWidth={contentMaxWidth} onMenuCollapse={onMenuCollapse} onMobileMenuChange={onMobileMenuChange}\n onMobileTabsChange={onMobileTabsChange}>\n {children}\n </AppLayoutFrame>\n </AppMenuContext.Provider>\n </PageTitleProvider>\n </ComponentTexts>\n );\n};\n"],"names":["theme"],"mappings":"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"}
1
+ {"version":3,"file":"AppLayout.js","sources":["../../src/appShell/AppLayout.jsx"],"sourcesContent":["// El marco de las pantallas con sesión, al estilo de las plantillas de MUI (y del marco de walk-ot). Dos estilos de\n// barra con las mismas props, para que el proyecto (o el `init` del CLI) solo elija:\n//\n// menuPosition=\"side\" (por omisión) menuPosition=\"top\" (apps de pocos módulos)\n// ┌──────────────────────────────────────────┐ ┌──────────────────────────────────────────┐\n// │ ☰ Logo Nombre · Título al deslizar · ⚙ (A)│ │ Logo · Inicio Pedidos Clientes ▾ · ⚙ (A) │\n// ├────────┬─────────────────────────────────┤ ├──────────────────────────────────────────┤\n// │ Menú │ contenido │ │ contenido │\n// │ por │ │ │ │\n// │ secc. │ │ │ │\n// └────────┴─────────────────────────────────┘ └──────────────────────────────────────────┘\n//\n// En el teléfono los dos son iguales: hamburguesa, título y ajustes en la barra; el menú sale en un cajón con el logo.\n//\n// Lo que trae, con su porqué:\n// - La barra va a todo lo ancho, con el logo y el nombre de la app a la izquierda, y el menú lateral debajo de ella\n// (como el DashboardLayout de MUI). La ☰ de la barra encoge el menú a solo íconos y lo recuerda (useDrawerCollapsed);\n// antes era un botón montado en la orilla del menú y se encimaba con él.\n// - El título de la página sube a la barra cuando su título grande sale de la vista (pageTitle.jsx).\n// - Escritorio y teléfono se eligen con CSS, no con useMediaQuery: el servidor (Next.js) ya pinta lo correcto.\n// - Dentro de la barra, para que se queden pegados al deslizar: los avisos del proyecto (ribbons), el de versión nueva\n// (NewBuildNotice; con vidrio flota aparte en su cápsula, ver NewBuildNotice.jsx) y la rayita de «cargando la pantalla»\n// (isNavigating). La barra publica su alto real, y el menú lateral empieza justo debajo de ella aunque crezca con un aviso.\n// - Con vidrio, en el teléfono la barra flota ABAJO en una cápsula, como la de Safari en el iPhone; y en escritorio, con\n// el menú encogido, la barra desaparece y se funde con el menú (☰ y logo arriba, ajustes y cuenta abajo).\n// - El primer Tab lleva a «Saltar al contenido» (WCAG 2.4.1) y el contenido es <main>. Respeta el área segura del\n// iPhone (la muesca) cuando la app corre instalada.\n// - Huecos para extender sin tocar el framework: headerActions, sidebarFooter, accountMenuItems, accountSettings, ribbons.\n// - Los ajustes de la app (letra, idioma, claro u oscuro y los del proyecto) van DENTRO del menú de la cuenta, no sueltos\n// en la barra (HeaderTools).\n// - El menú queda al alcance de las páginas (appMenuContext): PageHeading arma sus migas sola.\n// - Con el vidrio del tema (createToolkitTheme({glass: true})): el lienzo lleva manchas de color, y en escritorio la\n// barra y el menú lateral flotan a 8 px de la orilla y entre ellos, con esquinas redondas, para que el contenido pase\n// por detrás y se vea desenfocado; encogido, el menú es una cápsula. En el teléfono la barra sigue de orilla a orilla\n// (como en iOS). Sin vidrio, todo igual que siempre: el marco lo sabe por el tema (isGlassTheme), sin otra prop.\n// - Con vidrio y con el minimalista la barra no lleva franja, como las ventanas de macOS Tahoe (TOP_BAR.capsules, lo de\n// omisión): la ☰ con el nombre, el menú de arriba y la cuenta van cada uno en su cápsula, y el título queda suelto.\n// Con vidrio las cápsulas son de vidrio y el contenido pasa por debajo, desenfocado en la orilla (scrollEdgeStylesOf);\n// con el minimalista son bloques del tono de las tarjetas sobre la barra del color del fondo, también en el teléfono.\n// Con cápsulas el menú encogido ya no se funde con la barra: la cuenta y los ajustes se quedan arriba. Con\n// bar: TOP_BAR.band, la franja de lado a lado. Mismo alto y mismo lugar las dos: el menú lateral y las páginas no se\n// mueven.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaAppLayout con defaultProps y\n// styleOverrides de sus partes: skipLink, brand, brandLogo, brandText, brandName, brandCaption, titleArea, phoneTitle,\n// desktopTitle, railBrand, railLogo, collapseButton, root, scrollEdge, bar, toolbar, menuButton, spacer, tools,\n// progress, body, drawer, main, phoneSlot, content, phoneDrawer.\n//\n// Lo renderiza la app: arrow (regla de la casa).\nimport {useMemo, useState} from 'react';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport {useToolkitNavigation, useToolkitSettings} from '@/toolkit/toolkitContext.js';\nimport AppBar from '@mui/material/AppBar';\nimport Box from '@mui/material/Box';\nimport ButtonBase from '@mui/material/ButtonBase';\nimport Drawer from '@mui/material/Drawer';\nimport Fade from '@mui/material/Fade';\nimport IconButton from '@mui/material/IconButton';\nimport LinearProgress from '@mui/material/LinearProgress';\nimport Link from '@mui/material/Link';\nimport Toolbar from '@mui/material/Toolbar';\nimport Tooltip from '@mui/material/Tooltip';\nimport Typography from '@mui/material/Typography';\nimport {useTheme} from '@mui/material/styles';\nimport MenuIcon from '@mui/icons-material/Menu';\nimport MenuOpenIcon from '@mui/icons-material/MenuOpen';\n\nimport {AppMenuContext} from '@/appShell/appMenuContext.js';\nimport BarCapsule from '@/appShell/BarCapsule.jsx';\nimport {BarActionsSlotContext} from '@/appShell/barActionsSlot.js';\nimport HeaderTools from '@/appShell/HeaderTools.jsx';\nimport MobileTabBar from '@/appShell/MobileTabBar.jsx';\nimport Wordmark from '@/appShell/Wordmark.jsx';\nimport {PageTitleProvider, usePageTitle} from '@/appShell/pageTitle.jsx';\nimport {\n APP_BAR_HEIGHT_PIXELS, DESKTOP_MEDIA_QUERY, DRAWER_WIDTH_COLLAPSED, DRAWER_WIDTH_EXPANDED, GLASS_PANEL_GAP_PIXELS, MAIN_CONTENT_ID,\n FLOATING_BOTTOM_SPACE_CSS_VARIABLE, MOBILE_TAB_BAR_HEIGHT_PIXELS, PHONE_MEDIA_QUERY, drawerTransitionOf,\n} from '@/appShell/shellSizes.js';\nimport SideMenu from '@/appShell/SideMenu.jsx';\nimport {usesMobileTabBar} from '@/appShell/tabBarRule.js';\nimport TopMenu from '@/appShell/TopMenu.jsx';\nimport {useDrawerCollapsed} from '@/appShell/useDrawerCollapsed.js';\nimport ComponentTexts from '@/toolkit/ComponentTexts.jsx';\nimport NewBuildNotice, {NEW_BUILD_NOTICE_VARIANT} from '@/feedback/NewBuildNotice.jsx';\nimport {activeMenuItemOf, menuItemsWithIconsOf} from '@/navigation/appMenu.js';\nimport {useNavigationTrail} from '@/navigationTrail.js';\nimport {THEME_LOOK, TOP_BAR} from '@/theme/createToolkitTheme.js';\nimport {PANEL_RADIUS, ambientBackgroundOf, isGlassTheme, scrollEdgeStylesOf} from '@/theme/glassSurface.js';\nimport GlassLensFilter from '@/ui/layout/GlassLensFilter.jsx';\nimport {APP_BAR_HEIGHT, useAppBarHeightPublisher} from '@/ui/layout/appBarHeight.js';\nimport {piecePart, usePieceProps, withPieceSlots} from '@/theme/themePieces.js';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaAppLayout)\nconst THEME_NAME = 'CalcitaAppLayout';\nconst LayoutSkipLink = piecePart(THEME_NAME, 'SkipLink', Link);\nconst LayoutBrand = piecePart(THEME_NAME, 'Brand', ButtonBase);\nconst LayoutBrandLogo = piecePart(THEME_NAME, 'BrandLogo', Box);\nconst LayoutBrandText = piecePart(THEME_NAME, 'BrandText', Box);\nconst LayoutBrandName = piecePart(THEME_NAME, 'BrandName', Typography);\nconst LayoutBrandCaption = piecePart(THEME_NAME, 'BrandCaption', Typography);\nconst LayoutTitleArea = piecePart(THEME_NAME, 'TitleArea', Box);\nconst LayoutPhoneTitle = piecePart(THEME_NAME, 'PhoneTitle', Typography);\nconst LayoutDesktopTitle = piecePart(THEME_NAME, 'DesktopTitle', Typography);\nconst LayoutRailBrand = piecePart(THEME_NAME, 'RailBrand', ButtonBase);\nconst LayoutRailLogo = piecePart(THEME_NAME, 'RailLogo', Box);\nconst LayoutCollapseButton = piecePart(THEME_NAME, 'CollapseButton', IconButton);\nconst LayoutRoot = piecePart(THEME_NAME, 'Root', Box);\nconst LayoutScrollEdge = piecePart(THEME_NAME, 'ScrollEdge', Box);\nconst LayoutBar = piecePart(THEME_NAME, 'Bar', AppBar);\nconst LayoutToolbar = piecePart(THEME_NAME, 'Toolbar', Toolbar);\nconst LayoutMenuButton = piecePart(THEME_NAME, 'MenuButton', IconButton);\nconst LayoutSpacer = piecePart(THEME_NAME, 'Spacer', Box);\nconst LayoutTools = piecePart(THEME_NAME, 'Tools', Box);\nconst LayoutProgress = piecePart(THEME_NAME, 'Progress', LinearProgress);\nconst LayoutBody = piecePart(THEME_NAME, 'Body', Box);\nconst LayoutDrawer = piecePart(THEME_NAME, 'Drawer', Drawer);\nconst LayoutMain = piecePart(THEME_NAME, 'Main', Box);\nconst LayoutPhoneSlot = piecePart(THEME_NAME, 'PhoneSlot', Box);\nconst LayoutContent = piecePart(THEME_NAME, 'Content', Box);\nconst LayoutPhoneDrawer = piecePart(THEME_NAME, 'PhoneDrawer', Drawer);\n\n/** Los dos estilos de barra. */\nexport const MENU_POSITION = Object.freeze({side: 'side', top: 'top'});\n\nconst NAVIGATING_BAR_PIXELS = 2;\n\n/**\n * Un grupo de la barra: con la barra en cápsulas, su cápsula (BarCapsule: de vidrio, o con el minimalista un bloque del\n * tono de las tarjetas); con la franja, sus piezas tal cual (sin caja de más, para que la franja se quede idéntica).\n */\nconst BarGroup = ({isCapsule, sx, children}) => {\n if (!isCapsule) {\n return children;\n }\n // presentation: lo de adentro (la ☰, el nombre, la cuenta) ya se anuncia solo; el grupo es solo la forma\n return <BarCapsule role=\"presentation\" sx={sx}>{children}</BarCapsule>;\n};\n\n/** «Saltar al contenido»: escondido arriba hasta que llega el foco del teclado. */\nconst SkipToContentLink = () => {\n const {t} = useToolkitTranslation('layout');\n return (\n <LayoutSkipLink href={`#${MAIN_CONTENT_ID}`} ownSx={{\n position: 'absolute', left: 8, top: -48, zIndex: (theme) => theme.zIndex.tooltip + 1, bgcolor: 'background.paper',\n px: 1.5, py: 0.75, borderRadius: 1, boxShadow: 3, '&:focus': {top: 8},\n }}>\n {t('skipToContent')}\n </LayoutSkipLink>\n );\n};\n\n/** El logo y el nombre de la app en la barra (con su renglón chico, si lo hay), o el logo ancho; lleva al inicio. */\nconst BarBrand = ({logo, wordmark, brandName, brandCaption, homePath, sx}) => {\n const {Link: RouterLink} = useToolkitNavigation();\n return (\n <LayoutBrand component={RouterLink} to={homePath} aria-label={wordmark ? brandName : undefined}\n ownSx={[{alignItems: 'center', gap: 1.25, borderRadius: 1, flexShrink: 0, minWidth: 0, pr: 1, textAlign: 'left'}, sx]}>\n {wordmark ? <Wordmark>{wordmark}</Wordmark> : (\n <>\n {logo && <LayoutBrandLogo ownSx={{width: 28, height: 28, flex: '0 0 auto', display: 'flex', alignItems: 'center', justifyContent: 'center'}}>{logo}</LayoutBrandLogo>}\n <LayoutBrandText ownSx={{minWidth: 0}}>\n <LayoutBrandName variant=\"subtitle2\" component=\"span\" noWrap ownSx={{display: 'block', fontWeight: 600, lineHeight: 1.3}}>{brandName}</LayoutBrandName>\n {/* el renglón chico hereda el color de la barra (sobre el naranja, el gris del texto secundario no se leía) */}\n {brandCaption && <LayoutBrandCaption variant=\"caption\" component=\"span\" noWrap ownSx={{display: 'block', lineHeight: 1.3, opacity: 0.8}}>{brandCaption}</LayoutBrandCaption>}\n </LayoutBrandText>\n </>\n )}\n </LayoutBrand>\n );\n};\n\n/**\n * El título en la barra: en escritorio, después del nombre de la app y solo cuando el título grande ya no se ve; en el\n * teléfono siempre (o el nombre de la app).\n */\nconst BarTitle = ({brandName}) => {\n const {title, isTitleVisible} = usePageTitle();\n return (\n <LayoutTitleArea ownSx={{flexGrow: 1, minWidth: 0}}>\n <LayoutPhoneTitle variant=\"subtitle1\" component=\"p\" noWrap ownSx={{display: 'block', [DESKTOP_MEDIA_QUERY]: {display: 'none'}, fontWeight: 600}}>{title ?? brandName}</LayoutPhoneTitle>\n <Fade in={Boolean(title) && !isTitleVisible}>\n <LayoutDesktopTitle variant=\"subtitle1\" component=\"p\" noWrap\n ownSx={{display: 'none', [DESKTOP_MEDIA_QUERY]: {display: 'block'}, fontWeight: 600, ml: 1, pl: 2, borderLeft: '1px solid color-mix(in srgb, currentColor 30%, transparent)'}}>\n {title}\n </LayoutDesktopTitle>\n </Fade>\n </LayoutTitleArea>\n );\n};\n\n/** El logo solo, arriba del menú encogido que hace de barra; lleva al inicio. */\nconst RailBrand = ({logo, brandName, homePath}) => {\n const {Link: RouterLink} = useToolkitNavigation();\n return (\n <Tooltip title={brandName} placement=\"right\">\n <LayoutRailBrand component={RouterLink} to={homePath} aria-label={brandName}\n ownSx={{width: 44, height: 44, borderRadius: '10px', display: 'flex', alignItems: 'center', justifyContent: 'center'}}>\n <LayoutRailLogo ownSx={{width: 28, height: 28, display: 'flex', alignItems: 'center', justifyContent: 'center'}}>{logo}</LayoutRailLogo>\n </LayoutRailBrand>\n </Tooltip>\n );\n};\n\n/** La ☰ de escritorio: encoge el menú lateral a solo íconos o lo vuelve a abrir. */\nconst CollapseMenuButton = ({collapsed, onToggle}) => {\n const {t} = useToolkitTranslation('layout');\n const label = collapsed ? t('drawer.expand') : t('drawer.collapse');\n return (\n <Tooltip title={label}>\n <LayoutCollapseButton aria-label={label} aria-expanded={!collapsed} onClick={onToggle} ownSx={{display: 'none', [DESKTOP_MEDIA_QUERY]: {display: 'inline-flex'}, color: 'inherit'}}>\n {collapsed ? <MenuIcon /> : <MenuOpenIcon />}\n </LayoutCollapseButton>\n </Tooltip>\n );\n};\n\nconst AppLayoutFrame = ({\n logo, wordmark, brandName, brandCaption, homePath, menuItems, menuPosition, user, profilePath, accountMenuItems, onSignOut, isSigningOut, headerActions,\n accountSettings, menuBadges, sidebarFooter, showFontSizeToggle, showLanguageToggle, showColorSchemeToggle, ribbons, isNavigating, defaultCollapsed, minimizeTabBarOnScroll, contentMaxWidth,\n onMenuCollapse, onMobileMenuChange, onMobileTabsChange, children,\n}) => {\n const {t} = useToolkitTranslation('layout');\n const {useLocation} = useToolkitNavigation();\n const {pathname} = useLocation();\n const {collapsed, toggle} = useDrawerCollapsed(defaultCollapsed);\n const [isMobileMenuOpen, setIsMobileMenuOpenState] = useState(false);\n // cada cambio del menú también sale afuera (para medir, o para que el proyecto guarde la preferencia en su servidor)\n const toggleCollapsed = () => {\n toggle();\n onMenuCollapse?.(!collapsed);\n };\n const setIsMobileMenuOpen = (isOpen) => {\n setIsMobileMenuOpenState(isOpen);\n onMobileMenuChange?.(isOpen);\n };\n const appBarRef = useAppBarHeightPublisher();\n useNavigationTrail();\n\n const theme = useTheme();\n const isGlass = isGlassTheme(theme);\n // la barra de pestañas del teléfono (estilo Apple): con vidrio, y con el minimalista en cápsulas (usesMobileTabBar);\n // sin vidrio, o con el minimalista en franja, se queda la barra de MUI arriba con su cajón\n const usesTabBar = usesMobileTabBar(theme);\n\n const isSideMenu = menuPosition !== MENU_POSITION.top;\n // con vidrio y el menú encogido, en escritorio la barra de arriba desaparece y se funde con el menú: la ☰ y el logo van\n // arriba del menú y los ajustes y la cuenta abajo (lo pidió el autor). Si el proyecto trae avisos en la barra (ribbons),\n // la barra se queda: los avisos no tendrían dónde ir\n // la barra sin franja, en cápsulas (lo de omisión con vidrio y con el minimalista; TOP_BAR.band pide la franja). El\n // estilo de Stackcraft sin vidrio se queda con su barra de siempre\n const isMinimalLook = theme.toolkit?.look === THEME_LOOK.minimal;\n const usesBarCapsules = (isGlass || isMinimalLook) && theme.toolkit?.bar === TOP_BAR.capsules;\n // con vidrio, o con cápsulas, la barra y el menú lateral van a GLASS_PANEL_GAP_PIXELS de la orilla: la columna del menú\n // mide eso de más. OJO: con el minimalista en cápsulas era 0 y las cápsulas quedaban pegadas arriba (a 4 px) y el menú\n // pegado a la izquierda (lo reportó el autor; medido en Chrome)\n const panelGap = isGlass || usesBarCapsules ? GLASS_PANEL_GAP_PIXELS : 0;\n // con cápsulas no se funde: no hay franja que esconder, y la cuenta y los ajustes se quedan arriba en su cápsula en\n // lugar de bajar al pie del menú encogido (lo pidió el autor)\n const isBarMerged = isGlass && isSideMenu && collapsed && !ribbons && !usesBarCapsules;\n const drawerWidth = collapsed ? DRAWER_WIDTH_COLLAPSED : DRAWER_WIDTH_EXPANDED;\n const activeItem = activeMenuItemOf(menuItems, pathname);\n const sideMenuProps = {logo, wordmark, brandName, brandCaption, homePath, menuItems, activeItem, menuBadges, footer: sidebarFooter};\n // el lugar de la barra donde caen las acciones de cada pantalla (BarActions); con la barra fundida con el menú no hay\n // barra en escritorio y se quedan en la pantalla\n const [barActionsSlot, setBarActionsSlot] = useState(null);\n // en el teléfono con cápsulas no hay barra de arriba (la de pestañas va abajo): las acciones flotan arriba a la derecha\n const usesPhoneFloatingActions = usesTabBar && usesBarCapsules;\n const [phoneBarActionsSlot, setPhoneBarActionsSlot] = useState(null);\n const barActions = useMemo(() => ({\n slot: isBarMerged ? null : barActionsSlot,\n phoneSlot: usesPhoneFloatingActions ? phoneBarActionsSlot : null,\n usesCapsules: usesBarCapsules,\n }), [isBarMerged, barActionsSlot, usesPhoneFloatingActions, phoneBarActionsSlot, usesBarCapsules]);\n\n return (\n <BarActionsSlotContext.Provider value={barActions}>\n <LayoutRoot ownSx={[{display: 'flex', flexDirection: 'column', minHeight: '100vh', bgcolor: 'background.default'}, isGlass && ambientBackgroundOf]}>\n <SkipToContentLink />\n <GlassLensFilter />\n\n {/* en cápsulas, lo que pasa por debajo de la barra se desenfoca en la orilla: debajo del menú lateral, que sigue nítido */}\n {isGlass && usesBarCapsules && (\n <LayoutScrollEdge aria-hidden=\"true\"\n ownSx={(theme) => ({\n ...scrollEdgeStylesOf(theme), display: 'none', [DESKTOP_MEDIA_QUERY]: {display: 'block'},\n position: 'fixed', top: 0, left: 0, right: 0, height: `calc(${APP_BAR_HEIGHT} + ${panelGap}px)`,\n zIndex: theme.zIndex.drawer - 1, pointerEvents: 'none',\n })} />\n )}\n {/* en cápsulas con vidrio la barra va transparente (color=\"transparent\": el tema no le pone vidrio) y cada grupo\n lleva el suyo; con el minimalista se queda del color del fondo, que tapa lo que pasa por debajo */}\n <LayoutBar ref={appBarRef} position=\"sticky\" color={isGlass && usesBarCapsules ? 'transparent' : undefined}\n ownSx={(theme) => ({\n pt: 'env(safe-area-inset-top)',\n // encima del menú lateral, como en el DashboardLayout de MUI\n zIndex: theme.zIndex.drawer + 1,\n // con vidrio flota: en escritorio arriba, separada de las orillas; en el teléfono ABAJO, en una cápsula,\n // como la barra de Safari en el iPhone (en el teléfono se veía cuadrada y pegada arriba; lo reportaron).\n // Abajo se suma la zona del gesto de inicio del iPhone (safe-area) a la separación\n ...(isGlass && {\n // en cápsulas no se recorta: la sombra de cada cápsula se saldría cortada\n overflow: usesBarCapsules ? 'visible' : 'hidden',\n [DESKTOP_MEDIA_QUERY]: {\n top: panelGap, mt: `${panelGap}px`, mx: `${panelGap}px`, width: 'auto',\n borderRadius: PANEL_RADIUS,\n // sin la raya de abajo de la barra fija: no hay franja que separar\n ...(usesBarCapsules && {borderBottom: 0, boxShadow: 'none'}),\n ...(isBarMerged && {display: 'none'}),\n },\n }),\n // el minimalista en cápsulas no flota (su barra es del color del fondo y tapa lo que pasa por debajo):\n // la separación de las orillas va por dentro, para que las cápsulas queden donde las del vidrio\n ...(!isGlass && usesBarCapsules && {\n [DESKTOP_MEDIA_QUERY]: {pt: `calc(env(safe-area-inset-top) + ${panelGap}px)`, px: `${panelGap}px`},\n }),\n // en el teléfono la barra de pestañas (MobileTabBar) la reemplaza: con ella van el menú y la cuenta\n ...(usesTabBar && {[PHONE_MEDIA_QUERY]: {display: 'none'}}),\n })}>\n {/* a la izquierda, la ☰ queda alineada con los íconos del menú lateral (los dos a 32 px de su orilla) */}\n <LayoutToolbar disableGutters ownSx={{minHeight: {xs: APP_BAR_HEIGHT_PIXELS, sm: APP_BAR_HEIGHT_PIXELS}, gap: 1, pl: {xs: 1.5, md: isSideMenu ? 1.5 : 3}, pr: {xs: 1.5, md: 3}}}>\n {/* la ☰ del teléfono va en la primera cápsula (en escritorio la de encoger el menú y el nombre). OJO: dentro de\n una cápsula, sin el margen negativo de «orilla de inicio» de MUI (-12 px): el botón quedaba pegado a la\n curva. Así su círculo queda concéntrico con la cápsula */}\n <BarGroup isCapsule={usesBarCapsules}>\n <LayoutMenuButton edge=\"start\" aria-label={t('drawer.open')} aria-expanded={isMobileMenuOpen} onClick={() => setIsMobileMenuOpen(true)}\n ownSx={{display: 'inline-flex', [DESKTOP_MEDIA_QUERY]: {display: 'none'}, color: 'inherit', ...((isGlass || usesBarCapsules) && {ml: 0})}}>\n <MenuIcon />\n </LayoutMenuButton>\n {isSideMenu && <CollapseMenuButton collapsed={collapsed} onToggle={toggleCollapsed} />}\n <BarBrand logo={logo} wordmark={wordmark} brandName={brandName} brandCaption={brandCaption} homePath={homePath}\n sx={isSideMenu ? {display: 'none', [DESKTOP_MEDIA_QUERY]: {display: 'flex'}} : {display: 'flex'}} />\n </BarGroup>\n {isSideMenu ? (\n <BarTitle brandName={brandName} />\n ) : (\n <>\n {/* el menú de arriba no sale en el teléfono: su cápsula tampoco (vacía se vería) */}\n <BarGroup isCapsule={usesBarCapsules} sx={{display: 'none', [DESKTOP_MEDIA_QUERY]: {display: 'flex'}}}>\n <TopMenu menuItems={menuItems} activeItem={activeItem} />\n </BarGroup>\n <LayoutSpacer ownSx={{flexGrow: 1}} />\n </>\n )}\n {/* las acciones de la pantalla abierta (BarActions, y las de PageHeading con cápsulas): cada grupo cae aquí,\n antes de la cuenta. Solo en escritorio: en el teléfono flotan arriba (phoneBarActionsSlot, en el contenido) */}\n <LayoutTools ref={setBarActionsSlot} ownSx={{display: 'none', [DESKTOP_MEDIA_QUERY]: {display: 'flex'}, alignItems: 'center', gap: 1, minWidth: 0}} />\n <BarGroup isCapsule={usesBarCapsules}>\n <HeaderTools headerActions={headerActions} accountSettings={accountSettings} showFontSizeToggle={showFontSizeToggle} showLanguageToggle={showLanguageToggle}\n showColorSchemeToggle={showColorSchemeToggle} user={user} profilePath={profilePath} accountMenuItems={accountMenuItems}\n onSignOut={onSignOut} isSigningOut={isSigningOut} />\n </BarGroup>\n </LayoutToolbar>\n {ribbons}\n {/* con la barra de pestañas el aviso de versión nueva flota aparte, en su cápsula (en el teléfono esta barra no\n se ve); sin ella, franja dentro de la barra */}\n {!usesTabBar && <NewBuildNotice />}\n {isNavigating && (\n <LayoutProgress aria-label={t('navigating')} color=\"inherit\"\n ownSx={{position: 'absolute', bottom: 0, left: 0, right: 0, height: NAVIGATING_BAR_PIXELS}} />\n )}\n </LayoutBar>\n {usesTabBar && <NewBuildNotice variant={NEW_BUILD_NOTICE_VARIANT.floating} />}\n {usesTabBar && (\n <MobileTabBar menuItems={menuItems} activeItem={activeItem} menuBadges={menuBadges} moreFooter={sidebarFooter} minimizeOnScroll={minimizeTabBarOnScroll}\n onPinnedTabsChange={onMobileTabsChange}\n account={(\n <HeaderTools headerActions={headerActions} accountSettings={accountSettings} showFontSizeToggle={showFontSizeToggle}\n showLanguageToggle={showLanguageToggle} showColorSchemeToggle={showColorSchemeToggle} user={user}\n profilePath={profilePath} accountMenuItems={accountMenuItems} onSignOut={onSignOut} isSigningOut={isSigningOut} />\n )} />\n )}\n\n <LayoutBody ownSx={{display: 'flex', flexGrow: 1, minWidth: 0}}>\n {isSideMenu && (\n <LayoutDrawer variant=\"permanent\"\n ownSx={(theme) => ({\n display: 'none', [DESKTOP_MEDIA_QUERY]: {display: 'block'}, width: drawerWidth + panelGap, flexShrink: 0, whiteSpace: 'nowrap',\n transition: drawerTransitionOf(theme),\n '& .MuiDrawer-paper': {\n width: drawerWidth, left: panelGap, boxSizing: 'border-box', overflowX: 'hidden', transition: drawerTransitionOf(theme, ['width']),\n // justo debajo de la barra (su alto real, con avisos o sin ellos) y hasta abajo; si la barra se\n // fundió con el menú, de arriba a abajo\n ...(isBarMerged\n ? {top: panelGap, height: `calc(100% - ${panelGap * 2}px)`}\n : {top: `calc(${APP_BAR_HEIGHT} + ${panelGap}px)`, height: `calc(100% - ${APP_BAR_HEIGHT} - ${panelGap * 2}px)`}),\n // el panel flotante: separado de las orillas y sin la línea de la derecha (lo separa su brillo).\n // Encogido es una cápsula (radio de la mitad de su ancho), como las barras de pestañas de vidrio\n ...(isGlass && {\n border: 0,\n borderRadius: PANEL_RADIUS,\n }),\n },\n })}>\n <SideMenu {...sideMenuProps} showBrand={false} collapsed={collapsed}\n railTop={isBarMerged ? (\n <>\n <CollapseMenuButton collapsed={collapsed} onToggle={toggleCollapsed} />\n {logo && <RailBrand logo={logo} brandName={brandName} homePath={homePath} />}\n </>\n ) : undefined}\n railBottom={isBarMerged ? (\n <HeaderTools vertical headerActions={headerActions} accountSettings={accountSettings} showFontSizeToggle={showFontSizeToggle}\n showLanguageToggle={showLanguageToggle} showColorSchemeToggle={showColorSchemeToggle} user={user}\n profilePath={profilePath} accountMenuItems={accountMenuItems} onSignOut={onSignOut}\n isSigningOut={isSigningOut} />\n ) : undefined} />\n </LayoutDrawer>\n )}\n\n <LayoutMain component=\"main\" id={MAIN_CONTENT_ID} tabIndex={-1}\n ownSx={(theme) => ({\n flexGrow: 1, minWidth: 0, outline: 'none', px: {xs: 2, md: 3, lg: 4}, pt: 3, pb: 6,\n // con la barra de pestañas abajo (teléfono): arriba, lugar para la hora y la cámara del iPhone; abajo,\n // lugar para que la barra (que flota a GLASS_PANEL_GAP_PIXELS) no tape el final de la página\n ...(usesTabBar && {\n [PHONE_MEDIA_QUERY]: {\n pt: `calc(${theme.spacing(3)} + env(safe-area-inset-top))`,\n pb: `calc(${MOBILE_TAB_BAR_HEIGHT_PIXELS.portrait + GLASS_PANEL_GAP_PIXELS * 2}px + env(safe-area-inset-bottom) + ${theme.spacing(3)} + var(${FLOATING_BOTTOM_SPACE_CSS_VARIABLE}, 0px))`,\n },\n }),\n })}>\n {/* teléfono con cápsulas: el renglón de las acciones de la pantalla, arriba a la derecha. Va pegado (sticky)\n y no fijo: así ocupa su lugar arriba de la página (no tapa las migas ni el título) y al bajar se queda\n flotando. Vacío no se ve. Solo las cápsulas reciben clics: el hueco de la izquierda deja pasar el dedo\n a lo de abajo */}\n {usesPhoneFloatingActions && (\n <LayoutPhoneSlot ref={setPhoneBarActionsSlot} data-phone-bar-actions=\"\"\n ownSx={(theme) => ({\n display: 'none',\n [PHONE_MEDIA_QUERY]: {\n display: 'flex', '&:empty': {display: 'none'},\n position: 'sticky', top: `calc(env(safe-area-inset-top) + ${GLASS_PANEL_GAP_PIXELS}px)`, zIndex: theme.zIndex.appBar,\n justifyContent: 'flex-end', alignItems: 'center', gap: 1, mb: 2,\n pointerEvents: 'none', '& > *': {pointerEvents: 'auto'},\n },\n })} />\n )}\n <LayoutContent ownSx={{maxWidth: contentMaxWidth, mx: 'auto'}}>{children}</LayoutContent>\n </LayoutMain>\n </LayoutBody>\n\n {/* el cajón del teléfono (los dos estilos): con el logo arriba, se cierra al elegir una pantalla */}\n <LayoutPhoneDrawer variant=\"temporary\" open={isMobileMenuOpen} onClose={() => setIsMobileMenuOpen(false)} ModalProps={{keepMounted: true}}\n ownSx={{[DESKTOP_MEDIA_QUERY]: {display: 'none'}}}\n slotProps={{paper: {sx: {width: DRAWER_WIDTH_EXPANDED, boxSizing: 'border-box', pt: 'env(safe-area-inset-top)', pb: 'env(safe-area-inset-bottom)'}}}}>\n <SideMenu {...sideMenuProps} collapsed={false} onNavigate={() => setIsMobileMenuOpen(false)} />\n </LayoutPhoneDrawer>\n </LayoutRoot>\n </BarActionsSlotContext.Provider>\n );\n};\n\n/**\n * @param {object} props\n * @param {import('react').ReactNode} [props.logo] el logo chico (28 px), en la barra junto al nombre y en el cajón del teléfono\n * @param {import('react').ReactNode | {light?: import('react').ReactNode, dark?: import('react').ReactNode}} [props.wordmark] el logo\n * ancho, la marca con su nombre en una sola imagen (como el de muchas empresas), o uno para cada modo ({light, dark}: el de\n * color en claro y el blanco en oscuro): va en lugar del logo y el nombre en la barra y arriba del menú del teléfono, a 24 px de alto. Con el menú\n * encogido se queda el logo chico (logo), si lo hay. brandName sigue siendo su nombre para el lector de pantalla\n * @param {string} [props.brandName] el nombre de la app; por omisión el appName de ToolkitProvider\n * @param {string} [props.brandCaption] el renglón chico debajo del nombre («Panel de administración»)\n * @param {string} [props.homePath] por omisión '/'\n * @param {object[]} [props.menuItems] lo que regresa composeMenu\n * @param {'side'|'top'} [props.menuPosition] por omisión 'side' (MENU_POSITION)\n * @param {{name: string, email?: string, subtitle?: string, avatarUrl?: string}|null} [props.user] quién está dentro\n * @param {string} [props.profilePath] la ruta de Mi perfil\n * @param {object[]} [props.accountMenuItems] renglones propios en el menú de la cuenta ({to | onClick, label | labelKey, Icon})\n * @param {() => void} [props.onSignOut] sin él no sale «Salir» (una app sin sesión)\n * @param {boolean} [props.isSigningOut]\n * @param {import('react').ReactNode} [props.headerActions] botones propios en la barra, antes de la cuenta\n * @param {Record<string, number>} [props.menuBadges] los conteos del servidor por badgeKey de cada entrada del menú\n * (useMenuBadges): lo pendiente de cada pantalla, como numerito\n * @param {import('react').ReactNode} [props.accountSettings] ajustes propios del proyecto dentro del menú de la cuenta, debajo de\n * letra, idioma y claro u oscuro (con SettingSection, para que se vean igual)\n * @param {import('react').ReactNode} [props.sidebarFooter] lo de abajo del menú lateral (una tarjeta de ayuda…)\n * @param {boolean} [props.showFontSizeToggle] por omisión sí\n * @param {boolean} [props.showLanguageToggle] por omisión sí\n * @param {boolean} [props.showColorSchemeToggle] por omisión sí\n * @param {import('react').ReactNode} [props.ribbons] avisos propios dentro de la barra\n * @param {boolean} [props.isNavigating] la pantalla siguiente se está descargando (react-router: useIsNavigating)\n * @param {boolean} [props.defaultCollapsed] el menú lateral empieza encogido (la persona lo cambia y se recuerda)\n * @param {boolean} [props.minimizeTabBarOnScroll] en el teléfono con vidrio, la barra de pestañas se encoge al leer hacia\n * abajo y regresa al subir (como iOS 26); por omisión sí\n * @param {number|string} [props.contentMaxWidth] por omisión 1400\n * @param {(collapsed: boolean) => void} [props.onMenuCollapse] la persona encogió (true) o abrió (false) el menú lateral\n * @param {(isOpen: boolean) => void} [props.onMobileMenuChange] se abrió o se cerró el menú del teléfono (el cajón)\n * @param {(keys: string[]|null) => void} [props.onMobileTabsChange] la persona eligió sus pestañas del teléfono (las llaves\n * de menuItemKeyOf; null: regresó a las de omisión). Se recuerdan en el navegador; con esto el proyecto las puede guardar\n * en su servidor\n * @param {object} [props.texts] los textos que cambian, con la forma de `layout` en los textos del paquete (para todo el marco)\n * @param {import('react').ReactNode} props.children el contenido\n */\nconst AppLayoutContent = (props) => {\n // lo que el proyecto puso en su tema (components.CalcitaAppLayout.defaultProps) y encima lo que llega aquí\n const {\n logo, wordmark, brandName, brandCaption, homePath = '/', menuItems = [], menuPosition = MENU_POSITION.side, user = null, profilePath, accountMenuItems = [], onSignOut,\n isSigningOut = false, headerActions, accountSettings, menuBadges, sidebarFooter, showFontSizeToggle = true, showLanguageToggle = true, showColorSchemeToggle = true, ribbons,\n isNavigating = false, defaultCollapsed = false, minimizeTabBarOnScroll = true, contentMaxWidth = 1400, onMenuCollapse, onMobileMenuChange, onMobileTabsChange,\n texts, children,\n ...unknownProps\n} = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n const {appName} = useToolkitSettings();\n // un ícono ya pintado (icon) se vuelve componente aquí, una vez: las piezas del menú pintan siempre Icon\n const shownMenuItems = useMemo(() => menuItemsWithIconsOf(menuItems), [menuItems]);\n const appMenu = useMemo(() => ({menuItems: shownMenuItems}), [shownMenuItems]);\n // los textos del marco llegan a todas sus piezas (la cuenta, el menú, las pestañas del teléfono), cada una lee los suyos\n return (\n <ComponentTexts namespace=\"layout\" texts={texts}>\n <PageTitleProvider>\n <AppMenuContext.Provider value={appMenu}>\n <AppLayoutFrame logo={logo} wordmark={wordmark} brandName={brandName ?? appName} brandCaption={brandCaption} homePath={homePath} menuItems={shownMenuItems} menuPosition={menuPosition}\n user={user} profilePath={profilePath} accountMenuItems={accountMenuItems} onSignOut={onSignOut} isSigningOut={isSigningOut}\n headerActions={headerActions} accountSettings={accountSettings} menuBadges={menuBadges} sidebarFooter={sidebarFooter} showFontSizeToggle={showFontSizeToggle}\n showLanguageToggle={showLanguageToggle} showColorSchemeToggle={showColorSchemeToggle} ribbons={ribbons}\n isNavigating={isNavigating} defaultCollapsed={defaultCollapsed} minimizeTabBarOnScroll={minimizeTabBarOnScroll}\n contentMaxWidth={contentMaxWidth} onMenuCollapse={onMenuCollapse} onMobileMenuChange={onMobileMenuChange}\n onMobileTabsChange={onMobileTabsChange}>\n {children}\n </AppLayoutFrame>\n </AppMenuContext.Provider>\n </PageTitleProvider>\n </ComponentTexts>\n );\n};\n\n// lo que se exporta: la pieza con slots y slotProps para cambiar sus partes (themePieces.js)\nexport const AppLayout = withPieceSlots(AppLayoutContent, THEME_NAME);\n"],"names":["theme"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8FA,MAAM,aAAa;AACnB,MAAM,iBAAiB,UAAU,YAAY,YAAY,IAAI;AAC7D,MAAM,cAAc,UAAU,YAAY,SAAS,UAAU;AAC7D,MAAM,kBAAkB,UAAU,YAAY,aAAa,GAAG;AAC9D,MAAM,kBAAkB,UAAU,YAAY,aAAa,GAAG;AAC9D,MAAM,kBAAkB,UAAU,YAAY,aAAa,UAAU;AACrE,MAAM,qBAAqB,UAAU,YAAY,gBAAgB,UAAU;AAC3E,MAAM,kBAAkB,UAAU,YAAY,aAAa,GAAG;AAC9D,MAAM,mBAAmB,UAAU,YAAY,cAAc,UAAU;AACvE,MAAM,qBAAqB,UAAU,YAAY,gBAAgB,UAAU;AAC3E,MAAM,kBAAkB,UAAU,YAAY,aAAa,UAAU;AACrE,MAAM,iBAAiB,UAAU,YAAY,YAAY,GAAG;AAC5D,MAAM,uBAAuB,UAAU,YAAY,kBAAkB,UAAU;AAC/E,MAAM,aAAa,UAAU,YAAY,QAAQ,GAAG;AACpD,MAAM,mBAAmB,UAAU,YAAY,cAAc,GAAG;AAChE,MAAM,YAAY,UAAU,YAAY,OAAO,MAAM;AACrD,MAAM,gBAAgB,UAAU,YAAY,WAAW,OAAO;AAC9D,MAAM,mBAAmB,UAAU,YAAY,cAAc,UAAU;AACvE,MAAM,eAAe,UAAU,YAAY,UAAU,GAAG;AACxD,MAAM,cAAc,UAAU,YAAY,SAAS,GAAG;AACtD,MAAM,iBAAiB,UAAU,YAAY,YAAY,cAAc;AACvE,MAAM,aAAa,UAAU,YAAY,QAAQ,GAAG;AACpD,MAAM,eAAe,UAAU,YAAY,UAAU,MAAM;AAC3D,MAAM,aAAa,UAAU,YAAY,QAAQ,GAAG;AACpD,MAAM,kBAAkB,UAAU,YAAY,aAAa,GAAG;AAC9D,MAAM,gBAAgB,UAAU,YAAY,WAAW,GAAG;AAC1D,MAAM,oBAAoB,UAAU,YAAY,eAAe,MAAM;AAG9D,MAAM,gBAAgB,OAAO,OAAO,EAAC,MAAM,QAAQ,KAAK,OAAM;AAErE,MAAM,wBAAwB;AAM9B,MAAM,WAAW,CAAC,EAAC,WAAW,IAAI,eAAc;AAC5C,MAAI,CAAC,WAAW;AACZ,WAAO;AAAA,EACX;AAEA,SAAO,oBAAC,YAAA,EAAW,MAAK,gBAAe,IAAS,UAAS;AAC7D;AAGA,MAAM,oBAAoB,MAAM;AAC5B,QAAM,EAAC,EAAA,IAAK,sBAAsB,QAAQ;AAC1C,6BACK,gBAAA,EAAe,MAAM,IAAI,eAAe,IAAI,OAAO;AAAA,IAChD,UAAU;AAAA,IAAY,MAAM;AAAA,IAAG,KAAK;AAAA,IAAK,QAAQ,CAAC,UAAU,MAAM,OAAO,UAAU;AAAA,IAAG,SAAS;AAAA,IAC/F,IAAI;AAAA,IAAK,IAAI;AAAA,IAAM,cAAc;AAAA,IAAG,WAAW;AAAA,IAAG,WAAW,EAAC,KAAK,EAAA;AAAA,EAAC,GAEnE,UAAA,EAAE,eAAe,GACtB;AAER;AAGA,MAAM,WAAW,CAAC,EAAC,MAAM,UAAU,WAAW,cAAc,UAAU,SAAQ;AAC1E,QAAM,EAAC,MAAM,WAAA,IAAc,qBAAA;AAC3B,SACI;AAAA,IAAC;AAAA,IAAA;AAAA,MAAY,WAAW;AAAA,MAAY,IAAI;AAAA,MAAU,cAAY,WAAW,YAAY;AAAA,MACzE,OAAO,CAAC,EAAC,YAAY,UAAU,KAAK,MAAM,cAAc,GAAG,YAAY,GAAG,UAAU,GAAG,IAAI,GAAG,WAAW,OAAA,GAAS,EAAE;AAAA,MAC3H,UAAA,WAAW,oBAAC,UAAA,EAAU,UAAA,SAAA,CAAS,IAC5B,qBAAA,UAAA,EACK,UAAA;AAAA,QAAA,4BAAS,iBAAA,EAAgB,OAAO,EAAC,OAAO,IAAI,QAAQ,IAAI,MAAM,YAAY,SAAS,QAAQ,YAAY,UAAU,gBAAgB,SAAA,GAAY,UAAA,MAAK;AAAA,6BAClJ,iBAAA,EAAgB,OAAO,EAAC,UAAU,KAC/B,UAAA;AAAA,UAAA,oBAAC,mBAAgB,SAAQ,aAAY,WAAU,QAAO,QAAM,MAAC,OAAO,EAAC,SAAS,SAAS,YAAY,KAAK,YAAY,IAAA,GAAO,UAAA,WAAU;AAAA,UAEpI,gBAAgB,oBAAC,oBAAA,EAAmB,SAAQ,WAAU,WAAU,QAAO,QAAM,MAAC,OAAO,EAAC,SAAS,SAAS,YAAY,KAAK,SAAS,IAAA,GAAO,UAAA,aAAA,CAAa;AAAA,QAAA,EAAA,CAC3J;AAAA,MAAA,EAAA,CACJ;AAAA,IAAA;AAAA,EAAA;AAIhB;AAMA,MAAM,WAAW,CAAC,EAAC,gBAAe;AAC9B,QAAM,EAAC,OAAO,eAAA,IAAkB,aAAA;AAChC,SACI,qBAAC,mBAAgB,OAAO,EAAC,UAAU,GAAG,UAAU,KAC5C,UAAA;AAAA,IAAA,oBAAC,kBAAA,EAAiB,SAAQ,aAAY,WAAU,KAAI,QAAM,MAAC,OAAO,EAAC,SAAS,SAAS,CAAC,mBAAmB,GAAG,EAAC,SAAS,UAAS,YAAY,IAAA,GAAO,UAAA,SAAS,WAAU;AAAA,wBACpK,MAAA,EAAK,IAAI,QAAQ,KAAK,KAAK,CAAC,gBACzB,UAAA;AAAA,MAAC;AAAA,MAAA;AAAA,QAAmB,SAAQ;AAAA,QAAY,WAAU;AAAA,QAAI,QAAM;AAAA,QAChD,OAAO,EAAC,SAAS,QAAQ,CAAC,mBAAmB,GAAG,EAAC,SAAS,QAAA,GAAU,YAAY,KAAK,IAAI,GAAG,IAAI,GAAG,YAAY,8DAAA;AAAA,QACtH,UAAA;AAAA,MAAA;AAAA,IAAA,EACL,CACJ;AAAA,EAAA,GACJ;AAER;AAGA,MAAM,YAAY,CAAC,EAAC,MAAM,WAAW,eAAc;AAC/C,QAAM,EAAC,MAAM,WAAA,IAAc,qBAAA;AAC3B,SACI,oBAAC,SAAA,EAAQ,OAAO,WAAW,WAAU,SACjC,UAAA;AAAA,IAAC;AAAA,IAAA;AAAA,MAAgB,WAAW;AAAA,MAAY,IAAI;AAAA,MAAU,cAAY;AAAA,MACtD,OAAO,EAAC,OAAO,IAAI,QAAQ,IAAI,cAAc,QAAQ,SAAS,QAAQ,YAAY,UAAU,gBAAgB,SAAA;AAAA,MACpH,UAAA,oBAAC,gBAAA,EAAe,OAAO,EAAC,OAAO,IAAI,QAAQ,IAAI,SAAS,QAAQ,YAAY,UAAU,gBAAgB,SAAA,GAAY,UAAA,KAAA,CAAK;AAAA,IAAA;AAAA,EAAA,GAE/H;AAER;AAGA,MAAM,qBAAqB,CAAC,EAAC,WAAW,eAAc;AAClD,QAAM,EAAC,EAAA,IAAK,sBAAsB,QAAQ;AAC1C,QAAM,QAAQ,YAAY,EAAE,eAAe,IAAI,EAAE,iBAAiB;AAClE,SACI,oBAAC,SAAA,EAAQ,OAAO,OACZ,8BAAC,sBAAA,EAAqB,cAAY,OAAO,iBAAe,CAAC,WAAW,SAAS,UAAU,OAAO,EAAC,SAAS,QAAQ,CAAC,mBAAmB,GAAG,EAAC,SAAS,cAAA,GAAgB,OAAO,UAAA,GACnK,UAAA,gCAAa,UAAA,CAAA,CAAS,IAAK,oBAAC,cAAA,CAAA,CAAa,GAC9C,GACJ;AAER;AAEA,MAAM,iBAAiB,CAAC;AAAA,EACpB;AAAA,EAAM;AAAA,EAAU;AAAA,EAAW;AAAA,EAAc;AAAA,EAAU;AAAA,EAAW;AAAA,EAAc;AAAA,EAAM;AAAA,EAAa;AAAA,EAAkB;AAAA,EAAW;AAAA,EAAc;AAAA,EAC1I;AAAA,EAAiB;AAAA,EAAY;AAAA,EAAe;AAAA,EAAoB;AAAA,EAAoB;AAAA,EAAuB;AAAA,EAAS;AAAA,EAAc;AAAA,EAAkB;AAAA,EAAwB;AAAA,EAC5K;AAAA,EAAgB;AAAA,EAAoB;AAAA,EAAoB;AAC5D,MAAM;AACF,QAAM,EAAC,EAAA,IAAK,sBAAsB,QAAQ;AAC1C,QAAM,EAAC,YAAA,IAAe,qBAAA;AACtB,QAAM,EAAC,SAAA,IAAY,YAAA;AACnB,QAAM,EAAC,WAAW,WAAU,mBAAmB,gBAAgB;AAC/D,QAAM,CAAC,kBAAkB,wBAAwB,IAAI,SAAS,KAAK;AAEnE,QAAM,kBAAkB,MAAM;AAC1B,WAAA;AACA,qBAAiB,CAAC,SAAS;AAAA,EAC/B;AACA,QAAM,sBAAsB,CAAC,WAAW;AACpC,6BAAyB,MAAM;AAC/B,yBAAqB,MAAM;AAAA,EAC/B;AACA,QAAM,YAAY,yBAAA;AAClB,qBAAA;AAEA,QAAM,QAAQ,SAAA;AACd,QAAM,UAAU,aAAa,KAAK;AAGlC,QAAM,aAAa,iBAAiB,KAAK;AAEzC,QAAM,aAAa,iBAAiB,cAAc;AAMlD,QAAM,gBAAgB,MAAM,SAAS,SAAS,WAAW;AACzD,QAAM,mBAAmB,WAAW,kBAAkB,MAAM,SAAS,QAAQ,QAAQ;AAIrF,QAAM,WAAW,WAAW,kBAAkB,yBAAyB;AAGvE,QAAM,cAAc,WAAW,cAAc,aAAa,CAAC,WAAW,CAAC;AACvE,QAAM,cAAc,YAAY,yBAAyB;AACzD,QAAM,aAAa,iBAAiB,WAAW,QAAQ;AACvD,QAAM,gBAAgB,EAAC,MAAM,UAAU,WAAW,cAAc,UAAU,WAAW,YAAY,YAAY,QAAQ,cAAA;AAGrH,QAAM,CAAC,gBAAgB,iBAAiB,IAAI,SAAS,IAAI;AAEzD,QAAM,2BAA2B,cAAc;AAC/C,QAAM,CAAC,qBAAqB,sBAAsB,IAAI,SAAS,IAAI;AACnE,QAAM,aAAa,QAAQ,OAAO;AAAA,IAC9B,MAAM,cAAc,OAAO;AAAA,IAC3B,WAAW,2BAA2B,sBAAsB;AAAA,IAC5D,cAAc;AAAA,EAAA,IACd,CAAC,aAAa,gBAAgB,0BAA0B,qBAAqB,eAAe,CAAC;AAEjG,SACI,oBAAC,sBAAsB,UAAtB,EAA+B,OAAO,YACvC,UAAA,qBAAC,YAAA,EAAW,OAAO,CAAC,EAAC,SAAS,QAAQ,eAAe,UAAU,WAAW,SAAS,SAAS,wBAAuB,WAAW,mBAAmB,GAC7I,UAAA;AAAA,IAAA,oBAAC,mBAAA,EAAkB;AAAA,wBAClB,iBAAA,EAAgB;AAAA,IAGhB,WAAW,mBACR;AAAA,MAAC;AAAA,MAAA;AAAA,QAAiB,eAAY;AAAA,QACzB,OAAO,CAACA,YAAW;AAAA,UACf,GAAG,mBAAmBA,MAAK;AAAA,UAAG,SAAS;AAAA,UAAQ,CAAC,mBAAmB,GAAG,EAAC,SAAS,QAAA;AAAA,UAChF,UAAU;AAAA,UAAS,KAAK;AAAA,UAAG,MAAM;AAAA,UAAG,OAAO;AAAA,UAAG,QAAQ,QAAQ,cAAc,MAAM,QAAQ;AAAA,UAC1F,QAAQA,OAAM,OAAO,SAAS;AAAA,UAAG,eAAe;AAAA,QAAA;AAAA,MACpD;AAAA,IAAA;AAAA,IAIT;AAAA,MAAC;AAAA,MAAA;AAAA,QAAU,KAAK;AAAA,QAAW,UAAS;AAAA,QAAS,OAAO,WAAW,kBAAkB,gBAAgB;AAAA,QACzF,OAAO,CAACA,YAAW;AAAA,UACf,IAAI;AAAA;AAAA,UAEJ,QAAQA,OAAM,OAAO,SAAS;AAAA;AAAA;AAAA;AAAA,UAI9B,GAAI,WAAW;AAAA;AAAA,YAEX,UAAU,kBAAkB,YAAY;AAAA,YACxC,CAAC,mBAAmB,GAAG;AAAA,cACnB,KAAK;AAAA,cAAU,IAAI,GAAG,QAAQ;AAAA,cAAM,IAAI,GAAG,QAAQ;AAAA,cAAM,OAAO;AAAA,cAChE,cAAc;AAAA;AAAA,cAEd,GAAI,mBAAmB,EAAC,cAAc,GAAG,WAAW,OAAA;AAAA,cACpD,GAAI,eAAe,EAAC,SAAS,OAAA;AAAA,YAAM;AAAA,UACvC;AAAA;AAAA;AAAA,UAIJ,GAAI,CAAC,WAAW,mBAAmB;AAAA,YAC/B,CAAC,mBAAmB,GAAG,EAAC,IAAI,mCAAmC,QAAQ,OAAO,IAAI,GAAG,QAAQ,KAAA;AAAA,UAAI;AAAA;AAAA,UAGrG,GAAI,cAAc,EAAC,CAAC,iBAAiB,GAAG,EAAC,SAAS,OAAA,EAAM;AAAA,QAAC;AAAA,QAGjE,UAAA;AAAA,UAAA,qBAAC,eAAA,EAAc,gBAAc,MAAC,OAAO,EAAC,WAAW,EAAC,IAAI,uBAAuB,IAAI,sBAAA,GAAwB,KAAK,GAAG,IAAI,EAAC,IAAI,KAAK,IAAI,aAAa,MAAM,EAAA,GAAI,IAAI,EAAC,IAAI,KAAK,IAAI,EAAA,KAIxK,UAAA;AAAA,YAAA,qBAAC,UAAA,EAAS,WAAW,iBACjB,UAAA;AAAA,cAAA;AAAA,gBAAC;AAAA,gBAAA;AAAA,kBAAiB,MAAK;AAAA,kBAAQ,cAAY,EAAE,aAAa;AAAA,kBAAG,iBAAe;AAAA,kBAAkB,SAAS,MAAM,oBAAoB,IAAI;AAAA,kBACzH,OAAO,EAAC,SAAS,eAAe,CAAC,mBAAmB,GAAG,EAAC,SAAS,UAAS,OAAO,WAAW,IAAK,WAAW,oBAAoB,EAAC,IAAI,IAAC;AAAA,kBAC9I,8BAAC,UAAA,CAAA,CAAS;AAAA,gBAAA;AAAA,cAAA;AAAA,cAEb,cAAc,oBAAC,oBAAA,EAAmB,WAAsB,UAAU,iBAAiB;AAAA,cACpF;AAAA,gBAAC;AAAA,gBAAA;AAAA,kBAAS;AAAA,kBAAY;AAAA,kBAAoB;AAAA,kBAAsB;AAAA,kBAA4B;AAAA,kBAClF,IAAI,aAAa,EAAC,SAAS,QAAQ,CAAC,mBAAmB,GAAG,EAAC,SAAS,OAAA,MAAW,EAAC,SAAS,OAAA;AAAA,gBAAM;AAAA,cAAA;AAAA,YAAG,GAChH;AAAA,YACC,aACG,oBAAC,UAAA,EAAS,UAAA,CAAsB,IAEhC,qBAAA,UAAA,EAEI,UAAA;AAAA,cAAA,oBAAC,YAAS,WAAW,iBAAiB,IAAI,EAAC,SAAS,QAAQ,CAAC,mBAAmB,GAAG,EAAC,SAAS,YACzF,8BAAC,SAAA,EAAQ,WAAsB,YAAwB,GAC3D;AAAA,kCACC,cAAA,EAAa,OAAO,EAAC,UAAU,IAAC,CAAG;AAAA,YAAA,GACxC;AAAA,YAIJ,oBAAC,eAAY,KAAK,mBAAmB,OAAO,EAAC,SAAS,QAAQ,CAAC,mBAAmB,GAAG,EAAC,SAAS,UAAS,YAAY,UAAU,KAAK,GAAG,UAAU,EAAA,GAAI;AAAA,YACpJ,oBAAC,UAAA,EAAS,WAAW,iBACjB,UAAA;AAAA,cAAC;AAAA,cAAA;AAAA,gBAAY;AAAA,gBAA8B;AAAA,gBAAkC;AAAA,gBAAwC;AAAA,gBACxG;AAAA,gBAA8C;AAAA,gBAAY;AAAA,gBAA0B;AAAA,gBACpF;AAAA,gBAAsB;AAAA,cAAA;AAAA,YAAA,EAA4B,CACnE;AAAA,UAAA,GACJ;AAAA,UACC;AAAA,UAGA,CAAC,cAAc,oBAAC,gBAAA,EAAe;AAAA,UAC/B,gBACG;AAAA,YAAC;AAAA,YAAA;AAAA,cAAe,cAAY,EAAE,YAAY;AAAA,cAAG,OAAM;AAAA,cACnC,OAAO,EAAC,UAAU,YAAY,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,sBAAA;AAAA,YAAqB;AAAA,UAAA;AAAA,QAAG;AAAA,MAAA;AAAA,IAAA;AAAA,IAGnH,cAAc,oBAAC,gBAAA,EAAe,SAAS,yBAAyB,UAAU;AAAA,IAC1E,cACG;AAAA,MAAC;AAAA,MAAA;AAAA,QAAa;AAAA,QAAsB;AAAA,QAAwB;AAAA,QAAwB,YAAY;AAAA,QAAe,kBAAkB;AAAA,QACnH,oBAAoB;AAAA,QACpB,SACI;AAAA,UAAC;AAAA,UAAA;AAAA,YAAY;AAAA,YAA8B;AAAA,YAAkC;AAAA,YAChE;AAAA,YAAwC;AAAA,YAA8C;AAAA,YACtF;AAAA,YAA0B;AAAA,YAAoC;AAAA,YAAsB;AAAA,UAAA;AAAA,QAAA;AAAA,MAA4B;AAAA,IAAA;AAAA,IAInJ,qBAAC,YAAA,EAAW,OAAO,EAAC,SAAS,QAAQ,UAAU,GAAG,UAAU,EAAA,GACvD,UAAA;AAAA,MAAA,cACG;AAAA,QAAC;AAAA,QAAA;AAAA,UAAa,SAAQ;AAAA,UACd,OAAO,CAACA,YAAW;AAAA,YACf,SAAS;AAAA,YAAQ,CAAC,mBAAmB,GAAG,EAAC,SAAS,QAAA;AAAA,YAAU,OAAO,cAAc;AAAA,YAAU,YAAY;AAAA,YAAG,YAAY;AAAA,YACtH,YAAY,mBAAmBA,MAAK;AAAA,YACpC,sBAAsB;AAAA,cAClB,OAAO;AAAA,cAAa,MAAM;AAAA,cAAU,WAAW;AAAA,cAAc,WAAW;AAAA,cAAU,YAAY,mBAAmBA,QAAO,CAAC,OAAO,CAAC;AAAA;AAAA;AAAA,cAGjI,GAAI,cACE,EAAC,KAAK,UAAU,QAAQ,eAAe,WAAW,CAAC,MAAA,IACnD,EAAC,KAAK,QAAQ,cAAc,MAAM,QAAQ,OAAO,QAAQ,eAAe,cAAc,MAAM,WAAW,CAAC,MAAA;AAAA;AAAA;AAAA,cAG9G,GAAI,WAAW;AAAA,gBACX,QAAQ;AAAA,gBACR,cAAc;AAAA,cAAA;AAAA,YAClB;AAAA,UACJ;AAAA,UAER,UAAA;AAAA,YAAC;AAAA,YAAA;AAAA,cAAU,GAAG;AAAA,cAAe,WAAW;AAAA,cAAO;AAAA,cACrC,SAAS,cACL,qBAAA,UAAA,EACI,UAAA;AAAA,gBAAA,oBAAC,oBAAA,EAAmB,WAAsB,UAAU,gBAAA,CAAiB;AAAA,gBACpE,QAAQ,oBAAC,WAAA,EAAU,MAAY,WAAsB,SAAA,CAAoB;AAAA,cAAA,EAAA,CAC9E,IACA;AAAA,cACJ,YAAY,cACR;AAAA,gBAAC;AAAA,gBAAA;AAAA,kBAAY,UAAQ;AAAA,kBAAC;AAAA,kBAA8B;AAAA,kBAAkC;AAAA,kBACzE;AAAA,kBAAwC;AAAA,kBAA8C;AAAA,kBACtF;AAAA,kBAA0B;AAAA,kBAAoC;AAAA,kBAC9D;AAAA,gBAAA;AAAA,cAAA,IACb;AAAA,YAAA;AAAA,UAAA;AAAA,QAAW;AAAA,MAAA;AAAA,MAIjC;AAAA,QAAC;AAAA,QAAA;AAAA,UAAW,WAAU;AAAA,UAAO,IAAI;AAAA,UAAiB,UAAU;AAAA,UACvD,OAAO,CAACA,YAAW;AAAA,YACf,UAAU;AAAA,YAAG,UAAU;AAAA,YAAG,SAAS;AAAA,YAAQ,IAAI,EAAC,IAAI,GAAG,IAAI,GAAG,IAAI,EAAA;AAAA,YAAI,IAAI;AAAA,YAAG,IAAI;AAAA;AAAA;AAAA,YAGjF,GAAI,cAAc;AAAA,cACd,CAAC,iBAAiB,GAAG;AAAA,gBACjB,IAAI,QAAQA,OAAM,QAAQ,CAAC,CAAC;AAAA,gBAC5B,IAAI,QAAQ,6BAA6B,WAAW,yBAAyB,CAAC,sCAAsCA,OAAM,QAAQ,CAAC,CAAC,UAAU,kCAAkC;AAAA,cAAA;AAAA,YACpL;AAAA,UACJ;AAAA,UAMJ,UAAA;AAAA,YAAA,4BACG;AAAA,cAAC;AAAA,cAAA;AAAA,gBAAgB,KAAK;AAAA,gBAAwB,0BAAuB;AAAA,gBAChE,OAAO,CAACA,YAAW;AAAA,kBACf,SAAS;AAAA,kBACT,CAAC,iBAAiB,GAAG;AAAA,oBACjB,SAAS;AAAA,oBAAQ,WAAW,EAAC,SAAS,OAAA;AAAA,oBACtC,UAAU;AAAA,oBAAU,KAAK,mCAAmC,sBAAsB;AAAA,oBAAO,QAAQA,OAAM,OAAO;AAAA,oBAC9G,gBAAgB;AAAA,oBAAY,YAAY;AAAA,oBAAU,KAAK;AAAA,oBAAG,IAAI;AAAA,oBAC9D,eAAe;AAAA,oBAAQ,SAAS,EAAC,eAAe,OAAA;AAAA,kBAAM;AAAA,gBAC1D;AAAA,cACJ;AAAA,YAAA;AAAA,YAET,oBAAC,iBAAc,OAAO,EAAC,UAAU,iBAAiB,IAAI,OAAA,GAAU,SAAA,CAAS;AAAA,UAAA;AAAA,QAAA;AAAA,MAAA;AAAA,IAC7E,GACJ;AAAA,IAGA;AAAA,MAAC;AAAA,MAAA;AAAA,QAAkB,SAAQ;AAAA,QAAY,MAAM;AAAA,QAAkB,SAAS,MAAM,oBAAoB,KAAK;AAAA,QAAG,YAAY,EAAC,aAAa,KAAA;AAAA,QAC5H,OAAO,EAAC,CAAC,mBAAmB,GAAG,EAAC,SAAS,SAAM;AAAA,QAC/C,WAAW,EAAC,OAAO,EAAC,IAAI,EAAC,OAAO,uBAAuB,WAAW,cAAc,IAAI,4BAA4B,IAAI,8BAAA,IAA8B;AAAA,QACtJ,UAAA,oBAAC,UAAA,EAAU,GAAG,eAAe,WAAW,OAAO,YAAY,MAAM,oBAAoB,KAAK,EAAA,CAAG;AAAA,MAAA;AAAA,IAAA;AAAA,EACjG,EAAA,CACJ,EAAA,CACA;AAER;AA0CA,MAAM,mBAAmB,CAAC,UAAU;AAEhC,QAAM;AAAA,IACN;AAAA,IAAM;AAAA,IAAU;AAAA,IAAW;AAAA,IAAc,WAAW;AAAA,IAAK,YAAY,CAAA;AAAA,IAAI,eAAe,cAAc;AAAA,IAAM,OAAO;AAAA,IAAM;AAAA,IAAa,mBAAmB,CAAA;AAAA,IAAI;AAAA,IAC7J,eAAe;AAAA,IAAO;AAAA,IAAe;AAAA,IAAiB;AAAA,IAAY;AAAA,IAAe,qBAAqB;AAAA,IAAM,qBAAqB;AAAA,IAAM,wBAAwB;AAAA,IAAM;AAAA,IACrK,eAAe;AAAA,IAAO,mBAAmB;AAAA,IAAO,yBAAyB;AAAA,IAAM,kBAAkB;AAAA,IAAM;AAAA,IAAgB;AAAA,IAAoB;AAAA,IAC3I;AAAA,IAAO;AAAA,IACP,GAAG;AAAA,EAAA,IACH,cAAc,OAAO,UAAU;AAC/B,mBAAiB,YAAY,YAAY;AACzC,QAAM,EAAC,QAAA,IAAW,mBAAA;AAElB,QAAM,iBAAiB,QAAQ,MAAM,qBAAqB,SAAS,GAAG,CAAC,SAAS,CAAC;AACjF,QAAM,UAAU,QAAQ,OAAO,EAAC,WAAW,mBAAkB,CAAC,cAAc,CAAC;AAE7E,SACI,oBAAC,gBAAA,EAAe,WAAU,UAAS,OAC/B,UAAA,oBAAC,mBAAA,EACG,UAAA,oBAAC,eAAe,UAAf,EAAwB,OAAO,SAC5B,UAAA;AAAA,IAAC;AAAA,IAAA;AAAA,MAAe;AAAA,MAAY;AAAA,MAAoB,WAAW,aAAa;AAAA,MAAS;AAAA,MAA4B;AAAA,MAAoB,WAAW;AAAA,MAAgB;AAAA,MAC5I;AAAA,MAAY;AAAA,MAA0B;AAAA,MAAoC;AAAA,MAAsB;AAAA,MAChG;AAAA,MAA8B;AAAA,MAAkC;AAAA,MAAwB;AAAA,MAA8B;AAAA,MACtH;AAAA,MAAwC;AAAA,MAA8C;AAAA,MACtF;AAAA,MAA4B;AAAA,MAAoC;AAAA,MAChE;AAAA,MAAkC;AAAA,MAAgC;AAAA,MAClE;AAAA,MACX;AAAA,IAAA;AAAA,EAAA,EACL,CACJ,GACJ,GACJ;AAER;AAGO,MAAM,YAAY,eAAe,kBAAkB,UAAU;"}