innoboxrr-form-core 2.5.1 → 2.7.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.
package/README.md CHANGED
@@ -65,7 +65,9 @@ setTheme({
65
65
  | Menús | `menu`, `menuList`, `menuItem`, `menuItemDanger`, `menuSeparator`, `menuLabel` |
66
66
  | Paleta de comandos | `command`, `commandInput`, `commandList`, `commandGroup`, `commandItem`, `commandEmpty` |
67
67
  | Avisos | `toast`, `toastSuccess`, `toastDanger`, `toastWarning`, `toastTitle`, `toastClose`, `toastRegion` |
68
- | Tabla | `table`, `tableNumeric`, `tableSticky`, `tableSelect`, `tableResizer`, `tableEmpty`, `bulkBar`, `bulkCount` |
68
+ | Tabla | `table`, `tableNumeric`, `tableSticky`, `tableSelect`, `tableResizer`, `tableEmpty`, `bulkBar`, `bulkCount`, `tableSort`, `tableContainer`, `tableFooter`, `tablePager` |
69
+ | Listado | `datatable`, `datatableFilters`, `toolbarSpacer` |
70
+ | Campos compuestos | `fileDrop`, `fileDropHint`, `avatarPreview`, `codeInput`, `codeCell`, `group`, `groupTitle`, `dragHandle`, `iconButtonDanger` |
69
71
  | Edición en línea | `editable` |
70
72
  | Shell de aplicación | `shell`, `shellHeader`, `shellSidebar`, `shellMain` |
71
73
 
@@ -113,7 +115,16 @@ Los componentes de Vue y React envuelven exactamente este marcado.
113
115
  - **Menús**: `fe-menu` con `popover`, colocado con Floating UI.
114
116
  - **Tabla**: `fe-table-select` para la columna de casillas, `data-selected` en
115
117
  la fila, `fe-bulk-bar` para lo que se hace con la selección y
116
- `fe-table-resizer` para cambiar el ancho de una columna.
118
+ `fe-table-resizer` para cambiar el ancho de una columna. Una columna
119
+ ordenable lleva `aria-sort` en el `<th>` y dentro un `<button
120
+ class="fe-table-sort">`, para que se ordene también con el teclado.
121
+ - **Listado**: `fe-datatable` agrupa la `fe-toolbar` (con un
122
+ `fe-toolbar-spacer` que empuja lo que va a la derecha), el panel
123
+ `fe-datatable-filters`, la tabla dentro de un `fe-table-container` y el
124
+ `fe-table-footer` con el resumen y el `fe-table-pager`. El contenedor se
125
+ desplaza en horizontal cuando la tabla no cabe; para que además la cabecera
126
+ fija funcione al bajar, dale una altura máxima con
127
+ `--fe-table-max-height: 70vh`.
117
128
 
118
129
  Un `<dialog>` cerrado está oculto porque el navegador le pone `display: none`;
119
130
  por eso ninguna regla fija `display` fuera del estado `[open]`. Las capas que no
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "innoboxrr-form-core",
3
- "version": "2.5.1",
3
+ "version": "2.7.0",
4
4
  "description": "El nucleo agnostico de la interfaz innoboxrr: tema, iconos, estilos, archivos y zonas horarias.",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -1166,6 +1166,235 @@
1166
1166
  font-variant-numeric: tabular-nums;
1167
1167
  }
1168
1168
 
1169
+ /*
1170
+ * Ordenar tiene que poderse hacer con el teclado, así que dentro del <th> va
1171
+ * un botón. Hereda todo de la cabecera para no parecer un botón del navegador.
1172
+ */
1173
+ .fe-table-sort {
1174
+ display: inline-flex;
1175
+ align-items: center;
1176
+ gap: var(--fe-space-1);
1177
+ padding: 0;
1178
+ font: inherit;
1179
+ letter-spacing: inherit;
1180
+ text-transform: inherit;
1181
+ color: inherit;
1182
+ background: none;
1183
+ border: none;
1184
+ cursor: pointer;
1185
+ }
1186
+
1187
+ .fe-table-sort:focus-visible {
1188
+ outline: 2px solid var(--fe-focus);
1189
+ outline-offset: 2px;
1190
+ border-radius: var(--fe-radius-sm);
1191
+ }
1192
+
1193
+ /* Mientras llega la página siguiente, la actual se sigue viendo, atenuada. */
1194
+ .fe-table[aria-busy='true'] tbody {
1195
+ opacity: 0.6;
1196
+ }
1197
+
1198
+ /*
1199
+ * Una tabla más ancha que la pantalla se desplaza dentro de su contenedor, no
1200
+ * ensancha la página. Con una altura máxima, la cabecera fija también funciona
1201
+ * al bajar por un listado largo.
1202
+ */
1203
+ .fe-table-container {
1204
+ max-width: 100%;
1205
+ max-height: var(--fe-table-max-height);
1206
+ overflow: auto;
1207
+ }
1208
+
1209
+ /* ============================================================
1210
+ LISTADO
1211
+ ============================================================ */
1212
+
1213
+ /* Barra, filtros, tabla y pie de un listado, uno debajo de otro. */
1214
+ .fe-datatable {
1215
+ display: flex;
1216
+ flex-direction: column;
1217
+ min-width: 0;
1218
+ }
1219
+
1220
+ /* Lo que va detrás del separador en una barra se queda a la derecha. */
1221
+ .fe-toolbar-spacer {
1222
+ flex: 1 1 auto;
1223
+ }
1224
+
1225
+ .fe-datatable > .fe-bulk-bar {
1226
+ margin: var(--fe-space-2);
1227
+ }
1228
+
1229
+ .fe-datatable-filters {
1230
+ padding: var(--fe-space-4);
1231
+ border-bottom: 1px solid var(--fe-border);
1232
+ }
1233
+
1234
+ .fe-table-footer {
1235
+ display: flex;
1236
+ flex-wrap: wrap;
1237
+ align-items: center;
1238
+ justify-content: space-between;
1239
+ gap: var(--fe-space-3);
1240
+ padding: var(--fe-space-2) var(--fe-space-4);
1241
+ font-size: var(--fe-text-sm);
1242
+ font-variant-numeric: tabular-nums;
1243
+ color: var(--fe-text-muted);
1244
+ }
1245
+
1246
+ .fe-table-pager {
1247
+ display: flex;
1248
+ align-items: center;
1249
+ gap: var(--fe-space-2);
1250
+ }
1251
+
1252
+ /* En un formulario ocupa todo el ancho; aquí empujaría las flechas fuera. */
1253
+ .fe-table-pager .fe-select {
1254
+ width: auto;
1255
+ }
1256
+
1257
+ /* ============================================================
1258
+ CAMPOS COMPUESTOS
1259
+ ============================================================ */
1260
+
1261
+ /*
1262
+ * La zona para soltar archivos. Se resalta al pasar el ratón, al enfocarla y
1263
+ * mientras se arrastra algo encima (`data-dragging="true"`).
1264
+ */
1265
+ .fe-file-drop {
1266
+ box-sizing: border-box;
1267
+ display: flex;
1268
+ flex-direction: column;
1269
+ align-items: center;
1270
+ justify-content: center;
1271
+ gap: var(--fe-space-2);
1272
+ width: 100%;
1273
+ padding: var(--fe-space-6) var(--fe-space-4);
1274
+ font-size: var(--fe-text-sm);
1275
+ text-align: center;
1276
+ color: var(--fe-text-muted);
1277
+ background: var(--fe-surface);
1278
+ border: 2px dashed var(--fe-border-strong);
1279
+ border-radius: var(--fe-radius-lg);
1280
+ cursor: pointer;
1281
+ transition: border-color var(--fe-transition), background var(--fe-transition);
1282
+ }
1283
+
1284
+ .fe-file-drop p {
1285
+ margin: 0;
1286
+ }
1287
+
1288
+ .fe-file-drop:hover,
1289
+ .fe-file-drop[data-dragging='true'] {
1290
+ border-color: var(--fe-primary);
1291
+ background: var(--fe-primary-soft);
1292
+ }
1293
+
1294
+ .fe-file-drop:focus-visible {
1295
+ outline: 2px solid var(--fe-focus);
1296
+ outline-offset: 2px;
1297
+ }
1298
+
1299
+ .fe-file-drop-hint {
1300
+ font-size: var(--fe-text-xs);
1301
+ color: var(--fe-text-subtle);
1302
+ }
1303
+
1304
+ /* La miniatura de un avatar, que se pulsa para cambiarlo. */
1305
+ .fe-avatar-preview {
1306
+ box-sizing: border-box;
1307
+ width: 6rem;
1308
+ height: 6rem;
1309
+ object-fit: cover;
1310
+ border: 2px solid var(--fe-border);
1311
+ border-radius: var(--fe-radius-full);
1312
+ box-shadow: var(--fe-shadow);
1313
+ cursor: pointer;
1314
+ transition: border-color var(--fe-transition);
1315
+ }
1316
+
1317
+ .fe-avatar-preview:hover {
1318
+ border-color: var(--fe-primary);
1319
+ }
1320
+
1321
+ .fe-avatar-preview:focus-visible {
1322
+ outline: 2px solid var(--fe-focus);
1323
+ outline-offset: 2px;
1324
+ }
1325
+
1326
+ /* Las casillas de un código de un solo uso. */
1327
+ .fe-code-input {
1328
+ display: flex;
1329
+ justify-content: center;
1330
+ gap: var(--fe-space-2);
1331
+ }
1332
+
1333
+ .fe-code-cell {
1334
+ box-sizing: border-box;
1335
+ width: 3rem;
1336
+ height: 3rem;
1337
+ padding: 0;
1338
+ font-family: var(--fe-font);
1339
+ font-size: var(--fe-text-lg);
1340
+ text-align: center;
1341
+ color: var(--fe-text);
1342
+ background: var(--fe-surface);
1343
+ border: 1px solid var(--fe-border-strong);
1344
+ border-radius: var(--fe-radius);
1345
+ appearance: textfield;
1346
+ transition: border-color var(--fe-transition), box-shadow var(--fe-transition);
1347
+ }
1348
+
1349
+ .fe-code-cell:focus {
1350
+ outline: none;
1351
+ border-color: var(--fe-focus);
1352
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--fe-focus) 22%, transparent);
1353
+ caret-color: var(--fe-focus);
1354
+ }
1355
+
1356
+ .fe-code-cell::-webkit-outer-spin-button,
1357
+ .fe-code-cell::-webkit-inner-spin-button {
1358
+ appearance: none;
1359
+ margin: 0;
1360
+ }
1361
+
1362
+ /*
1363
+ * Un grupo de campos que se repite. Cada elemento es una superficie con su
1364
+ * barra: el tirador para ordenarlo, el título y las acciones.
1365
+ */
1366
+ .fe-group {
1367
+ display: flex;
1368
+ flex-direction: column;
1369
+ gap: var(--fe-space-2);
1370
+ }
1371
+
1372
+ .fe-group-title {
1373
+ margin: 0;
1374
+ font-size: var(--fe-text-base);
1375
+ font-weight: 600;
1376
+ color: var(--fe-text);
1377
+ }
1378
+
1379
+ .fe-drag-handle {
1380
+ cursor: grab;
1381
+ touch-action: none;
1382
+ }
1383
+
1384
+ .fe-drag-handle:active {
1385
+ cursor: grabbing;
1386
+ }
1387
+
1388
+ /* Va después del botón de icono genérico para ganarle el color al pasar. */
1389
+ .fe-icon-button-danger {
1390
+ color: var(--fe-danger);
1391
+ }
1392
+
1393
+ .fe-icon-button-danger:hover:not(:disabled) {
1394
+ color: var(--fe-danger);
1395
+ background: var(--fe-danger-soft);
1396
+ }
1397
+
1169
1398
  /* ============================================================
1170
1399
  EDICION EN LINEA
1171
1400
  ============================================================ */
