@stackcraftmx/calcita 0.56.0 → 0.58.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 (37) hide show
  1. package/README.md +83 -4
  2. package/dist/DataTable/ServerTableFilterDrawer.js +3 -1
  3. package/dist/DataTable/ServerTableFilterDrawer.js.map +1 -1
  4. package/dist/locales/en.js +15 -0
  5. package/dist/locales/en.js.map +1 -1
  6. package/dist/locales/es.js +15 -0
  7. package/dist/locales/es.js.map +1 -1
  8. package/dist/sortable/FormSortableField.js +27 -0
  9. package/dist/sortable/FormSortableField.js.map +1 -0
  10. package/dist/sortable/SortableTable.js +230 -0
  11. package/dist/sortable/SortableTable.js.map +1 -0
  12. package/dist/sortable/sortableRows.js +14 -0
  13. package/dist/sortable/sortableRows.js.map +1 -0
  14. package/dist/sortable.js +9 -0
  15. package/dist/sortable.js.map +1 -0
  16. package/dist/theme/components/minimalComponents.js +15 -0
  17. package/dist/theme/components/minimalComponents.js.map +1 -1
  18. package/dist/theme/glassSurface.js +10 -12
  19. package/dist/theme/glassSurface.js.map +1 -1
  20. package/dist/theme/themePieces.js +10 -4
  21. package/dist/theme/themePieces.js.map +1 -1
  22. package/dist/types/DataTable/ServerTableFilterDrawer.d.ts +2 -0
  23. package/dist/types/downloads/fileTypes.d.ts +4 -4
  24. package/dist/types/forms/SubmitButton.d.ts +1 -1
  25. package/dist/types/locales/en.d.ts +15 -0
  26. package/dist/types/locales/es.d.ts +15 -0
  27. package/dist/types/sortable/FormSortableField.d.ts +15 -0
  28. package/dist/types/sortable/SortableTable.d.ts +77 -0
  29. package/dist/types/sortable/sortableRows.d.ts +12 -0
  30. package/dist/types/sortable.d.ts +3 -0
  31. package/dist/types/ui/filters/FilterDrawer.d.ts +1 -0
  32. package/dist/types/ui/filters/filterDrawerFields.d.ts +77 -2
  33. package/dist/ui/filters/FilterDrawer.js +118 -53
  34. package/dist/ui/filters/FilterDrawer.js.map +1 -1
  35. package/dist/ui/filters/filterDrawerFields.js +65 -14
  36. package/dist/ui/filters/filterDrawerFields.js.map +1 -1
  37. package/package.json +5 -1
package/README.md CHANGED
@@ -5,8 +5,8 @@ transparente famoso por doblar la luz, y eso es lo que define al vidrio líquido
5
5
 
6
6
  Arranca un proyecto sin copiar y volver a probar lo de siempre: el marco de la app con menú y permisos, tabla de servidor,
7
7
  diálogos de confirmación, avisos, descargas, formularios, formatos de número y fecha, errores RFC 9457, reportes en Excel,
8
- la cuenta completa, mapa, calendario, tablero kanban, bandeja tipo correo y el tema con vidrio líquido, interpretado
9
- componente por componente según la guía de Apple.
8
+ la cuenta completa, mapa, calendario, tablero kanban, listas que se ordenan arrastrando, bandeja tipo correo y el tema con
9
+ vidrio líquido, interpretado componente por componente según la guía de Apple.
10
10
 
11
11
  JavaScript con sus tipos generados: se usa igual desde un proyecto en TypeScript. Sirve para un proyecto nuevo y también
12
12
  para meterlo por pedazos en un sistema que ya existe (ver «En un sistema que ya existe»).
@@ -244,6 +244,7 @@ Cada puerta pide solo sus librerías; un proyecto instala lo que usa.
244
244
  | `@stackcraftmx/calcita/maps` | `MapView`: mapa con marcadores del color del tema, el elegido con su globo, se acomoda solo; en oscuro, mosaicos oscuros | `leaflet`, `react-leaflet` 5 |
245
245
  | `@stackcraftmx/calcita/calendar` | `EventCalendar`: mes, semana, día y lista, con la barra del framework; arrastrar cambia la cita y regresa si el servidor dice que no. `EventDetails`: el detalle de una cita (lugar, liga de la reunión, invitados con su respuesta, recordatorio, notas) | `@fullcalendar/react`, `core`, `daygrid`, `timegrid`, `list`, `interaction` 6.1 |
