@stackcraftmx/calcita 0.31.0 → 0.32.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (278) 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/WizardLayout.js +4 -1
  138. package/dist/inputs/WizardLayout.js.map +1 -1
  139. package/dist/kanban/KanbanBoard.js +4 -1
  140. package/dist/kanban/KanbanBoard.js.map +1 -1
  141. package/dist/maps/MapView.js +4 -1
  142. package/dist/maps/MapView.js.map +1 -1
  143. package/dist/pwa/InstallAppSetting.js +3 -1
  144. package/dist/pwa/InstallAppSetting.js.map +1 -1
  145. package/dist/pwa/InstallInstructionsDialog.js +3 -1
  146. package/dist/pwa/InstallInstructionsDialog.js.map +1 -1
  147. package/dist/pwa/InstallPromptBanner.js +3 -1
  148. package/dist/pwa/InstallPromptBanner.js.map +1 -1
  149. package/dist/security/ActivityLog.js +3 -1
  150. package/dist/security/ActivityLog.js.map +1 -1
  151. package/dist/security/RecoveryCodesDialog.js +3 -1
  152. package/dist/security/RecoveryCodesDialog.js.map +1 -1
  153. package/dist/security/SessionsCard.js +3 -1
  154. package/dist/security/SessionsCard.js.map +1 -1
  155. package/dist/theme/createToolkitTheme.js +4 -1
  156. package/dist/theme/createToolkitTheme.js.map +1 -1
  157. package/dist/toolkit/ComponentTexts.js +3 -1
  158. package/dist/toolkit/ComponentTexts.js.map +1 -1
  159. package/dist/toolkit/ToolkitProvider.js +24 -3
  160. package/dist/toolkit/ToolkitProvider.js.map +1 -1
  161. package/dist/toolkit/toolkitContext.js.map +1 -1
  162. package/dist/toolkit/toolkitSettings.js +9 -0
  163. package/dist/toolkit/toolkitSettings.js.map +1 -1
  164. package/dist/toolkit/unknownProps.js +33 -0
  165. package/dist/toolkit/unknownProps.js.map +1 -0
  166. package/dist/types/DataTable/AuditTrailTable.d.ts +1 -1
  167. package/dist/types/DataTable/ColumnFilters/TextColumnFilter.d.ts +1 -1
  168. package/dist/types/DataTable/columns.d.ts +3 -1
  169. package/dist/types/access/Can.d.ts +1 -1
  170. package/dist/types/access/RequireAccess.d.ts +1 -1
  171. package/dist/types/account/AccountProvider.d.ts +1 -1
  172. package/dist/types/account/ForgotPasswordScreen.d.ts +1 -1
  173. package/dist/types/account/ResetPasswordScreen.d.ts +1 -1
  174. package/dist/types/appShell/MenuLinks.d.ts +1 -1
  175. package/dist/types/appShell/pageTitle.d.ts +1 -1
  176. package/dist/types/datePickers/DateInput.d.ts +1 -1
  177. package/dist/types/downloads/DownloadManager.d.ts +1 -1
  178. package/dist/types/formatting.d.ts +2 -1
  179. package/dist/types/forms/FormProblemAlert.d.ts +1 -1
  180. package/dist/types/forms/FormServerProblem.d.ts +1 -1
  181. package/dist/types/forms/FormWizard.d.ts +1 -1
  182. package/dist/types/forms/auth/ChangePasswordForm.d.ts +1 -1
  183. package/dist/types/forms/auth/ForgotPasswordForm.d.ts +1 -1
  184. package/dist/types/hookForm/FormProblemAlert.d.ts +1 -1
  185. package/dist/types/hookForm/FormWizard.d.ts +1 -1
  186. package/dist/types/index.d.ts +1 -1
  187. package/dist/types/inputs/CatalogInput.d.ts +1 -1
  188. package/dist/types/inputs/FieldFrame.d.ts +1 -1
  189. package/dist/types/inputs/NumberInput.d.ts +1 -1
  190. package/dist/types/pwa/InstallAppSetting.d.ts +1 -1
  191. package/dist/types/theme/createToolkitTheme.d.ts +1 -1
  192. package/dist/types/toolkit/ComponentTexts.d.ts +1 -1
  193. package/dist/types/toolkit/ToolkitProvider.d.ts +4 -1
  194. package/dist/types/toolkit/toolkitContext.d.ts +2 -1
  195. package/dist/types/toolkit/toolkitSettings.d.ts +13 -2
  196. package/dist/types/toolkit/unknownProps.d.ts +23 -0
  197. package/dist/types/ui/actions/CopyButton.d.ts +1 -1
  198. package/dist/types/ui/actions/SecretField.d.ts +1 -1
  199. package/dist/types/ui/labels/DictionaryText.d.ts +1 -1
  200. package/dist/types/ui/layout/FullPageLoader.d.ts +1 -1
  201. package/dist/types/ui/metrics/CalendarHeatmap.d.ts +9 -8
  202. package/dist/types/ui/metrics/chartParts.d.ts +3 -3
  203. package/dist/types/ui/metrics/heatmapScale.d.ts +23 -0
  204. package/dist/types/ui/navigation/DocumentTitle.d.ts +1 -1
  205. package/dist/ui/actions/ActionsMenu.js +3 -1
  206. package/dist/ui/actions/ActionsMenu.js.map +1 -1
  207. package/dist/ui/actions/CopyButton.js +3 -1
  208. package/dist/ui/actions/CopyButton.js.map +1 -1
  209. package/dist/ui/actions/DownloadMenu.js +4 -1
  210. package/dist/ui/actions/DownloadMenu.js.map +1 -1
  211. package/dist/ui/actions/SecretField.js +3 -1
  212. package/dist/ui/actions/SecretField.js.map +1 -1
  213. package/dist/ui/actions/SelectionActions.js +3 -1
  214. package/dist/ui/actions/SelectionActions.js.map +1 -1
  215. package/dist/ui/filters/DateRangeFilter.js +3 -1
  216. package/dist/ui/filters/DateRangeFilter.js.map +1 -1
  217. package/dist/ui/filters/PeriodRangeSelector.js +3 -1
  218. package/dist/ui/filters/PeriodRangeSelector.js.map +1 -1
  219. package/dist/ui/filters/QuickFilters.js +3 -1
  220. package/dist/ui/filters/QuickFilters.js.map +1 -1
  221. package/dist/ui/filters/SegmentedControl.js +3 -1
  222. package/dist/ui/filters/SegmentedControl.js.map +1 -1
  223. package/dist/ui/labels/DictionaryText.js +3 -1
  224. package/dist/ui/labels/DictionaryText.js.map +1 -1
  225. package/dist/ui/labels/StatusChip.js +3 -1
  226. package/dist/ui/labels/StatusChip.js.map +1 -1
  227. package/dist/ui/layout/CollapsibleSection.js +3 -1
  228. package/dist/ui/layout/CollapsibleSection.js.map +1 -1
  229. package/dist/ui/layout/ContentDialog.js +3 -1
  230. package/dist/ui/layout/ContentDialog.js.map +1 -1
  231. package/dist/ui/layout/DefinitionList.js +3 -1
  232. package/dist/ui/layout/DefinitionList.js.map +1 -1
  233. package/dist/ui/layout/DetailHeader.js +3 -1
  234. package/dist/ui/layout/DetailHeader.js.map +1 -1
  235. package/dist/ui/layout/ErrorPage.js +4 -1
  236. package/dist/ui/layout/ErrorPage.js.map +1 -1
  237. package/dist/ui/layout/FullPageLoader.js +3 -1
  238. package/dist/ui/layout/FullPageLoader.js.map +1 -1
  239. package/dist/ui/layout/PageHeader.js +3 -1
  240. package/dist/ui/layout/PageHeader.js.map +1 -1
  241. package/dist/ui/layout/PageHeading.js +3 -1
  242. package/dist/ui/layout/PageHeading.js.map +1 -1
  243. package/dist/ui/layout/ProfileHeader.js +3 -1
  244. package/dist/ui/layout/ProfileHeader.js.map +1 -1
  245. package/dist/ui/layout/SectionCard.js +3 -1
  246. package/dist/ui/layout/SectionCard.js.map +1 -1
  247. package/dist/ui/metrics/BarList.js +3 -1
  248. package/dist/ui/metrics/BarList.js.map +1 -1
  249. package/dist/ui/metrics/CalendarHeatmap.js +13 -4
  250. package/dist/ui/metrics/CalendarHeatmap.js.map +1 -1
  251. package/dist/ui/metrics/ChartTooltip.js.map +1 -1
  252. package/dist/ui/metrics/ColumnChart.js +4 -1
  253. package/dist/ui/metrics/ColumnChart.js.map +1 -1
  254. package/dist/ui/metrics/LineChart.js +4 -1
  255. package/dist/ui/metrics/LineChart.js.map +1 -1
  256. package/dist/ui/metrics/MetricCard.js +4 -1
  257. package/dist/ui/metrics/MetricCard.js.map +1 -1
  258. package/dist/ui/metrics/TableToggle.js +3 -1
  259. package/dist/ui/metrics/TableToggle.js.map +1 -1
  260. package/dist/ui/metrics/chartParts.js +7 -3
  261. package/dist/ui/metrics/chartParts.js.map +1 -1
  262. package/dist/ui/metrics/heatmapScale.js +15 -1
  263. package/dist/ui/metrics/heatmapScale.js.map +1 -1
  264. package/dist/ui/navigation/ColorSchemeToggle.js +3 -1
  265. package/dist/ui/navigation/ColorSchemeToggle.js.map +1 -1
  266. package/dist/ui/navigation/DocumentTitle.js +3 -1
  267. package/dist/ui/navigation/DocumentTitle.js.map +1 -1
  268. package/dist/ui/navigation/FontSizeToggle.js +3 -1
  269. package/dist/ui/navigation/FontSizeToggle.js.map +1 -1
  270. package/dist/ui/navigation/LanguageToggle.js +3 -1
  271. package/dist/ui/navigation/LanguageToggle.js.map +1 -1
  272. package/dist/ui/navigation/PageBreadcrumbs.js +3 -1
  273. package/dist/ui/navigation/PageBreadcrumbs.js.map +1 -1
  274. package/dist/ui/timeline/GroupedTimeline.js +3 -1
  275. package/dist/ui/timeline/GroupedTimeline.js.map +1 -1
  276. package/dist/upload/FileDropzone.js +4 -1
  277. package/dist/upload/FileDropzone.js.map +1 -1
  278. package/package.json +1 -1
package/README.md CHANGED
@@ -87,6 +87,7 @@ Sin nada más, todo sale en español, con la zona horaria del navegador, montos
87
87
  | `translate` | un traductor propio, por ejemplo i18next | ninguno |
88
88
  | `timeZone` | zona en que se pintan las horas | la del navegador |
89
89
  | `currency` | moneda de los montos (ISO 4217) | `MXN` |
90
+ | `hourCycle` | la hora de 24 horas («15:10») o de 12 con a.m. y p.m. («3:10 p.m.»): `HOUR_CYCLE.twentyFourHours` o `HOUR_CYCLE.twelveHours` | 24 horas |
90
91
  | `appName` | nombre en el título de la pestaña | ninguno |
91
92
  | `navigation` | el router: `{useNavigate, useLocation, Link}` | la del navegador |
92
93
  | `canAccess` | quién ve qué (menú, rutas, botones): la regla del proyecto, normalmente `createAccessChecker(...)` | solo lo que no tiene regla |
@@ -518,6 +519,12 @@ vocabulario):
518
519
  </ComponentTexts>