package/src/theme.js CHANGED
@@ -46,6 +46,14 @@ export const defaultTheme = {
46
46
  checkbox: 'fe-checkbox',
47
47
  radio: 'fe-radio',
48
48
  file: 'fe-file',
49
+ fileDrop: 'fe-file-drop',
50
+ fileDropHint: 'fe-file-drop-hint',
51
+ avatarPreview: 'fe-avatar-preview',
52
+ codeInput: 'fe-code-input',
53
+ codeCell: 'fe-code-cell',
54
+ group: 'fe-group',
55
+ groupTitle: 'fe-group-title',
56
+ dragHandle: 'fe-drag-handle',
49
57
 
50
58
  // BOTONES
51
59
  button: 'fe-button',
@@ -53,6 +61,7 @@ export const defaultTheme = {
53
61
  buttonDanger: 'fe-button-danger',
54
62
  buttonLink: 'fe-button-link',
55
63
  iconButton: 'fe-icon-button',
64
+ iconButtonDanger: 'fe-icon-button-danger',
56
65
 
57
66
  // NAVEGACION Y ACCIONES
58
67
  breadcrumb: 'fe-breadcrumb',
@@ -128,6 +137,13 @@ export const defaultTheme = {
128
137
  tableEmpty: 'fe-table-empty',
129
138
  bulkBar: 'fe-bulk-bar',
130
139
  bulkCount: 'fe-bulk-count',
140
+ tableSort: 'fe-table-sort',
141
+ tableContainer: 'fe-table-container',
142
+ tableFooter: 'fe-table-footer',
143
+ tablePager: 'fe-table-pager',
144
+ datatable: 'fe-datatable',
145
+ datatableFilters: 'fe-datatable-filters',
146
+ toolbarSpacer: 'fe-toolbar-spacer',
131
147
 
132
148
  // EDICION EN LINEA
133
149
  editable: 'fe-editable',
package/src/tokens.css CHANGED
@@ -128,6 +128,9 @@
128
128
  --fe-drawer-width: 32rem;
129
129
  --fe-command-width: 40rem;
130
130
  --fe-sidebar-width: 15rem;
131
+ /* Sin límite, la tabla crece con sus filas; con uno, la cabecera fija
132
+ funciona también al bajar por el listado. */
133
+ --fe-table-max-height: none;
131
134
  }
132
135
 
133
136
  /* La elección explícita de claro gana sobre un sistema en oscuro, de ahí el