246
246
  | `@stackcraftmx/calcita/kanban` | `KanbanBoard`: columnas con tope (y que se encogen, como un congelador) y tarjetas de producto (etiquetas, responsables, fecha, pendientes, terminar) que se arrastran con el ratón, el dedo o el teclado; `moveCard` para ver la movida al instante | `@hello-pangea/dnd` 18 |
247
+ | `@stackcraftmx/calcita/sortable` | `SortableTable`: una tabla chica cuyos renglones se arrastran (ratón, dedo o teclado) para ordenarlos, con su columna «Orden»; guarda al soltar (y regresa el renglón si el servidor dice que no) o en un formulario con `FormSortableField`; `moveRow` para mover sin arrastrar | `@hello-pangea/dnd` 18 |
247
248
 
248
249
  ## El tema
249
250
 
@@ -307,6 +308,36 @@ números, de fechas, monto con operador o uno propio); lo que se cambia adentro
307
308
  por filtro (`filterDrawerDefaultsOf`, `filterDrawerKindsOf`, `filterDrawerChipsOf`). Un monto viaja como `gte:500`
308
309
  (`comparisonOf` lo separa en el backend o en la pantalla).
309
310
 
311
+ Las fechas del cajón usan el calendario del navegador, así el cajón no obliga a instalar MUI X. Una app que ya trae
312
+ `/date-pickers` pone el suyo para que el cajón y sus formularios se vean igual: `slots={{dateInput: DateInput}}` en un
313
+ cajón (desde la tabla, `drawerProps`), o una vez en el tema para todas las listas. Un rango de fechas se acota con
314
+ `minDate`, `maxDate`, `disablePast` y `disableFuture`: el calendario no deja escoger fuera y cada extremo acota al otro. Si
315
+ alguien teclea una fecha fuera de los topes o un rango al revés, su campo lo dice y «Buscar» no busca; nada se borra solo.
316
+ Un `custom` con `keys` es un rango propio en un solo campo: guarda en sus dos llaves, cuenta como un filtro, da sus dos chips
317
+ y, con `isBackwards`, tampoco deja buscar al revés. Su `render` recibe todo el borrador (`values`, `setValue`), sus `keys` y
318
+ lo que esté mal en cada una (`errors`), ya dicho. En un cajón angosto, `stackPairsBelow` pone cada par uno arriba del otro.
319
+
320
+ ```jsx
321
+ import {DateInput, TimeInput} from '@stackcraftmx/calcita/date-pickers';
322
+
323
+ const FIELDS = [
324
+ {name: 'paid', label: 'Fecha de pago', kind: FILTER_FIELD_KIND.dateRange, minDate: '2026-01-01', disableFuture: true},
325
+ {
326
+ name: 'hours', label: 'Hora de compra', kind: FILTER_FIELD_KIND.custom, keys: {from: 'hour_from', to: 'hour_to'},
327
+ isBackwards: (from, to) => to < from,
328
+ render: ({values, setValue, keys: [fromKey, toKey], errors}) => (
329
+ <>
330
+ <TimeInput label="Desde" value={values[fromKey]} onChange={(time) => setValue(fromKey, time)} />
331
+ <TimeInput label="Hasta" value={values[toKey]} onChange={(time) => setValue(toKey, time)} error={errors[toKey]} />
332
+ </>
333
+ ),
334
+ },
335
+ ];
336
+
337
+ <ServerTableFilterDrawer fields={FIELDS} width={460} stackPairsBelow={420} drawerProps={{slots: {dateInput: DateInput}}} />
338
+ // o para todas las listas: createTheme({components: {CalcitaFilterDrawer: {defaultProps: {slots: {dateInput: DateInput}}}}})
339
+ ```
340
+
310
341
  ```jsx
311
342
  <BarActions label="Buscar en pedidos" order={1}>
312
343
  <IconButton aria-label="Buscar" onClick={openSearch}><SearchRoundedIcon /></IconButton>
@@ -336,6 +367,16 @@ se pueden escribir en `colorSchemes`.
336
367
  createToolkitTheme({glass: true, fields: {radius: 8, light: {fill: '#FFFFFF', hoverFill: '#FFFFFF', border: '#C4CDD5'}}});
337
368
  ```
