@stackcraftmx/calcita 0.31.0 → 0.32.1

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 (281) hide show
  1. package/README.md +7 -0
  2. package/dist/DataTable/AuditTrailDialog.js +4 -1
  3. package/dist/DataTable/AuditTrailDialog.js.map +1 -1
  4. package/dist/DataTable/AuditTrailTable.js +4 -1
  5. package/dist/DataTable/AuditTrailTable.js.map +1 -1
  6. package/dist/DataTable/ColumnFilters/HeaderFilterPopover.js +3 -1
  7. package/dist/DataTable/ColumnFilters/HeaderFilterPopover.js.map +1 -1
  8. package/dist/DataTable/ColumnFilters/MultiSelectColumnFilter.js +3 -1
  9. package/dist/DataTable/ColumnFilters/MultiSelectColumnFilter.js.map +1 -1
  10. package/dist/DataTable/ColumnFilters/SortableFilterHeader.js +4 -1
  11. package/dist/DataTable/ColumnFilters/SortableFilterHeader.js.map +1 -1
  12. package/dist/DataTable/ColumnFilters/TextColumnFilter.js +3 -1
  13. package/dist/DataTable/ColumnFilters/TextColumnFilter.js.map +1 -1
  14. package/dist/DataTable/EmptyState.js +3 -1
  15. package/dist/DataTable/EmptyState.js.map +1 -1
  16. package/dist/DataTable/FilterChips.js +3 -1
  17. package/dist/DataTable/FilterChips.js.map +1 -1
  18. package/dist/DataTable/GoToPage.js +3 -1
  19. package/dist/DataTable/GoToPage.js.map +1 -1
  20. package/dist/DataTable/ServerTable.js +4 -1
  21. package/dist/DataTable/ServerTable.js.map +1 -1
  22. package/dist/DataTable/columns.js +3 -1
  23. package/dist/DataTable/columns.js.map +1 -1
  24. package/dist/access/Can.js +3 -1
  25. package/dist/access/Can.js.map +1 -1
  26. package/dist/access/PermissionMatrix.js +3 -1
  27. package/dist/access/PermissionMatrix.js.map +1 -1
  28. package/dist/access/RequireAccess.js +3 -1
  29. package/dist/access/RequireAccess.js.map +1 -1
  30. package/dist/account/AccountProvider.js +3 -1
  31. package/dist/account/AccountProvider.js.map +1 -1
  32. package/dist/account/AccountSecuritySection.js +3 -1
  33. package/dist/account/AccountSecuritySection.js.map +1 -1
  34. package/dist/account/DemoTotpCodeButton.js +3 -1
  35. package/dist/account/DemoTotpCodeButton.js.map +1 -1
  36. package/dist/account/ForgotPasswordScreen.js +3 -1
  37. package/dist/account/ForgotPasswordScreen.js.map +1 -1
  38. package/dist/account/ProfileScreen.js +4 -1
  39. package/dist/account/ProfileScreen.js.map +1 -1
  40. package/dist/account/ResetPasswordScreen.js +4 -1
  41. package/dist/account/ResetPasswordScreen.js.map +1 -1
  42. package/dist/account/SignInScreen.js +3 -1
  43. package/dist/account/SignInScreen.js.map +1 -1
  44. package/dist/appShell/AccountMenu.js +3 -1
  45. package/dist/appShell/AccountMenu.js.map +1 -1
  46. package/dist/appShell/AppLayout.js +4 -1
  47. package/dist/appShell/AppLayout.js.map +1 -1
  48. package/dist/appShell/AppearanceSettings.js +4 -1
  49. package/dist/appShell/AppearanceSettings.js.map +1 -1
  50. package/dist/appShell/AuthLayout.js +3 -1
  51. package/dist/appShell/AuthLayout.js.map +1 -1
  52. package/dist/appShell/BarActions.js +3 -1
  53. package/dist/appShell/BarActions.js.map +1 -1
  54. package/dist/appShell/BarSearch.js +3 -1
  55. package/dist/appShell/BarSearch.js.map +1 -1
  56. package/dist/appShell/HeaderTools.js +4 -1
  57. package/dist/appShell/HeaderTools.js.map +1 -1
  58. package/dist/appShell/MenuLinks.js +3 -1
  59. package/dist/appShell/MenuLinks.js.map +1 -1
  60. package/dist/appShell/MobileTabBar.js +3 -1
  61. package/dist/appShell/MobileTabBar.js.map +1 -1
  62. package/dist/appShell/SettingsMenu.js +3 -1
  63. package/dist/appShell/SettingsMenu.js.map +1 -1
  64. package/dist/appShell/SideMenu.js +4 -1
  65. package/dist/appShell/SideMenu.js.map +1 -1
  66. package/dist/appShell/SideMenuEntry.js +3 -1
  67. package/dist/appShell/SideMenuEntry.js.map +1 -1
  68. package/dist/appShell/SubmenuActionsMenu.js +3 -1
  69. package/dist/appShell/SubmenuActionsMenu.js.map +1 -1
  70. package/dist/appShell/TabBarEditor.js +3 -1
  71. package/dist/appShell/TabBarEditor.js.map +1 -1
  72. package/dist/appShell/TopMenu.js +3 -1
  73. package/dist/appShell/TopMenu.js.map +1 -1
  74. package/dist/appShell/Wordmark.js +3 -1
  75. package/dist/appShell/Wordmark.js.map +1 -1
  76. package/dist/appShell/pageTitle.js +3 -1
  77. package/dist/appShell/pageTitle.js.map +1 -1
  78. package/dist/auth/PasswordChecklist.js +3 -1
  79. package/dist/auth/PasswordChecklist.js.map +1 -1
  80. package/dist/calendar/EventCalendar.js +4 -1
  81. package/dist/calendar/EventCalendar.js.map +1 -1
  82. package/dist/calendar/EventDetails.js +3 -1
  83. package/dist/calendar/EventDetails.js.map +1 -1
  84. package/dist/datePickers/DateInput.js +4 -1
  85. package/dist/datePickers/DateInput.js.map +1 -1
  86. package/dist/downloads/DownloadManager.js +3 -1
  87. package/dist/downloads/DownloadManager.js.map +1 -1
  88. package/dist/feedback/ConfirmDialog.js +4 -1
  89. package/dist/feedback/ConfirmDialog.js.map +1 -1
  90. package/dist/feedback/ModalWaiting.js +3 -1
  91. package/dist/feedback/ModalWaiting.js.map +1 -1
  92. package/dist/feedback/NewBuildNotice.js +3 -1
  93. package/dist/feedback/NewBuildNotice.js.map +1 -1
  94. package/dist/filepond/FileDropzone.js +4 -1
  95. package/dist/filepond/FileDropzone.js.map +1 -1
  96. package/dist/formatting.js +8 -5
  97. package/dist/formatting.js.map +1 -1
  98. package/dist/forms/FormProblemAlert.js +3 -1
  99. package/dist/forms/FormProblemAlert.js.map +1 -1
  100. package/dist/forms/FormServerProblem.js +3 -1
  101. package/dist/forms/FormServerProblem.js.map +1 -1
  102. package/dist/forms/FormWizard.js +3 -1
  103. package/dist/forms/FormWizard.js.map +1 -1
  104. package/dist/forms/auth/ChangePasswordForm.js +3 -1
  105. package/dist/forms/auth/ChangePasswordForm.js.map +1 -1
  106. package/dist/forms/auth/ForgotPasswordForm.js +3 -1
  107. package/dist/forms/auth/ForgotPasswordForm.js.map +1 -1
  108. package/dist/forms/auth/SignInForm.js +3 -1
  109. package/dist/forms/auth/SignInForm.js.map +1 -1
  110. package/dist/forms/security/SecondStepForm.js +3 -1
  111. package/dist/forms/security/SecondStepForm.js.map +1 -1
  112. package/dist/forms/security/TwoStepVerificationCard.js +3 -1
  113. package/dist/forms/security/TwoStepVerificationCard.js.map +1 -1
  114. package/dist/hookForm/FormProblemAlert.js +3 -1
  115. package/dist/hookForm/FormProblemAlert.js.map +1 -1
  116. package/dist/hookForm/FormWizard.js +3 -1
  117. package/dist/hookForm/FormWizard.js.map +1 -1
  118. package/dist/inbox/InboxLayout.js +4 -1
  119. package/dist/inbox/InboxLayout.js.map +1 -1
  120. package/dist/inbox/MessageList.js +4 -1
  121. package/dist/inbox/MessageList.js.map +1 -1
  122. package/dist/inbox/MessageView.js +3 -1
  123. package/dist/inbox/MessageView.js.map +1 -1
  124. package/dist/index.js +3 -1
  125. package/dist/inputs/CatalogInput.js +4 -1
  126. package/dist/inputs/CatalogInput.js.map +1 -1
  127. package/dist/inputs/ColorInput.js +4 -1
  128. package/dist/inputs/ColorInput.js.map +1 -1
  129. package/dist/inputs/FieldFrame.js +3 -1
  130. package/dist/inputs/FieldFrame.js.map +1 -1
  131. package/dist/inputs/FormSection.js +5 -2
  132. package/dist/inputs/FormSection.js.map +1 -1
  133. package/dist/inputs/NumberInput.js +4 -1
  134. package/dist/inputs/NumberInput.js.map +1 -1
  135. package/dist/inputs/SelectInput.js +4 -1
  136. package/dist/inputs/SelectInput.js.map +1 -1
  137. package/dist/inputs/TextInput.js +2 -0
  138. package/dist/inputs/TextInput.js.map +1 -1
  139. package/dist/inputs/WizardLayout.js +4 -1
  140. package/dist/inputs/WizardLayout.js.map +1 -1
  141. package/dist/kanban/KanbanBoard.js +4 -1
  142. package/dist/kanban/KanbanBoard.js.map +1 -1
  143. package/dist/maps/MapView.js +4 -1
  144. package/dist/maps/MapView.js.map +1 -1
  145. package/dist/pwa/InstallAppSetting.js +3 -1
  146. package/dist/pwa/InstallAppSetting.js.map +1 -1
  147. package/dist/pwa/InstallInstructionsDialog.js +3 -1
  148. package/dist/pwa/InstallInstructionsDialog.js.map +1 -1
  149. package/dist/pwa/InstallPromptBanner.js +3 -1
  150. package/dist/pwa/InstallPromptBanner.js.map +1 -1
  151. package/dist/security/ActivityLog.js +3 -1
  152. package/dist/security/ActivityLog.js.map +1 -1
  153. package/dist/security/RecoveryCodesDialog.js +3 -1
  154. package/dist/security/RecoveryCodesDialog.js.map +1 -1
  155. package/dist/security/SessionsCard.js +3 -1
  156. package/dist/security/SessionsCard.js.map +1 -1
  157. package/dist/theme/createToolkitTheme.js +4 -1
  158. package/dist/theme/createToolkitTheme.js.map +1 -1
  159. package/dist/toolkit/ComponentTexts.js +3 -1
  160. package/dist/toolkit/ComponentTexts.js.map +1 -1
  161. package/dist/toolkit/ToolkitProvider.js +24 -3
  162. package/dist/toolkit/ToolkitProvider.js.map +1 -1
  163. package/dist/toolkit/toolkitContext.js.map +1 -1
  164. package/dist/toolkit/toolkitSettings.js +9 -0
  165. package/dist/toolkit/toolkitSettings.js.map +1 -1
  166. package/dist/toolkit/unknownProps.js +33 -0
  167. package/dist/toolkit/unknownProps.js.map +1 -0
  168. package/dist/types/DataTable/AuditTrailTable.d.ts +1 -1
  169. package/dist/types/DataTable/ColumnFilters/TextColumnFilter.d.ts +1 -1
  170. package/dist/types/DataTable/columns.d.ts +3 -1
  171. package/dist/types/access/Can.d.ts +1 -1
  172. package/dist/types/access/RequireAccess.d.ts +1 -1
  173. package/dist/types/account/AccountProvider.d.ts +1 -1
  174. package/dist/types/account/ForgotPasswordScreen.d.ts +1 -1
  175. package/dist/types/account/ResetPasswordScreen.d.ts +1 -1
  176. package/dist/types/appShell/MenuLinks.d.ts +1 -1
  177. package/dist/types/appShell/pageTitle.d.ts +1 -1
  178. package/dist/types/datePickers/DateInput.d.ts +1 -1
  179. package/dist/types/downloads/DownloadManager.d.ts +1 -1
  180. package/dist/types/formatting.d.ts +2 -1
  181. package/dist/types/forms/FormProblemAlert.d.ts +1 -1
  182. package/dist/types/forms/FormServerProblem.d.ts +1 -1
  183. package/dist/types/forms/FormWizard.d.ts +1 -1
  184. package/dist/types/forms/auth/ChangePasswordForm.d.ts +1 -1
  185. package/dist/types/forms/auth/ForgotPasswordForm.d.ts +1 -1
  186. package/dist/types/hookForm/FormProblemAlert.d.ts +1 -1
  187. package/dist/types/hookForm/FormWizard.d.ts +1 -1
  188. package/dist/types/index.d.ts +1 -1
  189. package/dist/types/inputs/CatalogInput.d.ts +1 -1
  190. package/dist/types/inputs/FieldFrame.d.ts +1 -1
  191. package/dist/types/inputs/NumberInput.d.ts +1 -1
  192. package/dist/types/inputs/TextInput.d.ts +2 -1
  193. package/dist/types/pwa/InstallAppSetting.d.ts +1 -1
  194. package/dist/types/theme/createToolkitTheme.d.ts +1 -1
  195. package/dist/types/toolkit/ComponentTexts.d.ts +1 -1
  196. package/dist/types/toolkit/ToolkitProvider.d.ts +4 -1
  197. package/dist/types/toolkit/toolkitContext.d.ts +2 -1
  198. package/dist/types/toolkit/toolkitSettings.d.ts +13 -2
  199. package/dist/types/toolkit/unknownProps.d.ts +23 -0
  200. package/dist/types/ui/actions/CopyButton.d.ts +1 -1
  201. package/dist/types/ui/actions/SecretField.d.ts +1 -1
  202. package/dist/types/ui/labels/DictionaryText.d.ts +1 -1
  203. package/dist/types/ui/layout/FullPageLoader.d.ts +1 -1
  204. package/dist/types/ui/metrics/CalendarHeatmap.d.ts +9 -8
  205. package/dist/types/ui/metrics/chartParts.d.ts +3 -3
  206. package/dist/types/ui/metrics/heatmapScale.d.ts +23 -0
  207. package/dist/types/ui/navigation/DocumentTitle.d.ts +1 -1
  208. package/dist/ui/actions/ActionsMenu.js +3 -1
  209. package/dist/ui/actions/ActionsMenu.js.map +1 -1
  210. package/dist/ui/actions/CopyButton.js +3 -1
  211. package/dist/ui/actions/CopyButton.js.map +1 -1
  212. package/dist/ui/actions/DownloadMenu.js +4 -1
  213. package/dist/ui/actions/DownloadMenu.js.map +1 -1
  214. package/dist/ui/actions/SecretField.js +3 -1
  215. package/dist/ui/actions/SecretField.js.map +1 -1
  216. package/dist/ui/actions/SelectionActions.js +3 -1
  217. package/dist/ui/actions/SelectionActions.js.map +1 -1
  218. package/dist/ui/filters/DateRangeFilter.js +3 -1
  219. package/dist/ui/filters/DateRangeFilter.js.map +1 -1
  220. package/dist/ui/filters/PeriodRangeSelector.js +3 -1
  221. package/dist/ui/filters/PeriodRangeSelector.js.map +1 -1
  222. package/dist/ui/filters/QuickFilters.js +3 -1
  223. package/dist/ui/filters/QuickFilters.js.map +1 -1
  224. package/dist/ui/filters/SegmentedControl.js +3 -1
  225. package/dist/ui/filters/SegmentedControl.js.map +1 -1
  226. package/dist/ui/labels/DictionaryText.js +3 -1
  227. package/dist/ui/labels/DictionaryText.js.map +1 -1
  228. package/dist/ui/labels/StatusChip.js +3 -1
  229. package/dist/ui/labels/StatusChip.js.map +1 -1
  230. package/dist/ui/layout/CollapsibleSection.js +3 -1
  231. package/dist/ui/layout/CollapsibleSection.js.map +1 -1
  232. package/dist/ui/layout/ContentDialog.js +3 -1
  233. package/dist/ui/layout/ContentDialog.js.map +1 -1
  234. package/dist/ui/layout/DefinitionList.js +3 -1
  235. package/dist/ui/layout/DefinitionList.js.map +1 -1
  236. package/dist/ui/layout/DetailHeader.js +3 -1
  237. package/dist/ui/layout/DetailHeader.js.map +1 -1
  238. package/dist/ui/layout/ErrorPage.js +4 -1
  239. package/dist/ui/layout/ErrorPage.js.map +1 -1
  240. package/dist/ui/layout/FullPageLoader.js +3 -1
  241. package/dist/ui/layout/FullPageLoader.js.map +1 -1
  242. package/dist/ui/layout/PageHeader.js +3 -1
  243. package/dist/ui/layout/PageHeader.js.map +1 -1
  244. package/dist/ui/layout/PageHeading.js +3 -1
  245. package/dist/ui/layout/PageHeading.js.map +1 -1
  246. package/dist/ui/layout/ProfileHeader.js +3 -1
  247. package/dist/ui/layout/ProfileHeader.js.map +1 -1
  248. package/dist/ui/layout/SectionCard.js +3 -1
  249. package/dist/ui/layout/SectionCard.js.map +1 -1
  250. package/dist/ui/metrics/BarList.js +3 -1
  251. package/dist/ui/metrics/BarList.js.map +1 -1
  252. package/dist/ui/metrics/CalendarHeatmap.js +13 -4
  253. package/dist/ui/metrics/CalendarHeatmap.js.map +1 -1
  254. package/dist/ui/metrics/ChartTooltip.js.map +1 -1
  255. package/dist/ui/metrics/ColumnChart.js +4 -1
  256. package/dist/ui/metrics/ColumnChart.js.map +1 -1
  257. package/dist/ui/metrics/LineChart.js +4 -1
  258. package/dist/ui/metrics/LineChart.js.map +1 -1
  259. package/dist/ui/metrics/MetricCard.js +4 -1
  260. package/dist/ui/metrics/MetricCard.js.map +1 -1
  261. package/dist/ui/metrics/TableToggle.js +3 -1
  262. package/dist/ui/metrics/TableToggle.js.map +1 -1
  263. package/dist/ui/metrics/chartParts.js +7 -3
  264. package/dist/ui/metrics/chartParts.js.map +1 -1
  265. package/dist/ui/metrics/heatmapScale.js +15 -1
  266. package/dist/ui/metrics/heatmapScale.js.map +1 -1
  267. package/dist/ui/navigation/ColorSchemeToggle.js +3 -1
  268. package/dist/ui/navigation/ColorSchemeToggle.js.map +1 -1
  269. package/dist/ui/navigation/DocumentTitle.js +3 -1
  270. package/dist/ui/navigation/DocumentTitle.js.map +1 -1
  271. package/dist/ui/navigation/FontSizeToggle.js +3 -1
  272. package/dist/ui/navigation/FontSizeToggle.js.map +1 -1
  273. package/dist/ui/navigation/LanguageToggle.js +3 -1
  274. package/dist/ui/navigation/LanguageToggle.js.map +1 -1
  275. package/dist/ui/navigation/PageBreadcrumbs.js +3 -1
  276. package/dist/ui/navigation/PageBreadcrumbs.js.map +1 -1
  277. package/dist/ui/timeline/GroupedTimeline.js +3 -1
  278. package/dist/ui/timeline/GroupedTimeline.js.map +1 -1
  279. package/dist/upload/FileDropzone.js +4 -1
  280. package/dist/upload/FileDropzone.js.map +1 -1
  281. package/package.json +1 -1
@@ -8,6 +8,7 @@ import Select from "@mui/material/Select";
8
8
  import Stack from "@mui/material/Stack";
9
9
  import { rangeEndOptionsOf, rangeEndAfterStartChange } from "../../periodRanges.js";
10
10
  import { piecePart, usePieceProps } from "../../theme/themePieces.js";
11
+ import { warnUnknownProps } from "../../toolkit/unknownProps.js";
11
12
  const THEME_NAME = "CalcitaPeriodRangeSelector";
12
13
  const PeriodField = piecePart(THEME_NAME, "Field", FormControl);
13
14
  const PeriodSelectPart = piecePart(THEME_NAME, "Select", Select);
@@ -31,7 +32,8 @@ function PeriodSelect({ id, label, value, options, onChange }) {
31
32
  ] });
32
33
  }