519
520
  ```
520
521
 
522
+ Una opción que la pieza no conoce no se pierde en silencio: mientras se programa, la consola avisa una vez por pieza y opción
523
+ (`Calcita · ServerTable no conoce la opción «countNoun» y no la usa…`). Sirve sobre todo al pasar pantallas de un sistema que
524
+ ya existe, donde las opciones traen otros nombres (`countNoun` es `countLabel`; el `label` de la columna de detalle es
525
+ `ariaLabelOf`). En producción no avisa: Vite y Next cambian `process.env.NODE_ENV` al construir la app, y una página sin
526
+ empaquetador se toma como producción.
527
+
521
528
  ## En un sistema que ya existe
522
529
 
523
530
  Calcita entra por pedazos en un sistema hecho en PHP, JSP o .NET, sin reescribirlo: cada pedazo es una «isla» de React en
@@ -4,6 +4,7 @@ import Typography from "@mui/material/Typography";
4
4
  import AuditTrailTable from "./AuditTrailTable.js";
5
5
  import ContentDialog from "../ui/layout/ContentDialog.js";
6
6
  import { piecePart, usePieceProps } from "../theme/themePieces.js";
7
+ import { warnUnknownProps } from "../toolkit/unknownProps.js";
7
8
  const THEME_NAME = "CalcitaAuditTrailDialog";
8
9
  const AuditDescription = piecePart(THEME_NAME, "Description", Typography);
9
10
  function AuditTrailDialog(props) {
@@ -18,8 +19,10 @@ function AuditTrailDialog(props) {
18
19
  resultDictionary,
19
20
  extraColumns = [],
20
21
  header = null,
21
- eventSuffixOf = null
22
+ eventSuffixOf = null,
23
+ ...unknownProps
22
24
  } = usePieceProps(props, THEME_NAME);
25
+ warnUnknownProps(THEME_NAME, unknownProps);
23
26
  return /* @__PURE__ */ jsxs(ContentDialog, { open, onClose, title, children: [
24
27
  subtitle && /* @__PURE__ */ jsx(AuditDescription, { variant: "body2", color: "text.secondary", ownSx: { mb: 2 }, children: subtitle }),
25
28
  header,
@@ -1 +1 @@
1
- {"version":3,"file":"AuditTrailDialog.js","sources":["../../src/DataTable/AuditTrailDialog.jsx"],"sourcesContent":["// Diálogo de auditoría de un renglón: su historia de eventos, paginada y filtrada EN EL SERVIDOR (AuditTrailTable).\n//\n// Sirve para el historial de cualquier registro (un pedido, una cuenta).\n// Solo abre una vista: no ejecuta nada y por eso no lleva confirmación.\n//\n// Se abre como diálogo de contenido (ContentDialog): sube desde abajo y ocupa la pantalla debajo de la barra superior. Una\n// tabla con su historia se lee mejor a todo lo ancho que en un recuadro al centro, también en el teléfono.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaAuditTrailDialog con defaultProps y\n// styleOverrides de sus partes: description.\n//\n// Genérico del paquete: function (regla de la casa).\nimport Typography from '@mui/material/Typography';\n\nimport AuditTrailTable from '@/DataTable/AuditTrailTable.jsx';\nimport ContentDialog from '@/ui/layout/ContentDialog.jsx';\nimport {piecePart, usePieceProps} from '@/theme/themePieces.js';\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaAuditTrailDialog)\nconst THEME_NAME = 'CalcitaAuditTrailDialog';\nconst AuditDescription = piecePart(THEME_NAME, 'Description', Typography);\n\n/**\n * @param {object} props\n * @param {boolean} props.open\n * @param {() => void} props.onClose\n * @param {string} props.title ya traducido («Historial de Q3 · ago 2026»)\n * @param {import('react').ReactNode} [props.subtitle]\n * @param {string} props.subjectKey\n * @param {(tableRequest: object, signal: AbortSignal) => Promise<{rows: Array, total: number, facets?: object}>} props.fetchPage\n * @param {Record<string, object>} props.eventDictionary\n * @param {Record<string, object>} [props.resultDictionary]\n * @param {Array<object>} [props.extraColumns]\n * @param {import('react').ReactNode} [props.header] va entre el subtítulo y la tabla (p. ej. pestañas que cambian lo que se\n * consulta)\n * @param {(row: any) => string|null} [props.eventSuffixOf] complemento del evento de un renglón (AuditTrailTable)\n */\nexport default function AuditTrailDialog(props) {\n // lo que el proyecto puso en su tema (components.CalcitaAuditTrailDialog.defaultProps) y encima lo que llega aquí\n const {\n open, onClose, title, subtitle, subjectKey, fetchPage, eventDictionary, resultDictionary, extraColumns = [], header = null, eventSuffixOf = null,\n} = usePieceProps(props, THEME_NAME);\n return (\n <ContentDialog open={open} onClose={onClose} title={title}>\n {subtitle && (\n <AuditDescription variant=\"body2\" color=\"text.secondary\" ownSx={{mb: 2}}>{subtitle}</AuditDescription>\n )}\n {header}\n <AuditTrailTable\n subjectKey={open ? subjectKey : ''}\n fetchPage={fetchPage}\n eventDictionary={eventDictionary}\n resultDictionary={resultDictionary}\n extraColumns={extraColumns}\n eventSuffixOf={eventSuffixOf}\n ariaLabel={title}\n maxGridHeight={null}\n />\n </ContentDialog>\n );\n}\n"],"names":[],"mappings":";;;;;;AAmBA,MAAM,aAAa;AACnB,MAAM,mBAAmB,UAAU,YAAY,eAAe,UAAU;AAiBxE,SAAwB,iBAAiB,OAAO;AAE5C,QAAM;AAAA,IACN;AAAA,IAAM;AAAA,IAAS;AAAA,IAAO;AAAA,IAAU;AAAA,IAAY;AAAA,IAAW;AAAA,IAAiB;AAAA,IAAkB,eAAe,CAAA;AAAA,IAAI,SAAS;AAAA,IAAM,gBAAgB;AAAA,EAAA,IAC5I,cAAc,OAAO,UAAU;AAC/B,SACI,qBAAC,eAAA,EAAc,MAAY,SAAkB,OACxC,UAAA;AAAA,IAAA,YACG,oBAAC,kBAAA,EAAiB,SAAQ,SAAQ,OAAM,kBAAiB,OAAO,EAAC,IAAI,EAAA,GAAK,UAAA,SAAA,CAAS;AAAA,IAEtF;AAAA,IACD;AAAA,MAAC;AAAA,MAAA;AAAA,QACG,YAAY,OAAO,aAAa;AAAA,QAChC;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,WAAW;AAAA,QACX,eAAe;AAAA,MAAA;AAAA,IAAA;AAAA,EACnB,GACJ;AAER;"}
1
+ {"version":3,"file":"AuditTrailDialog.js","sources":["../../src/DataTable/AuditTrailDialog.jsx"],"sourcesContent":["// Diálogo de auditoría de un renglón: su historia de eventos, paginada y filtrada EN EL SERVIDOR (AuditTrailTable).\n//\n// Sirve para el historial de cualquier registro (un pedido, una cuenta).\n// Solo abre una vista: no ejecuta nada y por eso no lleva confirmación.\n//\n// Se abre como diálogo de contenido (ContentDialog): sube desde abajo y ocupa la pantalla debajo de la barra superior. Una\n// tabla con su historia se lee mejor a todo lo ancho que en un recuadro al centro, también en el teléfono.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaAuditTrailDialog con defaultProps y\n// styleOverrides de sus partes: description.\n//\n// Genérico del paquete: function (regla de la casa).\nimport Typography from '@mui/material/Typography';\n\nimport AuditTrailTable from '@/DataTable/AuditTrailTable.jsx';\nimport ContentDialog from '@/ui/layout/ContentDialog.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.CalcitaAuditTrailDialog)\nconst THEME_NAME = 'CalcitaAuditTrailDialog';\nconst AuditDescription = piecePart(THEME_NAME, 'Description', Typography);\n\n/**\n * @param {object} props\n * @param {boolean} props.open\n * @param {() => void} props.onClose\n * @param {string} props.title ya traducido («Historial de Q3 · ago 2026»)\n * @param {import('react').ReactNode} [props.subtitle]\n * @param {string} props.subjectKey\n * @param {(tableRequest: object, signal: AbortSignal) => Promise<{rows: Array, total: number, facets?: object}>} props.fetchPage\n * @param {Record<string, object>} props.eventDictionary\n * @param {Record<string, object>} [props.resultDictionary]\n * @param {Array<object>} [props.extraColumns]\n * @param {import('react').ReactNode} [props.header] va entre el subtítulo y la tabla (p. ej. pestañas que cambian lo que se\n * consulta)\n * @param {(row: any) => string|null} [props.eventSuffixOf] complemento del evento de un renglón (AuditTrailTable)\n */\nexport default function AuditTrailDialog(props) {\n // lo que el proyecto puso en su tema (components.CalcitaAuditTrailDialog.defaultProps) y encima lo que llega aquí\n const {\n open, onClose, title, subtitle, subjectKey, fetchPage, eventDictionary, resultDictionary, extraColumns = [], header = null, eventSuffixOf = null,\n ...unknownProps\n} = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n return (\n <ContentDialog open={open} onClose={onClose} title={title}>\n {subtitle && (\n <AuditDescription variant=\"body2\" color=\"text.secondary\" ownSx={{mb: 2}}>{subtitle}</AuditDescription>\n )}\n {header}\n <AuditTrailTable\n subjectKey={open ? subjectKey : ''}\n fetchPage={fetchPage}\n eventDictionary={eventDictionary}\n resultDictionary={resultDictionary}\n extraColumns={extraColumns}\n eventSuffixOf={eventSuffixOf}\n ariaLabel={title}\n maxGridHeight={null}\n />\n </ContentDialog>\n );\n}\n"],"names":[],"mappings":";;;;;;;AAoBA,MAAM,aAAa;AACnB,MAAM,mBAAmB,UAAU,YAAY,eAAe,UAAU;AAiBxE,SAAwB,iBAAiB,OAAO;AAE5C,QAAM;AAAA,IACN;AAAA,IAAM;AAAA,IAAS;AAAA,IAAO;AAAA,IAAU;AAAA,IAAY;AAAA,IAAW;AAAA,IAAiB;AAAA,IAAkB,eAAe,CAAA;AAAA,IAAI,SAAS;AAAA,IAAM,gBAAgB;AAAA,IAC5I,GAAG;AAAA,EAAA,IACH,cAAc,OAAO,UAAU;AAC/B,mBAAiB,YAAY,YAAY;AACzC,SACI,qBAAC,eAAA,EAAc,MAAY,SAAkB,OACxC,UAAA;AAAA,IAAA,YACG,oBAAC,kBAAA,EAAiB,SAAQ,SAAQ,OAAM,kBAAiB,OAAO,EAAC,IAAI,EAAA,GAAK,UAAA,SAAA,CAAS;AAAA,IAEtF;AAAA,IACD;AAAA,MAAC;AAAA,MAAA;AAAA,QACG,YAAY,OAAO,aAAa;AAAA,QAChC;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,WAAW;AAAA,QACX,eAAe;AAAA,MAAA;AAAA,IAAA;AAAA,EACnB,GACJ;AAER;"}
@@ -6,6 +6,7 @@ import { FILTER_KINDS } from "./useTableState.js";
6
6
  import { labelOf, lookup } from "../dictionaries/dictionaries.js";
7
7
  import { useFormatters } from "../toolkit/useFormatters.js";
8
8
  import StatusChip from "../ui/labels/StatusChip.js";
9
+ import { warnUnknownProps } from "../toolkit/unknownProps.js";
9
10
  const AUDIT_FILTER_DEFAULTS = { event: [] };
10
11
  const AUDIT_FILTER_KINDS = { event: FILTER_KINDS.multiSelect };
11
12
  function AuditTrailTable({
@@ -18,8 +19,10 @@ function AuditTrailTable({
18
19
  maxGridHeight = null,
19
20
  refreshToken,
20
21
  eventSuffixOf = null,
21
- texts
22
+ texts,
23
+ ...unknownProps
22
24
  }) {
25
+ warnUnknownProps("AuditTrailTable", unknownProps);
23
26
  const { t } = useToolkitTranslation(["table", "dictionaries"], texts);
24
27
  const { formatDateTime } = useFormatters();
25
28
  const columns = [
@@ -1 +1 @@
1
- {"version":3,"file":"AuditTrailTable.js","sources":["../../src/DataTable/AuditTrailTable.jsx"],"sourcesContent":["// Tabla de historial de un renglón: sus eventos, paginados y filtrados EN EL SERVIDOR (regla de tablas).\n//\n// La usan AuditTrailDialog (historial en un diálogo desde una lista) y los detalles con historial a la vista (p. ej. el\n// detalle de una cuenta). Recibe QUÉ consultar (fetchPage) y CÓMO nombrar los eventos (diccionarios) por props: core no\n// conoce el API.\n//\n// Filtros y página en memoria (sin prefijo de URL): el historial vive dentro de otra pantalla y escribir en la barra de\n// direcciones ensuciaría la URL de esa pantalla.\n//\n// Contrato de fetchPage: el de ServerTable ({filters: {event: [...]}, sortOrders, page, pageSize}) →\n// {rows: [{id, event, result, occurred_at, actor: {id, name}|null, ...}], total, facets: {event: [{value, total}]}}.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\n\nimport ServerTable from '@/DataTable/ServerTable.jsx';\nimport {FILTER_KINDS} from '@/DataTable/useTableState.js';\nimport {labelOf, lookup} from '@/dictionaries/dictionaries.js';\nimport {useFormatters} from '@/toolkit/useFormatters.js';\nimport StatusChip from '@/ui/labels/StatusChip.jsx';\n\n// OJO: constantes de módulo; objetos nuevos en cada render reinician el estado de la tabla\nconst AUDIT_FILTER_DEFAULTS = {event: []};\nconst AUDIT_FILTER_KINDS = {event: FILTER_KINDS.multiSelect};\n\n/**\n * @param {object} props\n * @param {string} props.subjectKey identifica el renglón (cambia la consulta al cambiar de renglón); '' no consulta\n * @param {(tableRequest: object, signal: AbortSignal) => Promise<{rows: Array, total: number, facets?: object}>} props.fetchPage\n * @param {Record<string, object>} props.eventDictionary\n * @param {Record<string, object>} [props.resultDictionary]\n * @param {Array<object>} [props.extraColumns] columnas del DataGrid propias del módulo (archivo, origen, motivo...)\n * @param {(row: any) => string|null} [props.eventSuffixOf] texto que va después del evento con « · » (p. ej. para\n * quién era la descarga); null = solo el evento\n * @param {string} props.ariaLabel\n * @param {number} [props.maxGridHeight]\n * @param {unknown} [props.refreshToken] cambia para volver a consultar (después de una acción sobre el mismo renglón)\n * @param {object} [props.texts] los textos que cambian, con la forma de `table` en los textos del paquete\n */\nexport default function AuditTrailTable({\n subjectKey, fetchPage, eventDictionary, resultDictionary, extraColumns = [], ariaLabel, maxGridHeight = null, refreshToken,\n eventSuffixOf = null, texts,\n}) {\n const {t} = useToolkitTranslation(['table', 'dictionaries'], texts);\n const {formatDateTime} = useFormatters();\n\n const columns = [\n {\n field: 'occurred_at', headerName: t('table:audit.columns.occurredAt'), width: 170, sortable: false,\n valueFormatter: (value) => (value ? formatDateTime(value) : '—'),\n },\n {\n field: 'event', headerName: t('table:audit.columns.event'), flex: 1, minWidth: 230, sortable: false,\n renderCell: ({row}) => <StatusChip variant=\"chip\" dictionary={eventDictionary} value={row.event} suffix={eventSuffixOf?.(row) ?? undefined} />,\n },\n ...(resultDictionary ? [{\n field: 'result', headerName: t('table:audit.columns.result'), width: 170, sortable: false,\n renderCell: ({row}) => <StatusChip dictionary={resultDictionary} value={row.result} />,\n }] : []),\n {\n field: 'actor', headerName: t('table:audit.columns.actor'), width: 190, sortable: false,\n // los eventos que escribe un proceso automático o la propia persona no tienen actor: se dice quién fue en palabras\n valueGetter: (value) => value?.name ?? t('table:audit.systemActor'),\n },\n ...extraColumns,\n ];\n\n // OJO: key={subjectKey}. Sin prefijo, los filtros viven en memoria dentro de ServerTable; si el diálogo o la página\n // siguen montados al pasar a otro renglón, el filtro de evento del renglón anterior se quedaría puesto\n return (\n <ServerTable\n key={subjectKey || 'without-subject'}\n queryKey={subjectKey ? `audit:${subjectKey}` : ''}\n enabled={Boolean(subjectKey)}\n fetchPage={fetchPage}\n refreshToken={refreshToken}\n columns={columns}\n filterDefaults={AUDIT_FILTER_DEFAULTS}\n filterKinds={AUDIT_FILTER_KINDS}\n searchField={null}\n chipConfig={[]}\n quickFilters={[{\n field: 'event',\n facetKey: 'event',\n caption: t('table:audit.eventFilterCaption'),\n renderLabel: (eventValue) => labelOf(lookup(eventDictionary, eventValue), t),\n }]}\n countLabel={(total) => t('table:audit.count', {count: total})}\n emptyLabel={t('table:audit.empty')}\n defaultPageSize={10}\n pageSizeOptions={[10, 25, 50]}\n maxGridHeight={maxGridHeight}\n ariaLabel={ariaLabel}\n />\n );\n}\n"],"names":[],"mappings":";;;;;;;;AAsBA,MAAM,wBAAwB,EAAC,OAAO,GAAC;AACvC,MAAM,qBAAqB,EAAC,OAAO,aAAa,YAAA;AAgBhD,SAAwB,gBAAgB;AAAA,EACpC;AAAA,EAAY;AAAA,EAAW;AAAA,EAAiB;AAAA,EAAkB,eAAe,CAAA;AAAA,EAAI;AAAA,EAAW,gBAAgB;AAAA,EAAM;AAAA,EAC9G,gBAAgB;AAAA,EAAM;AAC1B,GAAG;AACC,QAAM,EAAC,MAAK,sBAAsB,CAAC,SAAS,cAAc,GAAG,KAAK;AAClE,QAAM,EAAC,eAAA,IAAkB,cAAA;AAEzB,QAAM,UAAU;AAAA,IACZ;AAAA,MACI,OAAO;AAAA,MAAe,YAAY,EAAE,gCAAgC;AAAA,MAAG,OAAO;AAAA,MAAK,UAAU;AAAA,MAC7F,gBAAgB,CAAC,UAAW,QAAQ,eAAe,KAAK,IAAI;AAAA,IAAA;AAAA,IAEhE;AAAA,MACI,OAAO;AAAA,MAAS,YAAY,EAAE,2BAA2B;AAAA,MAAG,MAAM;AAAA,MAAG,UAAU;AAAA,MAAK,UAAU;AAAA,MAC9F,YAAY,CAAC,EAAC,UAAS,oBAAC,cAAW,SAAQ,QAAO,YAAY,iBAAiB,OAAO,IAAI,OAAO,QAAQ,gBAAgB,GAAG,KAAK,OAAA,CAAW;AAAA,IAAA;AAAA,IAEhJ,GAAI,mBAAmB,CAAC;AAAA,MACpB,OAAO;AAAA,MAAU,YAAY,EAAE,4BAA4B;AAAA,MAAG,OAAO;AAAA,MAAK,UAAU;AAAA,MACpF,YAAY,CAAC,EAAC,IAAA,MAAS,oBAAC,YAAA,EAAW,YAAY,kBAAkB,OAAO,IAAI,OAAA,CAAQ;AAAA,IAAA,CACvF,IAAI,CAAA;AAAA,IACL;AAAA,MACI,OAAO;AAAA,MAAS,YAAY,EAAE,2BAA2B;AAAA,MAAG,OAAO;AAAA,MAAK,UAAU;AAAA;AAAA,MAElF,aAAa,CAAC,UAAU,OAAO,QAAQ,EAAE,yBAAyB;AAAA,IAAA;AAAA,IAEtE,GAAG;AAAA,EAAA;AAKP,SACI;AAAA,IAAC;AAAA,IAAA;AAAA,MAEG,UAAU,aAAa,SAAS,UAAU,KAAK;AAAA,MAC/C,SAAS,QAAQ,UAAU;AAAA,MAC3B;AAAA,MACA;AAAA,MACA;AAAA,MACA,gBAAgB;AAAA,MAChB,aAAa;AAAA,MACb,aAAa;AAAA,MACb,YAAY,CAAA;AAAA,MACZ,cAAc,CAAC;AAAA,QACX,OAAO;AAAA,QACP,UAAU;AAAA,QACV,SAAS,EAAE,gCAAgC;AAAA,QAC3C,aAAa,CAAC,eAAe,QAAQ,OAAO,iBAAiB,UAAU,GAAG,CAAC;AAAA,MAAA,CAC9E;AAAA,MACD,YAAY,CAAC,UAAU,EAAE,qBAAqB,EAAC,OAAO,OAAM;AAAA,MAC5D,YAAY,EAAE,mBAAmB;AAAA,MACjC,iBAAiB;AAAA,MACjB,iBAAiB,CAAC,IAAI,IAAI,EAAE;AAAA,MAC5B;AAAA,MACA;AAAA,IAAA;AAAA,IArBK,cAAc;AAAA,EAAA;AAwB/B;"}
1
+ {"version":3,"file":"AuditTrailTable.js","sources":["../../src/DataTable/AuditTrailTable.jsx"],"sourcesContent":["// Tabla de historial de un renglón: sus eventos, paginados y filtrados EN EL SERVIDOR (regla de tablas).\n//\n// La usan AuditTrailDialog (historial en un diálogo desde una lista) y los detalles con historial a la vista (p. ej. el\n// detalle de una cuenta). Recibe QUÉ consultar (fetchPage) y CÓMO nombrar los eventos (diccionarios) por props: core no\n// conoce el API.\n//\n// Filtros y página en memoria (sin prefijo de URL): el historial vive dentro de otra pantalla y escribir en la barra de\n// direcciones ensuciaría la URL de esa pantalla.\n//\n// Contrato de fetchPage: el de ServerTable ({filters: {event: [...]}, sortOrders, page, pageSize}) →\n// {rows: [{id, event, result, occurred_at, actor: {id, name}|null, ...}], total, facets: {event: [{value, total}]}}.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\n\nimport ServerTable from '@/DataTable/ServerTable.jsx';\nimport {FILTER_KINDS} from '@/DataTable/useTableState.js';\nimport {labelOf, lookup} from '@/dictionaries/dictionaries.js';\nimport {useFormatters} from '@/toolkit/useFormatters.js';\nimport StatusChip from '@/ui/labels/StatusChip.jsx';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\n\n// OJO: constantes de módulo; objetos nuevos en cada render reinician el estado de la tabla\nconst AUDIT_FILTER_DEFAULTS = {event: []};\nconst AUDIT_FILTER_KINDS = {event: FILTER_KINDS.multiSelect};\n\n/**\n * @param {object} props\n * @param {string} props.subjectKey identifica el renglón (cambia la consulta al cambiar de renglón); '' no consulta\n * @param {(tableRequest: object, signal: AbortSignal) => Promise<{rows: Array, total: number, facets?: object}>} props.fetchPage\n * @param {Record<string, object>} props.eventDictionary\n * @param {Record<string, object>} [props.resultDictionary]\n * @param {Array<object>} [props.extraColumns] columnas del DataGrid propias del módulo (archivo, origen, motivo...)\n * @param {(row: any) => string|null} [props.eventSuffixOf] texto que va después del evento con « · » (p. ej. para\n * quién era la descarga); null = solo el evento\n * @param {string} props.ariaLabel\n * @param {number} [props.maxGridHeight]\n * @param {unknown} [props.refreshToken] cambia para volver a consultar (después de una acción sobre el mismo renglón)\n * @param {object} [props.texts] los textos que cambian, con la forma de `table` en los textos del paquete\n */\nexport default function AuditTrailTable({\n subjectKey, fetchPage, eventDictionary, resultDictionary, extraColumns = [], ariaLabel, maxGridHeight = null, refreshToken,\n eventSuffixOf = null, texts,\n ...unknownProps\n}) {\n warnUnknownProps('AuditTrailTable', unknownProps);\n const {t} = useToolkitTranslation(['table', 'dictionaries'], texts);\n const {formatDateTime} = useFormatters();\n\n const columns = [\n {\n field: 'occurred_at', headerName: t('table:audit.columns.occurredAt'), width: 170, sortable: false,\n valueFormatter: (value) => (value ? formatDateTime(value) : '—'),\n },\n {\n field: 'event', headerName: t('table:audit.columns.event'), flex: 1, minWidth: 230, sortable: false,\n renderCell: ({row}) => <StatusChip variant=\"chip\" dictionary={eventDictionary} value={row.event} suffix={eventSuffixOf?.(row) ?? undefined} />,\n },\n ...(resultDictionary ? [{\n field: 'result', headerName: t('table:audit.columns.result'), width: 170, sortable: false,\n renderCell: ({row}) => <StatusChip dictionary={resultDictionary} value={row.result} />,\n }] : []),\n {\n field: 'actor', headerName: t('table:audit.columns.actor'), width: 190, sortable: false,\n // los eventos que escribe un proceso automático o la propia persona no tienen actor: se dice quién fue en palabras\n valueGetter: (value) => value?.name ?? t('table:audit.systemActor'),\n },\n ...extraColumns,\n ];\n\n // OJO: key={subjectKey}. Sin prefijo, los filtros viven en memoria dentro de ServerTable; si el diálogo o la página\n // siguen montados al pasar a otro renglón, el filtro de evento del renglón anterior se quedaría puesto\n return (\n <ServerTable\n key={subjectKey || 'without-subject'}\n queryKey={subjectKey ? `audit:${subjectKey}` : ''}\n enabled={Boolean(subjectKey)}\n fetchPage={fetchPage}\n refreshToken={refreshToken}\n columns={columns}\n filterDefaults={AUDIT_FILTER_DEFAULTS}\n filterKinds={AUDIT_FILTER_KINDS}\n searchField={null}\n chipConfig={[]}\n quickFilters={[{\n field: 'event',\n facetKey: 'event',\n caption: t('table:audit.eventFilterCaption'),\n renderLabel: (eventValue) => labelOf(lookup(eventDictionary, eventValue), t),\n }]}\n countLabel={(total) => t('table:audit.count', {count: total})}\n emptyLabel={t('table:audit.empty')}\n defaultPageSize={10}\n pageSizeOptions={[10, 25, 50]}\n maxGridHeight={maxGridHeight}\n ariaLabel={ariaLabel}\n />\n );\n}\n"],"names":[],"mappings":";;;;;;;;;AAuBA,MAAM,wBAAwB,EAAC,OAAO,GAAC;AACvC,MAAM,qBAAqB,EAAC,OAAO,aAAa,YAAA;AAgBhD,SAAwB,gBAAgB;AAAA,EACpC;AAAA,EAAY;AAAA,EAAW;AAAA,EAAiB;AAAA,EAAkB,eAAe,CAAA;AAAA,EAAI;AAAA,EAAW,gBAAgB;AAAA,EAAM;AAAA,EAC9G,gBAAgB;AAAA,EAAM;AAAA,EACtB,GAAG;AACP,GAAG;AACC,mBAAiB,mBAAmB,YAAY;AAChD,QAAM,EAAC,MAAK,sBAAsB,CAAC,SAAS,cAAc,GAAG,KAAK;AAClE,QAAM,EAAC,eAAA,IAAkB,cAAA;AAEzB,QAAM,UAAU;AAAA,IACZ;AAAA,MACI,OAAO;AAAA,MAAe,YAAY,EAAE,gCAAgC;AAAA,MAAG,OAAO;AAAA,MAAK,UAAU;AAAA,MAC7F,gBAAgB,CAAC,UAAW,QAAQ,eAAe,KAAK,IAAI;AAAA,IAAA;AAAA,IAEhE;AAAA,MACI,OAAO;AAAA,MAAS,YAAY,EAAE,2BAA2B;AAAA,MAAG,MAAM;AAAA,MAAG,UAAU;AAAA,MAAK,UAAU;AAAA,MAC9F,YAAY,CAAC,EAAC,UAAS,oBAAC,cAAW,SAAQ,QAAO,YAAY,iBAAiB,OAAO,IAAI,OAAO,QAAQ,gBAAgB,GAAG,KAAK,OAAA,CAAW;AAAA,IAAA;AAAA,IAEhJ,GAAI,mBAAmB,CAAC;AAAA,MACpB,OAAO;AAAA,MAAU,YAAY,EAAE,4BAA4B;AAAA,MAAG,OAAO;AAAA,MAAK,UAAU;AAAA,MACpF,YAAY,CAAC,EAAC,IAAA,MAAS,oBAAC,YAAA,EAAW,YAAY,kBAAkB,OAAO,IAAI,OAAA,CAAQ;AAAA,IAAA,CACvF,IAAI,CAAA;AAAA,IACL;AAAA,MACI,OAAO;AAAA,MAAS,YAAY,EAAE,2BAA2B;AAAA,MAAG,OAAO;AAAA,MAAK,UAAU;AAAA;AAAA,MAElF,aAAa,CAAC,UAAU,OAAO,QAAQ,EAAE,yBAAyB;AAAA,IAAA;AAAA,IAEtE,GAAG;AAAA,EAAA;AAKP,SACI;AAAA,IAAC;AAAA,IAAA;AAAA,MAEG,UAAU,aAAa,SAAS,UAAU,KAAK;AAAA,MAC/C,SAAS,QAAQ,UAAU;AAAA,MAC3B;AAAA,MACA;AAAA,MACA;AAAA,MACA,gBAAgB;AAAA,MAChB,aAAa;AAAA,MACb,aAAa;AAAA,MACb,YAAY,CAAA;AAAA,MACZ,cAAc,CAAC;AAAA,QACX,OAAO;AAAA,QACP,UAAU;AAAA,QACV,SAAS,EAAE,gCAAgC;AAAA,QAC3C,aAAa,CAAC,eAAe,QAAQ,OAAO,iBAAiB,UAAU,GAAG,CAAC;AAAA,MAAA,CAC9E;AAAA,MACD,YAAY,CAAC,UAAU,EAAE,qBAAqB,EAAC,OAAO,OAAM;AAAA,MAC5D,YAAY,EAAE,mBAAmB;AAAA,MACjC,iBAAiB;AAAA,MACjB,iBAAiB,CAAC,IAAI,IAAI,EAAE;AAAA,MAC5B;AAAA,MACA;AAAA,IAAA;AAAA,IArBK,cAAc;AAAA,EAAA;AAwB/B;"}
@@ -12,12 +12,14 @@ import Tooltip from "@mui/material/Tooltip";
12
12
  import FilterAltIcon from "@mui/icons-material/FilterAlt";
13
13
  import FilterAltOutlinedIcon from "@mui/icons-material/FilterAltOutlined";
14
14
  import { piecePart, usePieceProps } from "../../theme/themePieces.js";
15
+ import { warnUnknownProps } from "../../toolkit/unknownProps.js";
15
16
  const THEME_NAME = "CalcitaHeaderFilter";
16
17
  const FilterButton = piecePart(THEME_NAME, "Button", IconButton);
17
18
  const FilterBadge = piecePart(THEME_NAME, "Badge", Badge);
18
19
  const FilterPanel = piecePart(THEME_NAME, "Panel", Box);
19
20
  function HeaderFilterPopover(props) {
20
- const { activeCount = 0, onClear, children } = usePieceProps(props, THEME_NAME);
21
+ const { activeCount = 0, onClear, children, ...unknownProps } = usePieceProps(props, THEME_NAME);
22
+ warnUnknownProps(THEME_NAME, unknownProps);
21
23
  const { t } = useToolkitTranslation("table");
22
24
  const [anchorElement, setAnchorElement] = useState(null);
23
25
  const isActive = activeCount > 0;
@@ -1 +1 @@
1
- {"version":3,"file":"HeaderFilterPopover.js","sources":["../../../src/DataTable/ColumnFilters/HeaderFilterPopover.jsx"],"sourcesContent":["// El icono de filtro del encabezado, con su globo.\n//\n// El badge trae el NÚMERO de valores activos en esa columna, no un punto: así se sabe sin abrir nada si se filtró por\n// uno o por seis.\n//\n// OJO: stopPropagation en el clic no es adorno. El título del encabezado ordena, y sin eso abrir el filtro también\n// cambiaría el orden.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaHeaderFilter con defaultProps y\n// styleOverrides de sus partes: button, badge, panel.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useState} from 'react';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport Badge from '@mui/material/Badge';\nimport Box from '@mui/material/Box';\nimport Button from '@mui/material/Button';\nimport IconButton from '@mui/material/IconButton';\nimport Popover from '@mui/material/Popover';\nimport Stack from '@mui/material/Stack';\nimport Tooltip from '@mui/material/Tooltip';\nimport FilterAltIcon from '@mui/icons-material/FilterAlt';\nimport FilterAltOutlinedIcon from '@mui/icons-material/FilterAltOutlined';\nimport {piecePart, usePieceProps} from '@/theme/themePieces.js';\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaHeaderFilter)\nconst THEME_NAME = 'CalcitaHeaderFilter';\nconst FilterButton = piecePart(THEME_NAME, 'Button', IconButton);\nconst FilterBadge = piecePart(THEME_NAME, 'Badge', Badge);\nconst FilterPanel = piecePart(THEME_NAME, 'Panel', Box);\n\n/**\n * @param {{activeCount?: number, onClear: () => void, children: import('react').ReactNode}} props children = el filtro\n */\nexport default function HeaderFilterPopover(props) {\n // lo que el proyecto puso en su tema (components.CalcitaHeaderFilter.defaultProps) y encima lo que llega aquí\n const {activeCount = 0, onClear, children} = usePieceProps(props, THEME_NAME);\n const {t} = useToolkitTranslation('table');\n const [anchorElement, setAnchorElement] = useState(null);\n const isActive = activeCount > 0;\n const tooltip = isActive ? t('columnFilter.activeTooltip', {count: activeCount}) : t('columnFilter.tooltip');\n\n return (\n <>\n <Tooltip title={tooltip}>\n <FilterButton size=\"small\" aria-label={tooltip}\n ownSx={{color: isActive ? 'primary.main' : 'action.active', opacity: isActive ? 1 : 0.45, overflow: 'visible'}}\n onClick={(event) => {\n event.stopPropagation();\n setAnchorElement(event.currentTarget);\n }}>\n {/* sin filtros NO se monta el Badge: MUI lo esconde con scale(0) y deja un artefacto en la esquina */}\n {isActive ? (\n <FilterBadge badgeContent={activeCount} color=\"primary\" overlap=\"circular\"\n ownSx={{'& .MuiBadge-badge': {fontSize: 10, fontWeight: 700, minWidth: 16, height: 16}}}>\n <FilterAltIcon fontSize=\"inherit\" />\n </FilterBadge>\n ) : <FilterAltOutlinedIcon fontSize=\"inherit\" />}\n </FilterButton>\n </Tooltip>\n\n <Popover open={Boolean(anchorElement)} anchorEl={anchorElement} onClose={() => setAnchorElement(null)}\n anchorOrigin={{vertical: 'bottom', horizontal: 'left'}}>\n <FilterPanel ownSx={{p: 2, minWidth: 280}}>\n <Stack spacing={1}>\n {children}\n <Button size=\"small\" disabled={!isActive}\n onClick={() => {\n onClear();\n setAnchorElement(null);\n }}>\n {t('columnFilter.clear')}\n </Button>\n </Stack>\n </FilterPanel>\n </Popover>\n </>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;AA0BA,MAAM,aAAa;AACnB,MAAM,eAAe,UAAU,YAAY,UAAU,UAAU;AAC/D,MAAM,cAAc,UAAU,YAAY,SAAS,KAAK;AACxD,MAAM,cAAc,UAAU,YAAY,SAAS,GAAG;AAKtD,SAAwB,oBAAoB,OAAO;AAE/C,QAAM,EAAC,cAAc,GAAG,SAAS,aAAY,cAAc,OAAO,UAAU;AAC5E,QAAM,EAAC,EAAA,IAAK,sBAAsB,OAAO;AACzC,QAAM,CAAC,eAAe,gBAAgB,IAAI,SAAS,IAAI;AACvD,QAAM,WAAW,cAAc;AAC/B,QAAM,UAAU,WAAW,EAAE,8BAA8B,EAAC,OAAO,YAAA,CAAY,IAAI,EAAE,sBAAsB;AAE3G,SACI,qBAAA,UAAA,EACI,UAAA;AAAA,IAAA,oBAAC,SAAA,EAAQ,OAAO,SACZ,UAAA;AAAA,MAAC;AAAA,MAAA;AAAA,QAAa,MAAK;AAAA,QAAQ,cAAY;AAAA,QAC3B,OAAO,EAAC,OAAO,WAAW,iBAAiB,iBAAiB,SAAS,WAAW,IAAI,MAAM,UAAU,UAAA;AAAA,QACpG,SAAS,CAAC,UAAU;AAChB,gBAAM,gBAAA;AACN,2BAAiB,MAAM,aAAa;AAAA,QACxC;AAAA,QAEP,UAAA,WACG;AAAA,UAAC;AAAA,UAAA;AAAA,YAAY,cAAc;AAAA,YAAa,OAAM;AAAA,YAAU,SAAQ;AAAA,YACzD,OAAO,EAAC,qBAAqB,EAAC,UAAU,IAAI,YAAY,KAAK,UAAU,IAAI,QAAQ,GAAA,EAAE;AAAA,YACxF,UAAA,oBAAC,eAAA,EAAc,UAAS,UAAA,CAAU;AAAA,UAAA;AAAA,QAAA,IAEtC,oBAAC,uBAAA,EAAsB,UAAS,UAAA,CAAU;AAAA,MAAA;AAAA,IAAA,GAEtD;AAAA,IAEA;AAAA,MAAC;AAAA,MAAA;AAAA,QAAQ,MAAM,QAAQ,aAAa;AAAA,QAAG,UAAU;AAAA,QAAe,SAAS,MAAM,iBAAiB,IAAI;AAAA,QAC3F,cAAc,EAAC,UAAU,UAAU,YAAY,OAAA;AAAA,QACpD,UAAA,oBAAC,aAAA,EAAY,OAAO,EAAC,GAAG,GAAG,UAAU,IAAA,GACjC,UAAA,qBAAC,OAAA,EAAM,SAAS,GACX,UAAA;AAAA,UAAA;AAAA,UACD;AAAA,YAAC;AAAA,YAAA;AAAA,cAAO,MAAK;AAAA,cAAQ,UAAU,CAAC;AAAA,cACxB,SAAS,MAAM;AACX,wBAAA;AACA,iCAAiB,IAAI;AAAA,cACzB;AAAA,cACH,YAAE,oBAAoB;AAAA,YAAA;AAAA,UAAA;AAAA,QAC3B,EAAA,CACJ,EAAA,CACJ;AAAA,MAAA;AAAA,IAAA;AAAA,EACJ,GACJ;AAER;"}
1
+ {"version":3,"file":"HeaderFilterPopover.js","sources":["../../../src/DataTable/ColumnFilters/HeaderFilterPopover.jsx"],"sourcesContent":["// El icono de filtro del encabezado, con su globo.\n//\n// El badge trae el NÚMERO de valores activos en esa columna, no un punto: así se sabe sin abrir nada si se filtró por\n// uno o por seis.\n//\n// OJO: stopPropagation en el clic no es adorno. El título del encabezado ordena, y sin eso abrir el filtro también\n// cambiaría el orden.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaHeaderFilter con defaultProps y\n// styleOverrides de sus partes: button, badge, panel.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useState} from 'react';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport Badge from '@mui/material/Badge';\nimport Box from '@mui/material/Box';\nimport Button from '@mui/material/Button';\nimport IconButton from '@mui/material/IconButton';\nimport Popover from '@mui/material/Popover';\nimport Stack from '@mui/material/Stack';\nimport Tooltip from '@mui/material/Tooltip';\nimport FilterAltIcon from '@mui/icons-material/FilterAlt';\nimport FilterAltOutlinedIcon from '@mui/icons-material/FilterAltOutlined';\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.CalcitaHeaderFilter)\nconst THEME_NAME = 'CalcitaHeaderFilter';\nconst FilterButton = piecePart(THEME_NAME, 'Button', IconButton);\nconst FilterBadge = piecePart(THEME_NAME, 'Badge', Badge);\nconst FilterPanel = piecePart(THEME_NAME, 'Panel', Box);\n\n/**\n * @param {{activeCount?: number, onClear: () => void, children: import('react').ReactNode}} props children = el filtro\n */\nexport default function HeaderFilterPopover(props) {\n // lo que el proyecto puso en su tema (components.CalcitaHeaderFilter.defaultProps) y encima lo que llega aquí\n const {activeCount = 0, onClear, children, ...unknownProps} = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n const {t} = useToolkitTranslation('table');\n const [anchorElement, setAnchorElement] = useState(null);\n const isActive = activeCount > 0;\n const tooltip = isActive ? t('columnFilter.activeTooltip', {count: activeCount}) : t('columnFilter.tooltip');\n\n return (\n <>\n <Tooltip title={tooltip}>\n <FilterButton size=\"small\" aria-label={tooltip}\n ownSx={{color: isActive ? 'primary.main' : 'action.active', opacity: isActive ? 1 : 0.45, overflow: 'visible'}}\n onClick={(event) => {\n event.stopPropagation();\n setAnchorElement(event.currentTarget);\n }}>\n {/* sin filtros NO se monta el Badge: MUI lo esconde con scale(0) y deja un artefacto en la esquina */}\n {isActive ? (\n <FilterBadge badgeContent={activeCount} color=\"primary\" overlap=\"circular\"\n ownSx={{'& .MuiBadge-badge': {fontSize: 10, fontWeight: 700, minWidth: 16, height: 16}}}>\n <FilterAltIcon fontSize=\"inherit\" />\n </FilterBadge>\n ) : <FilterAltOutlinedIcon fontSize=\"inherit\" />}\n </FilterButton>\n </Tooltip>\n\n <Popover open={Boolean(anchorElement)} anchorEl={anchorElement} onClose={() => setAnchorElement(null)}\n anchorOrigin={{vertical: 'bottom', horizontal: 'left'}}>\n <FilterPanel ownSx={{p: 2, minWidth: 280}}>\n <Stack spacing={1}>\n {children}\n <Button size=\"small\" disabled={!isActive}\n onClick={() => {\n onClear();\n setAnchorElement(null);\n }}>\n {t('columnFilter.clear')}\n </Button>\n </Stack>\n </FilterPanel>\n </Popover>\n </>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;AA2BA,MAAM,aAAa;AACnB,MAAM,eAAe,UAAU,YAAY,UAAU,UAAU;AAC/D,MAAM,cAAc,UAAU,YAAY,SAAS,KAAK;AACxD,MAAM,cAAc,UAAU,YAAY,SAAS,GAAG;AAKtD,SAAwB,oBAAoB,OAAO;AAE/C,QAAM,EAAC,cAAc,GAAG,SAAS,UAAU,GAAG,iBAAgB,cAAc,OAAO,UAAU;AAC7F,mBAAiB,YAAY,YAAY;AACzC,QAAM,EAAC,EAAA,IAAK,sBAAsB,OAAO;AACzC,QAAM,CAAC,eAAe,gBAAgB,IAAI,SAAS,IAAI;AACvD,QAAM,WAAW,cAAc;AAC/B,QAAM,UAAU,WAAW,EAAE,8BAA8B,EAAC,OAAO,YAAA,CAAY,IAAI,EAAE,sBAAsB;AAE3G,SACI,qBAAA,UAAA,EACI,UAAA;AAAA,IAAA,oBAAC,SAAA,EAAQ,OAAO,SACZ,UAAA;AAAA,MAAC;AAAA,MAAA;AAAA,QAAa,MAAK;AAAA,QAAQ,cAAY;AAAA,QAC3B,OAAO,EAAC,OAAO,WAAW,iBAAiB,iBAAiB,SAAS,WAAW,IAAI,MAAM,UAAU,UAAA;AAAA,QACpG,SAAS,CAAC,UAAU;AAChB,gBAAM,gBAAA;AACN,2BAAiB,MAAM,aAAa;AAAA,QACxC;AAAA,QAEP,UAAA,WACG;AAAA,UAAC;AAAA,UAAA;AAAA,YAAY,cAAc;AAAA,YAAa,OAAM;AAAA,YAAU,SAAQ;AAAA,YACzD,OAAO,EAAC,qBAAqB,EAAC,UAAU,IAAI,YAAY,KAAK,UAAU,IAAI,QAAQ,GAAA,EAAE;AAAA,YACxF,UAAA,oBAAC,eAAA,EAAc,UAAS,UAAA,CAAU;AAAA,UAAA;AAAA,QAAA,IAEtC,oBAAC,uBAAA,EAAsB,UAAS,UAAA,CAAU;AAAA,MAAA;AAAA,IAAA,GAEtD;AAAA,IAEA;AAAA,MAAC;AAAA,MAAA;AAAA,QAAQ,MAAM,QAAQ,aAAa;AAAA,QAAG,UAAU;AAAA,QAAe,SAAS,MAAM,iBAAiB,IAAI;AAAA,QAC3F,cAAc,EAAC,UAAU,UAAU,YAAY,OAAA;AAAA,QACpD,UAAA,oBAAC,aAAA,EAAY,OAAO,EAAC,GAAG,GAAG,UAAU,IAAA,GACjC,UAAA,qBAAC,OAAA,EAAM,SAAS,GACX,UAAA;AAAA,UAAA;AAAA,UACD;AAAA,YAAC;AAAA,YAAA;AAAA,cAAO,MAAK;AAAA,cAAQ,UAAU,CAAC;AAAA,cACxB,SAAS,MAAM;AACX,wBAAA;AACA,iCAAiB,IAAI;AAAA,cACzB;AAAA,cACH,YAAE,oBAAoB;AAAA,YAAA;AAAA,UAAA;AAAA,QAC3B,EAAA,CACJ,EAAA,CACJ;AAAA,MAAA;AAAA,IAAA;AAAA,EACJ,GACJ;AAER;"}
@@ -9,12 +9,14 @@ import TextField from "@mui/material/TextField";
9
9
  import Typography from "@mui/material/Typography";
10
10
  import { useFormatters } from "../../toolkit/useFormatters.js";
11
11
  import { piecePart, usePieceProps } from "../../theme/themePieces.js";
12
+ import { warnUnknownProps } from "../../toolkit/unknownProps.js";
12
13
  const THEME_NAME = "CalcitaMultiSelectFilter";
13
14
  const MultiList = piecePart(THEME_NAME, "List", Stack);
14
15
  const MultiOption = piecePart(THEME_NAME, "Option", Stack);
15
16
  const SEARCHABLE_FROM_OPTIONS = 8;
16
17
  function MultiSelectColumnFilter(props) {
17
- const { value = [], onChange, options = [], renderOption } = usePieceProps(props, THEME_NAME);
18
+ const { value = [], onChange, options = [], renderOption, ...unknownProps } = usePieceProps(props, THEME_NAME);
19
+ warnUnknownProps(THEME_NAME, unknownProps);
18
20
  const { t } = useToolkitTranslation("table");
19
21
  const { formatNumber } = useFormatters();
20
22
  const [searchText, setSearchText] = useState("");
@@ -1 +1 @@
1
- {"version":3,"file":"MultiSelectColumnFilter.js","sources":["../../../src/DataTable/ColumnFilters/MultiSelectColumnFilter.jsx"],"sourcesContent":["// Filtro de opciones de una columna.\n//\n// Dos cosas lo separan de un multi-select cualquiera:\n// - las opciones NO salen de las filas visibles: salen de las FACETAS que el servidor calcula sobre el resultado\n// COMPLETO (ofrecer solo lo que aparece en las primeras 25 filas convierte el filtro en adorno);\n// - cada opción trae su conteo, que es lo que deja decidir si vale la pena filtrar.\n//\n// Desde ocho opciones aparece una caja para buscar entre ellas.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaMultiSelectFilter con defaultProps y\n// styleOverrides de sus partes: list, option.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useState} from 'react';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport Checkbox from '@mui/material/Checkbox';\nimport FormControlLabel from '@mui/material/FormControlLabel';\nimport Stack from '@mui/material/Stack';\nimport TextField from '@mui/material/TextField';\nimport Typography from '@mui/material/Typography';\n\nimport {useFormatters} from '@/toolkit/useFormatters.js';\nimport {piecePart, usePieceProps} from '@/theme/themePieces.js';\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaMultiSelectFilter)\nconst THEME_NAME = 'CalcitaMultiSelectFilter';\nconst MultiList = piecePart(THEME_NAME, 'List', Stack);\nconst MultiOption = piecePart(THEME_NAME, 'Option', Stack);\n\nconst SEARCHABLE_FROM_OPTIONS = 8;\n\n/**\n * @param {object} props\n * @param {string[]} [props.value]\n * @param {(value: string[]) => void} props.onChange\n * @param {Array<{value: string, total: number}>} [props.options] faceta del servidor\n * @param {(value: string) => import('react').ReactNode} [props.renderOption] cómo se lee el valor (diccionario)\n */\nexport default function MultiSelectColumnFilter(props) {\n // lo que el proyecto puso en su tema (components.CalcitaMultiSelectFilter.defaultProps) y encima lo que llega aquí\n const {value = [], onChange, options = [], renderOption} = usePieceProps(props, THEME_NAME);\n const {t} = useToolkitTranslation('table');\n const {formatNumber} = useFormatters();\n const [searchText, setSearchText] = useState('');\n\n const toggleOption = (optionValue) => onChange(value.includes(optionValue)\n ? value.filter((currentValue) => currentValue !== optionValue)\n : [...value, optionValue]);\n\n const isSearchable = options.length >= SEARCHABLE_FROM_OPTIONS;\n const visibleOptions = isSearchable && searchText\n ? options.filter((option) => String(option.value).toLowerCase().includes(searchText.toLowerCase()))\n : options;\n\n return (\n <Stack spacing={1}>\n {isSearchable && (\n <TextField size=\"small\" autoFocus fullWidth placeholder={t('options.searchPlaceholder')} value={searchText}\n onChange={(event) => setSearchText(event.target.value)} />\n )}\n <MultiList ownSx={{maxHeight: 300, overflowY: 'auto'}}>\n {options.length === 0 && (\n <Typography variant=\"caption\" color=\"text.secondary\">{t('options.empty')}</Typography>\n )}\n {options.length > 0 && visibleOptions.length === 0 && (\n <Typography variant=\"caption\" color=\"text.secondary\">{t('options.noMatch', {text: searchText})}</Typography>\n )}\n {visibleOptions.map((option) => (\n <FormControlLabel\n key={option.value}\n control={<Checkbox size=\"small\" checked={value.includes(option.value)} onChange={() => toggleOption(option.value)} />}\n label={(\n <MultiOption direction=\"row\" spacing={0.75} ownSx={{alignItems: 'center'}}>\n {renderOption ? renderOption(option.value) : <Typography variant=\"body2\">{option.value}</Typography>}\n <Typography variant=\"caption\" color=\"text.secondary\">{formatNumber(option.total)}</Typography>\n </MultiOption>\n )}\n />\n ))}\n </MultiList>\n </Stack>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;;AAyBA,MAAM,aAAa;AACnB,MAAM,YAAY,UAAU,YAAY,QAAQ,KAAK;AACrD,MAAM,cAAc,UAAU,YAAY,UAAU,KAAK;AAEzD,MAAM,0BAA0B;AAShC,SAAwB,wBAAwB,OAAO;AAEnD,QAAM,EAAC,QAAQ,IAAI,UAAU,UAAU,IAAI,iBAAgB,cAAc,OAAO,UAAU;AAC1F,QAAM,EAAC,EAAA,IAAK,sBAAsB,OAAO;AACzC,QAAM,EAAC,aAAA,IAAgB,cAAA;AACvB,QAAM,CAAC,YAAY,aAAa,IAAI,SAAS,EAAE;AAE/C,QAAM,eAAe,CAAC,gBAAgB,SAAS,MAAM,SAAS,WAAW,IACnE,MAAM,OAAO,CAAC,iBAAiB,iBAAiB,WAAW,IAC3D,CAAC,GAAG,OAAO,WAAW,CAAC;AAE7B,QAAM,eAAe,QAAQ,UAAU;AACvC,QAAM,iBAAiB,gBAAgB,aACjC,QAAQ,OAAO,CAAC,WAAW,OAAO,OAAO,KAAK,EAAE,cAAc,SAAS,WAAW,YAAA,CAAa,CAAC,IAChG;AAEN,SACI,qBAAC,OAAA,EAAM,SAAS,GACX,UAAA;AAAA,IAAA,gBACG;AAAA,MAAC;AAAA,MAAA;AAAA,QAAU,MAAK;AAAA,QAAQ,WAAS;AAAA,QAAC,WAAS;AAAA,QAAC,aAAa,EAAE,2BAA2B;AAAA,QAAG,OAAO;AAAA,QACrF,UAAU,CAAC,UAAU,cAAc,MAAM,OAAO,KAAK;AAAA,MAAA;AAAA,IAAA;AAAA,IAEpE,qBAAC,aAAU,OAAO,EAAC,WAAW,KAAK,WAAW,UACzC,UAAA;AAAA,MAAA,QAAQ,WAAW,KAChB,oBAAC,YAAA,EAAW,SAAQ,WAAU,OAAM,kBAAkB,UAAA,EAAE,eAAe,EAAA,CAAE;AAAA,MAE5E,QAAQ,SAAS,KAAK,eAAe,WAAW,yBAC5C,YAAA,EAAW,SAAQ,WAAU,OAAM,kBAAkB,UAAA,EAAE,mBAAmB,EAAC,MAAM,WAAA,CAAW,GAAE;AAAA,MAElG,eAAe,IAAI,CAAC,WACjB;AAAA,QAAC;AAAA,QAAA;AAAA,UAEG,SAAS,oBAAC,UAAA,EAAS,MAAK,SAAQ,SAAS,MAAM,SAAS,OAAO,KAAK,GAAG,UAAU,MAAM,aAAa,OAAO,KAAK,GAAG;AAAA,UACnH,OACI,qBAAC,aAAA,EAAY,WAAU,OAAM,SAAS,MAAM,OAAO,EAAC,YAAY,SAAA,GAC3D,UAAA;AAAA,YAAA,eAAe,aAAa,OAAO,KAAK,wBAAK,YAAA,EAAW,SAAQ,SAAS,UAAA,OAAO,MAAA,CAAM;AAAA,YACvF,oBAAC,cAAW,SAAQ,WAAU,OAAM,kBAAkB,UAAA,aAAa,OAAO,KAAK,EAAA,CAAE;AAAA,UAAA,EAAA,CACrF;AAAA,QAAA;AAAA,QANC,OAAO;AAAA,MAAA,CASnB;AAAA,IAAA,EAAA,CACL;AAAA,EAAA,GACJ;AAER;"}
1
+ {"version":3,"file":"MultiSelectColumnFilter.js","sources":["../../../src/DataTable/ColumnFilters/MultiSelectColumnFilter.jsx"],"sourcesContent":["// Filtro de opciones de una columna.\n//\n// Dos cosas lo separan de un multi-select cualquiera:\n// - las opciones NO salen de las filas visibles: salen de las FACETAS que el servidor calcula sobre el resultado\n// COMPLETO (ofrecer solo lo que aparece en las primeras 25 filas convierte el filtro en adorno);\n// - cada opción trae su conteo, que es lo que deja decidir si vale la pena filtrar.\n//\n// Desde ocho opciones aparece una caja para buscar entre ellas.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaMultiSelectFilter con defaultProps y\n// styleOverrides de sus partes: list, option.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useState} from 'react';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport Checkbox from '@mui/material/Checkbox';\nimport FormControlLabel from '@mui/material/FormControlLabel';\nimport Stack from '@mui/material/Stack';\nimport TextField from '@mui/material/TextField';\nimport Typography from '@mui/material/Typography';\n\nimport {useFormatters} from '@/toolkit/useFormatters.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.CalcitaMultiSelectFilter)\nconst THEME_NAME = 'CalcitaMultiSelectFilter';\nconst MultiList = piecePart(THEME_NAME, 'List', Stack);\nconst MultiOption = piecePart(THEME_NAME, 'Option', Stack);\n\nconst SEARCHABLE_FROM_OPTIONS = 8;\n\n/**\n * @param {object} props\n * @param {string[]} [props.value]\n * @param {(value: string[]) => void} props.onChange\n * @param {Array<{value: string, total: number}>} [props.options] faceta del servidor\n * @param {(value: string) => import('react').ReactNode} [props.renderOption] cómo se lee el valor (diccionario)\n */\nexport default function MultiSelectColumnFilter(props) {\n // lo que el proyecto puso en su tema (components.CalcitaMultiSelectFilter.defaultProps) y encima lo que llega aquí\n const {value = [], onChange, options = [], renderOption, ...unknownProps} = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n const {t} = useToolkitTranslation('table');\n const {formatNumber} = useFormatters();\n const [searchText, setSearchText] = useState('');\n\n const toggleOption = (optionValue) => onChange(value.includes(optionValue)\n ? value.filter((currentValue) => currentValue !== optionValue)\n : [...value, optionValue]);\n\n const isSearchable = options.length >= SEARCHABLE_FROM_OPTIONS;\n const visibleOptions = isSearchable && searchText\n ? options.filter((option) => String(option.value).toLowerCase().includes(searchText.toLowerCase()))\n : options;\n\n return (\n <Stack spacing={1}>\n {isSearchable && (\n <TextField size=\"small\" autoFocus fullWidth placeholder={t('options.searchPlaceholder')} value={searchText}\n onChange={(event) => setSearchText(event.target.value)} />\n )}\n <MultiList ownSx={{maxHeight: 300, overflowY: 'auto'}}>\n {options.length === 0 && (\n <Typography variant=\"caption\" color=\"text.secondary\">{t('options.empty')}</Typography>\n )}\n {options.length > 0 && visibleOptions.length === 0 && (\n <Typography variant=\"caption\" color=\"text.secondary\">{t('options.noMatch', {text: searchText})}</Typography>\n )}\n {visibleOptions.map((option) => (\n <FormControlLabel\n key={option.value}\n control={<Checkbox size=\"small\" checked={value.includes(option.value)} onChange={() => toggleOption(option.value)} />}\n label={(\n <MultiOption direction=\"row\" spacing={0.75} ownSx={{alignItems: 'center'}}>\n {renderOption ? renderOption(option.value) : <Typography variant=\"body2\">{option.value}</Typography>}\n <Typography variant=\"caption\" color=\"text.secondary\">{formatNumber(option.total)}</Typography>\n </MultiOption>\n )}\n />\n ))}\n </MultiList>\n </Stack>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;;;AA0BA,MAAM,aAAa;AACnB,MAAM,YAAY,UAAU,YAAY,QAAQ,KAAK;AACrD,MAAM,cAAc,UAAU,YAAY,UAAU,KAAK;AAEzD,MAAM,0BAA0B;AAShC,SAAwB,wBAAwB,OAAO;AAEnD,QAAM,EAAC,QAAQ,IAAI,UAAU,UAAU,CAAA,GAAI,cAAc,GAAG,aAAA,IAAgB,cAAc,OAAO,UAAU;AAC3G,mBAAiB,YAAY,YAAY;AACzC,QAAM,EAAC,EAAA,IAAK,sBAAsB,OAAO;AACzC,QAAM,EAAC,aAAA,IAAgB,cAAA;AACvB,QAAM,CAAC,YAAY,aAAa,IAAI,SAAS,EAAE;AAE/C,QAAM,eAAe,CAAC,gBAAgB,SAAS,MAAM,SAAS,WAAW,IACnE,MAAM,OAAO,CAAC,iBAAiB,iBAAiB,WAAW,IAC3D,CAAC,GAAG,OAAO,WAAW,CAAC;AAE7B,QAAM,eAAe,QAAQ,UAAU;AACvC,QAAM,iBAAiB,gBAAgB,aACjC,QAAQ,OAAO,CAAC,WAAW,OAAO,OAAO,KAAK,EAAE,cAAc,SAAS,WAAW,YAAA,CAAa,CAAC,IAChG;AAEN,SACI,qBAAC,OAAA,EAAM,SAAS,GACX,UAAA;AAAA,IAAA,gBACG;AAAA,MAAC;AAAA,MAAA;AAAA,QAAU,MAAK;AAAA,QAAQ,WAAS;AAAA,QAAC,WAAS;AAAA,QAAC,aAAa,EAAE,2BAA2B;AAAA,QAAG,OAAO;AAAA,QACrF,UAAU,CAAC,UAAU,cAAc,MAAM,OAAO,KAAK;AAAA,MAAA;AAAA,IAAA;AAAA,IAEpE,qBAAC,aAAU,OAAO,EAAC,WAAW,KAAK,WAAW,UACzC,UAAA;AAAA,MAAA,QAAQ,WAAW,KAChB,oBAAC,YAAA,EAAW,SAAQ,WAAU,OAAM,kBAAkB,UAAA,EAAE,eAAe,EAAA,CAAE;AAAA,MAE5E,QAAQ,SAAS,KAAK,eAAe,WAAW,yBAC5C,YAAA,EAAW,SAAQ,WAAU,OAAM,kBAAkB,UAAA,EAAE,mBAAmB,EAAC,MAAM,WAAA,CAAW,GAAE;AAAA,MAElG,eAAe,IAAI,CAAC,WACjB;AAAA,QAAC;AAAA,QAAA;AAAA,UAEG,SAAS,oBAAC,UAAA,EAAS,MAAK,SAAQ,SAAS,MAAM,SAAS,OAAO,KAAK,GAAG,UAAU,MAAM,aAAa,OAAO,KAAK,GAAG;AAAA,UACnH,OACI,qBAAC,aAAA,EAAY,WAAU,OAAM,SAAS,MAAM,OAAO,EAAC,YAAY,SAAA,GAC3D,UAAA;AAAA,YAAA,eAAe,aAAa,OAAO,KAAK,wBAAK,YAAA,EAAW,SAAQ,SAAS,UAAA,OAAO,MAAA,CAAM;AAAA,YACvF,oBAAC,cAAW,SAAQ,WAAU,OAAM,kBAAkB,UAAA,aAAa,OAAO,KAAK,EAAA,CAAE;AAAA,UAAA,EAAA,CACrF;AAAA,QAAA;AAAA,QANC,OAAO;AAAA,MAAA,CASnB;AAAA,IAAA,EAAA,CACL;AAAA,EAAA,GACJ;AAER;"}
@@ -8,6 +8,7 @@ import Tooltip from "@mui/material/Tooltip";
8
8
  import Typography from "@mui/material/Typography";
9
9
  import HeaderFilterPopover from "./HeaderFilterPopover.js";
10
10
  import { piecePart, usePieceProps } from "../../theme/themePieces.js";
11
+ import { warnUnknownProps } from "../../toolkit/unknownProps.js";
11
12
  const THEME_NAME = "CalcitaSortableFilterHeader";
12
13
  const SortableTitle = piecePart(THEME_NAME, "Title", Typography);
13
14
  const SortableRoot = piecePart(THEME_NAME, "Root", Stack);
@@ -24,8 +25,10 @@ function SortableFilterHeader(props) {
24
25
  filterable = true,
25
26
  activeCount,
26
27
  onClear,
27
- children
28
+ children,
29
+ ...unknownProps
28
30
  } = usePieceProps(props, THEME_NAME);
31
+ warnUnknownProps(THEME_NAME, unknownProps);
29
32
  const { t } = useToolkitTranslation("table");
30
33
  const title = /* @__PURE__ */ jsx(SortableTitle, { variant: "caption", ownSx: { fontWeight: 700, whiteSpace: "nowrap" }, children: label });
31
34
  return /* @__PURE__ */ jsxs(SortableRoot, { direction: "row", spacing: 0.25, ownSx: { alignItems: "center" }, children: [
@@ -1 +1 @@
1
- {"version":3,"file":"SortableFilterHeader.js","sources":["../../../src/DataTable/ColumnFilters/SortableFilterHeader.jsx"],"sourcesContent":["// Encabezado con orden y filtro.\n//\n// El que ordena es el TÍTULO, no un botón aparte: es el gesto que ya tiene aprendido quien usa tablas. La flecha solo\n// aparece cuando la columna está ordenando, y su × quita ese orden sin tener que ciclar hasta el tercer clic.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaSortableFilterHeader con defaultProps y\n// styleOverrides de sus partes: title, root, sortButton, sortIndicator, clearButton.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport Box from '@mui/material/Box';\nimport ButtonBase from '@mui/material/ButtonBase';\nimport Stack from '@mui/material/Stack';\nimport Tooltip from '@mui/material/Tooltip';\nimport Typography from '@mui/material/Typography';\n\nimport HeaderFilterPopover from '@/DataTable/ColumnFilters/HeaderFilterPopover.jsx';\nimport {piecePart, usePieceProps} from '@/theme/themePieces.js';\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaSortableFilterHeader)\nconst THEME_NAME = 'CalcitaSortableFilterHeader';\nconst SortableTitle = piecePart(THEME_NAME, 'Title', Typography);\nconst SortableRoot = piecePart(THEME_NAME, 'Root', Stack);\nconst SortableSortButton = piecePart(THEME_NAME, 'SortButton', ButtonBase);\nconst SortableSortIndicator = piecePart(THEME_NAME, 'SortIndicator', Box);\nconst SortableClearButton = piecePart(THEME_NAME, 'ClearButton', ButtonBase);\n\n/**\n * @param {object} props\n * @param {string} props.label\n * @param {boolean} [props.sortable]\n * @param {{column: string, direction: 'asc'|'desc'}} [props.sortEntry]\n * @param {() => void} [props.onSort]\n * @param {() => void} [props.onClearSort]\n * @param {boolean} [props.filterable]\n * @param {number} [props.activeCount]\n * @param {() => void} [props.onClear]\n * @param {import('react').ReactNode} [props.children] el filtro de la columna\n */\nexport default function SortableFilterHeader(props) {\n // lo que el proyecto puso en su tema (components.CalcitaSortableFilterHeader.defaultProps) y encima lo que llega aquí\n const {\n label, sortable = true, sortEntry, onSort, onClearSort, filterable = true, activeCount, onClear, children,\n} = usePieceProps(props, THEME_NAME);\n const {t} = useToolkitTranslation('table');\n const title = <SortableTitle variant=\"caption\" ownSx={{fontWeight: 700, whiteSpace: 'nowrap'}}>{label}</SortableTitle>;\n\n return (\n <SortableRoot direction=\"row\" spacing={0.25} ownSx={{alignItems: 'center'}}>\n {sortable ? (\n <Tooltip title={t('sort.tooltip')}>\n <SortableSortButton onClick={onSort} ownSx={{gap: 0.25, borderRadius: 0.5}}>\n {title}\n {sortEntry && (\n <SortableSortIndicator component=\"span\" ownSx={{display: 'inline-flex', alignItems: 'center', color: 'primary.main', fontWeight: 700}}\n aria-label={sortEntry.direction === 'asc' ? t('sort.ascending') : t('sort.descending')}>\n {sortEntry.direction === 'asc' ? '↑' : '↓'}\n </SortableSortIndicator>\n )}\n </SortableSortButton>\n </Tooltip>\n ) : title}\n\n {sortEntry && onClearSort && (\n <Tooltip title={t('sort.clear')}>\n <SortableClearButton aria-label={t('sort.clear')}\n // sin opacidad: la × es un control y al 70% daba 2.90:1 sobre el encabezado de la tabla\n ownSx={{fontSize: 12, lineHeight: 1, color: 'primary.main', '&:hover': {color: 'primary.dark'}}}\n onClick={(event) => {\n event.stopPropagation();\n onClearSort();\n }}>\n ×\n </SortableClearButton>\n </Tooltip>\n )}\n\n {filterable && (\n <HeaderFilterPopover activeCount={activeCount} onClear={onClear}>{children}</HeaderFilterPopover>\n )}\n </SortableRoot>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;AAoBA,MAAM,aAAa;AACnB,MAAM,gBAAgB,UAAU,YAAY,SAAS,UAAU;AAC/D,MAAM,eAAe,UAAU,YAAY,QAAQ,KAAK;AACxD,MAAM,qBAAqB,UAAU,YAAY,cAAc,UAAU;AACzE,MAAM,wBAAwB,UAAU,YAAY,iBAAiB,GAAG;AACxE,MAAM,sBAAsB,UAAU,YAAY,eAAe,UAAU;AAc3E,SAAwB,qBAAqB,OAAO;AAEhD,QAAM;AAAA,IACN;AAAA,IAAO,WAAW;AAAA,IAAM;AAAA,IAAW;AAAA,IAAQ;AAAA,IAAa,aAAa;AAAA,IAAM;AAAA,IAAa;AAAA,IAAS;AAAA,EAAA,IACjG,cAAc,OAAO,UAAU;AAC/B,QAAM,EAAC,EAAA,IAAK,sBAAsB,OAAO;AACzC,QAAM,QAAQ,oBAAC,eAAA,EAAc,SAAQ,WAAU,OAAO,EAAC,YAAY,KAAK,YAAY,SAAA,GAAY,UAAA,MAAA,CAAM;AAEtG,SACI,qBAAC,cAAA,EAAa,WAAU,OAAM,SAAS,MAAM,OAAO,EAAC,YAAY,SAAA,GAC5D,UAAA;AAAA,IAAA,+BACI,SAAA,EAAQ,OAAO,EAAE,cAAc,GAC5B,UAAA,qBAAC,oBAAA,EAAmB,SAAS,QAAQ,OAAO,EAAC,KAAK,MAAM,cAAc,OACjE,UAAA;AAAA,MAAA;AAAA,MACA,aACG;AAAA,QAAC;AAAA,QAAA;AAAA,UAAsB,WAAU;AAAA,UAAO,OAAO,EAAC,SAAS,eAAe,YAAY,UAAU,OAAO,gBAAgB,YAAY,IAAA;AAAA,UAC5H,cAAY,UAAU,cAAc,QAAQ,EAAE,gBAAgB,IAAI,EAAE,iBAAiB;AAAA,UACrF,UAAA,UAAU,cAAc,QAAQ,MAAM;AAAA,QAAA;AAAA,MAAA;AAAA,IAC3C,EAAA,CAER,GACJ,IACA;AAAA,IAEH,aAAa,eACV,oBAAC,WAAQ,OAAO,EAAE,YAAY,GAC1B,UAAA;AAAA,MAAC;AAAA,MAAA;AAAA,QAAoB,cAAY,EAAE,YAAY;AAAA,QAEnC,OAAO,EAAC,UAAU,IAAI,YAAY,GAAG,OAAO,gBAAgB,WAAW,EAAC,OAAO,eAAA,EAAc;AAAA,QAC7F,SAAS,CAAC,UAAU;AAChB,gBAAM,gBAAA;AACN,sBAAA;AAAA,QACJ;AAAA,QAAG,UAAA;AAAA,MAAA;AAAA,IAAA,GAGnB;AAAA,IAGH,cACG,oBAAC,qBAAA,EAAoB,aAA0B,SAAmB,SAAA,CAAS;AAAA,EAAA,GAEnF;AAER;"}
1
+ {"version":3,"file":"SortableFilterHeader.js","sources":["../../../src/DataTable/ColumnFilters/SortableFilterHeader.jsx"],"sourcesContent":["// Encabezado con orden y filtro.\n//\n// El que ordena es el TÍTULO, no un botón aparte: es el gesto que ya tiene aprendido quien usa tablas. La flecha solo\n// aparece cuando la columna está ordenando, y su × quita ese orden sin tener que ciclar hasta el tercer clic.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaSortableFilterHeader con defaultProps y\n// styleOverrides de sus partes: title, root, sortButton, sortIndicator, clearButton.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport Box from '@mui/material/Box';\nimport ButtonBase from '@mui/material/ButtonBase';\nimport Stack from '@mui/material/Stack';\nimport Tooltip from '@mui/material/Tooltip';\nimport Typography from '@mui/material/Typography';\n\nimport HeaderFilterPopover from '@/DataTable/ColumnFilters/HeaderFilterPopover.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.CalcitaSortableFilterHeader)\nconst THEME_NAME = 'CalcitaSortableFilterHeader';\nconst SortableTitle = piecePart(THEME_NAME, 'Title', Typography);\nconst SortableRoot = piecePart(THEME_NAME, 'Root', Stack);\nconst SortableSortButton = piecePart(THEME_NAME, 'SortButton', ButtonBase);\nconst SortableSortIndicator = piecePart(THEME_NAME, 'SortIndicator', Box);\nconst SortableClearButton = piecePart(THEME_NAME, 'ClearButton', ButtonBase);\n\n/**\n * @param {object} props\n * @param {string} props.label\n * @param {boolean} [props.sortable]\n * @param {{column: string, direction: 'asc'|'desc'}} [props.sortEntry]\n * @param {() => void} [props.onSort]\n * @param {() => void} [props.onClearSort]\n * @param {boolean} [props.filterable]\n * @param {number} [props.activeCount]\n * @param {() => void} [props.onClear]\n * @param {import('react').ReactNode} [props.children] el filtro de la columna\n */\nexport default function SortableFilterHeader(props) {\n // lo que el proyecto puso en su tema (components.CalcitaSortableFilterHeader.defaultProps) y encima lo que llega aquí\n const {\n label, sortable = true, sortEntry, onSort, onClearSort, filterable = true, activeCount, onClear, children,\n ...unknownProps\n} = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n const {t} = useToolkitTranslation('table');\n const title = <SortableTitle variant=\"caption\" ownSx={{fontWeight: 700, whiteSpace: 'nowrap'}}>{label}</SortableTitle>;\n\n return (\n <SortableRoot direction=\"row\" spacing={0.25} ownSx={{alignItems: 'center'}}>\n {sortable ? (\n <Tooltip title={t('sort.tooltip')}>\n <SortableSortButton onClick={onSort} ownSx={{gap: 0.25, borderRadius: 0.5}}>\n {title}\n {sortEntry && (\n <SortableSortIndicator component=\"span\" ownSx={{display: 'inline-flex', alignItems: 'center', color: 'primary.main', fontWeight: 700}}\n aria-label={sortEntry.direction === 'asc' ? t('sort.ascending') : t('sort.descending')}>\n {sortEntry.direction === 'asc' ? '↑' : '↓'}\n </SortableSortIndicator>\n )}\n </SortableSortButton>\n </Tooltip>\n ) : title}\n\n {sortEntry && onClearSort && (\n <Tooltip title={t('sort.clear')}>\n <SortableClearButton aria-label={t('sort.clear')}\n // sin opacidad: la × es un control y al 70% daba 2.90:1 sobre el encabezado de la tabla\n ownSx={{fontSize: 12, lineHeight: 1, color: 'primary.main', '&:hover': {color: 'primary.dark'}}}\n onClick={(event) => {\n event.stopPropagation();\n onClearSort();\n }}>\n ×\n </SortableClearButton>\n </Tooltip>\n )}\n\n {filterable && (\n <HeaderFilterPopover activeCount={activeCount} onClear={onClear}>{children}</HeaderFilterPopover>\n )}\n </SortableRoot>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;;AAqBA,MAAM,aAAa;AACnB,MAAM,gBAAgB,UAAU,YAAY,SAAS,UAAU;AAC/D,MAAM,eAAe,UAAU,YAAY,QAAQ,KAAK;AACxD,MAAM,qBAAqB,UAAU,YAAY,cAAc,UAAU;AACzE,MAAM,wBAAwB,UAAU,YAAY,iBAAiB,GAAG;AACxE,MAAM,sBAAsB,UAAU,YAAY,eAAe,UAAU;AAc3E,SAAwB,qBAAqB,OAAO;AAEhD,QAAM;AAAA,IACN;AAAA,IAAO,WAAW;AAAA,IAAM;AAAA,IAAW;AAAA,IAAQ;AAAA,IAAa,aAAa;AAAA,IAAM;AAAA,IAAa;AAAA,IAAS;AAAA,IACjG,GAAG;AAAA,EAAA,IACH,cAAc,OAAO,UAAU;AAC/B,mBAAiB,YAAY,YAAY;AACzC,QAAM,EAAC,EAAA,IAAK,sBAAsB,OAAO;AACzC,QAAM,QAAQ,oBAAC,eAAA,EAAc,SAAQ,WAAU,OAAO,EAAC,YAAY,KAAK,YAAY,SAAA,GAAY,UAAA,MAAA,CAAM;AAEtG,SACI,qBAAC,cAAA,EAAa,WAAU,OAAM,SAAS,MAAM,OAAO,EAAC,YAAY,SAAA,GAC5D,UAAA;AAAA,IAAA,+BACI,SAAA,EAAQ,OAAO,EAAE,cAAc,GAC5B,UAAA,qBAAC,oBAAA,EAAmB,SAAS,QAAQ,OAAO,EAAC,KAAK,MAAM,cAAc,OACjE,UAAA;AAAA,MAAA;AAAA,MACA,aACG;AAAA,QAAC;AAAA,QAAA;AAAA,UAAsB,WAAU;AAAA,UAAO,OAAO,EAAC,SAAS,eAAe,YAAY,UAAU,OAAO,gBAAgB,YAAY,IAAA;AAAA,UAC5H,cAAY,UAAU,cAAc,QAAQ,EAAE,gBAAgB,IAAI,EAAE,iBAAiB;AAAA,UACrF,UAAA,UAAU,cAAc,QAAQ,MAAM;AAAA,QAAA;AAAA,MAAA;AAAA,IAC3C,EAAA,CAER,GACJ,IACA;AAAA,IAEH,aAAa,eACV,oBAAC,WAAQ,OAAO,EAAE,YAAY,GAC1B,UAAA;AAAA,MAAC;AAAA,MAAA;AAAA,QAAoB,cAAY,EAAE,YAAY;AAAA,QAEnC,OAAO,EAAC,UAAU,IAAI,YAAY,GAAG,OAAO,gBAAgB,WAAW,EAAC,OAAO,eAAA,EAAc;AAAA,QAC7F,SAAS,CAAC,UAAU;AAChB,gBAAM,gBAAA;AACN,sBAAA;AAAA,QACJ;AAAA,QAAG,UAAA;AAAA,MAAA;AAAA,IAAA,GAGnB;AAAA,IAGH,cACG,oBAAC,qBAAA,EAAoB,aAA0B,SAAmB,SAAA,CAAS;AAAA,EAAA,GAEnF;AAER;"}
@@ -3,7 +3,9 @@ import { jsx } from "react/jsx-runtime";
3
3
  import { useToolkitTranslation } from "../../toolkit/useToolkitTranslation.js";
4
4
  import TextField from "@mui/material/TextField";
5
5
  import { useDebouncedFilter } from "../useDebouncedFilter.js";
6
- function TextColumnFilter({ value, onChange, label }) {
6
+ import { warnUnknownProps } from "../../toolkit/unknownProps.js";
7
+ function TextColumnFilter({ value, onChange, label, ...unknownProps }) {
8
+ warnUnknownProps("TextColumnFilter", unknownProps);
7
9
  const { t } = useToolkitTranslation("table");
8
10
  const [draft, setDraft] = useDebouncedFilter(value, onChange);
9
11
  return /* @__PURE__ */ jsx(
@@ -1 +1 @@
1
- {"version":3,"file":"TextColumnFilter.js","sources":["../../../src/DataTable/ColumnFilters/TextColumnFilter.jsx"],"sourcesContent":["// Filtro de texto libre de una columna, con rebote (350 ms, igual que la caja de búsqueda de la tabla): sin él,\n// escribir cinco letras son cinco consultas y las respuestas llegan en desorden.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport TextField from '@mui/material/TextField';\n\nimport {useDebouncedFilter} from '@/DataTable/useDebouncedFilter.js';\n\n/**\n * @param {{value: string, onChange: (value: string) => void, label?: string}} props label ya traducido\n */\nexport default function TextColumnFilter({value, onChange, label}) {\n const {t} = useToolkitTranslation('table');\n const [draft, setDraft] = useDebouncedFilter(value, onChange);\n\n return (\n <TextField size=\"small\" autoFocus fullWidth label={label ?? t('columnFilter.contains')} value={draft}\n onChange={(event) => setDraft(event.target.value)} />\n );\n}\n"],"names":[],"mappings":";;;;;AAYA,SAAwB,iBAAiB,EAAC,OAAO,UAAU,SAAQ;AAC/D,QAAM,EAAC,EAAA,IAAK,sBAAsB,OAAO;AACzC,QAAM,CAAC,OAAO,QAAQ,IAAI,mBAAmB,OAAO,QAAQ;AAE5D,SACI;AAAA,IAAC;AAAA,IAAA;AAAA,MAAU,MAAK;AAAA,MAAQ,WAAS;AAAA,MAAC,WAAS;AAAA,MAAC,OAAO,SAAS,EAAE,uBAAuB;AAAA,MAAG,OAAO;AAAA,MACpF,UAAU,CAAC,UAAU,SAAS,MAAM,OAAO,KAAK;AAAA,IAAA;AAAA,EAAA;AAEnE;"}
1
+ {"version":3,"file":"TextColumnFilter.js","sources":["../../../src/DataTable/ColumnFilters/TextColumnFilter.jsx"],"sourcesContent":["// Filtro de texto libre de una columna, con rebote (350 ms, igual que la caja de búsqueda de la tabla): sin él,\n// escribir cinco letras son cinco consultas y las respuestas llegan en desorden.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport TextField from '@mui/material/TextField';\n\nimport {useDebouncedFilter} from '@/DataTable/useDebouncedFilter.js';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\n\n/**\n * @param {{value: string, onChange: (value: string) => void, label?: string}} props label ya traducido\n */\nexport default function TextColumnFilter({value, onChange, label, ...unknownProps}) {\n warnUnknownProps('TextColumnFilter', unknownProps);\n const {t} = useToolkitTranslation('table');\n const [draft, setDraft] = useDebouncedFilter(value, onChange);\n\n return (\n <TextField size=\"small\" autoFocus fullWidth label={label ?? t('columnFilter.contains')} value={draft}\n onChange={(event) => setDraft(event.target.value)} />\n );\n}\n"],"names":[],"mappings":";;;;;;AAaA,SAAwB,iBAAiB,EAAC,OAAO,UAAU,OAAO,GAAG,gBAAe;AAChF,mBAAiB,oBAAoB,YAAY;AACjD,QAAM,EAAC,EAAA,IAAK,sBAAsB,OAAO;AACzC,QAAM,CAAC,OAAO,QAAQ,IAAI,mBAAmB,OAAO,QAAQ;AAE5D,SACI;AAAA,IAAC;AAAA,IAAA;AAAA,MAAU,MAAK;AAAA,MAAQ,WAAS;AAAA,MAAC,WAAS;AAAA,MAAC,OAAO,SAAS,EAAE,uBAAuB;AAAA,MAAG,OAAO;AAAA,MACpF,UAAU,CAAC,UAAU,SAAS,MAAM,OAAO,KAAK;AAAA,IAAA;AAAA,EAAA;AAEnE;"}
@@ -8,11 +8,13 @@ import Typography from "@mui/material/Typography";
8
8
  import FilterListOffIcon from "@mui/icons-material/FilterListOff";
9
9
  import InboxOutlinedIcon from "@mui/icons-material/InboxOutlined";
10
10
  import { piecePart, usePieceProps } from "../theme/themePieces.js";
11
+ import { warnUnknownProps } from "../toolkit/unknownProps.js";
11
12
  const THEME_NAME = "CalcitaEmptyState";
12
13
  const EmptyRoot = piecePart(THEME_NAME, "Root", Stack);
13
14
  const EmptyIcon = piecePart(THEME_NAME, "Icon", Box);
14
15
  function EmptyState(props) {
15
- const { filtered = false, label, onClearFilters, texts } = usePieceProps(props, THEME_NAME);
16
+ const { filtered = false, label, onClearFilters, texts, ...unknownProps } = usePieceProps(props, THEME_NAME);
17
+ warnUnknownProps(THEME_NAME, unknownProps);
16
18
  const { t } = useToolkitTranslation("table", texts);
17
19
  const Icon = filtered ? FilterListOffIcon : InboxOutlinedIcon;
18
20
  return /* @__PURE__ */ jsxs(EmptyRoot, { spacing: 1, ownSx: { height: "100%", px: 3, textAlign: "center", alignItems: "center", justifyContent: "center" }, children: [
@@ -1 +1 @@
1
- {"version":3,"file":"EmptyState.js","sources":["../../src/DataTable/EmptyState.jsx"],"sourcesContent":["// Qué decir cuando la tabla no tiene filas.\n//\n// Son dos situaciones distintas y confundirlas hace daño:\n// - sin filtros puestos, la lista vacía es el RESULTADO y se dice tal cual (label);\n// - con filtros puestos, la lista vacía NO dice nada del conjunto: dice que lo filtrado no existe dentro de él. Ahí\n// sí hay algo que hacer, y el botón lo hace.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaEmptyState con defaultProps y\n// styleOverrides de sus partes: root, icon.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport Box from '@mui/material/Box';\nimport Button from '@mui/material/Button';\nimport Stack from '@mui/material/Stack';\nimport Typography from '@mui/material/Typography';\nimport FilterListOffIcon from '@mui/icons-material/FilterListOff';\nimport InboxOutlinedIcon from '@mui/icons-material/InboxOutlined';\nimport {piecePart, usePieceProps} from '@/theme/themePieces.js';\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaEmptyState)\nconst THEME_NAME = 'CalcitaEmptyState';\nconst EmptyRoot = piecePart(THEME_NAME, 'Root', Stack);\nconst EmptyIcon = piecePart(THEME_NAME, 'Icon', Box);\n\n/**\n * @param {object} [props]\n * @param {boolean} [props.filtered]\n * @param {string} [props.label] ya traducido\n * @param {() => void} [props.onClearFilters]\n * @param {object} [props.texts] los textos que cambian, con la forma de `table` en los textos del paquete\n */\nexport default function EmptyState(props) {\n // lo que el proyecto puso en su tema (components.CalcitaEmptyState.defaultProps) y encima lo que llega aquí\n const {filtered = false, label, onClearFilters, texts} = usePieceProps(props, THEME_NAME);\n const {t} = useToolkitTranslation('table', texts);\n const Icon = filtered ? FilterListOffIcon : InboxOutlinedIcon;\n\n return (\n <EmptyRoot spacing={1} ownSx={{height: '100%', px: 3, textAlign: 'center', alignItems: 'center', justifyContent: 'center'}}>\n <EmptyIcon ownSx={{color: 'text.disabled', display: 'flex'}}>\n <Icon fontSize=\"large\" />\n </EmptyIcon>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {filtered ? t('empty.filtered') : (label ?? t('empty.default'))}\n </Typography>\n {filtered && onClearFilters && (\n <Button size=\"small\" onClick={onClearFilters}>{t('empty.clearFilters')}</Button>\n )}\n </EmptyRoot>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;AAqBA,MAAM,aAAa;AACnB,MAAM,YAAY,UAAU,YAAY,QAAQ,KAAK;AACrD,MAAM,YAAY,UAAU,YAAY,QAAQ,GAAG;AASnD,SAAwB,WAAW,OAAO;AAEtC,QAAM,EAAC,WAAW,OAAO,OAAO,gBAAgB,UAAS,cAAc,OAAO,UAAU;AACxF,QAAM,EAAC,EAAA,IAAK,sBAAsB,SAAS,KAAK;AAChD,QAAM,OAAO,WAAW,oBAAoB;AAE5C,8BACK,WAAA,EAAU,SAAS,GAAG,OAAO,EAAC,QAAQ,QAAQ,IAAI,GAAG,WAAW,UAAU,YAAY,UAAU,gBAAgB,YAC7G,UAAA;AAAA,IAAA,oBAAC,WAAA,EAAU,OAAO,EAAC,OAAO,iBAAiB,SAAS,OAAA,GAChD,UAAA,oBAAC,MAAA,EAAK,UAAS,QAAA,CAAQ,GAC3B;AAAA,IACA,oBAAC,YAAA,EAAW,SAAQ,SAAQ,OAAM,kBAC7B,UAAA,WAAW,EAAE,gBAAgB,IAAK,SAAS,EAAE,eAAe,GACjE;AAAA,IACC,YAAY,kBACT,oBAAC,QAAA,EAAO,MAAK,SAAQ,SAAS,gBAAiB,UAAA,EAAE,oBAAoB,EAAA,CAAE;AAAA,EAAA,GAE/E;AAER;"}
1
+ {"version":3,"file":"EmptyState.js","sources":["../../src/DataTable/EmptyState.jsx"],"sourcesContent":["// Qué decir cuando la tabla no tiene filas.\n//\n// Son dos situaciones distintas y confundirlas hace daño:\n// - sin filtros puestos, la lista vacía es el RESULTADO y se dice tal cual (label);\n// - con filtros puestos, la lista vacía NO dice nada del conjunto: dice que lo filtrado no existe dentro de él. Ahí\n// sí hay algo que hacer, y el botón lo hace.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaEmptyState con defaultProps y\n// styleOverrides de sus partes: root, icon.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport Box from '@mui/material/Box';\nimport Button from '@mui/material/Button';\nimport Stack from '@mui/material/Stack';\nimport Typography from '@mui/material/Typography';\nimport FilterListOffIcon from '@mui/icons-material/FilterListOff';\nimport InboxOutlinedIcon from '@mui/icons-material/InboxOutlined';\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.CalcitaEmptyState)\nconst THEME_NAME = 'CalcitaEmptyState';\nconst EmptyRoot = piecePart(THEME_NAME, 'Root', Stack);\nconst EmptyIcon = piecePart(THEME_NAME, 'Icon', Box);\n\n/**\n * @param {object} [props]\n * @param {boolean} [props.filtered]\n * @param {string} [props.label] ya traducido\n * @param {() => void} [props.onClearFilters]\n * @param {object} [props.texts] los textos que cambian, con la forma de `table` en los textos del paquete\n */\nexport default function EmptyState(props) {\n // lo que el proyecto puso en su tema (components.CalcitaEmptyState.defaultProps) y encima lo que llega aquí\n const {filtered = false, label, onClearFilters, texts, ...unknownProps} = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n const {t} = useToolkitTranslation('table', texts);\n const Icon = filtered ? FilterListOffIcon : InboxOutlinedIcon;\n\n return (\n <EmptyRoot spacing={1} ownSx={{height: '100%', px: 3, textAlign: 'center', alignItems: 'center', justifyContent: 'center'}}>\n <EmptyIcon ownSx={{color: 'text.disabled', display: 'flex'}}>\n <Icon fontSize=\"large\" />\n </EmptyIcon>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {filtered ? t('empty.filtered') : (label ?? t('empty.default'))}\n </Typography>\n {filtered && onClearFilters && (\n <Button size=\"small\" onClick={onClearFilters}>{t('empty.clearFilters')}</Button>\n )}\n </EmptyRoot>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;;AAsBA,MAAM,aAAa;AACnB,MAAM,YAAY,UAAU,YAAY,QAAQ,KAAK;AACrD,MAAM,YAAY,UAAU,YAAY,QAAQ,GAAG;AASnD,SAAwB,WAAW,OAAO;AAEtC,QAAM,EAAC,WAAW,OAAO,OAAO,gBAAgB,OAAO,GAAG,aAAA,IAAgB,cAAc,OAAO,UAAU;AACzG,mBAAiB,YAAY,YAAY;AACzC,QAAM,EAAC,EAAA,IAAK,sBAAsB,SAAS,KAAK;AAChD,QAAM,OAAO,WAAW,oBAAoB;AAE5C,8BACK,WAAA,EAAU,SAAS,GAAG,OAAO,EAAC,QAAQ,QAAQ,IAAI,GAAG,WAAW,UAAU,YAAY,UAAU,gBAAgB,YAC7G,UAAA;AAAA,IAAA,oBAAC,WAAA,EAAU,OAAO,EAAC,OAAO,iBAAiB,SAAS,OAAA,GAChD,UAAA,oBAAC,MAAA,EAAK,UAAS,QAAA,CAAQ,GAC3B;AAAA,IACA,oBAAC,YAAA,EAAW,SAAQ,SAAQ,OAAM,kBAC7B,UAAA,WAAW,EAAE,gBAAgB,IAAK,SAAS,EAAE,eAAe,GACjE;AAAA,IACC,YAAY,kBACT,oBAAC,QAAA,EAAO,MAAK,SAAQ,SAAS,gBAAiB,UAAA,EAAE,oBAAoB,EAAA,CAAE;AAAA,EAAA,GAE/E;AAER;"}
@@ -9,12 +9,14 @@ import ClearAllIcon from "@mui/icons-material/ClearAll";
9
9
  import ScrollableRow from "../ui/layout/ScrollableRow.js";
10
10
  import Tag from "../ui/labels/Tag.js";
11
11
  import { piecePart, usePieceProps } from "../theme/themePieces.js";
12
+ import { warnUnknownProps } from "../toolkit/unknownProps.js";
12
13
  const THEME_NAME = "CalcitaFilterChips";
13
14
  const ChipsRoot = piecePart(THEME_NAME, "Root", Box);
14
15
  const ChipsHeader = piecePart(THEME_NAME, "Header", Stack);
15
16
  const ChipsClearButton = piecePart(THEME_NAME, "ClearButton", Button);
16
17
  function FilterChips(props) {
17
- const { chipConfig, filters, onSetFilter, onClearAll, quickActiveCount = 0, texts } = usePieceProps(props, THEME_NAME);
18
+ const { chipConfig, filters, onSetFilter, onClearAll, quickActiveCount = 0, texts, ...unknownProps } = usePieceProps(props, THEME_NAME);
19
+ warnUnknownProps(THEME_NAME, unknownProps);
18
20
  const { t } = useToolkitTranslation("table", texts);
19
21
  const chips = chipConfig.filter((chipDeclaration) => chipDeclaration.isActive(filters[chipDeclaration.key])).flatMap((chipDeclaration) => chipDeclaration.chipsFor(filters[chipDeclaration.key], onSetFilter));
20
22
  const activeCount = chips.length + quickActiveCount;
@@ -1 +1 @@
1
- {"version":3,"file":"FilterChips.js","sources":["../../src/DataTable/FilterChips.jsx"],"sourcesContent":["// Los filtros activos, a la vista y desarmables de a uno.\n//\n// Un filtro que solo se ve como un icono encendido en el encabezado se olvida: alguien filtra, se va al detalle,\n// regresa y lee el total como si fuera el de todo. Por eso los filtros puestos se dicen con todas sus letras arriba de\n// la tabla.\n//\n// Van en UNA tira que se desliza (ScrollableRow), no envolviéndose en renglones que empujan la tabla fuera de la\n// pantalla. La cuenta y \"Limpiar todo\" van en su propio renglón, arriba, para no tener que deslizar hasta encontrarlo.\n// Sin filtros activos no se pinta nada (ni el hueco).\n//\n// Los accesos rápidos cuentan aunque no tengan chip aquí: su propio chip encendido ya dice qué está elegido.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaFilterChips con defaultProps y\n// styleOverrides de sus partes: root, header, clearButton.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport Box from '@mui/material/Box';\nimport Button from '@mui/material/Button';\nimport Stack from '@mui/material/Stack';\nimport Typography from '@mui/material/Typography';\nimport ClearAllIcon from '@mui/icons-material/ClearAll';\n\nimport ScrollableRow from '@/ui/layout/ScrollableRow.jsx';\nimport Tag from '@/ui/labels/Tag.jsx';\nimport {piecePart, usePieceProps} from '@/theme/themePieces.js';\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaFilterChips)\nconst THEME_NAME = 'CalcitaFilterChips';\nconst ChipsRoot = piecePart(THEME_NAME, 'Root', Box);\nconst ChipsHeader = piecePart(THEME_NAME, 'Header', Stack);\nconst ChipsClearButton = piecePart(THEME_NAME, 'ClearButton', Button);\n\n/**\n * @param {object} props\n * @param {Array<object>} props.chipConfig lo que arma buildChipConfig\n * @param {object} props.filters\n * @param {(field: string, value: unknown) => void} props.onSetFilter\n * @param {() => void} props.onClearAll\n * @param {number} [props.quickActiveCount] accesos rápidos puestos que no tienen chip aquí\n * @param {object} [props.texts] los textos que cambian, con la forma de `table` en los textos del paquete\n */\nexport default function FilterChips(props) {\n // lo que el proyecto puso en su tema (components.CalcitaFilterChips.defaultProps) y encima lo que llega aquí\n const {chipConfig, filters, onSetFilter, onClearAll, quickActiveCount = 0, texts} = usePieceProps(props, THEME_NAME);\n const {t} = useToolkitTranslation('table', texts);\n const chips = chipConfig\n .filter((chipDeclaration) => chipDeclaration.isActive(filters[chipDeclaration.key]))\n .flatMap((chipDeclaration) => chipDeclaration.chipsFor(filters[chipDeclaration.key], onSetFilter));\n\n const activeCount = chips.length + quickActiveCount;\n // guard clause: sin filtros no se pinta nada\n if (activeCount === 0) {\n return null;\n }\n\n return (\n <ChipsRoot ownSx={{mb: 1.5, minWidth: 0}}>\n <ChipsHeader direction=\"row\" spacing={1} ownSx={{px: 0.25, alignItems: 'center', justifyContent: 'space-between'}}>\n <Typography variant=\"caption\" color=\"text.secondary\" noWrap>\n {t('chips.applied', {count: activeCount})}\n </Typography>\n <ChipsClearButton size=\"small\" color=\"error\" startIcon={<ClearAllIcon fontSize=\"small\" />} onClick={onClearAll}\n ownSx={{flexShrink: 0}}>\n {t('chips.clearAll')}\n </ChipsClearButton>\n </ChipsHeader>\n\n {chips.length > 0 && (\n <ScrollableRow>\n {chips.map(({id, label, onDelete}) => (\n <Tag key={id} label={label} color=\"primary\" onDelete={onDelete} sx={{flex: '0 0 auto'}} />\n ))}\n </ScrollableRow>\n )}\n </ChipsRoot>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;;AA4BA,MAAM,aAAa;AACnB,MAAM,YAAY,UAAU,YAAY,QAAQ,GAAG;AACnD,MAAM,cAAc,UAAU,YAAY,UAAU,KAAK;AACzD,MAAM,mBAAmB,UAAU,YAAY,eAAe,MAAM;AAWpE,SAAwB,YAAY,OAAO;AAEvC,QAAM,EAAC,YAAY,SAAS,aAAa,YAAY,mBAAmB,GAAG,MAAA,IAAS,cAAc,OAAO,UAAU;AACnH,QAAM,EAAC,EAAA,IAAK,sBAAsB,SAAS,KAAK;AAChD,QAAM,QAAQ,WACT,OAAO,CAAC,oBAAoB,gBAAgB,SAAS,QAAQ,gBAAgB,GAAG,CAAC,CAAC,EAClF,QAAQ,CAAC,oBAAoB,gBAAgB,SAAS,QAAQ,gBAAgB,GAAG,GAAG,WAAW,CAAC;AAErG,QAAM,cAAc,MAAM,SAAS;AAEnC,MAAI,gBAAgB,GAAG;AACnB,WAAO;AAAA,EACX;AAEA,SACI,qBAAC,aAAU,OAAO,EAAC,IAAI,KAAK,UAAU,KAClC,UAAA;AAAA,IAAA,qBAAC,aAAA,EAAY,WAAU,OAAM,SAAS,GAAG,OAAO,EAAC,IAAI,MAAM,YAAY,UAAU,gBAAgB,mBAC7F,UAAA;AAAA,MAAA,oBAAC,YAAA,EAAW,SAAQ,WAAU,OAAM,kBAAiB,QAAM,MACtD,UAAA,EAAE,iBAAiB,EAAC,OAAO,YAAA,CAAY,GAC5C;AAAA,MACA;AAAA,QAAC;AAAA,QAAA;AAAA,UAAiB,MAAK;AAAA,UAAQ,OAAM;AAAA,UAAQ,WAAW,oBAAC,cAAA,EAAa,UAAS,QAAA,CAAQ;AAAA,UAAI,SAAS;AAAA,UAC5F,OAAO,EAAC,YAAY,EAAA;AAAA,UACvB,YAAE,gBAAgB;AAAA,QAAA;AAAA,MAAA;AAAA,IACvB,GACJ;AAAA,IAEC,MAAM,SAAS,KACZ,oBAAC,eAAA,EACI,UAAA,MAAM,IAAI,CAAC,EAAC,IAAI,OAAO,SAAA,0BACnB,KAAA,EAAa,OAAc,OAAM,WAAU,UAAoB,IAAI,EAAC,MAAM,WAAA,KAAjE,EAA8E,CAC3F,EAAA,CACL;AAAA,EAAA,GAER;AAER;"}
1
+ {"version":3,"file":"FilterChips.js","sources":["../../src/DataTable/FilterChips.jsx"],"sourcesContent":["// Los filtros activos, a la vista y desarmables de a uno.\n//\n// Un filtro que solo se ve como un icono encendido en el encabezado se olvida: alguien filtra, se va al detalle,\n// regresa y lee el total como si fuera el de todo. Por eso los filtros puestos se dicen con todas sus letras arriba de\n// la tabla.\n//\n// Van en UNA tira que se desliza (ScrollableRow), no envolviéndose en renglones que empujan la tabla fuera de la\n// pantalla. La cuenta y \"Limpiar todo\" van en su propio renglón, arriba, para no tener que deslizar hasta encontrarlo.\n// Sin filtros activos no se pinta nada (ni el hueco).\n//\n// Los accesos rápidos cuentan aunque no tengan chip aquí: su propio chip encendido ya dice qué está elegido.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaFilterChips con defaultProps y\n// styleOverrides de sus partes: root, header, clearButton.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport Box from '@mui/material/Box';\nimport Button from '@mui/material/Button';\nimport Stack from '@mui/material/Stack';\nimport Typography from '@mui/material/Typography';\nimport ClearAllIcon from '@mui/icons-material/ClearAll';\n\nimport ScrollableRow from '@/ui/layout/ScrollableRow.jsx';\nimport Tag from '@/ui/labels/Tag.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.CalcitaFilterChips)\nconst THEME_NAME = 'CalcitaFilterChips';\nconst ChipsRoot = piecePart(THEME_NAME, 'Root', Box);\nconst ChipsHeader = piecePart(THEME_NAME, 'Header', Stack);\nconst ChipsClearButton = piecePart(THEME_NAME, 'ClearButton', Button);\n\n/**\n * @param {object} props\n * @param {Array<object>} props.chipConfig lo que arma buildChipConfig\n * @param {object} props.filters\n * @param {(field: string, value: unknown) => void} props.onSetFilter\n * @param {() => void} props.onClearAll\n * @param {number} [props.quickActiveCount] accesos rápidos puestos que no tienen chip aquí\n * @param {object} [props.texts] los textos que cambian, con la forma de `table` en los textos del paquete\n */\nexport default function FilterChips(props) {\n // lo que el proyecto puso en su tema (components.CalcitaFilterChips.defaultProps) y encima lo que llega aquí\n const {chipConfig, filters, onSetFilter, onClearAll, quickActiveCount = 0, texts, ...unknownProps} = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n const {t} = useToolkitTranslation('table', texts);\n const chips = chipConfig\n .filter((chipDeclaration) => chipDeclaration.isActive(filters[chipDeclaration.key]))\n .flatMap((chipDeclaration) => chipDeclaration.chipsFor(filters[chipDeclaration.key], onSetFilter));\n\n const activeCount = chips.length + quickActiveCount;\n // guard clause: sin filtros no se pinta nada\n if (activeCount === 0) {\n return null;\n }\n\n return (\n <ChipsRoot ownSx={{mb: 1.5, minWidth: 0}}>\n <ChipsHeader direction=\"row\" spacing={1} ownSx={{px: 0.25, alignItems: 'center', justifyContent: 'space-between'}}>\n <Typography variant=\"caption\" color=\"text.secondary\" noWrap>\n {t('chips.applied', {count: activeCount})}\n </Typography>\n <ChipsClearButton size=\"small\" color=\"error\" startIcon={<ClearAllIcon fontSize=\"small\" />} onClick={onClearAll}\n ownSx={{flexShrink: 0}}>\n {t('chips.clearAll')}\n </ChipsClearButton>\n </ChipsHeader>\n\n {chips.length > 0 && (\n <ScrollableRow>\n {chips.map(({id, label, onDelete}) => (\n <Tag key={id} label={label} color=\"primary\" onDelete={onDelete} sx={{flex: '0 0 auto'}} />\n ))}\n </ScrollableRow>\n )}\n </ChipsRoot>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;;;AA6BA,MAAM,aAAa;AACnB,MAAM,YAAY,UAAU,YAAY,QAAQ,GAAG;AACnD,MAAM,cAAc,UAAU,YAAY,UAAU,KAAK;AACzD,MAAM,mBAAmB,UAAU,YAAY,eAAe,MAAM;AAWpE,SAAwB,YAAY,OAAO;AAEvC,QAAM,EAAC,YAAY,SAAS,aAAa,YAAY,mBAAmB,GAAG,OAAO,GAAG,aAAA,IAAgB,cAAc,OAAO,UAAU;AACpI,mBAAiB,YAAY,YAAY;AACzC,QAAM,EAAC,EAAA,IAAK,sBAAsB,SAAS,KAAK;AAChD,QAAM,QAAQ,WACT,OAAO,CAAC,oBAAoB,gBAAgB,SAAS,QAAQ,gBAAgB,GAAG,CAAC,CAAC,EAClF,QAAQ,CAAC,oBAAoB,gBAAgB,SAAS,QAAQ,gBAAgB,GAAG,GAAG,WAAW,CAAC;AAErG,QAAM,cAAc,MAAM,SAAS;AAEnC,MAAI,gBAAgB,GAAG;AACnB,WAAO;AAAA,EACX;AAEA,SACI,qBAAC,aAAU,OAAO,EAAC,IAAI,KAAK,UAAU,KAClC,UAAA;AAAA,IAAA,qBAAC,aAAA,EAAY,WAAU,OAAM,SAAS,GAAG,OAAO,EAAC,IAAI,MAAM,YAAY,UAAU,gBAAgB,mBAC7F,UAAA;AAAA,MAAA,oBAAC,YAAA,EAAW,SAAQ,WAAU,OAAM,kBAAiB,QAAM,MACtD,UAAA,EAAE,iBAAiB,EAAC,OAAO,YAAA,CAAY,GAC5C;AAAA,MACA;AAAA,QAAC;AAAA,QAAA;AAAA,UAAiB,MAAK;AAAA,UAAQ,OAAM;AAAA,UAAQ,WAAW,oBAAC,cAAA,EAAa,UAAS,QAAA,CAAQ;AAAA,UAAI,SAAS;AAAA,UAC5F,OAAO,EAAC,YAAY,EAAA;AAAA,UACvB,YAAE,gBAAgB;AAAA,QAAA;AAAA,MAAA;AAAA,IACvB,GACJ;AAAA,IAEC,MAAM,SAAS,KACZ,oBAAC,eAAA,EACI,UAAA,MAAM,IAAI,CAAC,EAAC,IAAI,OAAO,SAAA,0BACnB,KAAA,EAAa,OAAc,OAAM,WAAU,UAAoB,IAAI,EAAC,MAAM,WAAA,KAAjE,EAA8E,CAC3F,EAAA,CACL;AAAA,EAAA,GAER;AAER;"}
@@ -7,6 +7,7 @@ import TextField from "@mui/material/TextField";
7
7
  import Typography from "@mui/material/Typography";
8
8
  import { useFormatters } from "../toolkit/useFormatters.js";
9
9
  import { piecePart, usePieceProps } from "../theme/themePieces.js";
10
+ import { warnUnknownProps } from "../toolkit/unknownProps.js";
10
11
  const THEME_NAME = "CalcitaGoToPage";
11
12
  const GoToRoot = piecePart(THEME_NAME, "Root", Stack);
12
13
  const GoToField = piecePart(THEME_NAME, "Field", Autocomplete);
@@ -21,7 +22,8 @@ function filterPages(pageNumbers, { inputValue }) {
21
22
  return [...startingWith, ...containing].slice(0, RENDER_LIMIT);
22
23
  }
23
24
  function GoToPage(props) {
24
- const { page, pageCount, onChange, texts } = usePieceProps(props, THEME_NAME);
25
+ const { page, pageCount, onChange, texts, ...unknownProps } = usePieceProps(props, THEME_NAME);
26
+ warnUnknownProps(THEME_NAME, unknownProps);
25
27
  const { t } = useToolkitTranslation("table", texts);
26
28
  const { formatNumber } = useFormatters();
27
29
  if (pageCount <= 1) {
@@ -1 +1 @@
1
- {"version":3,"file":"GoToPage.js","sources":["../../src/DataTable/GoToPage.jsx"],"sourcesContent":["// \"Ir a la página N\", como un selector con búsqueda.\n//\n// Con cientos de páginas, llegar a la 137 a punta de flechita no es navegar. Un Autocomplete dice las tres cosas sin\n// explicarlas: se abre y se ve la lista, se teclea y se filtra, se elige y ya.\n//\n// Tres detalles:\n// 1. la lista se recorta a RENDER_LIMIT opciones en el DOM; lo demás se alcanza tecleando;\n// 2. filtra por PREFIJO primero (teclear 13 da 13, 130, 131...) y luego por \"contiene\";\n// 3. con una sola página no se pinta: sería un control que no lleva a ningún lado.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaGoToPage con defaultProps y\n// styleOverrides de sus partes: root, field.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport Autocomplete from '@mui/material/Autocomplete';\nimport Stack from '@mui/material/Stack';\nimport TextField from '@mui/material/TextField';\nimport Typography from '@mui/material/Typography';\n\nimport {useFormatters} from '@/toolkit/useFormatters.js';\nimport {piecePart, usePieceProps} from '@/theme/themePieces.js';\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaGoToPage)\nconst THEME_NAME = 'CalcitaGoToPage';\nconst GoToRoot = piecePart(THEME_NAME, 'Root', Stack);\nconst GoToField = piecePart(THEME_NAME, 'Field', Autocomplete);\n\n// tope del DOM, no de la navegación\nconst RENDER_LIMIT = 100;\n\nfunction filterPages(pageNumbers, {inputValue}) {\n const typedText = inputValue.trim();\n if (!typedText) {\n return pageNumbers.slice(0, RENDER_LIMIT);\n }\n const startingWith = pageNumbers.filter((pageNumber) => String(pageNumber).startsWith(typedText));\n const containing = pageNumbers.filter((pageNumber) => !String(pageNumber).startsWith(typedText) && String(pageNumber).includes(typedText));\n return [...startingWith, ...containing].slice(0, RENDER_LIMIT);\n}\n\n/**\n * @param {object} props\n * @param {number} props.page cuenta desde 0\n * @param {number} props.pageCount\n * @param {(page: number) => void} props.onChange\n * @param {object} [props.texts] los textos que cambian, con la forma de `table` en los textos del paquete\n */\nexport default function GoToPage(props) {\n // lo que el proyecto puso en su tema (components.CalcitaGoToPage.defaultProps) y encima lo que llega aquí\n const {page, pageCount, onChange, texts} = usePieceProps(props, THEME_NAME);\n const {t} = useToolkitTranslation('table', texts);\n const {formatNumber} = useFormatters();\n\n // guard clause: con una página no hay a dónde ir\n if (pageCount <= 1) {\n return null;\n }\n\n // la persona cuenta desde 1 y el estado de la tabla desde 0: la conversión vive AQUÍ y en ningún otro lado\n const pageNumbers = Array.from({length: pageCount}, (unused, position) => position + 1);\n\n return (\n <GoToRoot direction=\"row\" spacing={0.75} ownSx={{alignItems: 'baseline'}}>\n <Typography variant=\"body2\" color=\"text.secondary\" noWrap>{t('goToPage.page')}</Typography>\n <GoToField\n size=\"small\"\n disableClearable\n openOnFocus\n autoHighlight\n options={pageNumbers}\n filterOptions={filterPages}\n value={page + 1}\n isOptionEqualToValue={(option, selectedValue) => option === selectedValue}\n getOptionLabel={(option) => String(option)}\n onChange={(event, selectedPageNumber) => {\n if (selectedPageNumber !== null && selectedPageNumber - 1 !== page) {\n onChange(selectedPageNumber - 1);\n }\n }}\n ownSx={{width: 78, '& .MuiAutocomplete-endAdornment': {right: 0}}}\n slotProps={{listbox: {sx: {maxHeight: 240}}}}\n renderInput={(params) => (\n <TextField {...params} variant=\"standard\"\n slotProps={{htmlInput: {...params.inputProps, inputMode: 'numeric', 'aria-label': t('goToPage.ariaLabel')}}} />\n )}\n />\n <Typography variant=\"body2\" color=\"text.secondary\" noWrap>\n {t('goToPage.of', {count: pageCount, total: formatNumber(pageCount)})}\n </Typography>\n </GoToRoot>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;AAwBA,MAAM,aAAa;AACnB,MAAM,WAAW,UAAU,YAAY,QAAQ,KAAK;AACpD,MAAM,YAAY,UAAU,YAAY,SAAS,YAAY;AAG7D,MAAM,eAAe;AAErB,SAAS,YAAY,aAAa,EAAC,cAAa;AAC5C,QAAM,YAAY,WAAW,KAAA;AAC7B,MAAI,CAAC,WAAW;AACZ,WAAO,YAAY,MAAM,GAAG,YAAY;AAAA,EAC5C;AACA,QAAM,eAAe,YAAY,OAAO,CAAC,eAAe,OAAO,UAAU,EAAE,WAAW,SAAS,CAAC;AAChG,QAAM,aAAa,YAAY,OAAO,CAAC,eAAe,CAAC,OAAO,UAAU,EAAE,WAAW,SAAS,KAAK,OAAO,UAAU,EAAE,SAAS,SAAS,CAAC;AACzI,SAAO,CAAC,GAAG,cAAc,GAAG,UAAU,EAAE,MAAM,GAAG,YAAY;AACjE;AASA,SAAwB,SAAS,OAAO;AAEpC,QAAM,EAAC,MAAM,WAAW,UAAU,UAAS,cAAc,OAAO,UAAU;AAC1E,QAAM,EAAC,EAAA,IAAK,sBAAsB,SAAS,KAAK;AAChD,QAAM,EAAC,aAAA,IAAgB,cAAA;AAGvB,MAAI,aAAa,GAAG;AAChB,WAAO;AAAA,EACX;AAGA,QAAM,cAAc,MAAM,KAAK,EAAC,QAAQ,UAAA,GAAY,CAAC,QAAQ,aAAa,WAAW,CAAC;AAEtF,SACI,qBAAC,UAAA,EAAS,WAAU,OAAM,SAAS,MAAM,OAAO,EAAC,YAAY,WAAA,GACzD,UAAA;AAAA,IAAA,oBAAC,YAAA,EAAW,SAAQ,SAAQ,OAAM,kBAAiB,QAAM,MAAE,UAAA,EAAE,eAAe,EAAA,CAAE;AAAA,IAC9E;AAAA,MAAC;AAAA,MAAA;AAAA,QACG,MAAK;AAAA,QACL,kBAAgB;AAAA,QAChB,aAAW;AAAA,QACX,eAAa;AAAA,QACb,SAAS;AAAA,QACT,eAAe;AAAA,QACf,OAAO,OAAO;AAAA,QACd,sBAAsB,CAAC,QAAQ,kBAAkB,WAAW;AAAA,QAC5D,gBAAgB,CAAC,WAAW,OAAO,MAAM;AAAA,QACzC,UAAU,CAAC,OAAO,uBAAuB;AACrC,cAAI,uBAAuB,QAAQ,qBAAqB,MAAM,MAAM;AAChE,qBAAS,qBAAqB,CAAC;AAAA,UACnC;AAAA,QACJ;AAAA,QACA,OAAO,EAAC,OAAO,IAAI,mCAAmC,EAAC,OAAO,IAAC;AAAA,QAC/D,WAAW,EAAC,SAAS,EAAC,IAAI,EAAC,WAAW,IAAA,IAAI;AAAA,QAC1C,aAAa,CAAC,WACV;AAAA,UAAC;AAAA,UAAA;AAAA,YAAW,GAAG;AAAA,YAAQ,SAAQ;AAAA,YACpB,WAAW,EAAC,WAAW,EAAC,GAAG,OAAO,YAAY,WAAW,WAAW,cAAc,EAAE,oBAAoB,IAAC;AAAA,UAAC;AAAA,QAAA;AAAA,MAAG;AAAA,IAAA;AAAA,wBAG/H,YAAA,EAAW,SAAQ,SAAQ,OAAM,kBAAiB,QAAM,MACpD,UAAA,EAAE,eAAe,EAAC,OAAO,WAAW,OAAO,aAAa,SAAS,EAAA,CAAE,EAAA,CACxE;AAAA,EAAA,GACJ;AAER;"}
1
+ {"version":3,"file":"GoToPage.js","sources":["../../src/DataTable/GoToPage.jsx"],"sourcesContent":["// \"Ir a la página N\", como un selector con búsqueda.\n//\n// Con cientos de páginas, llegar a la 137 a punta de flechita no es navegar. Un Autocomplete dice las tres cosas sin\n// explicarlas: se abre y se ve la lista, se teclea y se filtra, se elige y ya.\n//\n// Tres detalles:\n// 1. la lista se recorta a RENDER_LIMIT opciones en el DOM; lo demás se alcanza tecleando;\n// 2. filtra por PREFIJO primero (teclear 13 da 13, 130, 131...) y luego por \"contiene\";\n// 3. con una sola página no se pinta: sería un control que no lleva a ningún lado.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaGoToPage con defaultProps y\n// styleOverrides de sus partes: root, field.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport Autocomplete from '@mui/material/Autocomplete';\nimport Stack from '@mui/material/Stack';\nimport TextField from '@mui/material/TextField';\nimport Typography from '@mui/material/Typography';\n\nimport {useFormatters} from '@/toolkit/useFormatters.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.CalcitaGoToPage)\nconst THEME_NAME = 'CalcitaGoToPage';\nconst GoToRoot = piecePart(THEME_NAME, 'Root', Stack);\nconst GoToField = piecePart(THEME_NAME, 'Field', Autocomplete);\n\n// tope del DOM, no de la navegación\nconst RENDER_LIMIT = 100;\n\nfunction filterPages(pageNumbers, {inputValue}) {\n const typedText = inputValue.trim();\n if (!typedText) {\n return pageNumbers.slice(0, RENDER_LIMIT);\n }\n const startingWith = pageNumbers.filter((pageNumber) => String(pageNumber).startsWith(typedText));\n const containing = pageNumbers.filter((pageNumber) => !String(pageNumber).startsWith(typedText) && String(pageNumber).includes(typedText));\n return [...startingWith, ...containing].slice(0, RENDER_LIMIT);\n}\n\n/**\n * @param {object} props\n * @param {number} props.page cuenta desde 0\n * @param {number} props.pageCount\n * @param {(page: number) => void} props.onChange\n * @param {object} [props.texts] los textos que cambian, con la forma de `table` en los textos del paquete\n */\nexport default function GoToPage(props) {\n // lo que el proyecto puso en su tema (components.CalcitaGoToPage.defaultProps) y encima lo que llega aquí\n const {page, pageCount, onChange, texts, ...unknownProps} = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n const {t} = useToolkitTranslation('table', texts);\n const {formatNumber} = useFormatters();\n\n // guard clause: con una página no hay a dónde ir\n if (pageCount <= 1) {\n return null;\n }\n\n // la persona cuenta desde 1 y el estado de la tabla desde 0: la conversión vive AQUÍ y en ningún otro lado\n const pageNumbers = Array.from({length: pageCount}, (unused, position) => position + 1);\n\n return (\n <GoToRoot direction=\"row\" spacing={0.75} ownSx={{alignItems: 'baseline'}}>\n <Typography variant=\"body2\" color=\"text.secondary\" noWrap>{t('goToPage.page')}</Typography>\n <GoToField\n size=\"small\"\n disableClearable\n openOnFocus\n autoHighlight\n options={pageNumbers}\n filterOptions={filterPages}\n value={page + 1}\n isOptionEqualToValue={(option, selectedValue) => option === selectedValue}\n getOptionLabel={(option) => String(option)}\n onChange={(event, selectedPageNumber) => {\n if (selectedPageNumber !== null && selectedPageNumber - 1 !== page) {\n onChange(selectedPageNumber - 1);\n }\n }}\n ownSx={{width: 78, '& .MuiAutocomplete-endAdornment': {right: 0}}}\n slotProps={{listbox: {sx: {maxHeight: 240}}}}\n renderInput={(params) => (\n <TextField {...params} variant=\"standard\"\n slotProps={{htmlInput: {...params.inputProps, inputMode: 'numeric', 'aria-label': t('goToPage.ariaLabel')}}} />\n )}\n />\n <Typography variant=\"body2\" color=\"text.secondary\" noWrap>\n {t('goToPage.of', {count: pageCount, total: formatNumber(pageCount)})}\n </Typography>\n </GoToRoot>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;AAyBA,MAAM,aAAa;AACnB,MAAM,WAAW,UAAU,YAAY,QAAQ,KAAK;AACpD,MAAM,YAAY,UAAU,YAAY,SAAS,YAAY;AAG7D,MAAM,eAAe;AAErB,SAAS,YAAY,aAAa,EAAC,cAAa;AAC5C,QAAM,YAAY,WAAW,KAAA;AAC7B,MAAI,CAAC,WAAW;AACZ,WAAO,YAAY,MAAM,GAAG,YAAY;AAAA,EAC5C;AACA,QAAM,eAAe,YAAY,OAAO,CAAC,eAAe,OAAO,UAAU,EAAE,WAAW,SAAS,CAAC;AAChG,QAAM,aAAa,YAAY,OAAO,CAAC,eAAe,CAAC,OAAO,UAAU,EAAE,WAAW,SAAS,KAAK,OAAO,UAAU,EAAE,SAAS,SAAS,CAAC;AACzI,SAAO,CAAC,GAAG,cAAc,GAAG,UAAU,EAAE,MAAM,GAAG,YAAY;AACjE;AASA,SAAwB,SAAS,OAAO;AAEpC,QAAM,EAAC,MAAM,WAAW,UAAU,OAAO,GAAG,iBAAgB,cAAc,OAAO,UAAU;AAC3F,mBAAiB,YAAY,YAAY;AACzC,QAAM,EAAC,EAAA,IAAK,sBAAsB,SAAS,KAAK;AAChD,QAAM,EAAC,aAAA,IAAgB,cAAA;AAGvB,MAAI,aAAa,GAAG;AAChB,WAAO;AAAA,EACX;AAGA,QAAM,cAAc,MAAM,KAAK,EAAC,QAAQ,UAAA,GAAY,CAAC,QAAQ,aAAa,WAAW,CAAC;AAEtF,SACI,qBAAC,UAAA,EAAS,WAAU,OAAM,SAAS,MAAM,OAAO,EAAC,YAAY,WAAA,GACzD,UAAA;AAAA,IAAA,oBAAC,YAAA,EAAW,SAAQ,SAAQ,OAAM,kBAAiB,QAAM,MAAE,UAAA,EAAE,eAAe,EAAA,CAAE;AAAA,IAC9E;AAAA,MAAC;AAAA,MAAA;AAAA,QACG,MAAK;AAAA,QACL,kBAAgB;AAAA,QAChB,aAAW;AAAA,QACX,eAAa;AAAA,QACb,SAAS;AAAA,QACT,eAAe;AAAA,QACf,OAAO,OAAO;AAAA,QACd,sBAAsB,CAAC,QAAQ,kBAAkB,WAAW;AAAA,QAC5D,gBAAgB,CAAC,WAAW,OAAO,MAAM;AAAA,QACzC,UAAU,CAAC,OAAO,uBAAuB;AACrC,cAAI,uBAAuB,QAAQ,qBAAqB,MAAM,MAAM;AAChE,qBAAS,qBAAqB,CAAC;AAAA,UACnC;AAAA,QACJ;AAAA,QACA,OAAO,EAAC,OAAO,IAAI,mCAAmC,EAAC,OAAO,IAAC;AAAA,QAC/D,WAAW,EAAC,SAAS,EAAC,IAAI,EAAC,WAAW,IAAA,IAAI;AAAA,QAC1C,aAAa,CAAC,WACV;AAAA,UAAC;AAAA,UAAA;AAAA,YAAW,GAAG;AAAA,YAAQ,SAAQ;AAAA,YACpB,WAAW,EAAC,WAAW,EAAC,GAAG,OAAO,YAAY,WAAW,WAAW,cAAc,EAAE,oBAAoB,IAAC;AAAA,UAAC;AAAA,QAAA;AAAA,MAAG;AAAA,IAAA;AAAA,wBAG/H,YAAA,EAAW,SAAQ,SAAQ,OAAM,kBAAiB,QAAM,MACpD,UAAA,EAAE,eAAe,EAAC,OAAO,WAAW,OAAO,aAAa,SAAS,EAAA,CAAE,EAAA,CACxE;AAAA,EAAA,GACJ;AAER;"}
@@ -32,6 +32,7 @@ import { materialBackgroundOf } from "../theme/glassSurface.js";
32
32
  import QuickFilters from "../ui/filters/QuickFilters.js";
33
33
  import Tag from "../ui/labels/Tag.js";
34
34
  import { piecePart, usePieceProps } from "../theme/themePieces.js";
35
+ import { warnUnknownProps } from "../toolkit/unknownProps.js";
35
36
  const THEME_NAME = "CalcitaServerTable";
36
37
  const TableToolbar = piecePart(THEME_NAME, "Toolbar", Stack);
37
38
  const TableSummary = piecePart(THEME_NAME, "Summary", Box);
@@ -190,8 +191,10 @@ function ServerTable(props) {
190
191
  onLoaded,
191
192
  onLoadError,
192
193
  gridProps,
193
- texts
194
+ texts,
195
+ ...unknownProps
194
196
  } = usePieceProps(props, THEME_NAME);
197
+ warnUnknownProps(THEME_NAME, unknownProps);
195
198
  const { t, language } = useToolkitTranslation("table", texts);
196
199
  const { formatNumber } = useFormatters();
197
200
  const theme = useTheme();