338
369
 
370
+ Para cambiar el relleno solo en ciertos campos (los bloqueados, o todos en oscuro con el color de la marca), el tema del
371
+ proyecto pone la variable `--calcita-field-fill` (y `--calcita-field-hover-fill`, `--calcita-field-edge`,
372
+ `--calcita-field-hover-edge`) en el campo o en algo que lo contenga: todos los campos de Calcita la leen, los de
373
+ `FormSection` y los sueltos (un cajón de filtros, una ventana). Ponerle un `backgroundColor` al campo no siempre gana, porque
374
+ las reglas de Calcita llevan selectores largos; con la variable manda la definición más cercana.
375
+
376
+ ```js
377
+ MuiOutlinedInput: {styleOverrides: {root: ({theme}) => theme.applyStyles('dark', {'--calcita-field-fill': '#1E3A5F', '--calcita-field-hover-fill': '#1E3A5F'})}}
378
+ ```
379
+
339
380
  El minimalista separa las superficies por su tono con los grises de Apple. Para pintarlo con los colores de la marca:
340
381
  `minimalTones`, por modo, con el fondo de la página (`default`), las tarjetas (`paper`), el relleno de campos, grupos y
341
382
  botones sin color (`fill`) y lo que flota, como la barra del teléfono (`floating`). Lo que no se pase se queda con el gris