33
34
  function PeriodRangeSelector(props) {
34
- const { id, options, from, to, fromLabel, toLabel, onChange } = usePieceProps(props, THEME_NAME);
35
+ const { id, options, from, to, fromLabel, toLabel, onChange, ...unknownProps } = usePieceProps(props, THEME_NAME);
36
+ warnUnknownProps(THEME_NAME, unknownProps);
35
37
  const endOptions = rangeEndOptionsOf(options, from);
36
38
  return /* @__PURE__ */ jsxs(PeriodRoot, { direction: "row", spacing: 1.5, useFlexGap: true, ownSx: { alignItems: "center", flexWrap: "wrap" }, children: [
37
39
  /* @__PURE__ */ jsx(
@@ -1 +1 @@
1
- {"version":3,"file":"PeriodRangeSelector.js","sources":["../../../src/ui/filters/PeriodRangeSelector.jsx"],"sourcesContent":["// Un rango de periodos: «desde» y «hasta», cada uno una lista para elegir (de tal quincena a tal quincena, de tal mes a\n// tal mes). Se usa en lugar de un calendario porque los periodos no son días: solo se ofrecen los que existen, y los que no\n// se pueden elegir salen apagados con su razón.\n//\n// «Hasta» solo ofrece lo que hace un rango válido con «desde»: nada de antes y nada que salte un periodo apagado\n// (periodRanges.js). Al cambiar «desde», si el «hasta» que había ya no vale, se iguala a «desde».\n//\n// No sabe de quincenas ni de productos: recibe las opciones ya ordenadas y con sus textos traducidos.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaPeriodRangeSelector con defaultProps y\n// styleOverrides de sus partes: field, select, root.\n//\n// Genérico del paquete: function (regla de la casa).\nimport FormControl from '@mui/material/FormControl';\nimport InputLabel from '@mui/material/InputLabel';\nimport ListItemText from '@mui/material/ListItemText';\nimport MenuItem from '@mui/material/MenuItem';\nimport Select from '@mui/material/Select';\nimport Stack from '@mui/material/Stack';\n\nimport {rangeEndAfterStartChange, rangeEndOptionsOf} from '@/periodRanges.js';\nimport {piecePart, usePieceProps} from '@/theme/themePieces.js';\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaPeriodRangeSelector)\nconst THEME_NAME = 'CalcitaPeriodRangeSelector';\nconst PeriodField = piecePart(THEME_NAME, 'Field', FormControl);\nconst PeriodSelectPart = piecePart(THEME_NAME, 'Select', Select);\nconst PeriodRoot = piecePart(THEME_NAME, 'Root', Stack);\n\n// ancho de cada lista: cabe «septiembre 2026 · Q2» sin cortarse\nconst SELECT_MINIMUM_WIDTH = 210;\n\n/**\n * Una lista del rango.\n *\n * @param {object} props\n * @param {string} props.id\n * @param {string} props.label\n * @param {string} props.value\n * @param {(value: string) => void} props.onChange\n * @param {Array<{value: string, label: string, disabled: boolean, hint?: string}>} props.options\n */\nfunction PeriodSelect({id, label, value, options, onChange}) {\n return (\n <PeriodField size=\"small\" ownSx={{minWidth: SELECT_MINIMUM_WIDTH, flex: '0 0 auto'}}>\n <InputLabel id={`${id}-label`}>{label}</InputLabel>\n <PeriodSelectPart labelId={`${id}-label`} label={label} value={value ?? ''} onChange={(event) => onChange(event.target.value)}\n ownSx={{bgcolor: 'background.paper'}}\n renderValue={(selectedValue) => options.find((option) => option.value === selectedValue)?.label ?? ''}>\n {options.map((option) => (\n <MenuItem key={option.value} value={option.value} disabled={option.disabled}>\n {/* la razón de una opción apagada va debajo de su nombre: «sin validar» se lee sin tooltip */}\n <ListItemText primary={option.label} secondary={option.disabled ? option.hint : undefined} />\n </MenuItem>\n ))}\n </PeriodSelectPart>\n </PeriodField>\n );\n}\n\n/**\n * @param {object} props\n * @param {string} props.id prefijo de los id de las dos listas (accesibilidad)\n * @param {Array<{value: string, label: string, disabled: boolean, hint?: string}>} props.options en orden; ya\n * traducidas\n * @param {string|null} props.from\n * @param {string|null} props.to\n * @param {string} props.fromLabel ya traducido\n * @param {string} props.toLabel ya traducido\n * @param {(range: {from: string, to: string}) => void} props.onChange\n */\nexport default function PeriodRangeSelector(props) {\n // lo que el proyecto puso en su tema (components.CalcitaPeriodRangeSelector.defaultProps) y encima lo que llega aquí\n const {id, options, from, to, fromLabel, toLabel, onChange} = usePieceProps(props, THEME_NAME);\n const endOptions = rangeEndOptionsOf(options, from);\n\n return (\n <PeriodRoot direction=\"row\" spacing={1.5} useFlexGap ownSx={{alignItems: 'center', flexWrap: 'wrap'}}>\n <PeriodSelect id={`${id}-from`} label={fromLabel} value={from} options={options}\n onChange={(nextFrom) => onChange({from: nextFrom, to: rangeEndAfterStartChange(options, nextFrom, to)})} />\n <PeriodSelect id={`${id}-to`} label={toLabel} value={to} options={endOptions}\n onChange={(nextTo) => onChange({from, to: nextTo})} />\n </PeriodRoot>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;AAwBA,MAAM,aAAa;AACnB,MAAM,cAAc,UAAU,YAAY,SAAS,WAAW;AAC9D,MAAM,mBAAmB,UAAU,YAAY,UAAU,MAAM;AAC/D,MAAM,aAAa,UAAU,YAAY,QAAQ,KAAK;AAGtD,MAAM,uBAAuB;AAY7B,SAAS,aAAa,EAAC,IAAI,OAAO,OAAO,SAAS,YAAW;AACzD,SACI,qBAAC,aAAA,EAAY,MAAK,SAAQ,OAAO,EAAC,UAAU,sBAAsB,MAAM,WAAA,GACpE,UAAA;AAAA,IAAA,oBAAC,YAAA,EAAW,IAAI,GAAG,EAAE,UAAW,UAAA,OAAM;AAAA,IACtC;AAAA,MAAC;AAAA,MAAA;AAAA,QAAiB,SAAS,GAAG,EAAE;AAAA,QAAU;AAAA,QAAc,OAAO,SAAS;AAAA,QAAI,UAAU,CAAC,UAAU,SAAS,MAAM,OAAO,KAAK;AAAA,QACpH,OAAO,EAAC,SAAS,mBAAA;AAAA,QACjB,aAAa,CAAC,kBAAkB,QAAQ,KAAK,CAAC,WAAW,OAAO,UAAU,aAAa,GAAG,SAAS;AAAA,QACtG,UAAA,QAAQ,IAAI,CAAC,WACV,oBAAC,UAAA,EAA4B,OAAO,OAAO,OAAO,UAAU,OAAO,UAE/D,UAAA,oBAAC,gBAAa,SAAS,OAAO,OAAO,WAAW,OAAO,WAAW,OAAO,OAAO,OAAA,CAAW,EAAA,GAFhF,OAAO,KAGtB,CACH;AAAA,MAAA;AAAA,IAAA;AAAA,EACL,GACJ;AAER;AAaA,SAAwB,oBAAoB,OAAO;AAE/C,QAAM,EAAC,IAAI,SAAS,MAAM,IAAI,WAAW,SAAS,SAAA,IAAY,cAAc,OAAO,UAAU;AAC7F,QAAM,aAAa,kBAAkB,SAAS,IAAI;AAElD,SACI,qBAAC,YAAA,EAAW,WAAU,OAAM,SAAS,KAAK,YAAU,MAAC,OAAO,EAAC,YAAY,UAAU,UAAU,UACzF,UAAA;AAAA,IAAA;AAAA,MAAC;AAAA,MAAA;AAAA,QAAa,IAAI,GAAG,EAAE;AAAA,QAAS,OAAO;AAAA,QAAW,OAAO;AAAA,QAAM;AAAA,QACjD,UAAU,CAAC,aAAa,SAAS,EAAC,MAAM,UAAU,IAAI,yBAAyB,SAAS,UAAU,EAAE,GAAE;AAAA,MAAA;AAAA,IAAA;AAAA,IACpH;AAAA,MAAC;AAAA,MAAA;AAAA,QAAa,IAAI,GAAG,EAAE;AAAA,QAAO,OAAO;AAAA,QAAS,OAAO;AAAA,QAAI,SAAS;AAAA,QACpD,UAAU,CAAC,WAAW,SAAS,EAAC,MAAM,IAAI,QAAO;AAAA,MAAA;AAAA,IAAA;AAAA,EAAG,GACtE;AAER;"}
1
+ {"version":3,"file":"PeriodRangeSelector.js","sources":["../../../src/ui/filters/PeriodRangeSelector.jsx"],"sourcesContent":["// Un rango de periodos: «desde» y «hasta», cada uno una lista para elegir (de tal quincena a tal quincena, de tal mes a\n// tal mes). Se usa en lugar de un calendario porque los periodos no son días: solo se ofrecen los que existen, y los que no\n// se pueden elegir salen apagados con su razón.\n//\n// «Hasta» solo ofrece lo que hace un rango válido con «desde»: nada de antes y nada que salte un periodo apagado\n// (periodRanges.js). Al cambiar «desde», si el «hasta» que había ya no vale, se iguala a «desde».\n//\n// No sabe de quincenas ni de productos: recibe las opciones ya ordenadas y con sus textos traducidos.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaPeriodRangeSelector con defaultProps y\n// styleOverrides de sus partes: field, select, root.\n//\n// Genérico del paquete: function (regla de la casa).\nimport FormControl from '@mui/material/FormControl';\nimport InputLabel from '@mui/material/InputLabel';\nimport ListItemText from '@mui/material/ListItemText';\nimport MenuItem from '@mui/material/MenuItem';\nimport Select from '@mui/material/Select';\nimport Stack from '@mui/material/Stack';\n\nimport {rangeEndAfterStartChange, rangeEndOptionsOf} from '@/periodRanges.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.CalcitaPeriodRangeSelector)\nconst THEME_NAME = 'CalcitaPeriodRangeSelector';\nconst PeriodField = piecePart(THEME_NAME, 'Field', FormControl);\nconst PeriodSelectPart = piecePart(THEME_NAME, 'Select', Select);\nconst PeriodRoot = piecePart(THEME_NAME, 'Root', Stack);\n\n// ancho de cada lista: cabe «septiembre 2026 · Q2» sin cortarse\nconst SELECT_MINIMUM_WIDTH = 210;\n\n/**\n * Una lista del rango.\n *\n * @param {object} props\n * @param {string} props.id\n * @param {string} props.label\n * @param {string} props.value\n * @param {(value: string) => void} props.onChange\n * @param {Array<{value: string, label: string, disabled: boolean, hint?: string}>} props.options\n */\nfunction PeriodSelect({id, label, value, options, onChange}) {\n return (\n <PeriodField size=\"small\" ownSx={{minWidth: SELECT_MINIMUM_WIDTH, flex: '0 0 auto'}}>\n <InputLabel id={`${id}-label`}>{label}</InputLabel>\n <PeriodSelectPart labelId={`${id}-label`} label={label} value={value ?? ''} onChange={(event) => onChange(event.target.value)}\n ownSx={{bgcolor: 'background.paper'}}\n renderValue={(selectedValue) => options.find((option) => option.value === selectedValue)?.label ?? ''}>\n {options.map((option) => (\n <MenuItem key={option.value} value={option.value} disabled={option.disabled}>\n {/* la razón de una opción apagada va debajo de su nombre: «sin validar» se lee sin tooltip */}\n <ListItemText primary={option.label} secondary={option.disabled ? option.hint : undefined} />\n </MenuItem>\n ))}\n </PeriodSelectPart>\n </PeriodField>\n );\n}\n\n/**\n * @param {object} props\n * @param {string} props.id prefijo de los id de las dos listas (accesibilidad)\n * @param {Array<{value: string, label: string, disabled: boolean, hint?: string}>} props.options en orden; ya\n * traducidas\n * @param {string|null} props.from\n * @param {string|null} props.to\n * @param {string} props.fromLabel ya traducido\n * @param {string} props.toLabel ya traducido\n * @param {(range: {from: string, to: string}) => void} props.onChange\n */\nexport default function PeriodRangeSelector(props) {\n // lo que el proyecto puso en su tema (components.CalcitaPeriodRangeSelector.defaultProps) y encima lo que llega aquí\n const {id, options, from, to, fromLabel, toLabel, onChange, ...unknownProps} = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n const endOptions = rangeEndOptionsOf(options, from);\n\n return (\n <PeriodRoot direction=\"row\" spacing={1.5} useFlexGap ownSx={{alignItems: 'center', flexWrap: 'wrap'}}>\n <PeriodSelect id={`${id}-from`} label={fromLabel} value={from} options={options}\n onChange={(nextFrom) => onChange({from: nextFrom, to: rangeEndAfterStartChange(options, nextFrom, to)})} />\n <PeriodSelect id={`${id}-to`} label={toLabel} value={to} options={endOptions}\n onChange={(nextTo) => onChange({from, to: nextTo})} />\n </PeriodRoot>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;;AAyBA,MAAM,aAAa;AACnB,MAAM,cAAc,UAAU,YAAY,SAAS,WAAW;AAC9D,MAAM,mBAAmB,UAAU,YAAY,UAAU,MAAM;AAC/D,MAAM,aAAa,UAAU,YAAY,QAAQ,KAAK;AAGtD,MAAM,uBAAuB;AAY7B,SAAS,aAAa,EAAC,IAAI,OAAO,OAAO,SAAS,YAAW;AACzD,SACI,qBAAC,aAAA,EAAY,MAAK,SAAQ,OAAO,EAAC,UAAU,sBAAsB,MAAM,WAAA,GACpE,UAAA;AAAA,IAAA,oBAAC,YAAA,EAAW,IAAI,GAAG,EAAE,UAAW,UAAA,OAAM;AAAA,IACtC;AAAA,MAAC;AAAA,MAAA;AAAA,QAAiB,SAAS,GAAG,EAAE;AAAA,QAAU;AAAA,QAAc,OAAO,SAAS;AAAA,QAAI,UAAU,CAAC,UAAU,SAAS,MAAM,OAAO,KAAK;AAAA,QACpH,OAAO,EAAC,SAAS,mBAAA;AAAA,QACjB,aAAa,CAAC,kBAAkB,QAAQ,KAAK,CAAC,WAAW,OAAO,UAAU,aAAa,GAAG,SAAS;AAAA,QACtG,UAAA,QAAQ,IAAI,CAAC,WACV,oBAAC,UAAA,EAA4B,OAAO,OAAO,OAAO,UAAU,OAAO,UAE/D,UAAA,oBAAC,gBAAa,SAAS,OAAO,OAAO,WAAW,OAAO,WAAW,OAAO,OAAO,OAAA,CAAW,EAAA,GAFhF,OAAO,KAGtB,CACH;AAAA,MAAA;AAAA,IAAA;AAAA,EACL,GACJ;AAER;AAaA,SAAwB,oBAAoB,OAAO;AAE/C,QAAM,EAAC,IAAI,SAAS,MAAM,IAAI,WAAW,SAAS,UAAU,GAAG,aAAA,IAAgB,cAAc,OAAO,UAAU;AAC9G,mBAAiB,YAAY,YAAY;AACzC,QAAM,aAAa,kBAAkB,SAAS,IAAI;AAElD,SACI,qBAAC,YAAA,EAAW,WAAU,OAAM,SAAS,KAAK,YAAU,MAAC,OAAO,EAAC,YAAY,UAAU,UAAU,UACzF,UAAA;AAAA,IAAA;AAAA,MAAC;AAAA,MAAA;AAAA,QAAa,IAAI,GAAG,EAAE;AAAA,QAAS,OAAO;AAAA,QAAW,OAAO;AAAA,QAAM;AAAA,QACjD,UAAU,CAAC,aAAa,SAAS,EAAC,MAAM,UAAU,IAAI,yBAAyB,SAAS,UAAU,EAAE,GAAE;AAAA,MAAA;AAAA,IAAA;AAAA,IACpH;AAAA,MAAC;AAAA,MAAA;AAAA,QAAa,IAAI,GAAG,EAAE;AAAA,QAAO,OAAO;AAAA,QAAS,OAAO;AAAA,QAAI,SAAS;AAAA,QACpD,UAAU,CAAC,WAAW,SAAS,EAAC,MAAM,IAAI,QAAO;AAAA,MAAA;AAAA,IAAA;AAAA,EAAG,GACtE;AAER;"}
@@ -8,6 +8,7 @@ import Chip from "@mui/material/Chip";
8
8
  import Typography from "@mui/material/Typography";
9
9
  import ScrollableRow from "../layout/ScrollableRow.js";
10
10
  import { piecePart, usePieceProps } from "../../theme/themePieces.js";
11
+ import { warnUnknownProps } from "../../toolkit/unknownProps.js";
11
12
  const THEME_NAME = "CalcitaQuickFilters";
12
13
  const QuickRoot = piecePart(THEME_NAME, "Root", Box);
13
14
  const QuickCaption = piecePart(THEME_NAME, "Caption", Typography);
@@ -32,7 +33,8 @@ function compactCount(count) {
32
33
  return String(count);
33
34
  }
34
35
  function QuickFilters(props) {
35
- const { value, onChange, options = [], caption, ariaLabel, extra, texts } = usePieceProps(props, THEME_NAME);
36
+ const { value, onChange, options = [], caption, ariaLabel, extra, texts, ...unknownProps } = usePieceProps(props, THEME_NAME);
37
+ warnUnknownProps(THEME_NAME, unknownProps);
36
38
  const { t } = useToolkitTranslation("table", texts);
37
39
  const activeChip = useRef(null);
38
40
  const isFirstRender = useRef(true);
@@ -1 +1 @@
1
- {"version":3,"file":"QuickFilters.js","sources":["../../../src/ui/filters/QuickFilters.jsx"],"sourcesContent":["// Accesos rápidos: una tira de chips donde se elige UNO (p. ej. el estatus de un pedido).\n//\n// Es el complemento de FilterChips, no lo mismo:\n// - FilterChips dice qué filtros están PUESTOS y sirve para quitarlos;\n// - esto dice qué opciones HAY y sirve para saltar entre ellas de un toque.\n//\n// El conteo de cada chip sale de las facetas del servidor, contadas sobre el conjunto COMPLETO y sin este filtro\n// puesto: al elegir una, las demás siguen diciendo cuántas tienen.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaQuickFilters con defaultProps y\n// styleOverrides de sus partes: root, caption, chip, chipLabel, chipCount.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useEffect, useRef} from 'react';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport Box from '@mui/material/Box';\nimport {alpha} from '@mui/material/styles';\nimport Chip from '@mui/material/Chip';\nimport Typography from '@mui/material/Typography';\n\nimport ScrollableRow from '@/ui/layout/ScrollableRow.jsx';\nimport {piecePart, usePieceProps} from '@/theme/themePieces.js';\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaQuickFilters)\nconst THEME_NAME = 'CalcitaQuickFilters';\nconst QuickRoot = piecePart(THEME_NAME, 'Root', Box);\nconst QuickCaption = piecePart(THEME_NAME, 'Caption', Typography);\nconst QuickChip = piecePart(THEME_NAME, 'Chip', Chip);\nconst QuickChipLabel = piecePart(THEME_NAME, 'ChipLabel', Box);\nconst QuickChipCount = piecePart(THEME_NAME, 'ChipCount', Box);\n\n\n// qué tan marcado va el velo del contador del filtro elegido\nconst ACTIVE_COUNT_VEIL_OPACITY = 0.18;\n\n/**\n * El velo del contador del filtro elegido: el color del texto base (negro en claro, blanco en oscuro) casi transparente.\n * Un tema con variables CSS trae ese color en theme.vars; el tema por omisión de MUI, en su modo.\n *\n * @param {object} theme tema de MUI\n * @returns {string} color CSS\n */\nfunction activeCountVeilOf(theme) {\n if (theme.vars) {\n return `rgba(${theme.vars.palette.common.onBackgroundChannel} / ${ACTIVE_COUNT_VEIL_OPACITY})`;\n }\n const baseTextColor = theme.palette.mode === 'dark' ? theme.palette.common.white : theme.palette.common.black;\n\n return alpha(baseTextColor, ACTIVE_COUNT_VEIL_OPACITY);\n}\n\n/** \"99+\" arriba de 99 y \"1.2k\" arriba de 999: el chip no se estira. */\nfunction compactCount(count) {\n if (count > 999) {\n return `${(count / 1000).toFixed(1)}k`;\n }\n if (count > 99) {\n return '99+';\n }\n return String(count);\n}\n\n/**\n * @param {object} props\n * @param {string} props.value opción activa ('' = todas)\n * @param {(value: string) => void} props.onChange\n * @param {Array<{value: string, label: import('react').ReactNode, count?: number}>} [props.options]\n * @param {import('react').ReactNode} [props.caption]\n * @param {string} [props.ariaLabel]\n * @param {import('react').ReactNode} [props.extra] al final de la tira (p. ej. un rango de fechas)\n * @param {object} [props.texts] los textos que cambian, con la forma de `table` en los textos del paquete\n */\nexport default function QuickFilters(props) {\n // lo que el proyecto puso en su tema (components.CalcitaQuickFilters.defaultProps) y encima lo que llega aquí\n const {value, onChange, options = [], caption, ariaLabel, extra, texts} = usePieceProps(props, THEME_NAME);\n const {t} = useToolkitTranslation('table', texts);\n const activeChip = useRef(null);\n const isFirstRender = useRef(true);\n\n // al cambiar la selección desde fuera (alguien limpió los filtros) el chip activo se trae a la vista; en el primer\n // render sin animación: una tira que se mueve sola al abrir la pantalla se siente rota\n useEffect(() => {\n if (!activeChip.current) {\n return;\n }\n const behavior = isFirstRender.current ? 'instant' : 'smooth';\n isFirstRender.current = false;\n activeChip.current.scrollIntoView({behavior, block: 'nearest', inline: 'center'});\n }, [value]);\n\n // guard clause: con una sola opción no hay entre qué saltar\n if (options.length <= 1) {\n return null;\n }\n\n return (\n <QuickRoot ownSx={{mb: 1}}>\n {caption && (\n <QuickCaption variant=\"caption\" color=\"text.secondary\" ownSx={{px: 0.25}}>{caption}</QuickCaption>\n )}\n <ScrollableRow role=\"tablist\" aria-label={ariaLabel}>\n {options.map((option) => {\n const isActive = option.value === value;\n return (\n <QuickChip\n key={option.value || '__all__'}\n ref={isActive ? activeChip : null}\n role=\"tab\"\n aria-selected={isActive}\n clickable\n onClick={() => onChange(isActive ? '' : option.value)}\n // el elegido trae su ×: \"volver a Todas\" no se descubre solo\n onDelete={isActive && option.value ? () => onChange('') : undefined}\n variant={isActive ? 'filled' : 'outlined'}\n color={isActive ? 'primary' : 'default'}\n label={(\n <QuickChipLabel component=\"span\" ownSx={{display: 'inline-flex', alignItems: 'center', gap: 0.75}}>\n <span>{option.label}</span>\n {option.count !== null && option.count !== undefined && (\n <QuickChipCount component=\"span\"\n aria-label={t('quickFilters.countAriaLabel', {count: option.count})}\n // velo del color del texto base (negro en claro, blanco en oscuro) y no rgba fijo\n ownSx={(theme) => ({\n px: 0.75, borderRadius: '6px', fontSize: 11, fontWeight: 700, minWidth: 18,\n textAlign: 'center', color: 'inherit',\n bgcolor: isActive ? activeCountVeilOf(theme) : 'action.selected',\n })}>\n {compactCount(option.count)}\n </QuickChipCount>\n )}\n </QuickChipLabel>\n )}\n ownSx={{flex: '0 0 auto', height: 32}}\n />\n );\n })}\n {extra}\n </ScrollableRow>\n </QuickRoot>\n );\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"QuickFilters.js","sources":["../../../src/ui/filters/QuickFilters.jsx"],"sourcesContent":["// Accesos rápidos: una tira de chips donde se elige UNO (p. ej. el estatus de un pedido).\n//\n// Es el complemento de FilterChips, no lo mismo:\n// - FilterChips dice qué filtros están PUESTOS y sirve para quitarlos;\n// - esto dice qué opciones HAY y sirve para saltar entre ellas de un toque.\n//\n// El conteo de cada chip sale de las facetas del servidor, contadas sobre el conjunto COMPLETO y sin este filtro\n// puesto: al elegir una, las demás siguen diciendo cuántas tienen.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaQuickFilters con defaultProps y\n// styleOverrides de sus partes: root, caption, chip, chipLabel, chipCount.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useEffect, useRef} from 'react';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport Box from '@mui/material/Box';\nimport {alpha} from '@mui/material/styles';\nimport Chip from '@mui/material/Chip';\nimport Typography from '@mui/material/Typography';\n\nimport ScrollableRow from '@/ui/layout/ScrollableRow.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.CalcitaQuickFilters)\nconst THEME_NAME = 'CalcitaQuickFilters';\nconst QuickRoot = piecePart(THEME_NAME, 'Root', Box);\nconst QuickCaption = piecePart(THEME_NAME, 'Caption', Typography);\nconst QuickChip = piecePart(THEME_NAME, 'Chip', Chip);\nconst QuickChipLabel = piecePart(THEME_NAME, 'ChipLabel', Box);\nconst QuickChipCount = piecePart(THEME_NAME, 'ChipCount', Box);\n\n\n// qué tan marcado va el velo del contador del filtro elegido\nconst ACTIVE_COUNT_VEIL_OPACITY = 0.18;\n\n/**\n * El velo del contador del filtro elegido: el color del texto base (negro en claro, blanco en oscuro) casi transparente.\n * Un tema con variables CSS trae ese color en theme.vars; el tema por omisión de MUI, en su modo.\n *\n * @param {object} theme tema de MUI\n * @returns {string} color CSS\n */\nfunction activeCountVeilOf(theme) {\n if (theme.vars) {\n return `rgba(${theme.vars.palette.common.onBackgroundChannel} / ${ACTIVE_COUNT_VEIL_OPACITY})`;\n }\n const baseTextColor = theme.palette.mode === 'dark' ? theme.palette.common.white : theme.palette.common.black;\n\n return alpha(baseTextColor, ACTIVE_COUNT_VEIL_OPACITY);\n}\n\n/** \"99+\" arriba de 99 y \"1.2k\" arriba de 999: el chip no se estira. */\nfunction compactCount(count) {\n if (count > 999) {\n return `${(count / 1000).toFixed(1)}k`;\n }\n if (count > 99) {\n return '99+';\n }\n return String(count);\n}\n\n/**\n * @param {object} props\n * @param {string} props.value opción activa ('' = todas)\n * @param {(value: string) => void} props.onChange\n * @param {Array<{value: string, label: import('react').ReactNode, count?: number}>} [props.options]\n * @param {import('react').ReactNode} [props.caption]\n * @param {string} [props.ariaLabel]\n * @param {import('react').ReactNode} [props.extra] al final de la tira (p. ej. un rango de fechas)\n * @param {object} [props.texts] los textos que cambian, con la forma de `table` en los textos del paquete\n */\nexport default function QuickFilters(props) {\n // lo que el proyecto puso en su tema (components.CalcitaQuickFilters.defaultProps) y encima lo que llega aquí\n const {value, onChange, options = [], caption, ariaLabel, extra, texts, ...unknownProps} = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n const {t} = useToolkitTranslation('table', texts);\n const activeChip = useRef(null);\n const isFirstRender = useRef(true);\n\n // al cambiar la selección desde fuera (alguien limpió los filtros) el chip activo se trae a la vista; en el primer\n // render sin animación: una tira que se mueve sola al abrir la pantalla se siente rota\n useEffect(() => {\n if (!activeChip.current) {\n return;\n }\n const behavior = isFirstRender.current ? 'instant' : 'smooth';\n isFirstRender.current = false;\n activeChip.current.scrollIntoView({behavior, block: 'nearest', inline: 'center'});\n }, [value]);\n\n // guard clause: con una sola opción no hay entre qué saltar\n if (options.length <= 1) {\n return null;\n }\n\n return (\n <QuickRoot ownSx={{mb: 1}}>\n {caption && (\n <QuickCaption variant=\"caption\" color=\"text.secondary\" ownSx={{px: 0.25}}>{caption}</QuickCaption>\n )}\n <ScrollableRow role=\"tablist\" aria-label={ariaLabel}>\n {options.map((option) => {\n const isActive = option.value === value;\n return (\n <QuickChip\n key={option.value || '__all__'}\n ref={isActive ? activeChip : null}\n role=\"tab\"\n aria-selected={isActive}\n clickable\n onClick={() => onChange(isActive ? '' : option.value)}\n // el elegido trae su ×: \"volver a Todas\" no se descubre solo\n onDelete={isActive && option.value ? () => onChange('') : undefined}\n variant={isActive ? 'filled' : 'outlined'}\n color={isActive ? 'primary' : 'default'}\n label={(\n <QuickChipLabel component=\"span\" ownSx={{display: 'inline-flex', alignItems: 'center', gap: 0.75}}>\n <span>{option.label}</span>\n {option.count !== null && option.count !== undefined && (\n <QuickChipCount component=\"span\"\n aria-label={t('quickFilters.countAriaLabel', {count: option.count})}\n // velo del color del texto base (negro en claro, blanco en oscuro) y no rgba fijo\n ownSx={(theme) => ({\n px: 0.75, borderRadius: '6px', fontSize: 11, fontWeight: 700, minWidth: 18,\n textAlign: 'center', color: 'inherit',\n bgcolor: isActive ? activeCountVeilOf(theme) : 'action.selected',\n })}>\n {compactCount(option.count)}\n </QuickChipCount>\n )}\n </QuickChipLabel>\n )}\n ownSx={{flex: '0 0 auto', height: 32}}\n />\n );\n })}\n {extra}\n </ScrollableRow>\n </QuickRoot>\n );\n}\n"],"names":[],"mappings":"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"}
@@ -6,6 +6,7 @@ import { styled, useThemeProps } from "@mui/material/styles";
6
6
  import { isGlassTheme, glassDropOf } from "../../theme/glassSurface.js";
7
7
  import { textSizeOf } from "../../theme/appleTracking.js";
8
8
  import ScrollableRow from "../layout/ScrollableRow.js";
9
+ import { warnUnknownProps } from "../../toolkit/unknownProps.js";
9
10
  const ROW_SHADOW_ROOM = 0.5;
10
11
  const GLASS_SEGMENT_MIN_HEIGHT_PIXELS = 34;
11
12
  const SEGMENTED_CONTROL_SX = {
@@ -63,7 +64,8 @@ function glassSegmentedSxOf(theme) {
63
64
  const THEME_NAME = "CalcitaSegmentedControl";
64
65
  const SegmentedControlRoot = styled(ToggleButtonGroup, { name: THEME_NAME, slot: "Root" })(({ theme }) => theme.unstable_sx([SEGMENTED_CONTROL_SX, glassSegmentedSxOf(theme)]));
65
66
  function SegmentedControl(props) {
66
- const { options, value, onChange, ariaLabel } = useThemeProps({ props, name: THEME_NAME });
67
+ const { options, value, onChange, ariaLabel, ...unknownProps } = useThemeProps({ props, name: THEME_NAME });
68
+ warnUnknownProps(THEME_NAME, unknownProps);
67
69
  return (
68
70
  // la fila deja 4 px arriba y abajo para que la sombra no se corte (ScrollableRow, py 0.5); el margen negativo los
69
71
  // devuelve: el control mide sus 40 px y se alinea con los campos de junto (quedaba 4 px más arriba)
@@ -1 +1 @@
1
- {"version":3,"file":"SegmentedControl.js","sources":["../../../src/ui/filters/SegmentedControl.jsx"],"sourcesContent":["// Pestañas en píldora: una tira de botones donde se elige UNO (el producto de una lista, la vista de un\n// tablero). Va en un renglón que se desliza en el teléfono, como las pestañas de una app móvil.\n//\n// SEGMENTED_CONTROL_SX es el estilo de la tira; se exporta para quien arma su propia tira con menús adentro (una barra\n// de productos con menús).\n//\n// Con el vidrio del tema es el control segmentado de Liquid Glass: la tira sin borde y lo elegido en la «gota» (la misma\n// de las pestañas y de los botones de opción), no en un relleno de color. Con el naranja fijo le ganaba al vidrio, no se\n// parecía a las pestañas de al lado y en oscuro quedaba con letra negra.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaSegmentedControl con styleOverrides.root\n// (la tira y, adentro, sus opciones: '& .MuiToggleButton-root') y defaultProps.\n//\n// Genérico del paquete: function (regla de la casa).\nimport ToggleButton from '@mui/material/ToggleButton';\nimport ToggleButtonGroup from '@mui/material/ToggleButtonGroup';\nimport {styled, useThemeProps} from '@mui/material/styles';\n\nimport {glassDropOf, isGlassTheme} from '@/theme/glassSurface.js';\nimport {textSizeOf} from '@/theme/appleTracking.js';\nimport ScrollableRow from '@/ui/layout/ScrollableRow.jsx';\n\n// con vidrio, el alto de cada opción: con el margen de la tira (3 px arriba y abajo) da los 40 px de un campo\n// el aire de la fila para la sombra, en unidades de spacing (4 px)\nconst ROW_SHADOW_ROOM = 0.5;\nconst GLASS_SEGMENT_MIN_HEIGHT_PIXELS = 34;\n\nexport const SEGMENTED_CONTROL_SX = {\n gap: 0.5,\n p: 0.375,\n border: 1,\n borderColor: 'divider',\n borderRadius: 999,\n flexWrap: 'nowrap',\n flex: '0 0 auto',\n '& .MuiToggleButton-root': {\n border: 0, borderRadius: '999px', m: 0, px: 1.75, py: 0.375,\n ...textSizeOf(13), fontWeight: 600, textTransform: 'none', color: 'text.secondary', whiteSpace: 'nowrap',\n },\n // la píldora de cada opción. OJO: con dos clases; el grupo de MUI quita las esquinas y junta los botones de en medio con\n // reglas de dos clases (& .MuiToggleButtonGroup-middleButton). Antes se le ganaba con !important, y así el tema del\n // proyecto tampoco podía cambiar la forma\n '& .MuiToggleButton-root.MuiToggleButtonGroup-grouped': {border: 0, borderRadius: '999px', m: 0},\n '& .MuiToggleButton-root.Mui-selected, & .MuiToggleButton-root.Mui-selected:hover': {\n bgcolor: 'primary.main', color: 'primary.contrastText',\n },\n};\n\n/**\n * Lo que cambia con vidrio: sin borde (la tira ya se marca sola) y lo elegido en su gota.\n *\n * @param {object} theme\n * @returns {object}\n */\nfunction glassSegmentedSxOf(theme) {\n // con el minimalista: la tira gris y lo elegido un escalón arriba, como el de Apple (los pone el tema); sin el naranja lleno\n if (theme.toolkit?.look === 'minimal') {\n return {\n border: 0,\n '& .MuiToggleButton-root': {minHeight: GLASS_SEGMENT_MIN_HEIGHT_PIXELS},\n '& .MuiToggleButton-root.Mui-selected, & .MuiToggleButton-root.Mui-selected:hover': {\n bgcolor: 'background.paper', color: 'text.primary', ...theme.applyStyles('dark', {bgcolor: 'rgba(118, 118, 128, 0.36)'}),\n },\n };\n }\n if (!isGlassTheme(theme)) {\n return {};\n }\n return {\n border: 0,\n // del mismo alto que un campo (40 px con su margen de 3 px arriba y abajo): en una fila de filtros junto a «Desde» y\n // «Hasta» quedaba más bajito y descuadrado (lo reportaron)\n '& .MuiToggleButton-root': {minHeight: GLASS_SEGMENT_MIN_HEIGHT_PIXELS},\n '& .MuiToggleButton-root.Mui-selected, & .MuiToggleButton-root.Mui-selected:hover': {...glassDropOf(theme), color: 'text.primary'},\n };\n}\n\n// el nombre de la pieza en el tema (theme.components.CalcitaSegmentedControl)\nconst THEME_NAME = 'CalcitaSegmentedControl';\n\n// la tira con su estilo y el de vidrio o minimalista; el tema del proyecto (styleOverrides.root) va después y le gana\nconst SegmentedControlRoot = styled(ToggleButtonGroup, {name: THEME_NAME, slot: 'Root'})(({theme}) => (\n theme.unstable_sx([SEGMENTED_CONTROL_SX, glassSegmentedSxOf(theme)])\n));\n\n/**\n * @param {object} props\n * @param {Array<{value: string, label: string, disabled?: boolean}>} props.options en el orden en que se pintan; ya\n * traducidas\n * @param {string|null} props.value\n * @param {(value: string) => void} props.onChange\n * @param {string} props.ariaLabel ya traducido\n */\nexport default function SegmentedControl(props) {\n // lo que el proyecto puso en su tema (components.CalcitaSegmentedControl.defaultProps) y encima lo que llega aquí\n const {options, value, onChange, ariaLabel} = useThemeProps({props, name: THEME_NAME});\n return (\n // la fila deja 4 px arriba y abajo para que la sombra no se corte (ScrollableRow, py 0.5); el margen negativo los\n // devuelve: el control mide sus 40 px y se alinea con los campos de junto (quedaba 4 px más arriba)\n <ScrollableRow gap={1} py={ROW_SHADOW_ROOM} sx={{alignItems: 'center', my: -ROW_SHADOW_ROOM}}>\n <SegmentedControlRoot exclusive size=\"small\" value={value} aria-label={ariaLabel}\n // quitar la selección no existe: un clic en la pestaña elegida no la apaga\n onChange={(event, nextValue) => nextValue !== null && onChange(nextValue)}>\n {options.map((option) => (\n <ToggleButton key={option.value} value={option.value} disabled={option.disabled}>{option.label}</ToggleButton>\n ))}\n </SegmentedControlRoot>\n </ScrollableRow>\n );\n}\n"],"names":[],"mappings":";;;;;;;;AAwBA,MAAM,kBAAkB;AACxB,MAAM,kCAAkC;AAEjC,MAAM,uBAAuB;AAAA,EAChC,KAAK;AAAA,EACL,GAAG;AAAA,EACH,QAAQ;AAAA,EACR,aAAa;AAAA,EACb,cAAc;AAAA,EACd,UAAU;AAAA,EACV,MAAM;AAAA,EACN,2BAA2B;AAAA,IACvB,QAAQ;AAAA,IAAG,cAAc;AAAA,IAAS,GAAG;AAAA,IAAG,IAAI;AAAA,IAAM,IAAI;AAAA,IACtD,GAAG,WAAW,EAAE;AAAA,IAAG,YAAY;AAAA,IAAK,eAAe;AAAA,IAAQ,OAAO;AAAA,IAAkB,YAAY;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,EAKpG,wDAAwD,EAAC,QAAQ,GAAG,cAAc,SAAS,GAAG,EAAA;AAAA,EAC9F,oFAAoF;AAAA,IAChF,SAAS;AAAA,IAAgB,OAAO;AAAA,EAAA;AAExC;AAQA,SAAS,mBAAmB,OAAO;AAE/B,MAAI,MAAM,SAAS,SAAS,WAAW;AACnC,WAAO;AAAA,MACH,QAAQ;AAAA,MACR,2BAA2B,EAAC,WAAW,gCAAA;AAAA,MACvC,oFAAoF;AAAA,QAChF,SAAS;AAAA,QAAoB,OAAO;AAAA,QAAgB,GAAG,MAAM,YAAY,QAAQ,EAAC,SAAS,6BAA4B;AAAA,MAAA;AAAA,IAC3H;AAAA,EAER;AACA,MAAI,CAAC,aAAa,KAAK,GAAG;AACtB,WAAO,CAAA;AAAA,EACX;AACA,SAAO;AAAA,IACH,QAAQ;AAAA;AAAA;AAAA,IAGR,2BAA2B,EAAC,WAAW,gCAAA;AAAA,IACvC,oFAAoF,EAAC,GAAG,YAAY,KAAK,GAAG,OAAO,eAAA;AAAA,EAAc;AAEzI;AAGA,MAAM,aAAa;AAGnB,MAAM,uBAAuB,OAAO,mBAAmB,EAAC,MAAM,YAAY,MAAM,QAAO,EAAE,CAAC,EAAC,MAAA,MACvF,MAAM,YAAY,CAAC,sBAAsB,mBAAmB,KAAK,CAAC,CAAC,CACtE;AAUD,SAAwB,iBAAiB,OAAO;AAE5C,QAAM,EAAC,SAAS,OAAO,UAAU,UAAA,IAAa,cAAc,EAAC,OAAO,MAAM,YAAW;AACrF;AAAA;AAAA;AAAA,IAGI,oBAAC,eAAA,EAAc,KAAK,GAAG,IAAI,iBAAiB,IAAI,EAAC,YAAY,UAAU,IAAI,CAAC,mBACxE,UAAA;AAAA,MAAC;AAAA,MAAA;AAAA,QAAqB,WAAS;AAAA,QAAC,MAAK;AAAA,QAAQ;AAAA,QAAc,cAAY;AAAA,QAEpD,UAAU,CAAC,OAAO,cAAc,cAAc,QAAQ,SAAS,SAAS;AAAA,QACtF,kBAAQ,IAAI,CAAC,WACV,oBAAC,gBAAgC,OAAO,OAAO,OAAO,UAAU,OAAO,UAAW,UAAA,OAAO,MAAA,GAAtE,OAAO,KAAqE,CAClG;AAAA,MAAA;AAAA,IAAA,EACL,CACJ;AAAA;AAER;"}
1
+ {"version":3,"file":"SegmentedControl.js","sources":["../../../src/ui/filters/SegmentedControl.jsx"],"sourcesContent":["// Pestañas en píldora: una tira de botones donde se elige UNO (el producto de una lista, la vista de un\n// tablero). Va en un renglón que se desliza en el teléfono, como las pestañas de una app móvil.\n//\n// SEGMENTED_CONTROL_SX es el estilo de la tira; se exporta para quien arma su propia tira con menús adentro (una barra\n// de productos con menús).\n//\n// Con el vidrio del tema es el control segmentado de Liquid Glass: la tira sin borde y lo elegido en la «gota» (la misma\n// de las pestañas y de los botones de opción), no en un relleno de color. Con el naranja fijo le ganaba al vidrio, no se\n// parecía a las pestañas de al lado y en oscuro quedaba con letra negra.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaSegmentedControl con styleOverrides.root\n// (la tira y, adentro, sus opciones: '& .MuiToggleButton-root') y defaultProps.\n//\n// Genérico del paquete: function (regla de la casa).\nimport ToggleButton from '@mui/material/ToggleButton';\nimport ToggleButtonGroup from '@mui/material/ToggleButtonGroup';\nimport {styled, useThemeProps} from '@mui/material/styles';\n\nimport {glassDropOf, isGlassTheme} from '@/theme/glassSurface.js';\nimport {textSizeOf} from '@/theme/appleTracking.js';\nimport ScrollableRow from '@/ui/layout/ScrollableRow.jsx';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\n\n// con vidrio, el alto de cada opción: con el margen de la tira (3 px arriba y abajo) da los 40 px de un campo\n// el aire de la fila para la sombra, en unidades de spacing (4 px)\nconst ROW_SHADOW_ROOM = 0.5;\nconst GLASS_SEGMENT_MIN_HEIGHT_PIXELS = 34;\n\nexport const SEGMENTED_CONTROL_SX = {\n gap: 0.5,\n p: 0.375,\n border: 1,\n borderColor: 'divider',\n borderRadius: 999,\n flexWrap: 'nowrap',\n flex: '0 0 auto',\n '& .MuiToggleButton-root': {\n border: 0, borderRadius: '999px', m: 0, px: 1.75, py: 0.375,\n ...textSizeOf(13), fontWeight: 600, textTransform: 'none', color: 'text.secondary', whiteSpace: 'nowrap',\n },\n // la píldora de cada opción. OJO: con dos clases; el grupo de MUI quita las esquinas y junta los botones de en medio con\n // reglas de dos clases (& .MuiToggleButtonGroup-middleButton). Antes se le ganaba con !important, y así el tema del\n // proyecto tampoco podía cambiar la forma\n '& .MuiToggleButton-root.MuiToggleButtonGroup-grouped': {border: 0, borderRadius: '999px', m: 0},\n '& .MuiToggleButton-root.Mui-selected, & .MuiToggleButton-root.Mui-selected:hover': {\n bgcolor: 'primary.main', color: 'primary.contrastText',\n },\n};\n\n/**\n * Lo que cambia con vidrio: sin borde (la tira ya se marca sola) y lo elegido en su gota.\n *\n * @param {object} theme\n * @returns {object}\n */\nfunction glassSegmentedSxOf(theme) {\n // con el minimalista: la tira gris y lo elegido un escalón arriba, como el de Apple (los pone el tema); sin el naranja lleno\n if (theme.toolkit?.look === 'minimal') {\n return {\n border: 0,\n '& .MuiToggleButton-root': {minHeight: GLASS_SEGMENT_MIN_HEIGHT_PIXELS},\n '& .MuiToggleButton-root.Mui-selected, & .MuiToggleButton-root.Mui-selected:hover': {\n bgcolor: 'background.paper', color: 'text.primary', ...theme.applyStyles('dark', {bgcolor: 'rgba(118, 118, 128, 0.36)'}),\n },\n };\n }\n if (!isGlassTheme(theme)) {\n return {};\n }\n return {\n border: 0,\n // del mismo alto que un campo (40 px con su margen de 3 px arriba y abajo): en una fila de filtros junto a «Desde» y\n // «Hasta» quedaba más bajito y descuadrado (lo reportaron)\n '& .MuiToggleButton-root': {minHeight: GLASS_SEGMENT_MIN_HEIGHT_PIXELS},\n '& .MuiToggleButton-root.Mui-selected, & .MuiToggleButton-root.Mui-selected:hover': {...glassDropOf(theme), color: 'text.primary'},\n };\n}\n\n// el nombre de la pieza en el tema (theme.components.CalcitaSegmentedControl)\nconst THEME_NAME = 'CalcitaSegmentedControl';\n\n// la tira con su estilo y el de vidrio o minimalista; el tema del proyecto (styleOverrides.root) va después y le gana\nconst SegmentedControlRoot = styled(ToggleButtonGroup, {name: THEME_NAME, slot: 'Root'})(({theme}) => (\n theme.unstable_sx([SEGMENTED_CONTROL_SX, glassSegmentedSxOf(theme)])\n));\n\n/**\n * @param {object} props\n * @param {Array<{value: string, label: string, disabled?: boolean}>} props.options en el orden en que se pintan; ya\n * traducidas\n * @param {string|null} props.value\n * @param {(value: string) => void} props.onChange\n * @param {string} props.ariaLabel ya traducido\n */\nexport default function SegmentedControl(props) {\n // lo que el proyecto puso en su tema (components.CalcitaSegmentedControl.defaultProps) y encima lo que llega aquí\n const {options, value, onChange, ariaLabel, ...unknownProps} = useThemeProps({props, name: THEME_NAME});\n warnUnknownProps(THEME_NAME, unknownProps);\n return (\n // la fila deja 4 px arriba y abajo para que la sombra no se corte (ScrollableRow, py 0.5); el margen negativo los\n // devuelve: el control mide sus 40 px y se alinea con los campos de junto (quedaba 4 px más arriba)\n <ScrollableRow gap={1} py={ROW_SHADOW_ROOM} sx={{alignItems: 'center', my: -ROW_SHADOW_ROOM}}>\n <SegmentedControlRoot exclusive size=\"small\" value={value} aria-label={ariaLabel}\n // quitar la selección no existe: un clic en la pestaña elegida no la apaga\n onChange={(event, nextValue) => nextValue !== null && onChange(nextValue)}>\n {options.map((option) => (\n <ToggleButton key={option.value} value={option.value} disabled={option.disabled}>{option.label}</ToggleButton>\n ))}\n </SegmentedControlRoot>\n </ScrollableRow>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;AAyBA,MAAM,kBAAkB;AACxB,MAAM,kCAAkC;AAEjC,MAAM,uBAAuB;AAAA,EAChC,KAAK;AAAA,EACL,GAAG;AAAA,EACH,QAAQ;AAAA,EACR,aAAa;AAAA,EACb,cAAc;AAAA,EACd,UAAU;AAAA,EACV,MAAM;AAAA,EACN,2BAA2B;AAAA,IACvB,QAAQ;AAAA,IAAG,cAAc;AAAA,IAAS,GAAG;AAAA,IAAG,IAAI;AAAA,IAAM,IAAI;AAAA,IACtD,GAAG,WAAW,EAAE;AAAA,IAAG,YAAY;AAAA,IAAK,eAAe;AAAA,IAAQ,OAAO;AAAA,IAAkB,YAAY;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,EAKpG,wDAAwD,EAAC,QAAQ,GAAG,cAAc,SAAS,GAAG,EAAA;AAAA,EAC9F,oFAAoF;AAAA,IAChF,SAAS;AAAA,IAAgB,OAAO;AAAA,EAAA;AAExC;AAQA,SAAS,mBAAmB,OAAO;AAE/B,MAAI,MAAM,SAAS,SAAS,WAAW;AACnC,WAAO;AAAA,MACH,QAAQ;AAAA,MACR,2BAA2B,EAAC,WAAW,gCAAA;AAAA,MACvC,oFAAoF;AAAA,QAChF,SAAS;AAAA,QAAoB,OAAO;AAAA,QAAgB,GAAG,MAAM,YAAY,QAAQ,EAAC,SAAS,6BAA4B;AAAA,MAAA;AAAA,IAC3H;AAAA,EAER;AACA,MAAI,CAAC,aAAa,KAAK,GAAG;AACtB,WAAO,CAAA;AAAA,EACX;AACA,SAAO;AAAA,IACH,QAAQ;AAAA;AAAA;AAAA,IAGR,2BAA2B,EAAC,WAAW,gCAAA;AAAA,IACvC,oFAAoF,EAAC,GAAG,YAAY,KAAK,GAAG,OAAO,eAAA;AAAA,EAAc;AAEzI;AAGA,MAAM,aAAa;AAGnB,MAAM,uBAAuB,OAAO,mBAAmB,EAAC,MAAM,YAAY,MAAM,QAAO,EAAE,CAAC,EAAC,MAAA,MACvF,MAAM,YAAY,CAAC,sBAAsB,mBAAmB,KAAK,CAAC,CAAC,CACtE;AAUD,SAAwB,iBAAiB,OAAO;AAE5C,QAAM,EAAC,SAAS,OAAO,UAAU,WAAW,GAAG,aAAA,IAAgB,cAAc,EAAC,OAAO,MAAM,YAAW;AACtG,mBAAiB,YAAY,YAAY;AACzC;AAAA;AAAA;AAAA,IAGI,oBAAC,eAAA,EAAc,KAAK,GAAG,IAAI,iBAAiB,IAAI,EAAC,YAAY,UAAU,IAAI,CAAC,mBACxE,UAAA;AAAA,MAAC;AAAA,MAAA;AAAA,QAAqB,WAAS;AAAA,QAAC,MAAK;AAAA,QAAQ;AAAA,QAAc,cAAY;AAAA,QAEpD,UAAU,CAAC,OAAO,cAAc,cAAc,QAAQ,SAAS,SAAS;AAAA,QACtF,kBAAQ,IAAI,CAAC,WACV,oBAAC,gBAAgC,OAAO,OAAO,OAAO,UAAU,OAAO,UAAW,UAAA,OAAO,MAAA,GAAtE,OAAO,KAAqE,CAClG;AAAA,MAAA;AAAA,IAAA,EACL,CACJ;AAAA;AAER;"}
@@ -1,7 +1,9 @@
1
1
  "use client";
2
2
  import { useToolkitTranslation } from "../../toolkit/useToolkitTranslation.js";
3
3
  import { labelOf, lookup } from "../../dictionaries/dictionaries.js";
4
- function DictionaryText({ dictionary, value }) {
4
+ import { warnUnknownProps } from "../../toolkit/unknownProps.js";
5
+ function DictionaryText({ dictionary, value, ...unknownProps }) {
6
+ warnUnknownProps("DictionaryText", unknownProps);
5
7
  const { t } = useToolkitTranslation("dictionaries");
6
8
  return labelOf(lookup(dictionary, value), t);
7
9
  }
@@ -1 +1 @@
1
- {"version":3,"file":"DictionaryText.js","sources":["../../../src/ui/labels/DictionaryText.jsx"],"sourcesContent":["// Solo el texto de un valor de diccionario (sin punto, chip ni tooltip), para listas de dato → valor o títulos.\n// Si el valor no está en el diccionario se pinta su código crudo (ver labelOf en dictionaries/dictionaries.js).\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\n\nimport {labelOf, lookup} from '@/dictionaries/dictionaries.js';\n\n/**\n * @param {{dictionary: Record<string, object>, value: string|null|undefined}} props\n */\nexport default function DictionaryText({dictionary, value}) {\n const {t} = useToolkitTranslation('dictionaries');\n return labelOf(lookup(dictionary, value), t);\n}\n"],"names":[],"mappings":";;;AAWA,SAAwB,eAAe,EAAC,YAAY,SAAQ;AACxD,QAAM,EAAC,EAAA,IAAK,sBAAsB,cAAc;AAChD,SAAO,QAAQ,OAAO,YAAY,KAAK,GAAG,CAAC;AAC/C;"}
1
+ {"version":3,"file":"DictionaryText.js","sources":["../../../src/ui/labels/DictionaryText.jsx"],"sourcesContent":["// Solo el texto de un valor de diccionario (sin punto, chip ni tooltip), para listas de dato → valor o títulos.\n// Si el valor no está en el diccionario se pinta su código crudo (ver labelOf en dictionaries/dictionaries.js).\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\n\nimport {labelOf, lookup} from '@/dictionaries/dictionaries.js';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\n\n/**\n * @param {{dictionary: Record<string, object>, value: string|null|undefined}} props\n */\nexport default function DictionaryText({dictionary, value, ...unknownProps}) {\n warnUnknownProps('DictionaryText', unknownProps);\n const {t} = useToolkitTranslation('dictionaries');\n return labelOf(lookup(dictionary, value), t);\n}\n"],"names":[],"mappings":";;;;AAYA,SAAwB,eAAe,EAAC,YAAY,OAAO,GAAG,gBAAe;AACzE,mBAAiB,kBAAkB,YAAY;AAC/C,QAAM,EAAC,EAAA,IAAK,sBAAsB,cAAc;AAChD,SAAO,QAAQ,OAAO,YAAY,KAAK,GAAG,CAAC;AAC/C;"}
@@ -8,6 +8,7 @@ import { styled, useThemeProps } from "@mui/material/styles";
8
8
  import { lookup, labelOf, shortLabelOf } from "../../dictionaries/dictionaries.js";
9
9
  import { paletteOf } from "../../theme/components/paletteOf.js";
10
10
  import { lightDarkStylesOf } from "../../theme/lightDarkStyles.js";
11
+ import { warnUnknownProps } from "../../toolkit/unknownProps.js";
11
12
  const THEME_NAME = "CalcitaStatusChip";
12
13
  const PALETTE_TONES = ["primary", "secondary", "success", "warning", "error", "info"];
13
14
  function paletteToneOf(theme, tone) {
@@ -35,7 +36,8 @@ const StatusChipDot = styled("span", { name: THEME_NAME, slot: "Dot" })(({ theme
35
36
  const StatusChipLabel = styled("span", { name: THEME_NAME, slot: "Label" })({ minWidth: 0, overflow: "hidden", textOverflow: "ellipsis" });
36
37
  const StatusChipChip = styled(Chip, { name: THEME_NAME, slot: "Chip" })({});
37
38
  function StatusChip(props) {
38
- const { dictionary, value, variant = "dot", short = false, suffix, tooltip: customTooltip, sx } = useThemeProps({ props, name: THEME_NAME });
39
+ const { dictionary, value, variant = "dot", short = false, suffix, tooltip: customTooltip, sx, ...unknownProps } = useThemeProps({ props, name: THEME_NAME });
40
+ warnUnknownProps(THEME_NAME, unknownProps);
39
41
  const { t } = useToolkitTranslation("dictionaries");
40
42
  const dictionaryEntry = lookup(dictionary, value);
41
43
  const fullLabel = labelOf(dictionaryEntry, t);
@@ -1 +1 @@
1
- {"version":3,"file":"StatusChip.js","sources":["../../../src/ui/labels/StatusChip.jsx"],"sourcesContent":["// Estatus pintado desde un diccionario (dictionaries/dictionaries.js): etiqueta, tooltip y color salen del diccionario,\n// nunca del componente que lo usa. Un valor que no está en el diccionario se pinta con su código crudo.\n//\n// Dos formas:\n// - variant=\"dot\" (por defecto): punto de color + texto, sin fondo. Para la columna de estado de una tabla.\n// - variant=\"chip\": Chip de MUI con contorno, para formatos, hallazgos o encabezados.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaStatusChip con defaultProps (p. ej.\n// {variant: 'chip'}) y styleOverrides de sus partes: root (el renglón del punto y el texto), dot, label y chip.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport Box from '@mui/material/Box';\nimport Chip from '@mui/material/Chip';\nimport Tooltip from '@mui/material/Tooltip';\nimport {styled, useThemeProps} from '@mui/material/styles';\n\nimport {labelOf, lookup, shortLabelOf} from '@/dictionaries/dictionaries.js';\nimport {paletteOf} from '@/theme/components/paletteOf.js';\nimport {lightDarkStylesOf} from '@/theme/lightDarkStyles.js';\n\n// el nombre de la pieza en el tema (theme.components.CalcitaStatusChip)\nconst THEME_NAME = 'CalcitaStatusChip';\n// los colores que trae la paleta; otro (o «default») se pinta neutro\nconst PALETTE_TONES = ['primary', 'secondary', 'success', 'warning', 'error', 'info'];\n\n/** El color del diccionario si la paleta lo tiene; si no, null (neutro). */\nfunction paletteToneOf(theme, tone) {\n return PALETTE_TONES.includes(tone) && paletteOf(theme)[tone] ? paletteOf(theme)[tone] : null;\n}\n\n// el punto y el texto. El texto va en el tono oscuro de su color en claro y en el claro en oscuro: con el oscuro también en\n// modo oscuro casi no se leía (el «Suspendido» rojo sobre la tabla oscura, lo vio el usuario). Con lightDarkStylesOf para\n// que el tema del proyecto (styleOverrides.root) le gane también en oscuro\nconst StatusChipRoot = styled('span', {name: THEME_NAME, slot: 'Root'})(({theme, ownerState}) => {\n const color = paletteToneOf(theme, ownerState.tone);\n return {\n display: 'inline-flex', alignItems: 'center', gap: theme.spacing(0.75),\n fontSize: 13, fontWeight: 500, whiteSpace: 'nowrap',\n ...(color\n ? lightDarkStylesOf(theme, {color: color.dark}, {color: color.light})\n : {color: paletteOf(theme).text.secondary}),\n };\n});\n\n// OJO: flexShrink 0; en una celda angosta el punto se encogía a 0 px y el estado perdía su color\nconst StatusChipDot = styled('span', {name: THEME_NAME, slot: 'Dot'})(({theme, ownerState}) => ({\n width: 6, height: 6, flexShrink: 0, borderRadius: '50%',\n backgroundColor: paletteToneOf(theme, ownerState.tone)?.main ?? paletteOf(theme).text.disabled,\n}));\n\n// el texto en su propio span: un nodo de texto suelto dentro de un flex se corta sin «…»\nconst StatusChipLabel = styled('span', {name: THEME_NAME, slot: 'Label'})({minWidth: 0, overflow: 'hidden', textOverflow: 'ellipsis'});\n\nconst StatusChipChip = styled(Chip, {name: THEME_NAME, slot: 'Chip'})({});\n\n/**\n * @param {object} props\n * @param {Record<string, object>} props.dictionary p. ej. BATCH_STATUS\n * @param {string|null|undefined} props.value código del API\n * @param {'dot'|'chip'} [props.variant]\n * @param {boolean} [props.short] pinta la palabra corta de la entrada (shortLabelKey), para una columna angosta; el\n * nombre completo queda en el tooltip, antes de su explicación\n * @param {string} [props.suffix] texto que va después de la etiqueta con \" · \" (p. ej. un conteo ya formateado)\n * @param {import('react').ReactNode} [props.tooltip] SUSTITUYE al tooltip del diccionario; úsalo cuando el renglón tiene algo más\n * que decir. OJO: no envuelvas este componente en otro Tooltip, porque el suyo sigue ahí y se ven los dos encimados\n * @param {object} [props.sx] ajustes de estilo del Chip (solo variant=\"chip\")\n */\nexport default function StatusChip(props) {\n // lo que el proyecto puso en su tema (components.CalcitaStatusChip.defaultProps) y encima lo que llega aquí\n const {dictionary, value, variant = 'dot', short = false, suffix, tooltip: customTooltip, sx} = useThemeProps({props, name: THEME_NAME});\n const {t} = useToolkitTranslation('dictionaries');\n const dictionaryEntry = lookup(dictionary, value);\n const fullLabel = labelOf(dictionaryEntry, t);\n const entryLabel = short ? shortLabelOf(dictionaryEntry, t) : fullLabel;\n const label = suffix ? `${entryLabel} · ${suffix}` : entryLabel;\n // el de quien lo usa gana: si pasa uno, el del diccionario no se pinta y no hay dos globos\n const explanation = customTooltip ?? t(dictionaryEntry.tooltipKey, {defaultValue: ''});\n // la palabra corta deja fuera parte del nombre: el tooltip lo dice completo y, debajo, su explicación\n const tooltip = entryLabel === fullLabel ? explanation : (\n <Box component=\"span\" sx={{display: 'flex', flexDirection: 'column', gap: 0.25}}>\n <Box component=\"span\" sx={{fontWeight: 700}}>{fullLabel}</Box>\n {explanation && <Box component=\"span\">{explanation}</Box>}\n </Box>\n );\n\n const ownerState = {tone: dictionaryEntry.color, variant};\n const content = variant === 'chip' ? (\n <StatusChipChip size=\"small\" label={label} color={dictionaryEntry.color} variant=\"outlined\" sx={sx} />\n ) : (\n <StatusChipRoot ownerState={ownerState}>\n <StatusChipDot aria-hidden=\"true\" ownerState={ownerState} />\n <StatusChipLabel ownerState={ownerState}>{label}</StatusChipLabel>\n </StatusChipRoot>\n );\n\n // guard clause: sin tooltip no envolvemos (un Tooltip vacío igual agrega listeners)\n if (!tooltip) {\n return content;\n }\n return <Tooltip title={tooltip}>{content}</Tooltip>;\n}\n"],"names":[],"mappings":";;;;;;;;;;AAsBA,MAAM,aAAa;AAEnB,MAAM,gBAAgB,CAAC,WAAW,aAAa,WAAW,WAAW,SAAS,MAAM;AAGpF,SAAS,cAAc,OAAO,MAAM;AAChC,SAAO,cAAc,SAAS,IAAI,KAAK,UAAU,KAAK,EAAE,IAAI,IAAI,UAAU,KAAK,EAAE,IAAI,IAAI;AAC7F;AAKA,MAAM,iBAAiB,OAAO,QAAQ,EAAC,MAAM,YAAY,MAAM,OAAA,CAAO,EAAE,CAAC,EAAC,OAAO,iBAAgB;AAC7F,QAAM,QAAQ,cAAc,OAAO,WAAW,IAAI;AAClD,SAAO;AAAA,IACH,SAAS;AAAA,IAAe,YAAY;AAAA,IAAU,KAAK,MAAM,QAAQ,IAAI;AAAA,IACrE,UAAU;AAAA,IAAI,YAAY;AAAA,IAAK,YAAY;AAAA,IAC3C,GAAI,QACE,kBAAkB,OAAO,EAAC,OAAO,MAAM,QAAO,EAAC,OAAO,MAAM,MAAA,CAAM,IAClE,EAAC,OAAO,UAAU,KAAK,EAAE,KAAK,UAAA;AAAA,EAAS;AAErD,CAAC;AAGD,MAAM,gBAAgB,OAAO,QAAQ,EAAC,MAAM,YAAY,MAAM,MAAA,CAAM,EAAE,CAAC,EAAC,OAAO,kBAAiB;AAAA,EAC5F,OAAO;AAAA,EAAG,QAAQ;AAAA,EAAG,YAAY;AAAA,EAAG,cAAc;AAAA,EAClD,iBAAiB,cAAc,OAAO,WAAW,IAAI,GAAG,QAAQ,UAAU,KAAK,EAAE,KAAK;AAC1F,EAAE;AAGF,MAAM,kBAAkB,OAAO,QAAQ,EAAC,MAAM,YAAY,MAAM,QAAA,CAAQ,EAAE,EAAC,UAAU,GAAG,UAAU,UAAU,cAAc,YAAW;AAErI,MAAM,iBAAiB,OAAO,MAAM,EAAC,MAAM,YAAY,MAAM,QAAO,EAAE,EAAE;AAcxE,SAAwB,WAAW,OAAO;AAEtC,QAAM,EAAC,YAAY,OAAO,UAAU,OAAO,QAAQ,OAAO,QAAQ,SAAS,eAAe,OAAM,cAAc,EAAC,OAAO,MAAM,YAAW;AACvI,QAAM,EAAC,EAAA,IAAK,sBAAsB,cAAc;AAChD,QAAM,kBAAkB,OAAO,YAAY,KAAK;AAChD,QAAM,YAAY,QAAQ,iBAAiB,CAAC;AAC5C,QAAM,aAAa,QAAQ,aAAa,iBAAiB,CAAC,IAAI;AAC9D,QAAM,QAAQ,SAAS,GAAG,UAAU,MAAM,MAAM,KAAK;AAErD,QAAM,cAAc,iBAAiB,EAAE,gBAAgB,YAAY,EAAC,cAAc,IAAG;AAErF,QAAM,UAAU,eAAe,YAAY,cACvC,qBAAC,OAAI,WAAU,QAAO,IAAI,EAAC,SAAS,QAAQ,eAAe,UAAU,KAAK,QACtE,UAAA;AAAA,IAAA,oBAAC,KAAA,EAAI,WAAU,QAAO,IAAI,EAAC,YAAY,IAAA,GAAO,UAAA,UAAA,CAAU;AAAA,IACvD,eAAe,oBAAC,KAAA,EAAI,WAAU,QAAQ,UAAA,YAAA,CAAY;AAAA,EAAA,GACvD;AAGJ,QAAM,aAAa,EAAC,MAAM,gBAAgB,OAAO,QAAA;AACjD,QAAM,UAAU,YAAY,SACxB,oBAAC,gBAAA,EAAe,MAAK,SAAQ,OAAc,OAAO,gBAAgB,OAAO,SAAQ,YAAW,IAAQ,IAEpG,qBAAC,kBAAe,YACZ,UAAA;AAAA,IAAA,oBAAC,eAAA,EAAc,eAAY,QAAO,WAAA,CAAwB;AAAA,IAC1D,oBAAC,iBAAA,EAAgB,YAAyB,UAAA,MAAA,CAAM;AAAA,EAAA,GACpD;AAIJ,MAAI,CAAC,SAAS;AACV,WAAO;AAAA,EACX;AACA,SAAO,oBAAC,SAAA,EAAQ,OAAO,SAAU,UAAA,SAAQ;AAC7C;"}
1
+ {"version":3,"file":"StatusChip.js","sources":["../../../src/ui/labels/StatusChip.jsx"],"sourcesContent":["// Estatus pintado desde un diccionario (dictionaries/dictionaries.js): etiqueta, tooltip y color salen del diccionario,\n// nunca del componente que lo usa. Un valor que no está en el diccionario se pinta con su código crudo.\n//\n// Dos formas:\n// - variant=\"dot\" (por defecto): punto de color + texto, sin fondo. Para la columna de estado de una tabla.\n// - variant=\"chip\": Chip de MUI con contorno, para formatos, hallazgos o encabezados.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaStatusChip con defaultProps (p. ej.\n// {variant: 'chip'}) y styleOverrides de sus partes: root (el renglón del punto y el texto), dot, label y chip.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport Box from '@mui/material/Box';\nimport Chip from '@mui/material/Chip';\nimport Tooltip from '@mui/material/Tooltip';\nimport {styled, useThemeProps} from '@mui/material/styles';\n\nimport {labelOf, lookup, shortLabelOf} from '@/dictionaries/dictionaries.js';\nimport {paletteOf} from '@/theme/components/paletteOf.js';\nimport {lightDarkStylesOf} from '@/theme/lightDarkStyles.js';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\n\n// el nombre de la pieza en el tema (theme.components.CalcitaStatusChip)\nconst THEME_NAME = 'CalcitaStatusChip';\n// los colores que trae la paleta; otro (o «default») se pinta neutro\nconst PALETTE_TONES = ['primary', 'secondary', 'success', 'warning', 'error', 'info'];\n\n/** El color del diccionario si la paleta lo tiene; si no, null (neutro). */\nfunction paletteToneOf(theme, tone) {\n return PALETTE_TONES.includes(tone) && paletteOf(theme)[tone] ? paletteOf(theme)[tone] : null;\n}\n\n// el punto y el texto. El texto va en el tono oscuro de su color en claro y en el claro en oscuro: con el oscuro también en\n// modo oscuro casi no se leía (el «Suspendido» rojo sobre la tabla oscura, lo vio el usuario). Con lightDarkStylesOf para\n// que el tema del proyecto (styleOverrides.root) le gane también en oscuro\nconst StatusChipRoot = styled('span', {name: THEME_NAME, slot: 'Root'})(({theme, ownerState}) => {\n const color = paletteToneOf(theme, ownerState.tone);\n return {\n display: 'inline-flex', alignItems: 'center', gap: theme.spacing(0.75),\n fontSize: 13, fontWeight: 500, whiteSpace: 'nowrap',\n ...(color\n ? lightDarkStylesOf(theme, {color: color.dark}, {color: color.light})\n : {color: paletteOf(theme).text.secondary}),\n };\n});\n\n// OJO: flexShrink 0; en una celda angosta el punto se encogía a 0 px y el estado perdía su color\nconst StatusChipDot = styled('span', {name: THEME_NAME, slot: 'Dot'})(({theme, ownerState}) => ({\n width: 6, height: 6, flexShrink: 0, borderRadius: '50%',\n backgroundColor: paletteToneOf(theme, ownerState.tone)?.main ?? paletteOf(theme).text.disabled,\n}));\n\n// el texto en su propio span: un nodo de texto suelto dentro de un flex se corta sin «…»\nconst StatusChipLabel = styled('span', {name: THEME_NAME, slot: 'Label'})({minWidth: 0, overflow: 'hidden', textOverflow: 'ellipsis'});\n\nconst StatusChipChip = styled(Chip, {name: THEME_NAME, slot: 'Chip'})({});\n\n/**\n * @param {object} props\n * @param {Record<string, object>} props.dictionary p. ej. BATCH_STATUS\n * @param {string|null|undefined} props.value código del API\n * @param {'dot'|'chip'} [props.variant]\n * @param {boolean} [props.short] pinta la palabra corta de la entrada (shortLabelKey), para una columna angosta; el\n * nombre completo queda en el tooltip, antes de su explicación\n * @param {string} [props.suffix] texto que va después de la etiqueta con \" · \" (p. ej. un conteo ya formateado)\n * @param {import('react').ReactNode} [props.tooltip] SUSTITUYE al tooltip del diccionario; úsalo cuando el renglón tiene algo más\n * que decir. OJO: no envuelvas este componente en otro Tooltip, porque el suyo sigue ahí y se ven los dos encimados\n * @param {object} [props.sx] ajustes de estilo del Chip (solo variant=\"chip\")\n */\nexport default function StatusChip(props) {\n // lo que el proyecto puso en su tema (components.CalcitaStatusChip.defaultProps) y encima lo que llega aquí\n const {dictionary, value, variant = 'dot', short = false, suffix, tooltip: customTooltip, sx, ...unknownProps} = useThemeProps({props, name: THEME_NAME});\n warnUnknownProps(THEME_NAME, unknownProps);\n const {t} = useToolkitTranslation('dictionaries');\n const dictionaryEntry = lookup(dictionary, value);\n const fullLabel = labelOf(dictionaryEntry, t);\n const entryLabel = short ? shortLabelOf(dictionaryEntry, t) : fullLabel;\n const label = suffix ? `${entryLabel} · ${suffix}` : entryLabel;\n // el de quien lo usa gana: si pasa uno, el del diccionario no se pinta y no hay dos globos\n const explanation = customTooltip ?? t(dictionaryEntry.tooltipKey, {defaultValue: ''});\n // la palabra corta deja fuera parte del nombre: el tooltip lo dice completo y, debajo, su explicación\n const tooltip = entryLabel === fullLabel ? explanation : (\n <Box component=\"span\" sx={{display: 'flex', flexDirection: 'column', gap: 0.25}}>\n <Box component=\"span\" sx={{fontWeight: 700}}>{fullLabel}</Box>\n {explanation && <Box component=\"span\">{explanation}</Box>}\n </Box>\n );\n\n const ownerState = {tone: dictionaryEntry.color, variant};\n const content = variant === 'chip' ? (\n <StatusChipChip size=\"small\" label={label} color={dictionaryEntry.color} variant=\"outlined\" sx={sx} />\n ) : (\n <StatusChipRoot ownerState={ownerState}>\n <StatusChipDot aria-hidden=\"true\" ownerState={ownerState} />\n <StatusChipLabel ownerState={ownerState}>{label}</StatusChipLabel>\n </StatusChipRoot>\n );\n\n // guard clause: sin tooltip no envolvemos (un Tooltip vacío igual agrega listeners)\n if (!tooltip) {\n return content;\n }\n return <Tooltip title={tooltip}>{content}</Tooltip>;\n}\n"],"names":[],"mappings":";;;;;;;;;;;AAuBA,MAAM,aAAa;AAEnB,MAAM,gBAAgB,CAAC,WAAW,aAAa,WAAW,WAAW,SAAS,MAAM;AAGpF,SAAS,cAAc,OAAO,MAAM;AAChC,SAAO,cAAc,SAAS,IAAI,KAAK,UAAU,KAAK,EAAE,IAAI,IAAI,UAAU,KAAK,EAAE,IAAI,IAAI;AAC7F;AAKA,MAAM,iBAAiB,OAAO,QAAQ,EAAC,MAAM,YAAY,MAAM,OAAA,CAAO,EAAE,CAAC,EAAC,OAAO,iBAAgB;AAC7F,QAAM,QAAQ,cAAc,OAAO,WAAW,IAAI;AAClD,SAAO;AAAA,IACH,SAAS;AAAA,IAAe,YAAY;AAAA,IAAU,KAAK,MAAM,QAAQ,IAAI;AAAA,IACrE,UAAU;AAAA,IAAI,YAAY;AAAA,IAAK,YAAY;AAAA,IAC3C,GAAI,QACE,kBAAkB,OAAO,EAAC,OAAO,MAAM,QAAO,EAAC,OAAO,MAAM,MAAA,CAAM,IAClE,EAAC,OAAO,UAAU,KAAK,EAAE,KAAK,UAAA;AAAA,EAAS;AAErD,CAAC;AAGD,MAAM,gBAAgB,OAAO,QAAQ,EAAC,MAAM,YAAY,MAAM,MAAA,CAAM,EAAE,CAAC,EAAC,OAAO,kBAAiB;AAAA,EAC5F,OAAO;AAAA,EAAG,QAAQ;AAAA,EAAG,YAAY;AAAA,EAAG,cAAc;AAAA,EAClD,iBAAiB,cAAc,OAAO,WAAW,IAAI,GAAG,QAAQ,UAAU,KAAK,EAAE,KAAK;AAC1F,EAAE;AAGF,MAAM,kBAAkB,OAAO,QAAQ,EAAC,MAAM,YAAY,MAAM,QAAA,CAAQ,EAAE,EAAC,UAAU,GAAG,UAAU,UAAU,cAAc,YAAW;AAErI,MAAM,iBAAiB,OAAO,MAAM,EAAC,MAAM,YAAY,MAAM,QAAO,EAAE,EAAE;AAcxE,SAAwB,WAAW,OAAO;AAEtC,QAAM,EAAC,YAAY,OAAO,UAAU,OAAO,QAAQ,OAAO,QAAQ,SAAS,eAAe,IAAI,GAAG,iBAAgB,cAAc,EAAC,OAAO,MAAM,YAAW;AACxJ,mBAAiB,YAAY,YAAY;AACzC,QAAM,EAAC,EAAA,IAAK,sBAAsB,cAAc;AAChD,QAAM,kBAAkB,OAAO,YAAY,KAAK;AAChD,QAAM,YAAY,QAAQ,iBAAiB,CAAC;AAC5C,QAAM,aAAa,QAAQ,aAAa,iBAAiB,CAAC,IAAI;AAC9D,QAAM,QAAQ,SAAS,GAAG,UAAU,MAAM,MAAM,KAAK;AAErD,QAAM,cAAc,iBAAiB,EAAE,gBAAgB,YAAY,EAAC,cAAc,IAAG;AAErF,QAAM,UAAU,eAAe,YAAY,cACvC,qBAAC,OAAI,WAAU,QAAO,IAAI,EAAC,SAAS,QAAQ,eAAe,UAAU,KAAK,QACtE,UAAA;AAAA,IAAA,oBAAC,KAAA,EAAI,WAAU,QAAO,IAAI,EAAC,YAAY,IAAA,GAAO,UAAA,UAAA,CAAU;AAAA,IACvD,eAAe,oBAAC,KAAA,EAAI,WAAU,QAAQ,UAAA,YAAA,CAAY;AAAA,EAAA,GACvD;AAGJ,QAAM,aAAa,EAAC,MAAM,gBAAgB,OAAO,QAAA;AACjD,QAAM,UAAU,YAAY,SACxB,oBAAC,gBAAA,EAAe,MAAK,SAAQ,OAAc,OAAO,gBAAgB,OAAO,SAAQ,YAAW,IAAQ,IAEpG,qBAAC,kBAAe,YACZ,UAAA;AAAA,IAAA,oBAAC,eAAA,EAAc,eAAY,QAAO,WAAA,CAAwB;AAAA,IAC1D,oBAAC,iBAAA,EAAgB,YAAyB,UAAA,MAAA,CAAM;AAAA,EAAA,GACpD;AAIJ,MAAI,CAAC,SAAS;AACV,WAAO;AAAA,EACX;AACA,SAAO,oBAAC,SAAA,EAAQ,OAAO,SAAU,UAAA,SAAQ;AAC7C;"}
@@ -8,6 +8,7 @@ import Box from "@mui/material/Box";
8
8
  import Typography from "@mui/material/Typography";
9
9
  import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
10
10
  import { piecePart, usePieceProps } from "../../theme/themePieces.js";
11
+ import { warnUnknownProps } from "../../toolkit/unknownProps.js";
11
12
  const THEME_NAME = "CalcitaCollapsibleSection";
12
13
  const CollapsibleRoot = piecePart(THEME_NAME, "Root", Box);
13
14
  const CollapsibleAccordion = piecePart(THEME_NAME, "Accordion", Accordion);
@@ -31,7 +32,8 @@ const HEADER_SX = {
31
32
  "& .MuiAccordionSummary-content": { my: 0.75, minWidth: 0 }
32
33
  };
33
34
  function CollapsibleSection(props) {
34
- const { collapsedTitle, expandedTitle, hint = "", defaultExpanded = false, onExpandedChange, children } = usePieceProps(props, THEME_NAME);
35
+ const { collapsedTitle, expandedTitle, hint = "", defaultExpanded = false, onExpandedChange, children, ...unknownProps } = usePieceProps(props, THEME_NAME);
36
+ warnUnknownProps(THEME_NAME, unknownProps);
35
37
  const [isExpanded, setIsExpanded] = useState(defaultExpanded);
36
38
  const changeExpanded = (nextIsExpanded) => {
37
39
  setIsExpanded(nextIsExpanded);
@@ -1 +1 @@
1
- {"version":3,"file":"CollapsibleSection.js","sources":["../../../src/ui/layout/CollapsibleSection.jsx"],"sourcesContent":["// Sección que se pliega: un encabezado que se toca y, debajo, el contenido, que se abre y se cierra.\n//\n// Para qué: en una página de detalle las cifras quedan a la vista y lo demás se guarda aquí; quien quiere más, lo abre.\n//\n// El encabezado se ve como lo que es, un botón a todo lo ancho: recuadro, la flecha ADELANTE del texto y otro fondo al pasar\n// el cursor. Su texto dice lo que va a pasar al tocarlo («Ver el detalle…» plegada, «Ocultar el detalle…» abierta) y,\n// plegada, un renglón más chico dice qué hay adentro: así nadie tiene que abrirla para saber si ahí está lo que busca.\n// No dice «dé clic»: en el teléfono no hay clic, y un tooltip tampoco se ve ahí.\n//\n// El contenido va sin fondo ni borde propios: adentro van tarjetas (SectionCard) y un recuadro alrededor se vería como\n// tarjeta dentro de tarjeta.\n//\n// OJO: el acordeón de MUI se quita el margen de arriba cuando está abierto y es el primero de su tipo entre sus hermanos.\n// Dentro de un Stack, que separa a sus hijos con margen, eso hacía brincar el encabezado 16 px al abrir y al cerrar. Por eso\n// va envuelto en una caja: el margen del Stack cae en la caja y el encabezado se queda quieto.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaCollapsibleSection con defaultProps y\n// styleOverrides de sus partes: root, accordion, summary, titleArea, collapsedTitle, expandedTitle, details.\n//\n// Genérico del paquete: function (regla de la casa). No sabe de negocio: sus textos llegan ya traducidos.\nimport {useState} from 'react';\nimport Accordion from '@mui/material/Accordion';\nimport AccordionDetails from '@mui/material/AccordionDetails';\nimport AccordionSummary from '@mui/material/AccordionSummary';\nimport Box from '@mui/material/Box';\nimport Typography from '@mui/material/Typography';\nimport ExpandMoreIcon from '@mui/icons-material/ExpandMore';\nimport {piecePart, usePieceProps} from '@/theme/themePieces.js';\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaCollapsibleSection)\nconst THEME_NAME = 'CalcitaCollapsibleSection';\nconst CollapsibleRoot = piecePart(THEME_NAME, 'Root', Box);\nconst CollapsibleAccordion = piecePart(THEME_NAME, 'Accordion', Accordion);\nconst CollapsibleSummary = piecePart(THEME_NAME, 'Summary', AccordionSummary);\nconst CollapsibleTitleArea = piecePart(THEME_NAME, 'TitleArea', Box);\nconst CollapsibleCollapsedTitle = piecePart(THEME_NAME, 'CollapsedTitle', Typography);\nconst CollapsibleExpandedTitle = piecePart(THEME_NAME, 'ExpandedTitle', Typography);\nconst CollapsibleDetails = piecePart(THEME_NAME, 'Details', AccordionDetails);\n\n// el mismo radio de las tarjetas (theme/components/surfaces.js): el encabezado se lee como una pieza más de la página\nconst CARD_BORDER_RADIUS_PIXELS = 10;\n\nconst HEADER_SX = {\n // la flecha adelante del texto: al final del renglón quedaba lejos de lo que se lee y pasaba inadvertida\n flexDirection: 'row-reverse', gap: 1, px: 1.5, minHeight: 44,\n border: 1, borderColor: 'divider', borderRadius: `${CARD_BORDER_RADIUS_PIXELS}px`, bgcolor: 'background.paper',\n '&:hover': {bgcolor: 'action.hover'},\n '& .MuiAccordionSummary-content': {my: 0.75, minWidth: 0},\n};\n\n/**\n * @param {object} props\n * @param {string} props.collapsedTitle lo que dice plegada, ya traducido («Ver el detalle de la validación»)\n * @param {string} props.expandedTitle lo que dice abierta («Ocultar el detalle de la validación»)\n * @param {string} [props.hint] plegada, qué hay adentro («Incluye resumen, motivos de rechazo y descargas.»)\n * @param {boolean} [props.defaultExpanded] si empieza abierta; por omisión empieza plegada\n * @param {(isExpanded: boolean) => void} [props.onExpandedChange] la persona la abrió o la plegó (por ejemplo, para pedir lo de\n * adentro hasta que se abre)\n * @param {import('react').ReactNode} props.children\n */\nexport default function CollapsibleSection(props) {\n // lo que el proyecto puso en su tema (components.CalcitaCollapsibleSection.defaultProps) y encima lo que llega aquí\n const {collapsedTitle, expandedTitle, hint = '', defaultExpanded = false, onExpandedChange, children} = usePieceProps(props, THEME_NAME);\n const [isExpanded, setIsExpanded] = useState(defaultExpanded);\n const changeExpanded = (nextIsExpanded) => {\n setIsExpanded(nextIsExpanded);\n onExpandedChange?.(nextIsExpanded);\n };\n\n return (\n <CollapsibleRoot ownSx={{minWidth: 0}}>\n <CollapsibleAccordion expanded={isExpanded} onChange={(changeEvent, nextIsExpanded) => changeExpanded(nextIsExpanded)}\n disableGutters elevation={0} square ownSx={{bgcolor: 'transparent', '&::before': {display: 'none'}}}>\n {/* NOTA: el acordeón ya envuelve este renglón en un encabezado (h3); los textos van como span para no anidar dos */}\n <CollapsibleSummary expandIcon={<ExpandMoreIcon color=\"primary\" />} ownSx={HEADER_SX}>\n <CollapsibleTitleArea ownSx={{minWidth: 0}}>\n <CollapsibleCollapsedTitle variant=\"subtitle2\" component=\"span\" color=\"primary\" ownSx={{display: 'block'}}>\n {isExpanded ? expandedTitle : collapsedTitle}\n </CollapsibleCollapsedTitle>\n {!isExpanded && hint && (\n <CollapsibleExpandedTitle variant=\"caption\" component=\"span\" color=\"text.secondary\" ownSx={{display: 'block'}}>{hint}</CollapsibleExpandedTitle>\n )}\n </CollapsibleTitleArea>\n </CollapsibleSummary>\n <CollapsibleDetails ownSx={{p: 0, pt: 2}}>{children}</CollapsibleDetails>\n </CollapsibleAccordion>\n </CollapsibleRoot>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;AA8BA,MAAM,aAAa;AACnB,MAAM,kBAAkB,UAAU,YAAY,QAAQ,GAAG;AACzD,MAAM,uBAAuB,UAAU,YAAY,aAAa,SAAS;AACzE,MAAM,qBAAqB,UAAU,YAAY,WAAW,gBAAgB;AAC5E,MAAM,uBAAuB,UAAU,YAAY,aAAa,GAAG;AACnE,MAAM,4BAA4B,UAAU,YAAY,kBAAkB,UAAU;AACpF,MAAM,2BAA2B,UAAU,YAAY,iBAAiB,UAAU;AAClF,MAAM,qBAAqB,UAAU,YAAY,WAAW,gBAAgB;AAG5E,MAAM,4BAA4B;AAElC,MAAM,YAAY;AAAA;AAAA,EAEd,eAAe;AAAA,EAAe,KAAK;AAAA,EAAG,IAAI;AAAA,EAAK,WAAW;AAAA,EAC1D,QAAQ;AAAA,EAAG,aAAa;AAAA,EAAW,cAAc,GAAG,yBAAyB;AAAA,EAAM,SAAS;AAAA,EAC5F,WAAW,EAAC,SAAS,eAAA;AAAA,EACrB,kCAAkC,EAAC,IAAI,MAAM,UAAU,EAAA;AAC3D;AAYA,SAAwB,mBAAmB,OAAO;AAE9C,QAAM,EAAC,gBAAgB,eAAe,OAAO,IAAI,kBAAkB,OAAO,kBAAkB,SAAA,IAAY,cAAc,OAAO,UAAU;AACvI,QAAM,CAAC,YAAY,aAAa,IAAI,SAAS,eAAe;AAC5D,QAAM,iBAAiB,CAAC,mBAAmB;AACvC,kBAAc,cAAc;AAC5B,uBAAmB,cAAc;AAAA,EACrC;AAEA,6BACK,iBAAA,EAAgB,OAAO,EAAC,UAAU,KAC/B,UAAA;AAAA,IAAC;AAAA,IAAA;AAAA,MAAqB,UAAU;AAAA,MAAY,UAAU,CAAC,aAAa,mBAAmB,eAAe,cAAc;AAAA,MACzG,gBAAc;AAAA,MAAC,WAAW;AAAA,MAAG,QAAM;AAAA,MAAC,OAAO,EAAC,SAAS,eAAe,aAAa,EAAC,SAAS,SAAM;AAAA,MAExG,UAAA;AAAA,QAAA,oBAAC,oBAAA,EAAmB,YAAY,oBAAC,gBAAA,EAAe,OAAM,UAAA,CAAU,GAAI,OAAO,WACvE,+BAAC,sBAAA,EAAqB,OAAO,EAAC,UAAU,KACpC,UAAA;AAAA,UAAA,oBAAC,2BAAA,EAA0B,SAAQ,aAAY,WAAU,QAAO,OAAM,WAAU,OAAO,EAAC,SAAS,QAAA,GAC5F,UAAA,aAAa,gBAAgB,gBAClC;AAAA,UACC,CAAC,cAAc,QACZ,oBAAC,0BAAA,EAAyB,SAAQ,WAAU,WAAU,QAAO,OAAM,kBAAiB,OAAO,EAAC,SAAS,QAAA,GAAW,UAAA,KAAA,CAAK;AAAA,QAAA,EAAA,CAE7H,EAAA,CACJ;AAAA,QACA,oBAAC,sBAAmB,OAAO,EAAC,GAAG,GAAG,IAAI,EAAA,GAAK,SAAA,CAAS;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA,GAE5D;AAER;"}
1
+ {"version":3,"file":"CollapsibleSection.js","sources":["../../../src/ui/layout/CollapsibleSection.jsx"],"sourcesContent":["// Sección que se pliega: un encabezado que se toca y, debajo, el contenido, que se abre y se cierra.\n//\n// Para qué: en una página de detalle las cifras quedan a la vista y lo demás se guarda aquí; quien quiere más, lo abre.\n//\n// El encabezado se ve como lo que es, un botón a todo lo ancho: recuadro, la flecha ADELANTE del texto y otro fondo al pasar\n// el cursor. Su texto dice lo que va a pasar al tocarlo («Ver el detalle…» plegada, «Ocultar el detalle…» abierta) y,\n// plegada, un renglón más chico dice qué hay adentro: así nadie tiene que abrirla para saber si ahí está lo que busca.\n// No dice «dé clic»: en el teléfono no hay clic, y un tooltip tampoco se ve ahí.\n//\n// El contenido va sin fondo ni borde propios: adentro van tarjetas (SectionCard) y un recuadro alrededor se vería como\n// tarjeta dentro de tarjeta.\n//\n// OJO: el acordeón de MUI se quita el margen de arriba cuando está abierto y es el primero de su tipo entre sus hermanos.\n// Dentro de un Stack, que separa a sus hijos con margen, eso hacía brincar el encabezado 16 px al abrir y al cerrar. Por eso\n// va envuelto en una caja: el margen del Stack cae en la caja y el encabezado se queda quieto.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaCollapsibleSection con defaultProps y\n// styleOverrides de sus partes: root, accordion, summary, titleArea, collapsedTitle, expandedTitle, details.\n//\n// Genérico del paquete: function (regla de la casa). No sabe de negocio: sus textos llegan ya traducidos.\nimport {useState} from 'react';\nimport Accordion from '@mui/material/Accordion';\nimport AccordionDetails from '@mui/material/AccordionDetails';\nimport AccordionSummary from '@mui/material/AccordionSummary';\nimport Box from '@mui/material/Box';\nimport Typography from '@mui/material/Typography';\nimport ExpandMoreIcon from '@mui/icons-material/ExpandMore';\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.CalcitaCollapsibleSection)\nconst THEME_NAME = 'CalcitaCollapsibleSection';\nconst CollapsibleRoot = piecePart(THEME_NAME, 'Root', Box);\nconst CollapsibleAccordion = piecePart(THEME_NAME, 'Accordion', Accordion);\nconst CollapsibleSummary = piecePart(THEME_NAME, 'Summary', AccordionSummary);\nconst CollapsibleTitleArea = piecePart(THEME_NAME, 'TitleArea', Box);\nconst CollapsibleCollapsedTitle = piecePart(THEME_NAME, 'CollapsedTitle', Typography);\nconst CollapsibleExpandedTitle = piecePart(THEME_NAME, 'ExpandedTitle', Typography);\nconst CollapsibleDetails = piecePart(THEME_NAME, 'Details', AccordionDetails);\n\n// el mismo radio de las tarjetas (theme/components/surfaces.js): el encabezado se lee como una pieza más de la página\nconst CARD_BORDER_RADIUS_PIXELS = 10;\n\nconst HEADER_SX = {\n // la flecha adelante del texto: al final del renglón quedaba lejos de lo que se lee y pasaba inadvertida\n flexDirection: 'row-reverse', gap: 1, px: 1.5, minHeight: 44,\n border: 1, borderColor: 'divider', borderRadius: `${CARD_BORDER_RADIUS_PIXELS}px`, bgcolor: 'background.paper',\n '&:hover': {bgcolor: 'action.hover'},\n '& .MuiAccordionSummary-content': {my: 0.75, minWidth: 0},\n};\n\n/**\n * @param {object} props\n * @param {string} props.collapsedTitle lo que dice plegada, ya traducido («Ver el detalle de la validación»)\n * @param {string} props.expandedTitle lo que dice abierta («Ocultar el detalle de la validación»)\n * @param {string} [props.hint] plegada, qué hay adentro («Incluye resumen, motivos de rechazo y descargas.»)\n * @param {boolean} [props.defaultExpanded] si empieza abierta; por omisión empieza plegada\n * @param {(isExpanded: boolean) => void} [props.onExpandedChange] la persona la abrió o la plegó (por ejemplo, para pedir lo de\n * adentro hasta que se abre)\n * @param {import('react').ReactNode} props.children\n */\nexport default function CollapsibleSection(props) {\n // lo que el proyecto puso en su tema (components.CalcitaCollapsibleSection.defaultProps) y encima lo que llega aquí\n const {collapsedTitle, expandedTitle, hint = '', defaultExpanded = false, onExpandedChange, children, ...unknownProps} = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n const [isExpanded, setIsExpanded] = useState(defaultExpanded);\n const changeExpanded = (nextIsExpanded) => {\n setIsExpanded(nextIsExpanded);\n onExpandedChange?.(nextIsExpanded);\n };\n\n return (\n <CollapsibleRoot ownSx={{minWidth: 0}}>\n <CollapsibleAccordion expanded={isExpanded} onChange={(changeEvent, nextIsExpanded) => changeExpanded(nextIsExpanded)}\n disableGutters elevation={0} square ownSx={{bgcolor: 'transparent', '&::before': {display: 'none'}}}>\n {/* NOTA: el acordeón ya envuelve este renglón en un encabezado (h3); los textos van como span para no anidar dos */}\n <CollapsibleSummary expandIcon={<ExpandMoreIcon color=\"primary\" />} ownSx={HEADER_SX}>\n <CollapsibleTitleArea ownSx={{minWidth: 0}}>\n <CollapsibleCollapsedTitle variant=\"subtitle2\" component=\"span\" color=\"primary\" ownSx={{display: 'block'}}>\n {isExpanded ? expandedTitle : collapsedTitle}\n </CollapsibleCollapsedTitle>\n {!isExpanded && hint && (\n <CollapsibleExpandedTitle variant=\"caption\" component=\"span\" color=\"text.secondary\" ownSx={{display: 'block'}}>{hint}</CollapsibleExpandedTitle>\n )}\n </CollapsibleTitleArea>\n </CollapsibleSummary>\n <CollapsibleDetails ownSx={{p: 0, pt: 2}}>{children}</CollapsibleDetails>\n </CollapsibleAccordion>\n </CollapsibleRoot>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;;AA+BA,MAAM,aAAa;AACnB,MAAM,kBAAkB,UAAU,YAAY,QAAQ,GAAG;AACzD,MAAM,uBAAuB,UAAU,YAAY,aAAa,SAAS;AACzE,MAAM,qBAAqB,UAAU,YAAY,WAAW,gBAAgB;AAC5E,MAAM,uBAAuB,UAAU,YAAY,aAAa,GAAG;AACnE,MAAM,4BAA4B,UAAU,YAAY,kBAAkB,UAAU;AACpF,MAAM,2BAA2B,UAAU,YAAY,iBAAiB,UAAU;AAClF,MAAM,qBAAqB,UAAU,YAAY,WAAW,gBAAgB;AAG5E,MAAM,4BAA4B;AAElC,MAAM,YAAY;AAAA;AAAA,EAEd,eAAe;AAAA,EAAe,KAAK;AAAA,EAAG,IAAI;AAAA,EAAK,WAAW;AAAA,EAC1D,QAAQ;AAAA,EAAG,aAAa;AAAA,EAAW,cAAc,GAAG,yBAAyB;AAAA,EAAM,SAAS;AAAA,EAC5F,WAAW,EAAC,SAAS,eAAA;AAAA,EACrB,kCAAkC,EAAC,IAAI,MAAM,UAAU,EAAA;AAC3D;AAYA,SAAwB,mBAAmB,OAAO;AAE9C,QAAM,EAAC,gBAAgB,eAAe,OAAO,IAAI,kBAAkB,OAAO,kBAAkB,UAAU,GAAG,aAAA,IAAgB,cAAc,OAAO,UAAU;AACxJ,mBAAiB,YAAY,YAAY;AACzC,QAAM,CAAC,YAAY,aAAa,IAAI,SAAS,eAAe;AAC5D,QAAM,iBAAiB,CAAC,mBAAmB;AACvC,kBAAc,cAAc;AAC5B,uBAAmB,cAAc;AAAA,EACrC;AAEA,6BACK,iBAAA,EAAgB,OAAO,EAAC,UAAU,KAC/B,UAAA;AAAA,IAAC;AAAA,IAAA;AAAA,MAAqB,UAAU;AAAA,MAAY,UAAU,CAAC,aAAa,mBAAmB,eAAe,cAAc;AAAA,MACzG,gBAAc;AAAA,MAAC,WAAW;AAAA,MAAG,QAAM;AAAA,MAAC,OAAO,EAAC,SAAS,eAAe,aAAa,EAAC,SAAS,SAAM;AAAA,MAExG,UAAA;AAAA,QAAA,oBAAC,oBAAA,EAAmB,YAAY,oBAAC,gBAAA,EAAe,OAAM,UAAA,CAAU,GAAI,OAAO,WACvE,+BAAC,sBAAA,EAAqB,OAAO,EAAC,UAAU,KACpC,UAAA;AAAA,UAAA,oBAAC,2BAAA,EAA0B,SAAQ,aAAY,WAAU,QAAO,OAAM,WAAU,OAAO,EAAC,SAAS,QAAA,GAC5F,UAAA,aAAa,gBAAgB,gBAClC;AAAA,UACC,CAAC,cAAc,QACZ,oBAAC,0BAAA,EAAyB,SAAQ,WAAU,WAAU,QAAO,OAAM,kBAAiB,OAAO,EAAC,SAAS,QAAA,GAAW,UAAA,KAAA,CAAK;AAAA,QAAA,EAAA,CAE7H,EAAA,CACJ;AAAA,QACA,oBAAC,sBAAmB,OAAO,EAAC,GAAG,GAAG,IAAI,EAAA,GAAK,SAAA,CAAS;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA,GAE5D;AAER;"}
@@ -10,6 +10,7 @@ import Typography from "@mui/material/Typography";
10
10
  import CloseIcon from "@mui/icons-material/Close";
11
11
  import { APP_BAR_HEIGHT } from "./appBarHeight.js";
12
12
  import { piecePart, usePieceProps } from "../../theme/themePieces.js";
13
+ import { warnUnknownProps } from "../../toolkit/unknownProps.js";
13
14
  const THEME_NAME = "CalcitaContentDialog";
14
15
  const DialogHeader = piecePart(THEME_NAME, "Header", Box);
15
16
  const DialogTitle = piecePart(THEME_NAME, "Title", Typography);
@@ -56,7 +57,8 @@ function SlideUp(props) {
56
57
  return /* @__PURE__ */ jsx(Slide, { direction: "up", ...props });
57
58
  }
58
59
  function ContentDialog(props) {
59
- const { open, onClose, title, children, texts } = usePieceProps(props, THEME_NAME);
60
+ const { open, onClose, title, children, texts, ...unknownProps } = usePieceProps(props, THEME_NAME);
61
+ warnUnknownProps(THEME_NAME, unknownProps);
60
62
  const { t } = useToolkitTranslation("common", texts);
61
63
  const titleId = useId();
62
64
  return /* @__PURE__ */ jsxs(
@@ -1 +1 @@
1
- {"version":3,"file":"ContentDialog.js","sources":["../../../src/ui/layout/ContentDialog.jsx"],"sourcesContent":["// Diálogo de contenido: la «hoja de lectura» (la «page sheet» de Apple) para una vista grande que se lee, como un historial\n// con su tabla. Las confirmaciones y los formularios cortos siguen en su recuadro al centro (ConfirmDialog): esto es para\n// leer, no para contestar una pregunta.\n//\n// Cómo se ve, como en el iPad y en la Mac: una hoja SÓLIDA (para leer no va vidrio) con esquinas redondas, que sube desde\n// abajo; en escritorio centrada, de un ancho que se lee cómodo (SHEET_MAX_WIDTH_PIXELS) y debajo de la barra de arriba, que se\n// queda a la vista (atenuada) para no perder dónde se está; en el teléfono, separada de las orillas y casi de alto completo.\n// Antes ocupaba la pantalla de orilla a orilla: un rectángulo gris plano con renglones larguísimos (lo reportaron).\n//\n// Cómo se arma: un encabezado que no se mueve (el título y la X para cerrar) y un cuerpo que se desliza si no cabe.\n//\n// OJO: el alto de la barra superior no es fijo (con un aviso adentro mide más): se usa el que publica el layout\n// (APP_BAR_HEIGHT), no un número.\n//\n// Solo abre una vista: se cierra con la X, con Escape o con un clic afuera, sin confirmación.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaContentDialog con defaultProps y\n// styleOverrides de sus partes: header, title, closeButton, body.\n//\n// Genérico del paquete: function (regla de la casa). No sabe de negocio: el título y el contenido llegan ya traducidos.\nimport {useId} from 'react';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport Box from '@mui/material/Box';\nimport Dialog from '@mui/material/Dialog';\nimport IconButton from '@mui/material/IconButton';\nimport Slide from '@mui/material/Slide';\nimport Typography from '@mui/material/Typography';\nimport CloseIcon from '@mui/icons-material/Close';\n\nimport {APP_BAR_HEIGHT} from '@/ui/layout/appBarHeight.js';\nimport {piecePart, usePieceProps} from '@/theme/themePieces.js';\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaContentDialog)\nconst THEME_NAME = 'CalcitaContentDialog';\nconst DialogHeader = piecePart(THEME_NAME, 'Header', Box);\nconst DialogTitle = piecePart(THEME_NAME, 'Title', Typography);\nconst DialogCloseButton = piecePart(THEME_NAME, 'CloseButton', IconButton);\nconst DialogBody = piecePart(THEME_NAME, 'Body', Box);\n\n// la hoja: lo ancho máximo en escritorio (un texto de 16 px se lee cómodo y cabe una tabla), su separación de las orillas y\n// la de su encabezado\nconst SHEET_MAX_WIDTH_PIXELS = 880;\nconst SHEET_GAP_PIXELS = 8;\nconst SHEET_PHONE_TOP_PIXELS = 24;\nconst SHEET_RADIUS_PIXELS = 20;\n\n/**\n * La hoja: fija a la ventana y centrada. Va como diálogo fullScreen (así el vidrio del tema la deja sólida y el fondo de\n * atrás no se desenfoca: la barra se sigue leyendo), con su tamaño y sus esquinas propios.\n * OJO: el alto del fullScreen de MUI es 100 %, que con top y bottom se saldría por abajo: va 'auto'.\n *\n * @param {object} theme\n * @returns {object}\n */\nfunction sheetSxOf(theme) {\n const palette = (theme.vars ?? theme).palette;\n return {\n position: 'fixed',\n m: 0,\n height: 'auto',\n maxHeight: 'none',\n borderRadius: `${SHEET_RADIUS_PIXELS}px`,\n // el que se desliza es el cuerpo, no la hoja: así el encabezado se queda quieto\n display: 'flex',\n flexDirection: 'column',\n overflow: 'hidden',\n backgroundColor: palette.background.paper,\n backgroundImage: 'none',\n boxShadow: `0 0 0 1px ${palette.divider}, 0 24px 64px rgba(0, 0, 0, 0.28)`,\n // en oscuro, un poco más clara que lo de atrás: lo que va al frente se aclara (HIG «Dark Mode»)\n ...theme.applyStyles('dark', {backgroundColor: `color-mix(in srgb, ${palette.background.paper}, white 6%)`}),\n // escritorio: centrada, debajo de la barra\n top: `calc(${APP_BAR_HEIGHT} + ${SHEET_GAP_PIXELS}px)`,\n bottom: SHEET_GAP_PIXELS,\n left: 0,\n right: 0,\n mx: 'auto',\n width: `min(${SHEET_MAX_WIDTH_PIXELS}px, calc(100% - ${SHEET_GAP_PIXELS * 4}px))`,\n maxWidth: 'none',\n // teléfono: separada de las orillas y casi de alto completo (la barra está abajo o es de MUI arriba: la hoja la tapa)\n [theme.breakpoints.down('md')]: {\n top: `calc(env(safe-area-inset-top) + ${SHEET_PHONE_TOP_PIXELS}px)`,\n bottom: `calc(env(safe-area-inset-bottom) + ${SHEET_GAP_PIXELS}px)`,\n width: `calc(100% - ${SHEET_GAP_PIXELS * 2}px)`,\n },\n };\n}\n\n/**\n * La animación de la hoja: entra desde abajo y sale por donde entró.\n *\n * @param {object} props lo que MUI le pasa a la animación de un diálogo (si está abierto, su contenido, sus tiempos)\n */\nfunction SlideUp(props) {\n return <Slide direction=\"up\" {...props} />;\n}\n\n/**\n * @param {object} props\n * @param {boolean} props.open\n * @param {() => void} props.onClose\n * @param {string} props.title texto ya traducido\n * @param {import('react').ReactNode} props.children\n * @param {object} [props.texts] los textos que cambian, con la forma de `common` en los textos del paquete\n */\nexport default function ContentDialog(props) {\n // lo que el proyecto puso en su tema (components.CalcitaContentDialog.defaultProps) y encima lo que llega aquí\n const {open, onClose, title, children, texts} = usePieceProps(props, THEME_NAME);\n const {t} = useToolkitTranslation('common', texts);\n const titleId = useId();\n\n return (\n <Dialog open={open} onClose={onClose} aria-labelledby={titleId} fullScreen\n slots={{transition: SlideUp}} slotProps={{paper: {sx: sheetSxOf}}}>\n <DialogHeader ownSx={{\n display: 'flex', alignItems: 'center', gap: 2, flexShrink: 0, minHeight: 60, pl: {xs: 2.5, md: 4}, pr: {xs: 1.5, md: 2}, py: 1,\n borderBottom: 1, borderColor: 'divider',\n }}>\n <DialogTitle id={titleId} variant=\"h6\" component=\"h2\" ownSx={{flex: 1, minWidth: 0}}>{title}</DialogTitle>\n {/* la X de Apple: en un círculo gris tenue, no suelta */}\n <DialogCloseButton onClick={onClose} aria-label={t('actions.close')} size=\"small\"\n ownSx={{bgcolor: 'action.hover', '&:hover': {bgcolor: 'action.selected'}}}>\n <CloseIcon fontSize=\"small\" />\n </DialogCloseButton>\n </DialogHeader>\n <DialogBody ownSx={{flex: 1, minHeight: 0, overflow: 'auto', px: {xs: 2.5, md: 4}, py: {xs: 2, md: 3}}}>\n {children}\n </DialogBody>\n </Dialog>\n );\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ContentDialog.js","sources":["../../../src/ui/layout/ContentDialog.jsx"],"sourcesContent":["// Diálogo de contenido: la «hoja de lectura» (la «page sheet» de Apple) para una vista grande que se lee, como un historial\n// con su tabla. Las confirmaciones y los formularios cortos siguen en su recuadro al centro (ConfirmDialog): esto es para\n// leer, no para contestar una pregunta.\n//\n// Cómo se ve, como en el iPad y en la Mac: una hoja SÓLIDA (para leer no va vidrio) con esquinas redondas, que sube desde\n// abajo; en escritorio centrada, de un ancho que se lee cómodo (SHEET_MAX_WIDTH_PIXELS) y debajo de la barra de arriba, que se\n// queda a la vista (atenuada) para no perder dónde se está; en el teléfono, separada de las orillas y casi de alto completo.\n// Antes ocupaba la pantalla de orilla a orilla: un rectángulo gris plano con renglones larguísimos (lo reportaron).\n//\n// Cómo se arma: un encabezado que no se mueve (el título y la X para cerrar) y un cuerpo que se desliza si no cabe.\n//\n// OJO: el alto de la barra superior no es fijo (con un aviso adentro mide más): se usa el que publica el layout\n// (APP_BAR_HEIGHT), no un número.\n//\n// Solo abre una vista: se cierra con la X, con Escape o con un clic afuera, sin confirmación.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaContentDialog con defaultProps y\n// styleOverrides de sus partes: header, title, closeButton, body.\n//\n// Genérico del paquete: function (regla de la casa). No sabe de negocio: el título y el contenido llegan ya traducidos.\nimport {useId} from 'react';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport Box from '@mui/material/Box';\nimport Dialog from '@mui/material/Dialog';\nimport IconButton from '@mui/material/IconButton';\nimport Slide from '@mui/material/Slide';\nimport Typography from '@mui/material/Typography';\nimport CloseIcon from '@mui/icons-material/Close';\n\nimport {APP_BAR_HEIGHT} 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.CalcitaContentDialog)\nconst THEME_NAME = 'CalcitaContentDialog';\nconst DialogHeader = piecePart(THEME_NAME, 'Header', Box);\nconst DialogTitle = piecePart(THEME_NAME, 'Title', Typography);\nconst DialogCloseButton = piecePart(THEME_NAME, 'CloseButton', IconButton);\nconst DialogBody = piecePart(THEME_NAME, 'Body', Box);\n\n// la hoja: lo ancho máximo en escritorio (un texto de 16 px se lee cómodo y cabe una tabla), su separación de las orillas y\n// la de su encabezado\nconst SHEET_MAX_WIDTH_PIXELS = 880;\nconst SHEET_GAP_PIXELS = 8;\nconst SHEET_PHONE_TOP_PIXELS = 24;\nconst SHEET_RADIUS_PIXELS = 20;\n\n/**\n * La hoja: fija a la ventana y centrada. Va como diálogo fullScreen (así el vidrio del tema la deja sólida y el fondo de\n * atrás no se desenfoca: la barra se sigue leyendo), con su tamaño y sus esquinas propios.\n * OJO: el alto del fullScreen de MUI es 100 %, que con top y bottom se saldría por abajo: va 'auto'.\n *\n * @param {object} theme\n * @returns {object}\n */\nfunction sheetSxOf(theme) {\n const palette = (theme.vars ?? theme).palette;\n return {\n position: 'fixed',\n m: 0,\n height: 'auto',\n maxHeight: 'none',\n borderRadius: `${SHEET_RADIUS_PIXELS}px`,\n // el que se desliza es el cuerpo, no la hoja: así el encabezado se queda quieto\n display: 'flex',\n flexDirection: 'column',\n overflow: 'hidden',\n backgroundColor: palette.background.paper,\n backgroundImage: 'none',\n boxShadow: `0 0 0 1px ${palette.divider}, 0 24px 64px rgba(0, 0, 0, 0.28)`,\n // en oscuro, un poco más clara que lo de atrás: lo que va al frente se aclara (HIG «Dark Mode»)\n ...theme.applyStyles('dark', {backgroundColor: `color-mix(in srgb, ${palette.background.paper}, white 6%)`}),\n // escritorio: centrada, debajo de la barra\n top: `calc(${APP_BAR_HEIGHT} + ${SHEET_GAP_PIXELS}px)`,\n bottom: SHEET_GAP_PIXELS,\n left: 0,\n right: 0,\n mx: 'auto',\n width: `min(${SHEET_MAX_WIDTH_PIXELS}px, calc(100% - ${SHEET_GAP_PIXELS * 4}px))`,\n maxWidth: 'none',\n // teléfono: separada de las orillas y casi de alto completo (la barra está abajo o es de MUI arriba: la hoja la tapa)\n [theme.breakpoints.down('md')]: {\n top: `calc(env(safe-area-inset-top) + ${SHEET_PHONE_TOP_PIXELS}px)`,\n bottom: `calc(env(safe-area-inset-bottom) + ${SHEET_GAP_PIXELS}px)`,\n width: `calc(100% - ${SHEET_GAP_PIXELS * 2}px)`,\n },\n };\n}\n\n/**\n * La animación de la hoja: entra desde abajo y sale por donde entró.\n *\n * @param {object} props lo que MUI le pasa a la animación de un diálogo (si está abierto, su contenido, sus tiempos)\n */\nfunction SlideUp(props) {\n return <Slide direction=\"up\" {...props} />;\n}\n\n/**\n * @param {object} props\n * @param {boolean} props.open\n * @param {() => void} props.onClose\n * @param {string} props.title texto ya traducido\n * @param {import('react').ReactNode} props.children\n * @param {object} [props.texts] los textos que cambian, con la forma de `common` en los textos del paquete\n */\nexport default function ContentDialog(props) {\n // lo que el proyecto puso en su tema (components.CalcitaContentDialog.defaultProps) y encima lo que llega aquí\n const {open, onClose, title, children, texts, ...unknownProps} = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n const {t} = useToolkitTranslation('common', texts);\n const titleId = useId();\n\n return (\n <Dialog open={open} onClose={onClose} aria-labelledby={titleId} fullScreen\n slots={{transition: SlideUp}} slotProps={{paper: {sx: sheetSxOf}}}>\n <DialogHeader ownSx={{\n display: 'flex', alignItems: 'center', gap: 2, flexShrink: 0, minHeight: 60, pl: {xs: 2.5, md: 4}, pr: {xs: 1.5, md: 2}, py: 1,\n borderBottom: 1, borderColor: 'divider',\n }}>\n <DialogTitle id={titleId} variant=\"h6\" component=\"h2\" ownSx={{flex: 1, minWidth: 0}}>{title}</DialogTitle>\n {/* la X de Apple: en un círculo gris tenue, no suelta */}\n <DialogCloseButton onClick={onClose} aria-label={t('actions.close')} size=\"small\"\n ownSx={{bgcolor: 'action.hover', '&:hover': {bgcolor: 'action.selected'}}}>\n <CloseIcon fontSize=\"small\" />\n </DialogCloseButton>\n </DialogHeader>\n <DialogBody ownSx={{flex: 1, minHeight: 0, overflow: 'auto', px: {xs: 2.5, md: 4}, py: {xs: 2, md: 3}}}>\n {children}\n </DialogBody>\n </Dialog>\n );\n}\n"],"names":[],"mappings":"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"}
@@ -3,13 +3,15 @@ import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import Box from "@mui/material/Box";
4
4
  import Typography from "@mui/material/Typography";
5
5
  import { piecePart, usePieceProps } from "../../theme/themePieces.js";
6
+ import { warnUnknownProps } from "../../toolkit/unknownProps.js";
6
7
  const THEME_NAME = "CalcitaDefinitionList";
7
8
  const DefinitionRoot = piecePart(THEME_NAME, "Root", Box);
8
9
  const DefinitionEntry = piecePart(THEME_NAME, "Entry", Box);
9
10
  const DefinitionLabel = piecePart(THEME_NAME, "Label", Typography);
10
11
  const DefinitionValue = piecePart(THEME_NAME, "Value", Typography);
11
12
  function DefinitionList(props) {
12
- const { entries, layout = "columns", labelWidth = 150 } = usePieceProps(props, THEME_NAME);
13
+ const { entries, layout = "columns", labelWidth = 150, ...unknownProps } = usePieceProps(props, THEME_NAME);
14
+ warnUnknownProps(THEME_NAME, unknownProps);
13
15
  const isStacked = layout === "stacked";
14
16
  return /* @__PURE__ */ jsx(DefinitionRoot, { component: "dl", ownSx: {
15
17
  m: 0,
@@ -1 +1 @@
1
- {"version":3,"file":"DefinitionList.js","sources":["../../../src/ui/layout/DefinitionList.jsx"],"sourcesContent":["// Lista de dato → valor (<dl>).\n//\n// Dos acomodos:\n// columns (por omisión) el dato en gris a la izquierda y su valor a la derecha; para tarjetas anchas\n// stacked el dato chico arriba de su valor; para columnas angostas, donde un nombre largo\n// («Codificación del archivo») se partiría en dos renglones al lado de su valor\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaDefinitionList con defaultProps y\n// styleOverrides de sus partes: root, entry, label, value.\n//\n// Genérico del paquete: function (regla de la casa). Los textos llegan ya traducidos y el valor puede ser cualquier nodo (un\n// chip, un texto en monoespaciada...).\nimport Box from '@mui/material/Box';\nimport Typography from '@mui/material/Typography';\nimport {piecePart, usePieceProps} from '@/theme/themePieces.js';\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaDefinitionList)\nconst THEME_NAME = 'CalcitaDefinitionList';\nconst DefinitionRoot = piecePart(THEME_NAME, 'Root', Box);\nconst DefinitionEntry = piecePart(THEME_NAME, 'Entry', Box);\nconst DefinitionLabel = piecePart(THEME_NAME, 'Label', Typography);\nconst DefinitionValue = piecePart(THEME_NAME, 'Value', Typography);\n\n/**\n * @param {object} props\n * @param {Array<{label: string, value: import('react').ReactNode}>} props.entries en el orden en que se pintan; el label es la\n * llave\n * @param {'columns'|'stacked'} [props.layout]\n * @param {number} [props.labelWidth] ancho en px de la columna del dato (solo columns)\n */\nexport default function DefinitionList(props) {\n // lo que el proyecto puso en su tema (components.CalcitaDefinitionList.defaultProps) y encima lo que llega aquí\n const {entries, layout = 'columns', labelWidth = 150} = usePieceProps(props, THEME_NAME);\n const isStacked = layout === 'stacked';\n\n return (\n <DefinitionRoot component=\"dl\" ownSx={{\n m: 0, display: 'grid',\n gridTemplateColumns: isStacked ? 'minmax(0, 1fr)' : `${labelWidth}px minmax(0, 1fr)`,\n columnGap: 2, rowGap: isStacked ? 0.25 : 1,\n }}>\n {entries.map(({label, value}, entryPosition) => (\n <DefinitionEntry key={label} ownSx={{display: 'contents'}}>\n <DefinitionLabel component=\"dt\" variant={isStacked ? 'caption' : 'body2'} color=\"text.secondary\"\n ownSx={isStacked && entryPosition > 0 ? {mt: 1.25} : undefined}>\n {label}\n </DefinitionLabel>\n <DefinitionValue component=\"dd\" variant=\"body2\" ownSx={{m: 0, overflowWrap: 'anywhere'}}>{value}</DefinitionValue>\n </DefinitionEntry>\n ))}\n </DefinitionRoot>\n );\n}\n"],"names":[],"mappings":";;;;;AAiBA,MAAM,aAAa;AACnB,MAAM,iBAAiB,UAAU,YAAY,QAAQ,GAAG;AACxD,MAAM,kBAAkB,UAAU,YAAY,SAAS,GAAG;AAC1D,MAAM,kBAAkB,UAAU,YAAY,SAAS,UAAU;AACjE,MAAM,kBAAkB,UAAU,YAAY,SAAS,UAAU;AASjE,SAAwB,eAAe,OAAO;AAE1C,QAAM,EAAC,SAAS,SAAS,WAAW,aAAa,QAAO,cAAc,OAAO,UAAU;AACvF,QAAM,YAAY,WAAW;AAE7B,SACI,oBAAC,gBAAA,EAAe,WAAU,MAAK,OAAO;AAAA,IAClC,GAAG;AAAA,IAAG,SAAS;AAAA,IACf,qBAAqB,YAAY,mBAAmB,GAAG,UAAU;AAAA,IACjE,WAAW;AAAA,IAAG,QAAQ,YAAY,OAAO;AAAA,EAAA,GAExC,UAAA,QAAQ,IAAI,CAAC,EAAC,OAAO,SAAQ,uCACzB,iBAAA,EAA4B,OAAO,EAAC,SAAS,cAC1C,UAAA;AAAA,IAAA;AAAA,MAAC;AAAA,MAAA;AAAA,QAAgB,WAAU;AAAA,QAAK,SAAS,YAAY,YAAY;AAAA,QAAS,OAAM;AAAA,QACpE,OAAO,aAAa,gBAAgB,IAAI,EAAC,IAAI,SAAQ;AAAA,QAC5D,UAAA;AAAA,MAAA;AAAA,IAAA;AAAA,IAEL,oBAAC,iBAAA,EAAgB,WAAU,MAAK,SAAQ,SAAQ,OAAO,EAAC,GAAG,GAAG,cAAc,WAAA,GAAc,UAAA,MAAA,CAAM;AAAA,EAAA,KAL9E,KAMtB,CACH,GACL;AAER;"}
1
+ {"version":3,"file":"DefinitionList.js","sources":["../../../src/ui/layout/DefinitionList.jsx"],"sourcesContent":["// Lista de dato → valor (<dl>).\n//\n// Dos acomodos:\n// columns (por omisión) el dato en gris a la izquierda y su valor a la derecha; para tarjetas anchas\n// stacked el dato chico arriba de su valor; para columnas angostas, donde un nombre largo\n// («Codificación del archivo») se partiría en dos renglones al lado de su valor\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaDefinitionList con defaultProps y\n// styleOverrides de sus partes: root, entry, label, value.\n//\n// Genérico del paquete: function (regla de la casa). Los textos llegan ya traducidos y el valor puede ser cualquier nodo (un\n// chip, un texto en monoespaciada...).\nimport Box from '@mui/material/Box';\nimport Typography from '@mui/material/Typography';\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.CalcitaDefinitionList)\nconst THEME_NAME = 'CalcitaDefinitionList';\nconst DefinitionRoot = piecePart(THEME_NAME, 'Root', Box);\nconst DefinitionEntry = piecePart(THEME_NAME, 'Entry', Box);\nconst DefinitionLabel = piecePart(THEME_NAME, 'Label', Typography);\nconst DefinitionValue = piecePart(THEME_NAME, 'Value', Typography);\n\n/**\n * @param {object} props\n * @param {Array<{label: string, value: import('react').ReactNode}>} props.entries en el orden en que se pintan; el label es la\n * llave\n * @param {'columns'|'stacked'} [props.layout]\n * @param {number} [props.labelWidth] ancho en px de la columna del dato (solo columns)\n */\nexport default function DefinitionList(props) {\n // lo que el proyecto puso en su tema (components.CalcitaDefinitionList.defaultProps) y encima lo que llega aquí\n const {entries, layout = 'columns', labelWidth = 150, ...unknownProps} = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n const isStacked = layout === 'stacked';\n\n return (\n <DefinitionRoot component=\"dl\" ownSx={{\n m: 0, display: 'grid',\n gridTemplateColumns: isStacked ? 'minmax(0, 1fr)' : `${labelWidth}px minmax(0, 1fr)`,\n columnGap: 2, rowGap: isStacked ? 0.25 : 1,\n }}>\n {entries.map(({label, value}, entryPosition) => (\n <DefinitionEntry key={label} ownSx={{display: 'contents'}}>\n <DefinitionLabel component=\"dt\" variant={isStacked ? 'caption' : 'body2'} color=\"text.secondary\"\n ownSx={isStacked && entryPosition > 0 ? {mt: 1.25} : undefined}>\n {label}\n </DefinitionLabel>\n <DefinitionValue component=\"dd\" variant=\"body2\" ownSx={{m: 0, overflowWrap: 'anywhere'}}>{value}</DefinitionValue>\n </DefinitionEntry>\n ))}\n </DefinitionRoot>\n );\n}\n"],"names":[],"mappings":";;;;;;AAkBA,MAAM,aAAa;AACnB,MAAM,iBAAiB,UAAU,YAAY,QAAQ,GAAG;AACxD,MAAM,kBAAkB,UAAU,YAAY,SAAS,GAAG;AAC1D,MAAM,kBAAkB,UAAU,YAAY,SAAS,UAAU;AACjE,MAAM,kBAAkB,UAAU,YAAY,SAAS,UAAU;AASjE,SAAwB,eAAe,OAAO;AAE1C,QAAM,EAAC,SAAS,SAAS,WAAW,aAAa,KAAK,GAAG,aAAA,IAAgB,cAAc,OAAO,UAAU;AACxG,mBAAiB,YAAY,YAAY;AACzC,QAAM,YAAY,WAAW;AAE7B,SACI,oBAAC,gBAAA,EAAe,WAAU,MAAK,OAAO;AAAA,IAClC,GAAG;AAAA,IAAG,SAAS;AAAA,IACf,qBAAqB,YAAY,mBAAmB,GAAG,UAAU;AAAA,IACjE,WAAW;AAAA,IAAG,QAAQ,YAAY,OAAO;AAAA,EAAA,GAExC,UAAA,QAAQ,IAAI,CAAC,EAAC,OAAO,SAAQ,uCACzB,iBAAA,EAA4B,OAAO,EAAC,SAAS,cAC1C,UAAA;AAAA,IAAA;AAAA,MAAC;AAAA,MAAA;AAAA,QAAgB,WAAU;AAAA,QAAK,SAAS,YAAY,YAAY;AAAA,QAAS,OAAM;AAAA,QACpE,OAAO,aAAa,gBAAgB,IAAI,EAAC,IAAI,SAAQ;AAAA,QAC5D,UAAA;AAAA,MAAA;AAAA,IAAA;AAAA,IAEL,oBAAC,iBAAA,EAAgB,WAAU,MAAK,SAAQ,SAAQ,OAAO,EAAC,GAAG,GAAG,cAAc,WAAA,GAAc,UAAA,MAAA,CAAM;AAAA,EAAA,KAL9E,KAMtB,CACH,GACL;AAER;"}
@@ -7,6 +7,7 @@ import Typography from "@mui/material/Typography";
7
7
  import { useRegisterPageTitle } from "../../appShell/pageTitle.js";
8
8
  import DocumentTitle from "../navigation/DocumentTitle.js";
9
9
  import { piecePart, usePieceProps } from "../../theme/themePieces.js";
10
+ import { warnUnknownProps } from "../../toolkit/unknownProps.js";
10
11
  const THEME_NAME = "CalcitaDetailHeader";
11
12
  const DetailRoot = piecePart(THEME_NAME, "Root", Box);
12
13
  const DetailTitleArea = piecePart(THEME_NAME, "TitleArea", Box);
@@ -14,7 +15,8 @@ const DetailTitle = piecePart(THEME_NAME, "Title", Typography);
14
15
  const DetailBadges = piecePart(THEME_NAME, "Badges", Stack);
15
16
  const DetailActions = piecePart(THEME_NAME, "Actions", Stack);
16
17
  function DetailHeader(props) {
17
- const { title, eyebrow, badges, actions, documentTitle } = usePieceProps(props, THEME_NAME);
18
+ const { title, eyebrow, badges, actions, documentTitle, ...unknownProps } = usePieceProps(props, THEME_NAME);
19
+ warnUnknownProps(THEME_NAME, unknownProps);
18
20
  const titleRef = useRef(null);
19
21
  useRegisterPageTitle(title, titleRef);
20
22
  return /* @__PURE__ */ jsxs(DetailRoot, { component: "header", ownSx: { display: "flex", flexWrap: "wrap", alignItems: "flex-end", justifyContent: "space-between", gap: 2, mb: 2.5 }, children: [
@@ -1 +1 @@
1
- {"version":3,"file":"DetailHeader.js","sources":["../../../src/ui/layout/DetailHeader.jsx"],"sourcesContent":["// Encabezado de una página de detalle (un solo registro: un pedido, un usuario...): eyebrow con el contexto, el título\n// que dice QUÉ registro es, sus insignias a un lado del título (estatus, intento...) y las acciones a la derecha.\n//\n// Por qué aparte de PageHeader: ese es el encabezado centrado de un listado. En un detalle lo primero que se lee es qué\n// registro se está viendo y en qué estado está; por eso el título y sus insignias van juntos, arriba a la izquierda.\n//\n// También pone el título de la pestaña (DocumentTitle) y, dentro de AppLayout, sube el título a la barra al deslizar.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaDetailHeader con defaultProps y\n// styleOverrides de sus partes: root, titleArea, title, badges, actions.\n//\n// Genérico del paquete: function (regla de la casa). No sabe de negocio: todo llega por props, ya traducido.\nimport {useRef} from 'react';\nimport Box from '@mui/material/Box';\nimport Stack from '@mui/material/Stack';\nimport Typography from '@mui/material/Typography';\n\nimport {useRegisterPageTitle} from '@/appShell/pageTitle.jsx';\nimport DocumentTitle from '@/ui/navigation/DocumentTitle.jsx';\nimport {piecePart, usePieceProps} from '@/theme/themePieces.js';\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaDetailHeader)\nconst THEME_NAME = 'CalcitaDetailHeader';\nconst DetailRoot = piecePart(THEME_NAME, 'Root', Box);\nconst DetailTitleArea = piecePart(THEME_NAME, 'TitleArea', Box);\nconst DetailTitle = piecePart(THEME_NAME, 'Title', Typography);\nconst DetailBadges = piecePart(THEME_NAME, 'Badges', Stack);\nconst DetailActions = piecePart(THEME_NAME, 'Actions', Stack);\n\n/**\n * @param {object} props\n * @param {string} props.title texto ya traducido\n * @param {string} [props.eyebrow] contexto arriba del título (p. ej. el producto)\n * @param {import('react').ReactNode} [props.badges] insignias junto al título (chips de estatus, intento...)\n * @param {import('react').ReactNode} [props.actions] botones a la derecha\n * @param {string} [props.documentTitle] título de la pestaña si difiere del visible\n */\nexport default function DetailHeader(props) {\n // lo que el proyecto puso en su tema (components.CalcitaDetailHeader.defaultProps) y encima lo que llega aquí\n const {title, eyebrow, badges, actions, documentTitle} = usePieceProps(props, THEME_NAME);\n const titleRef = useRef(null);\n useRegisterPageTitle(title, titleRef);\n return (\n <DetailRoot component=\"header\" ownSx={{display: 'flex', flexWrap: 'wrap', alignItems: 'flex-end', justifyContent: 'space-between', gap: 2, mb: 2.5}}>\n <DocumentTitle title={documentTitle ?? title} />\n <DetailTitleArea ownSx={{minWidth: 0}}>\n {/* el contexto se lee de un vistazo (en overline se veía\n muy chico); text.secondary y no text.disabled: se lee (WCAG no lo exime) */}\n {eyebrow && <DetailTitle variant=\"subtitle1\" color=\"text.secondary\" component=\"p\" ownSx={{fontWeight: 700}}>{eyebrow}</DetailTitle>}\n <DetailBadges direction=\"row\" spacing={1.5} useFlexGap ownSx={{alignItems: 'center', flexWrap: 'wrap'}}>\n <Typography ref={titleRef} variant=\"h5\" component=\"h1\">{title}</Typography>\n {badges}\n </DetailBadges>\n </DetailTitleArea>\n {actions && <DetailActions direction=\"row\" spacing={1} useFlexGap ownSx={{flexWrap: 'wrap'}}>{actions}</DetailActions>}\n </DetailRoot>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;AAsBA,MAAM,aAAa;AACnB,MAAM,aAAa,UAAU,YAAY,QAAQ,GAAG;AACpD,MAAM,kBAAkB,UAAU,YAAY,aAAa,GAAG;AAC9D,MAAM,cAAc,UAAU,YAAY,SAAS,UAAU;AAC7D,MAAM,eAAe,UAAU,YAAY,UAAU,KAAK;AAC1D,MAAM,gBAAgB,UAAU,YAAY,WAAW,KAAK;AAU5D,SAAwB,aAAa,OAAO;AAExC,QAAM,EAAC,OAAO,SAAS,QAAQ,SAAS,kBAAiB,cAAc,OAAO,UAAU;AACxF,QAAM,WAAW,OAAO,IAAI;AAC5B,uBAAqB,OAAO,QAAQ;AACpC,8BACK,YAAA,EAAW,WAAU,UAAS,OAAO,EAAC,SAAS,QAAQ,UAAU,QAAQ,YAAY,YAAY,gBAAgB,iBAAiB,KAAK,GAAG,IAAI,OAC3I,UAAA;AAAA,IAAA,oBAAC,eAAA,EAAc,OAAO,iBAAiB,MAAA,CAAO;AAAA,yBAC7C,iBAAA,EAAgB,OAAO,EAAC,UAAU,KAG9B,UAAA;AAAA,MAAA,WAAW,oBAAC,aAAA,EAAY,SAAQ,aAAY,OAAM,kBAAiB,WAAU,KAAI,OAAO,EAAC,YAAY,IAAA,GAAO,UAAA,SAAQ;AAAA,MACrH,qBAAC,cAAA,EAAa,WAAU,OAAM,SAAS,KAAK,YAAU,MAAC,OAAO,EAAC,YAAY,UAAU,UAAU,UAC3F,UAAA;AAAA,QAAA,oBAAC,cAAW,KAAK,UAAU,SAAQ,MAAK,WAAU,MAAM,UAAA,MAAA,CAAM;AAAA,QAC7D;AAAA,MAAA,EAAA,CACL;AAAA,IAAA,GACJ;AAAA,IACC,WAAW,oBAAC,eAAA,EAAc,WAAU,OAAM,SAAS,GAAG,YAAU,MAAC,OAAO,EAAC,UAAU,OAAA,GAAU,UAAA,QAAA,CAAQ;AAAA,EAAA,GAC1G;AAER;"}
1
+ {"version":3,"file":"DetailHeader.js","sources":["../../../src/ui/layout/DetailHeader.jsx"],"sourcesContent":["// Encabezado de una página de detalle (un solo registro: un pedido, un usuario...): eyebrow con el contexto, el título\n// que dice QUÉ registro es, sus insignias a un lado del título (estatus, intento...) y las acciones a la derecha.\n//\n// Por qué aparte de PageHeader: ese es el encabezado centrado de un listado. En un detalle lo primero que se lee es qué\n// registro se está viendo y en qué estado está; por eso el título y sus insignias van juntos, arriba a la izquierda.\n//\n// También pone el título de la pestaña (DocumentTitle) y, dentro de AppLayout, sube el título a la barra al deslizar.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaDetailHeader con defaultProps y\n// styleOverrides de sus partes: root, titleArea, title, badges, actions.\n//\n// Genérico del paquete: function (regla de la casa). No sabe de negocio: todo llega por props, ya traducido.\nimport {useRef} from 'react';\nimport Box from '@mui/material/Box';\nimport Stack from '@mui/material/Stack';\nimport Typography from '@mui/material/Typography';\n\nimport {useRegisterPageTitle} from '@/appShell/pageTitle.jsx';\nimport DocumentTitle from '@/ui/navigation/DocumentTitle.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.CalcitaDetailHeader)\nconst THEME_NAME = 'CalcitaDetailHeader';\nconst DetailRoot = piecePart(THEME_NAME, 'Root', Box);\nconst DetailTitleArea = piecePart(THEME_NAME, 'TitleArea', Box);\nconst DetailTitle = piecePart(THEME_NAME, 'Title', Typography);\nconst DetailBadges = piecePart(THEME_NAME, 'Badges', Stack);\nconst DetailActions = piecePart(THEME_NAME, 'Actions', Stack);\n\n/**\n * @param {object} props\n * @param {string} props.title texto ya traducido\n * @param {string} [props.eyebrow] contexto arriba del título (p. ej. el producto)\n * @param {import('react').ReactNode} [props.badges] insignias junto al título (chips de estatus, intento...)\n * @param {import('react').ReactNode} [props.actions] botones a la derecha\n * @param {string} [props.documentTitle] título de la pestaña si difiere del visible\n */\nexport default function DetailHeader(props) {\n // lo que el proyecto puso en su tema (components.CalcitaDetailHeader.defaultProps) y encima lo que llega aquí\n const {title, eyebrow, badges, actions, documentTitle, ...unknownProps} = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n const titleRef = useRef(null);\n useRegisterPageTitle(title, titleRef);\n return (\n <DetailRoot component=\"header\" ownSx={{display: 'flex', flexWrap: 'wrap', alignItems: 'flex-end', justifyContent: 'space-between', gap: 2, mb: 2.5}}>\n <DocumentTitle title={documentTitle ?? title} />\n <DetailTitleArea ownSx={{minWidth: 0}}>\n {/* el contexto se lee de un vistazo (en overline se veía\n muy chico); text.secondary y no text.disabled: se lee (WCAG no lo exime) */}\n {eyebrow && <DetailTitle variant=\"subtitle1\" color=\"text.secondary\" component=\"p\" ownSx={{fontWeight: 700}}>{eyebrow}</DetailTitle>}\n <DetailBadges direction=\"row\" spacing={1.5} useFlexGap ownSx={{alignItems: 'center', flexWrap: 'wrap'}}>\n <Typography ref={titleRef} variant=\"h5\" component=\"h1\">{title}</Typography>\n {badges}\n </DetailBadges>\n </DetailTitleArea>\n {actions && <DetailActions direction=\"row\" spacing={1} useFlexGap ownSx={{flexWrap: 'wrap'}}>{actions}</DetailActions>}\n </DetailRoot>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;AAuBA,MAAM,aAAa;AACnB,MAAM,aAAa,UAAU,YAAY,QAAQ,GAAG;AACpD,MAAM,kBAAkB,UAAU,YAAY,aAAa,GAAG;AAC9D,MAAM,cAAc,UAAU,YAAY,SAAS,UAAU;AAC7D,MAAM,eAAe,UAAU,YAAY,UAAU,KAAK;AAC1D,MAAM,gBAAgB,UAAU,YAAY,WAAW,KAAK;AAU5D,SAAwB,aAAa,OAAO;AAExC,QAAM,EAAC,OAAO,SAAS,QAAQ,SAAS,eAAe,GAAG,aAAA,IAAgB,cAAc,OAAO,UAAU;AACzG,mBAAiB,YAAY,YAAY;AACzC,QAAM,WAAW,OAAO,IAAI;AAC5B,uBAAqB,OAAO,QAAQ;AACpC,8BACK,YAAA,EAAW,WAAU,UAAS,OAAO,EAAC,SAAS,QAAQ,UAAU,QAAQ,YAAY,YAAY,gBAAgB,iBAAiB,KAAK,GAAG,IAAI,OAC3I,UAAA;AAAA,IAAA,oBAAC,eAAA,EAAc,OAAO,iBAAiB,MAAA,CAAO;AAAA,yBAC7C,iBAAA,EAAgB,OAAO,EAAC,UAAU,KAG9B,UAAA;AAAA,MAAA,WAAW,oBAAC,aAAA,EAAY,SAAQ,aAAY,OAAM,kBAAiB,WAAU,KAAI,OAAO,EAAC,YAAY,IAAA,GAAO,UAAA,SAAQ;AAAA,MACrH,qBAAC,cAAA,EAAa,WAAU,OAAM,SAAS,KAAK,YAAU,MAAC,OAAO,EAAC,YAAY,UAAU,UAAU,UAC3F,UAAA;AAAA,QAAA,oBAAC,cAAW,KAAK,UAAU,SAAQ,MAAK,WAAU,MAAM,UAAA,MAAA,CAAM;AAAA,QAC7D;AAAA,MAAA,EAAA,CACL;AAAA,IAAA,GACJ;AAAA,IACC,WAAW,oBAAC,eAAA,EAAc,WAAU,OAAM,SAAS,GAAG,YAAU,MAAC,OAAO,EAAC,UAAU,OAAA,GAAU,UAAA,QAAA,CAAQ;AAAA,EAAA,GAC1G;AAER;"}
@@ -10,6 +10,7 @@ import LockOutlinedIcon from "@mui/icons-material/LockOutlined";
10
10
  import SystemUpdateAltRoundedIcon from "@mui/icons-material/SystemUpdateAltRounded";
11
11
  import TravelExploreOutlinedIcon from "@mui/icons-material/TravelExploreOutlined";
12
12
  import { piecePart, usePieceProps } from "../../theme/themePieces.js";
13
+ import { warnUnknownProps } from "../../toolkit/unknownProps.js";
13
14
  const THEME_NAME = "CalcitaErrorPage";
14
15
  const ErrorRoot = piecePart(THEME_NAME, "Root", Stack);
15
16
  const ErrorActions = piecePart(THEME_NAME, "Actions", Stack);
@@ -34,8 +35,10 @@ function ErrorPage(props) {
34
35
  actions,
35
36
  icon,
36
37
  children,
37
- texts
38
+ texts,
39
+ ...unknownProps
38
40
  } = usePieceProps(props, THEME_NAME);
41
+ warnUnknownProps(THEME_NAME, unknownProps);
39
42
  const { t } = useToolkitTranslation("errorPage", texts);
40
43
  const { Link } = useToolkitNavigation();
41
44
  const look = ERROR_PAGE_LOOK[kind] ?? ERROR_PAGE_LOOK[ERROR_PAGE_KIND.serverError];
@@ -1 +1 @@
1
- {"version":3,"file":"ErrorPage.js","sources":["../../../src/ui/layout/ErrorPage.jsx"],"sourcesContent":["// La pantalla de un error de navegación: la página no existe (404), no tiene permiso (403) o algo falló (500). Dice en\n// palabras normales qué pasó y qué hacer, con el número chico abajo como referencia técnica, y el botón para salir de ahí.\n//\n// <ErrorPage kind={ERROR_PAGE_KIND.notFound} /> el 404 del router (ruta '*')\n// <ErrorPage kind={ERROR_PAGE_KIND.serverError} onRetry={reload} /> la pantalla tronó (errorElement del router)\n// <ErrorPage kind={ERROR_PAGE_KIND.newVersion} onRetry={reload} /> se publicó otra versión con la pestaña abierta\n//\n// Los textos salen del paquete (namespace errorPage) en el idioma activo; title y text los cambian para un caso propio, y\n// `texts` cualquier otro («Ir al inicio», «Intentar de nuevo»).\n//\n// Se extiende sin tocar el framework: botones suyos junto a los de la casa (extraActions: «Contactar a soporte») o en lugar\n// de ellos (actions), algo debajo del texto (children: el teléfono de soporte, un folio), otro ícono (icon) y el evento de\n// «Ir al inicio» (onGoHome). La de «sin permiso» de las rutas se cambia con withAccess(…, {fallback}) y la de error de ruta\n// pasándole estas mismas props a RouteErrorScreen (/react-router).\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaErrorPage con defaultProps y\n// styleOverrides de sus partes: root, actions.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport {useToolkitNavigation} from '@/toolkit/toolkitContext.js';\nimport Button from '@mui/material/Button';\nimport Stack from '@mui/material/Stack';\nimport Typography from '@mui/material/Typography';\nimport ErrorOutlineOutlinedIcon from '@mui/icons-material/ErrorOutlineOutlined';\nimport LockOutlinedIcon from '@mui/icons-material/LockOutlined';\nimport SystemUpdateAltRoundedIcon from '@mui/icons-material/SystemUpdateAltRounded';\nimport TravelExploreOutlinedIcon from '@mui/icons-material/TravelExploreOutlined';\nimport {piecePart, usePieceProps} from '@/theme/themePieces.js';\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaErrorPage)\nconst THEME_NAME = 'CalcitaErrorPage';\nconst ErrorRoot = piecePart(THEME_NAME, 'Root', Stack);\nconst ErrorActions = piecePart(THEME_NAME, 'Actions', Stack);\n\n/** Los errores que tiene pantalla propia. */\nexport const ERROR_PAGE_KIND = Object.freeze({notFound: 'notFound', forbidden: 'forbidden', serverError: 'serverError', newVersion: 'newVersion'});\n\n// el ícono, el color y el código HTTP de cada uno (el código va chico: es la referencia técnica, no el mensaje)\nconst ERROR_PAGE_LOOK = Object.freeze({\n [ERROR_PAGE_KIND.notFound]: {Icon: TravelExploreOutlinedIcon, color: 'info', httpStatus: 404},\n [ERROR_PAGE_KIND.forbidden]: {Icon: LockOutlinedIcon, color: 'warning', httpStatus: 403},\n [ERROR_PAGE_KIND.serverError]: {Icon: ErrorOutlineOutlinedIcon, color: 'error', httpStatus: 500},\n // no es un error de nadie: se publicó otra versión; sin código, y el botón dice «Recargar»\n [ERROR_PAGE_KIND.newVersion]: {Icon: SystemUpdateAltRoundedIcon, color: 'info', httpStatus: null, retryKey: 'reload'},\n});\nconst ICON_PIXELS = 56;\n\n/**\n * @param {object} props\n * @param {string} props.kind uno de ERROR_PAGE_KIND\n * @param {string} [props.title] ya traducido; por omisión el del paquete\n * @param {import('react').ReactNode} [props.text] ya traducido; por omisión el del paquete\n * @param {string} [props.homePath] a dónde lleva «Ir al inicio» (por omisión '/')\n * @param {() => void} [props.onRetry] con él sale «Intentar de nuevo»\n * @param {() => void} [props.onGoHome] al picar «Ir al inicio», antes de ir (para avisar o limpiar algo)\n * @param {import('react').ReactNode} [props.extraActions] botones suyos junto a los de la casa\n * @param {import('react').ReactNode} [props.actions] botones suyos EN LUGAR de los de la casa\n * @param {import('react').ReactNode} [props.icon] otro ícono; por omisión el de cada error\n * @param {import('react').ReactNode} [props.children] algo debajo del texto (el teléfono de soporte, un folio)\n * @param {object} [props.texts] los textos que cambian, con la forma de `errorPage` en los textos del paquete:\n * {goHome: 'Volver al tablero', notFound: {title: '…'}}\n */\nexport default function ErrorPage(props) {\n // lo que el proyecto puso en su tema (components.CalcitaErrorPage.defaultProps) y encima lo que llega aquí\n const {\n kind, title, text, homePath = '/', onRetry, onGoHome, extraActions, actions, icon, children, texts,\n} = usePieceProps(props, THEME_NAME);\n const {t} = useToolkitTranslation('errorPage', texts);\n const {Link} = useToolkitNavigation();\n const look = ERROR_PAGE_LOOK[kind] ?? ERROR_PAGE_LOOK[ERROR_PAGE_KIND.serverError];\n\n return (\n <ErrorRoot spacing={2} ownSx={{alignItems: 'center', textAlign: 'center', py: {xs: 6, md: 10}, px: 2, maxWidth: 560, mx: 'auto'}}>\n {icon ?? <look.Icon color={look.color} sx={{fontSize: ICON_PIXELS}} />}\n <Typography variant=\"h4\" component=\"h1\">{title ?? t(`${kind}.title`)}</Typography>\n <Typography variant=\"body1\" color=\"text.secondary\">{text ?? t(`${kind}.text`)}</Typography>\n {children}\n <ErrorActions direction={{xs: 'column', sm: 'row'}} spacing={1.5} useFlexGap ownSx={{pt: 1, flexWrap: 'wrap', justifyContent: 'center'}}>\n {actions ?? (\n <>\n {onRetry && <Button variant=\"contained\" onClick={onRetry}>{t(look.retryKey ?? 'retry')}</Button>}\n <Button variant={onRetry ? 'outlined' : 'contained'} component={Link} to={homePath} onClick={onGoHome}>{t('goHome')}</Button>\n {extraActions}\n </>\n )}\n </ErrorActions>\n {look.httpStatus && <Typography variant=\"caption\" color=\"text.disabled\">{look.httpStatus}</Typography>}\n </ErrorRoot>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;;;AA+BA,MAAM,aAAa;AACnB,MAAM,YAAY,UAAU,YAAY,QAAQ,KAAK;AACrD,MAAM,eAAe,UAAU,YAAY,WAAW,KAAK;AAGpD,MAAM,kBAAkB,OAAO,OAAO,EAAC,UAAU,YAAY,WAAW,aAAa,aAAa,eAAe,YAAY,aAAA,CAAa;AAGjJ,MAAM,kBAAkB,OAAO,OAAO;AAAA,EAClC,CAAC,gBAAgB,QAAQ,GAAG,EAAC,MAAM,2BAA2B,OAAO,QAAQ,YAAY,IAAA;AAAA,EACzF,CAAC,gBAAgB,SAAS,GAAG,EAAC,MAAM,kBAAkB,OAAO,WAAW,YAAY,IAAA;AAAA,EACpF,CAAC,gBAAgB,WAAW,GAAG,EAAC,MAAM,0BAA0B,OAAO,SAAS,YAAY,IAAA;AAAA;AAAA,EAE5F,CAAC,gBAAgB,UAAU,GAAG,EAAC,MAAM,4BAA4B,OAAO,QAAQ,YAAY,MAAM,UAAU,SAAA;AAChH,CAAC;AACD,MAAM,cAAc;AAiBpB,SAAwB,UAAU,OAAO;AAErC,QAAM;AAAA,IACN;AAAA,IAAM;AAAA,IAAO;AAAA,IAAM,WAAW;AAAA,IAAK;AAAA,IAAS;AAAA,IAAU;AAAA,IAAc;AAAA,IAAS;AAAA,IAAM;AAAA,IAAU;AAAA,EAAA,IAC7F,cAAc,OAAO,UAAU;AAC/B,QAAM,EAAC,EAAA,IAAK,sBAAsB,aAAa,KAAK;AACpD,QAAM,EAAC,KAAA,IAAQ,qBAAA;AACf,QAAM,OAAO,gBAAgB,IAAI,KAAK,gBAAgB,gBAAgB,WAAW;AAEjF,SACI,qBAAC,aAAU,SAAS,GAAG,OAAO,EAAC,YAAY,UAAU,WAAW,UAAU,IAAI,EAAC,IAAI,GAAG,IAAI,GAAA,GAAK,IAAI,GAAG,UAAU,KAAK,IAAI,OAAA,GACpH,UAAA;AAAA,IAAA,QAAQ,oBAAC,KAAK,MAAL,EAAU,OAAO,KAAK,OAAO,IAAI,EAAC,UAAU,YAAA,EAAW,CAAG;AAAA,IACpE,oBAAC,YAAA,EAAW,SAAQ,MAAK,WAAU,MAAM,UAAA,SAAS,EAAE,GAAG,IAAI,QAAQ,EAAA,CAAE;AAAA,IACrE,oBAAC,YAAA,EAAW,SAAQ,SAAQ,OAAM,kBAAkB,UAAA,QAAQ,EAAE,GAAG,IAAI,OAAO,EAAA,CAAE;AAAA,IAC7E;AAAA,IACD,oBAAC,gBAAa,WAAW,EAAC,IAAI,UAAU,IAAI,MAAA,GAAQ,SAAS,KAAK,YAAU,MAAC,OAAO,EAAC,IAAI,GAAG,UAAU,QAAQ,gBAAgB,YACzH,UAAA,WACG,qBAAA,UAAA,EACK,UAAA;AAAA,MAAA,WAAW,oBAAC,QAAA,EAAO,SAAQ,aAAY,SAAS,SAAU,UAAA,EAAE,KAAK,YAAY,OAAO,EAAA,CAAE;AAAA,MACvF,oBAAC,QAAA,EAAO,SAAS,UAAU,aAAa,aAAa,WAAW,MAAM,IAAI,UAAU,SAAS,UAAW,UAAA,EAAE,QAAQ,GAAE;AAAA,MACnH;AAAA,IAAA,EAAA,CACL,EAAA,CAER;AAAA,IACC,KAAK,cAAc,oBAAC,YAAA,EAAW,SAAQ,WAAU,OAAM,iBAAiB,UAAA,KAAK,WAAA,CAAW;AAAA,EAAA,GAC7F;AAER;"}
1
+ {"version":3,"file":"ErrorPage.js","sources":["../../../src/ui/layout/ErrorPage.jsx"],"sourcesContent":["// La pantalla de un error de navegación: la página no existe (404), no tiene permiso (403) o algo falló (500). Dice en\n// palabras normales qué pasó y qué hacer, con el número chico abajo como referencia técnica, y el botón para salir de ahí.\n//\n// <ErrorPage kind={ERROR_PAGE_KIND.notFound} /> el 404 del router (ruta '*')\n// <ErrorPage kind={ERROR_PAGE_KIND.serverError} onRetry={reload} /> la pantalla tronó (errorElement del router)\n// <ErrorPage kind={ERROR_PAGE_KIND.newVersion} onRetry={reload} /> se publicó otra versión con la pestaña abierta\n//\n// Los textos salen del paquete (namespace errorPage) en el idioma activo; title y text los cambian para un caso propio, y\n// `texts` cualquier otro («Ir al inicio», «Intentar de nuevo»).\n//\n// Se extiende sin tocar el framework: botones suyos junto a los de la casa (extraActions: «Contactar a soporte») o en lugar\n// de ellos (actions), algo debajo del texto (children: el teléfono de soporte, un folio), otro ícono (icon) y el evento de\n// «Ir al inicio» (onGoHome). La de «sin permiso» de las rutas se cambia con withAccess(…, {fallback}) y la de error de ruta\n// pasándole estas mismas props a RouteErrorScreen (/react-router).\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaErrorPage con defaultProps y\n// styleOverrides de sus partes: root, actions.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport {useToolkitNavigation} from '@/toolkit/toolkitContext.js';\nimport Button from '@mui/material/Button';\nimport Stack from '@mui/material/Stack';\nimport Typography from '@mui/material/Typography';\nimport ErrorOutlineOutlinedIcon from '@mui/icons-material/ErrorOutlineOutlined';\nimport LockOutlinedIcon from '@mui/icons-material/LockOutlined';\nimport SystemUpdateAltRoundedIcon from '@mui/icons-material/SystemUpdateAltRounded';\nimport TravelExploreOutlinedIcon from '@mui/icons-material/TravelExploreOutlined';\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.CalcitaErrorPage)\nconst THEME_NAME = 'CalcitaErrorPage';\nconst ErrorRoot = piecePart(THEME_NAME, 'Root', Stack);\nconst ErrorActions = piecePart(THEME_NAME, 'Actions', Stack);\n\n/** Los errores que tiene pantalla propia. */\nexport const ERROR_PAGE_KIND = Object.freeze({notFound: 'notFound', forbidden: 'forbidden', serverError: 'serverError', newVersion: 'newVersion'});\n\n// el ícono, el color y el código HTTP de cada uno (el código va chico: es la referencia técnica, no el mensaje)\nconst ERROR_PAGE_LOOK = Object.freeze({\n [ERROR_PAGE_KIND.notFound]: {Icon: TravelExploreOutlinedIcon, color: 'info', httpStatus: 404},\n [ERROR_PAGE_KIND.forbidden]: {Icon: LockOutlinedIcon, color: 'warning', httpStatus: 403},\n [ERROR_PAGE_KIND.serverError]: {Icon: ErrorOutlineOutlinedIcon, color: 'error', httpStatus: 500},\n // no es un error de nadie: se publicó otra versión; sin código, y el botón dice «Recargar»\n [ERROR_PAGE_KIND.newVersion]: {Icon: SystemUpdateAltRoundedIcon, color: 'info', httpStatus: null, retryKey: 'reload'},\n});\nconst ICON_PIXELS = 56;\n\n/**\n * @param {object} props\n * @param {string} props.kind uno de ERROR_PAGE_KIND\n * @param {string} [props.title] ya traducido; por omisión el del paquete\n * @param {import('react').ReactNode} [props.text] ya traducido; por omisión el del paquete\n * @param {string} [props.homePath] a dónde lleva «Ir al inicio» (por omisión '/')\n * @param {() => void} [props.onRetry] con él sale «Intentar de nuevo»\n * @param {() => void} [props.onGoHome] al picar «Ir al inicio», antes de ir (para avisar o limpiar algo)\n * @param {import('react').ReactNode} [props.extraActions] botones suyos junto a los de la casa\n * @param {import('react').ReactNode} [props.actions] botones suyos EN LUGAR de los de la casa\n * @param {import('react').ReactNode} [props.icon] otro ícono; por omisión el de cada error\n * @param {import('react').ReactNode} [props.children] algo debajo del texto (el teléfono de soporte, un folio)\n * @param {object} [props.texts] los textos que cambian, con la forma de `errorPage` en los textos del paquete:\n * {goHome: 'Volver al tablero', notFound: {title: '…'}}\n */\nexport default function ErrorPage(props) {\n // lo que el proyecto puso en su tema (components.CalcitaErrorPage.defaultProps) y encima lo que llega aquí\n const {\n kind, title, text, homePath = '/', onRetry, onGoHome, extraActions, actions, icon, children, texts,\n ...unknownProps\n} = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n const {t} = useToolkitTranslation('errorPage', texts);\n const {Link} = useToolkitNavigation();\n const look = ERROR_PAGE_LOOK[kind] ?? ERROR_PAGE_LOOK[ERROR_PAGE_KIND.serverError];\n\n return (\n <ErrorRoot spacing={2} ownSx={{alignItems: 'center', textAlign: 'center', py: {xs: 6, md: 10}, px: 2, maxWidth: 560, mx: 'auto'}}>\n {icon ?? <look.Icon color={look.color} sx={{fontSize: ICON_PIXELS}} />}\n <Typography variant=\"h4\" component=\"h1\">{title ?? t(`${kind}.title`)}</Typography>\n <Typography variant=\"body1\" color=\"text.secondary\">{text ?? t(`${kind}.text`)}</Typography>\n {children}\n <ErrorActions direction={{xs: 'column', sm: 'row'}} spacing={1.5} useFlexGap ownSx={{pt: 1, flexWrap: 'wrap', justifyContent: 'center'}}>\n {actions ?? (\n <>\n {onRetry && <Button variant=\"contained\" onClick={onRetry}>{t(look.retryKey ?? 'retry')}</Button>}\n <Button variant={onRetry ? 'outlined' : 'contained'} component={Link} to={homePath} onClick={onGoHome}>{t('goHome')}</Button>\n {extraActions}\n </>\n )}\n </ErrorActions>\n {look.httpStatus && <Typography variant=\"caption\" color=\"text.disabled\">{look.httpStatus}</Typography>}\n </ErrorRoot>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;AAgCA,MAAM,aAAa;AACnB,MAAM,YAAY,UAAU,YAAY,QAAQ,KAAK;AACrD,MAAM,eAAe,UAAU,YAAY,WAAW,KAAK;AAGpD,MAAM,kBAAkB,OAAO,OAAO,EAAC,UAAU,YAAY,WAAW,aAAa,aAAa,eAAe,YAAY,aAAA,CAAa;AAGjJ,MAAM,kBAAkB,OAAO,OAAO;AAAA,EAClC,CAAC,gBAAgB,QAAQ,GAAG,EAAC,MAAM,2BAA2B,OAAO,QAAQ,YAAY,IAAA;AAAA,EACzF,CAAC,gBAAgB,SAAS,GAAG,EAAC,MAAM,kBAAkB,OAAO,WAAW,YAAY,IAAA;AAAA,EACpF,CAAC,gBAAgB,WAAW,GAAG,EAAC,MAAM,0BAA0B,OAAO,SAAS,YAAY,IAAA;AAAA;AAAA,EAE5F,CAAC,gBAAgB,UAAU,GAAG,EAAC,MAAM,4BAA4B,OAAO,QAAQ,YAAY,MAAM,UAAU,SAAA;AAChH,CAAC;AACD,MAAM,cAAc;AAiBpB,SAAwB,UAAU,OAAO;AAErC,QAAM;AAAA,IACN;AAAA,IAAM;AAAA,IAAO;AAAA,IAAM,WAAW;AAAA,IAAK;AAAA,IAAS;AAAA,IAAU;AAAA,IAAc;AAAA,IAAS;AAAA,IAAM;AAAA,IAAU;AAAA,IAC7F,GAAG;AAAA,EAAA,IACH,cAAc,OAAO,UAAU;AAC/B,mBAAiB,YAAY,YAAY;AACzC,QAAM,EAAC,EAAA,IAAK,sBAAsB,aAAa,KAAK;AACpD,QAAM,EAAC,KAAA,IAAQ,qBAAA;AACf,QAAM,OAAO,gBAAgB,IAAI,KAAK,gBAAgB,gBAAgB,WAAW;AAEjF,SACI,qBAAC,aAAU,SAAS,GAAG,OAAO,EAAC,YAAY,UAAU,WAAW,UAAU,IAAI,EAAC,IAAI,GAAG,IAAI,GAAA,GAAK,IAAI,GAAG,UAAU,KAAK,IAAI,OAAA,GACpH,UAAA;AAAA,IAAA,QAAQ,oBAAC,KAAK,MAAL,EAAU,OAAO,KAAK,OAAO,IAAI,EAAC,UAAU,YAAA,EAAW,CAAG;AAAA,IACpE,oBAAC,YAAA,EAAW,SAAQ,MAAK,WAAU,MAAM,UAAA,SAAS,EAAE,GAAG,IAAI,QAAQ,EAAA,CAAE;AAAA,IACrE,oBAAC,YAAA,EAAW,SAAQ,SAAQ,OAAM,kBAAkB,UAAA,QAAQ,EAAE,GAAG,IAAI,OAAO,EAAA,CAAE;AAAA,IAC7E;AAAA,IACD,oBAAC,gBAAa,WAAW,EAAC,IAAI,UAAU,IAAI,MAAA,GAAQ,SAAS,KAAK,YAAU,MAAC,OAAO,EAAC,IAAI,GAAG,UAAU,QAAQ,gBAAgB,YACzH,UAAA,WACG,qBAAA,UAAA,EACK,UAAA;AAAA,MAAA,WAAW,oBAAC,QAAA,EAAO,SAAQ,aAAY,SAAS,SAAU,UAAA,EAAE,KAAK,YAAY,OAAO,EAAA,CAAE;AAAA,MACvF,oBAAC,QAAA,EAAO,SAAS,UAAU,aAAa,aAAa,WAAW,MAAM,IAAI,UAAU,SAAS,UAAW,UAAA,EAAE,QAAQ,GAAE;AAAA,MACnH;AAAA,IAAA,EAAA,CACL,EAAA,CAER;AAAA,IACC,KAAK,cAAc,oBAAC,YAAA,EAAW,SAAQ,WAAU,OAAM,iBAAiB,UAAA,KAAK,WAAA,CAAW;AAAA,EAAA,GAC7F;AAER;"}
@@ -4,9 +4,11 @@ import { useToolkitTranslation } from "../../toolkit/useToolkitTranslation.js";
4
4
  import Box from "@mui/material/Box";
5
5
  import CircularProgress from "@mui/material/CircularProgress";
6
6
  import { piecePart } from "../../theme/themePieces.js";
7
+ import { warnUnknownProps } from "../../toolkit/unknownProps.js";
7
8
  const THEME_NAME = "CalcitaFullPageLoader";
8
9
  const LoaderRoot = piecePart(THEME_NAME, "Root", Box);
9
- function FullPageLoader({ texts } = {}) {
10
+ function FullPageLoader({ texts, ...unknownProps } = {}) {
11
+ warnUnknownProps("FullPageLoader", unknownProps);
10
12
  const { t } = useToolkitTranslation("common", texts);
11
13
  return /* @__PURE__ */ jsx(LoaderRoot, { role: "status", "aria-live": "polite", ownSx: { display: "grid", placeItems: "center", minHeight: "100vh", bgcolor: "background.default" }, children: /* @__PURE__ */ jsx(CircularProgress, { "aria-label": t("status.loading") }) });
12
14
  }
@@ -1 +1 @@
1
- {"version":3,"file":"FullPageLoader.js","sources":["../../../src/ui/layout/FullPageLoader.jsx"],"sourcesContent":["// Indicador de carga a pantalla completa, mientras se sabe si hay sesión.\n// Sin él, el formulario de login parpadea medio segundo antes de que aparezca la pantalla de quien ya entró.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaFullPageLoader con defaultProps y\n// styleOverrides de sus partes: root.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport Box from '@mui/material/Box';\nimport CircularProgress from '@mui/material/CircularProgress';\nimport {piecePart} from '@/theme/themePieces.js';\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaFullPageLoader)\nconst THEME_NAME = 'CalcitaFullPageLoader';\nconst LoaderRoot = piecePart(THEME_NAME, 'Root', Box);\n\n/**\n * @param {object} [props]\n * @param {object} [props.texts] los textos que cambian, con la forma de `common` en los textos del paquete\n */\nexport default function FullPageLoader({texts} = {}) {\n const {t} = useToolkitTranslation('common', texts);\n\n return (\n <LoaderRoot role=\"status\" aria-live=\"polite\" ownSx={{display: 'grid', placeItems: 'center', minHeight: '100vh', bgcolor: 'background.default'}}>\n <CircularProgress aria-label={t('status.loading')} />\n </LoaderRoot>\n );\n}\n"],"names":[],"mappings":";;;;;;AAaA,MAAM,aAAa;AACnB,MAAM,aAAa,UAAU,YAAY,QAAQ,GAAG;AAMpD,SAAwB,eAAe,EAAC,MAAA,IAAS,IAAI;AACjD,QAAM,EAAC,EAAA,IAAK,sBAAsB,UAAU,KAAK;AAEjD,SACI,oBAAC,cAAW,MAAK,UAAS,aAAU,UAAS,OAAO,EAAC,SAAS,QAAQ,YAAY,UAAU,WAAW,SAAS,SAAS,qBAAA,GACrH,UAAA,oBAAC,oBAAiB,cAAY,EAAE,gBAAgB,EAAA,CAAG,EAAA,CACvD;AAER;"}
1
+ {"version":3,"file":"FullPageLoader.js","sources":["../../../src/ui/layout/FullPageLoader.jsx"],"sourcesContent":["// Indicador de carga a pantalla completa, mientras se sabe si hay sesión.\n// Sin él, el formulario de login parpadea medio segundo antes de que aparezca la pantalla de quien ya entró.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaFullPageLoader con defaultProps y\n// styleOverrides de sus partes: root.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport Box from '@mui/material/Box';\nimport CircularProgress from '@mui/material/CircularProgress';\nimport {piecePart} 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.CalcitaFullPageLoader)\nconst THEME_NAME = 'CalcitaFullPageLoader';\nconst LoaderRoot = piecePart(THEME_NAME, 'Root', Box);\n\n/**\n * @param {object} [props]\n * @param {object} [props.texts] los textos que cambian, con la forma de `common` en los textos del paquete\n */\nexport default function FullPageLoader({texts, ...unknownProps} = {}) {\n warnUnknownProps('FullPageLoader', unknownProps);\n const {t} = useToolkitTranslation('common', texts);\n\n return (\n <LoaderRoot role=\"status\" aria-live=\"polite\" ownSx={{display: 'grid', placeItems: 'center', minHeight: '100vh', bgcolor: 'background.default'}}>\n <CircularProgress aria-label={t('status.loading')} />\n </LoaderRoot>\n );\n}\n"],"names":[],"mappings":";;;;;;;AAcA,MAAM,aAAa;AACnB,MAAM,aAAa,UAAU,YAAY,QAAQ,GAAG;AAMpD,SAAwB,eAAe,EAAC,OAAO,GAAG,aAAA,IAAgB,CAAA,GAAI;AAClE,mBAAiB,kBAAkB,YAAY;AAC/C,QAAM,EAAC,EAAA,IAAK,sBAAsB,UAAU,KAAK;AAEjD,SACI,oBAAC,cAAW,MAAK,UAAS,aAAU,UAAS,OAAO,EAAC,SAAS,QAAQ,YAAY,UAAU,WAAW,SAAS,SAAS,qBAAA,GACrH,UAAA,oBAAC,oBAAiB,cAAY,EAAE,gBAAgB,EAAA,CAAG,EAAA,CACvD;AAER;"}