@@ -368,7 +409,8 @@ createTheme({components: {CalcitaRecordCard: {defaultProps: {slotProps: {root: {
368
409
  ```
369
410
 
370
411
  `className`, `style` y `sx` de `slotProps` se suman a los de Calcita; una pieza dentro de otra igual no toma los `slots` de la
371
- de afuera. `TextInput` es la excepción: su `slotProps` es el del `TextField` de MUI (`input`, `htmlInput`…). Una pieza propia
412
+ de afuera. Una parte propia no recibe el estilo de Calcita ni, si la parte es un `Stack`, su acomodo (`spacing`,
413
+ `direction`): eso lo pone ella; lo que la pantalla le dé en `slotProps` sí le llega. `TextInput` es la excepción: su `slotProps` es el del `TextField` de MUI (`input`, `htmlInput`…). Una pieza propia
372
414
  del proyecto se arma con lo mismo: `piecePart`, `usePieceProps` y `withPieceSlots`.
373
415
 
374
416
  El `sx` de la pantalla se **combina regla por regla** con el de la pieza, no la reemplaza: en la tabla,
@@ -429,7 +471,7 @@ Para hacer lo mismo en un componente propio: `sx={[{p: 2}, ...sxListOf(sx)]}` (u
429
471
  | `CalcitaFileInput` | `root`, `button`, `fileChip`, `empty` |
430
472
  | `CalcitaFileUploadInput` | `root`, `fileName`, `status`, `button`, `helper` |
431
473
  | `CalcitaFilterChips` | `root`, `header`, `clearButton` |
432
- | `CalcitaFilterDrawer` | `header`, `body`, `footer` |
474
+ | `CalcitaFilterDrawer` | `header`, `body`, `footer`, `dateInput` |
433
475
  | `CalcitaFontSizeToggle` | `button` |
434
476
  | `CalcitaFormProblemAlert` | `root` |
435
477
  | `CalcitaFormRow` | `root`, `label`, `control` |
@@ -495,6 +537,7 @@ Para hacer lo mismo en un componente propio: `sx={[{p: 2}, ...sxListOf(sx)]}` (u
495
537
  | `CalcitaSignInForm` | `footer` |
496
538
  | `CalcitaSignInScreen` | `alert` |
497
539
  | `CalcitaSortableFilterHeader` | `title`, `root`, `sortButton`, `sortIndicator`, `clearButton` |
540
+ | `CalcitaSortableTable` | `root`, `container`, `table`, `head`, `headerRow`, `headerCell`, `body`, `row`, `handleCell`, `handle`, `positionCell`, `cell`, `empty`, `helperText`, `announcer` |
498
541
  | `CalcitaStackedCell` | `root`, `line`, `label`, `valueRow`, `primary`, `secondary`, `note` |
499
542
  | `CalcitaStatusChip` | `root`, `dot`, `label`, `chip` |
500
543
  | `CalcitaSubmenuActionsMenu` | `badge` |
@@ -682,6 +725,42 @@ const columns = [
682
725
  para decidirlo desde la pantalla.
683
726
  - `gridSx` se combina con los estilos de la tabla regla por regla; `gridProps` pasa lo demás al DataGrid.
684
727
 
728
+ ## Listas que se ordenan (`/sortable`)
729
+
730
+ Para una lista chica donde el orden de los renglones es el dato (qué se surte primero, en qué orden pasa la ruta, qué se
731
+ hace antes): `SortableTable` es una tabla cuyos renglones se arrastran con el ratón, el dedo o el teclado (espacio, flechas,
732
+ espacio), con la columna «Orden» 1..n que se renumera sola. Pide `@hello-pangea/dnd`, la misma del tablero kanban. La tabla
733
+ de servidor no sirve para esto: en MUI X, ordenar renglones arrastrando es de su versión de paga; esta lista va completa en
734
+ el navegador.
735
+
736
+ ```jsx
737
+ import {FormSortableField, SortableTable, moveRow} from '@stackcraftmx/calcita/sortable';
738
+
739
+ // guardar al soltar: si la promesa truena (el servidor dijo que no), el renglón regresa solo a su lugar
740
+ <SortableTable rows={orders} ariaLabel="Orden de surtido" getRowLabel={(order) => order.folio}
741
+ columns={[{field: 'folio', headerName: 'Pedido', width: 120}, {field: 'customer', headerName: 'Cliente', flex: 1}]}
742
+ onReorder={async ({rows}) => {
743
+ await api.put('/packing', rows.map((order, index) => ({order_id: order.id, priority: index + 1})));
744
+ setOrders(rows);
745
+ }} />
746
+
747
+ // en un formulario de formik: el valor del campo es la lista en su orden; al soltar, el formulario queda cambiado
748
+ <FormSortableField name="stops" ariaLabel="Ruta de reparto" columns={columns} />
749
+ // al guardar: values.stops.map((stop, index) => ({branch_id: stop.id, stop: index + 1}))
750
+ ```
751
+
752
+ - `onReorder` recibe los renglones ya en su orden nuevo (`rows`), el id del que se movió y de dónde a dónde (desde 0). Si no
753
+ regresa nada, la pantalla pone los renglones nuevos. Si regresa una promesa, la tabla enseña el orden nuevo al instante,
754
+ no deja mover otro mientras se guarda y, si truena, lo regresa a su lugar y el lector de pantalla lo anuncia.
755
+ - El error de la lista (una regla de yup sobre el arreglo, o el 422 del servidor con `applyServerProblem`) sale abajo de la
756
+ tabla. Con react-hook-form: `SortableTable` dentro de un `Controller` (`rows={field.value}`,
757
+ `onReorder={({rows}) => field.onChange(rows)}`).
758
+ - Las columnas: `width` fijo, o `flex` y `minWidth` para repartirse el espacio libre; abajo de su mínimo, la tabla se desliza
759
+ de lado (en el teléfono). `renderCell(row, {position})` para una celda a la medida. Los renglones conservan su tipo en
760
+ TypeScript.
761
+ - `moveRow(rows, desde, hasta)` mueve sin arrastrar (un botón «Subir» de la pantalla). `showPosition={false}` quita la
762
+ columna «Orden»; `disabled` la deja de solo lectura; `texts` y el tema (`CalcitaSortableTable`) cambian lo demás.
763
+
685
764
  ## Eventos y textos de cada componente
686
765
 
687
766
  Cada componente de la casa avisa hacia afuera todo lo que pasa adentro (`onSelect`, `onChange`, `onViewChange`,
@@ -12,7 +12,7 @@ import { piecePart, withPieceSlots, usePieceProps } from "../theme/themePieces.j
12
12
  const THEME_NAME = "CalcitaServerTableFilterDrawer";
13
13
  const ServerTableFilterDrawerButton = piecePart(THEME_NAME, "Button", Button);
14
14
  function ServerTableFilterDrawerContent(props) {
15
- const { fields, anchor, width, title, buttonLabel, onApply, children, texts, ...unknownProps } = usePieceProps(props, THEME_NAME);
15
+ const { fields, anchor, width, title, buttonLabel, onApply, stackPairsBelow, drawerProps, children, texts, ...unknownProps } = usePieceProps(props, THEME_NAME);
16
16
  warnUnknownProps(THEME_NAME, unknownProps);
17
17
  const { t } = useToolkitTranslation("common", texts);
18
18
  const { filters, setFilters } = useTableFilter();
@@ -33,6 +33,7 @@ function ServerTableFilterDrawerContent(props) {
33
33
  /* @__PURE__ */ jsx(
34
34
  FilterDrawer,
35
35
  {
36
+ ...drawerProps,
36
37
  open: isOpen,
37
38
  onClose: () => setIsOpen(false),
38
39
  fields,
@@ -40,6 +41,7 @@ function ServerTableFilterDrawerContent(props) {
40
41
  anchor,
41
42
  width,
42
43
  title,
44
+ stackPairsBelow,
43
45
  texts,
44
46
  onApply: (values) => {
45
47
  setFilters(values);
@@ -1 +1 @@
1
- {"version":3,"file":"ServerTableFilterDrawer.js","sources":["../../src/DataTable/ServerTableFilterDrawer.jsx"],"sourcesContent":["// El botón «Filtros» de ServerTable con su cajón de búsqueda (FilterDrawer): se pone en toolbarExtra y lee y cambia los\n// filtros de SU tabla (los de la dirección, los mismos de los chips). El botón dice cuántos filtros del cajón hay puestos.\n//\n// const FILTER_FIELDS = [{name: 'total', label: 'Total', kind: FILTER_FIELD_KIND.comparison, prefix: '$'}, …];\n// <ServerTable … filterDefaults={{...MIS_DEFAULTS, ...filterDrawerDefaultsOf(FILTER_FIELDS)}}\n// filterKinds={{...MIS_KINDS, ...filterDrawerKindsOf(FILTER_FIELDS)}}\n// chipConfig={buildChipConfig(filterDrawerChipsOf(FILTER_FIELDS, {t, formatDate}))}\n// toolbarExtra={<ServerTableFilterDrawer fields={FILTER_FIELDS} />} />\n//\n// filterDefaults: la tabla solo guarda en la dirección lo que declara ahí. filterKinds: las listas se leen como lista. Los\n// chips dicen cada filtro en palabras y cada uno se quita con su ×.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaServerTableFilterDrawer con defaultProps, styleOverrides de\n// sus partes (button) y slots/slotProps para cambiarlas.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useState} from 'react';\nimport Button from '@mui/material/Button';\nimport TuneRoundedIcon from '@mui/icons-material/TuneRounded';\n\nimport {useTableFilter} from '@/DataTable/filterContext.js';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\nimport FilterDrawer from '@/ui/filters/FilterDrawer.jsx';\nimport {activeDrawerFilterCountOf} from '@/ui/filters/filterDrawerFields.js';\nimport {piecePart, usePieceProps, withPieceSlots} from '@/theme/themePieces.js';\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaServerTableFilterDrawer)\nconst THEME_NAME = 'CalcitaServerTableFilterDrawer';\nconst ServerTableFilterDrawerButton = piecePart(THEME_NAME, 'Button', Button);\n\n/**\n * @param {object} props\n * @param {object[]} props.fields los campos del cajón (filterDrawerFields.js)\n * @param {'left'|'right'} [props.anchor] de qué lado sale; por omisión la derecha\n * @param {number} [props.width] su ancho en escritorio\n * @param {string} [props.title] ya traducido; por omisión «Filtros»\n * @param {string} [props.buttonLabel] ya traducido; por omisión «Filtros» (con los puestos, «Filtros (3)»)\n * @param {(values: Record<string, unknown>) => void} [props.onApply] aviso de lo que se buscó (la tabla ya se filtró)\n * @param {import('react').ReactNode} [props.children] algo más abajo de los campos del cajón\n * @param {object} [props.texts] los textos que cambian, con la forma de `common` en los textos del paquete\n */\nfunction ServerTableFilterDrawerContent(props) {\n const {fields, anchor, width, title, buttonLabel, onApply, children, texts, ...unknownProps} = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n const {t} = useToolkitTranslation('common', texts);\n const {filters, setFilters} = useTableFilter();\n const [isOpen, setIsOpen] = useState(false);\n const activeCount = activeDrawerFilterCountOf(fields, filters);\n\n return (\n <>\n <ServerTableFilterDrawerButton size=\"small\" variant={activeCount > 0 ? 'contained' : 'outlined'} startIcon={<TuneRoundedIcon />}\n aria-haspopup=\"dialog\" onClick={() => setIsOpen(true)}>\n {activeCount > 0 ? t('filterDrawer.openWithCount', {count: activeCount}) : (buttonLabel ?? t('filterDrawer.open'))}\n </ServerTableFilterDrawerButton>\n <FilterDrawer open={isOpen} onClose={() => setIsOpen(false)} fields={fields} values={filters} anchor={anchor} width={width} title={title}\n texts={texts}\n onApply={(values) => {\n setFilters(values);\n onApply?.(values);\n }}>\n {children}\n </FilterDrawer>\n </>\n );\n}\n\n// lo que se exporta: la pieza con slots y slotProps para cambiar sus partes (themePieces.js)\nconst ServerTableFilterDrawer = withPieceSlots(ServerTableFilterDrawerContent, THEME_NAME);\nexport default ServerTableFilterDrawer;\n"],"names":[],"mappings":";;;;;;;;;;;AA4BA,MAAM,aAAa;AACnB,MAAM,gCAAgC,UAAU,YAAY,UAAU,MAAM;AAa5E,SAAS,+BAA+B,OAAO;AAC3C,QAAM,EAAC,QAAQ,QAAQ,OAAO,OAAO,aAAa,SAAS,UAAU,OAAO,GAAG,aAAA,IAAgB,cAAc,OAAO,UAAU;AAC9H,mBAAiB,YAAY,YAAY;AACzC,QAAM,EAAC,EAAA,IAAK,sBAAsB,UAAU,KAAK;AACjD,QAAM,EAAC,SAAS,WAAA,IAAc,eAAA;AAC9B,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAS,KAAK;AAC1C,QAAM,cAAc,0BAA0B,QAAQ,OAAO;AAE7D,SACI,qBAAA,UAAA,EACI,UAAA;AAAA,IAAA;AAAA,MAAC;AAAA,MAAA;AAAA,QAA8B,MAAK;AAAA,QAAQ,SAAS,cAAc,IAAI,cAAc;AAAA,QAAY,+BAAY,iBAAA,EAAgB;AAAA,QACrH,iBAAc;AAAA,QAAS,SAAS,MAAM,UAAU,IAAI;AAAA,QACvD,UAAA,cAAc,IAAI,EAAE,8BAA8B,EAAC,OAAO,YAAA,CAAY,IAAK,eAAe,EAAE,mBAAmB;AAAA,MAAA;AAAA,IAAA;AAAA,IAEpH;AAAA,MAAC;AAAA,MAAA;AAAA,QAAa,MAAM;AAAA,QAAQ,SAAS,MAAM,UAAU,KAAK;AAAA,QAAG;AAAA,QAAgB,QAAQ;AAAA,QAAS;AAAA,QAAgB;AAAA,QAAc;AAAA,QAC9G;AAAA,QACA,SAAS,CAAC,WAAW;AACjB,qBAAW,MAAM;AACjB,oBAAU,MAAM;AAAA,QACpB;AAAA,QACT;AAAA,MAAA;AAAA,IAAA;AAAA,EACL,GACJ;AAER;AAGA,MAAM,0BAA0B,eAAe,gCAAgC,UAAU;"}
1
+ {"version":3,"file":"ServerTableFilterDrawer.js","sources":["../../src/DataTable/ServerTableFilterDrawer.jsx"],"sourcesContent":["// El botón «Filtros» de ServerTable con su cajón de búsqueda (FilterDrawer): se pone en toolbarExtra y lee y cambia los\n// filtros de SU tabla (los de la dirección, los mismos de los chips). El botón dice cuántos filtros del cajón hay puestos.\n//\n// const FILTER_FIELDS = [{name: 'total', label: 'Total', kind: FILTER_FIELD_KIND.comparison, prefix: '$'}, …];\n// <ServerTable … filterDefaults={{...MIS_DEFAULTS, ...filterDrawerDefaultsOf(FILTER_FIELDS)}}\n// filterKinds={{...MIS_KINDS, ...filterDrawerKindsOf(FILTER_FIELDS)}}\n// chipConfig={buildChipConfig(filterDrawerChipsOf(FILTER_FIELDS, {t, formatDate}))}\n// toolbarExtra={<ServerTableFilterDrawer fields={FILTER_FIELDS} />} />\n//\n// filterDefaults: la tabla solo guarda en la dirección lo que declara ahí. filterKinds: las listas se leen como lista. Los\n// chips dicen cada filtro en palabras y cada uno se quita con su ×.\n//\n// Lo demás del cajón (su calendario propio, sus partes) va en drawerProps: <ServerTableFilterDrawer fields={…}\n// drawerProps={{slots: {dateInput: DateInput}}} />. Los slots de aquí son del botón.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaServerTableFilterDrawer con defaultProps, styleOverrides de\n// sus partes (button) y slots/slotProps para cambiarlas.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useState} from 'react';\nimport Button from '@mui/material/Button';\nimport TuneRoundedIcon from '@mui/icons-material/TuneRounded';\n\nimport {useTableFilter} from '@/DataTable/filterContext.js';\nimport {useToolkitTranslation} from '@/toolkit/useToolkitTranslation.js';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\nimport FilterDrawer from '@/ui/filters/FilterDrawer.jsx';\nimport {activeDrawerFilterCountOf} from '@/ui/filters/filterDrawerFields.js';\nimport {piecePart, usePieceProps, withPieceSlots} from '@/theme/themePieces.js';\n\n// el nombre de la pieza en el tema y sus partes (theme.components.CalcitaServerTableFilterDrawer)\nconst THEME_NAME = 'CalcitaServerTableFilterDrawer';\nconst ServerTableFilterDrawerButton = piecePart(THEME_NAME, 'Button', Button);\n\n/**\n * @param {object} props\n * @param {object[]} props.fields los campos del cajón (filterDrawerFields.js)\n * @param {'left'|'right'} [props.anchor] de qué lado sale; por omisión la derecha\n * @param {number} [props.width] su ancho en escritorio\n * @param {string} [props.title] ya traducido; por omisión «Filtros»\n * @param {string} [props.buttonLabel] ya traducido; por omisión «Filtros» (con los puestos, «Filtros (3)»)\n * @param {(values: Record<string, unknown>) => void} [props.onApply] aviso de lo que se buscó (la tabla ya se filtró)\n * @param {number} [props.stackPairsBelow] en px: si el cajón mide menos, cada par («desde» y «hasta») va uno arriba del otro\n * @param {object} [props.drawerProps] lo demás de FilterDrawer: slots (dateInput, body…), slotProps, applyLabel, closeOnApply\n * @param {import('react').ReactNode} [props.children] algo más abajo de los campos del cajón\n * @param {object} [props.texts] los textos que cambian, con la forma de `common` en los textos del paquete\n */\nfunction ServerTableFilterDrawerContent(props) {\n const {fields, anchor, width, title, buttonLabel, onApply, stackPairsBelow, drawerProps, children, texts, ...unknownProps} = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n const {t} = useToolkitTranslation('common', texts);\n const {filters, setFilters} = useTableFilter();\n const [isOpen, setIsOpen] = useState(false);\n const activeCount = activeDrawerFilterCountOf(fields, filters);\n\n return (\n <>\n <ServerTableFilterDrawerButton size=\"small\" variant={activeCount > 0 ? 'contained' : 'outlined'} startIcon={<TuneRoundedIcon />}\n aria-haspopup=\"dialog\" onClick={() => setIsOpen(true)}>\n {activeCount > 0 ? t('filterDrawer.openWithCount', {count: activeCount}) : (buttonLabel ?? t('filterDrawer.open'))}\n </ServerTableFilterDrawerButton>\n <FilterDrawer {...drawerProps} open={isOpen} onClose={() => setIsOpen(false)} fields={fields} values={filters} anchor={anchor} width={width}\n title={title} stackPairsBelow={stackPairsBelow} texts={texts}\n onApply={(values) => {\n setFilters(values);\n onApply?.(values);\n }}>\n {children}\n </FilterDrawer>\n </>\n );\n}\n\n// lo que se exporta: la pieza con slots y slotProps para cambiar sus partes (themePieces.js)\nconst ServerTableFilterDrawer = withPieceSlots(ServerTableFilterDrawerContent, THEME_NAME);\nexport default ServerTableFilterDrawer;\n"],"names":[],"mappings":";;;;;;;;;;;AA+BA,MAAM,aAAa;AACnB,MAAM,gCAAgC,UAAU,YAAY,UAAU,MAAM;AAe5E,SAAS,+BAA+B,OAAO;AAC3C,QAAM,EAAC,QAAQ,QAAQ,OAAO,OAAO,aAAa,SAAS,iBAAiB,aAAa,UAAU,OAAO,GAAG,aAAA,IAAgB,cAAc,OAAO,UAAU;AAC5J,mBAAiB,YAAY,YAAY;AACzC,QAAM,EAAC,EAAA,IAAK,sBAAsB,UAAU,KAAK;AACjD,QAAM,EAAC,SAAS,WAAA,IAAc,eAAA;AAC9B,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAS,KAAK;AAC1C,QAAM,cAAc,0BAA0B,QAAQ,OAAO;AAE7D,SACI,qBAAA,UAAA,EACI,UAAA;AAAA,IAAA;AAAA,MAAC;AAAA,MAAA;AAAA,QAA8B,MAAK;AAAA,QAAQ,SAAS,cAAc,IAAI,cAAc;AAAA,QAAY,+BAAY,iBAAA,EAAgB;AAAA,QACrH,iBAAc;AAAA,QAAS,SAAS,MAAM,UAAU,IAAI;AAAA,QACvD,UAAA,cAAc,IAAI,EAAE,8BAA8B,EAAC,OAAO,YAAA,CAAY,IAAK,eAAe,EAAE,mBAAmB;AAAA,MAAA;AAAA,IAAA;AAAA,IAEpH;AAAA,MAAC;AAAA,MAAA;AAAA,QAAc,GAAG;AAAA,QAAa,MAAM;AAAA,QAAQ,SAAS,MAAM,UAAU,KAAK;AAAA,QAAG;AAAA,QAAgB,QAAQ;AAAA,QAAS;AAAA,QAAgB;AAAA,QACjH;AAAA,QAAc;AAAA,QAAkC;AAAA,QAChD,SAAS,CAAC,WAAW;AACjB,qBAAW,MAAM;AACjB,oBAAU,MAAM;AAAA,QACpB;AAAA,QACT;AAAA,MAAA;AAAA,IAAA;AAAA,EACL,GACJ;AAER;AAGA,MAAM,0BAA0B,eAAe,gCAAgC,UAAU;"}
@@ -214,6 +214,8 @@ const en = Object.freeze({
214
214
  "lte": "At most"
215
215
  },
216
216
  "rangeBackwards": "It must be equal to or greater than «From».",
217
+ "dateBeforeMin": "It cannot be before {{date}}.",
218
+ "dateAfterMax": "It cannot be after {{date}}.",
217
219
  "chipFrom": "{{label}} from",
218
220
  "chipTo": "{{label}} to"
219
221
  },
@@ -955,6 +957,19 @@ const en = Object.freeze({
955
957
  "emptyFiltered": "No card here matches the search.",
956
958
  "empty": "No cards. Drag one here."
957
959
  },
960
+ "sortableTable": {
961
+ "instructions": "To move a row with the keyboard: space to lift it, up and down arrows to move it and space to drop it. Escape leaves it where it was.",
962
+ "handleHeader": "Move",
963
+ "handle": "Move “{{title}}”, position {{position}}",
964
+ "position": "Order",
965
+ "lifted": "You lifted “{{title}}”, position {{position}} of {{total}}.",
966
+ "moving": "Going to position {{position}} of {{total}}.",
967
+ "dropped": "You dropped “{{title}}” in position {{position}} of {{total}}.",
968
+ "cancelled": "“{{title}}” stayed in position {{position}}.",
969
+ "reverted": "“{{title}}” could not be moved: it went back to position {{position}}.",
970
+ "empty": "No rows.",
971
+ "noValue": "—"
972
+ },
958
973
  "inbox": {
959
974
  "labels": "Labels",
960
975
  "select": "Select “{{subject}}”",