innoboxrr-form-core 2.2.0 → 2.4.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 +99 -29
- package/package.json +2 -2
- package/src/components.css +660 -10
- package/src/icons.js +27 -0
- package/src/theme.js +57 -0
- package/src/tokens.css +41 -0
package/README.md
CHANGED
|
@@ -1,49 +1,75 @@
|
|
|
1
1
|
# innoboxrr-form-core
|
|
2
2
|
|
|
3
|
-
Lo que comparten [`innoboxrr-form-elements`](../form-elements) (Vue)
|
|
4
|
-
[`innoboxrr-react-form-elements`](../react-form-elements) (React) y
|
|
5
|
-
de ningún framework
|
|
3
|
+
Lo que comparten [`innoboxrr-form-elements`](../form-elements) (Vue),
|
|
4
|
+
[`innoboxrr-react-form-elements`](../react-form-elements) (React) y los dos
|
|
5
|
+
datatables, y no depende de ningún framework: el tema, los iconos, las hojas de
|
|
6
|
+
estilo, los archivos y las zonas horarias.
|
|
6
7
|
|
|
7
|
-
Estaba duplicado en los
|
|
8
|
-
|
|
8
|
+
Estaba duplicado en los paquetes, que es exactamente como dos copias empiezan a
|
|
9
|
+
divergir.
|
|
9
10
|
|
|
10
11
|
```
|
|
11
12
|
npm i innoboxrr-form-core
|
|
12
13
|
```
|
|
13
14
|
|
|
14
|
-
##
|
|
15
|
+
## Estilos
|
|
16
|
+
|
|
17
|
+
```js
|
|
18
|
+
import 'innoboxrr-form-core/styles'
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Una sola importación trae las tres hojas: `tokens.css` (las variables),
|
|
22
|
+
`layout.css` (las utilidades de maquetación) y `components.css` (los
|
|
23
|
+
componentes). Nada de lo generado necesita UIkit, Tailwind ni Font Awesome.
|
|
24
|
+
|
|
25
|
+
Colores, formas, densidad, capas y movimiento son variables CSS. Para cambiar el
|
|
26
|
+
aspecto de todo, se redefinen:
|
|
15
27
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
28
|
+
```css
|
|
29
|
+
:root {
|
|
30
|
+
--fe-primary: #7c3aed;
|
|
31
|
+
--fe-radius: 10px;
|
|
32
|
+
--fe-density: 0.875;
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
El modo oscuro responde a la preferencia del sistema y a un `data-theme="dark"`
|
|
37
|
+
en la raíz; `data-theme="light"` fuerza el claro aunque el sistema esté en
|
|
38
|
+
oscuro.
|
|
39
|
+
|
|
40
|
+
## Tema
|
|
20
41
|
|
|
21
|
-
|
|
42
|
+
Un mapa de tokens que la aplicación ajusta **una vez**, al arrancar. Cada token
|
|
43
|
+
apunta a una clase del sistema propio (`fe-*`), así que el caso normal es no
|
|
44
|
+
tocarlo; sirve para apuntar un token a las clases de otro sistema visual cuando
|
|
45
|
+
la aplicación ya tiene el suyo:
|
|
22
46
|
|
|
23
47
|
```js
|
|
24
48
|
import { setTheme } from 'innoboxrr-form-core'
|
|
25
49
|
|
|
26
50
|
setTheme({
|
|
27
51
|
input: 'form-control',
|
|
28
|
-
select: 'form-select',
|
|
29
52
|
button: 'btn btn-primary',
|
|
30
53
|
})
|
|
31
54
|
```
|
|
32
55
|
|
|
33
|
-
Los tokens:
|
|
34
|
-
|
|
35
56
|
| Grupo | Tokens |
|
|
36
57
|
|---|---|
|
|
37
58
|
| Envoltorios | `field`, `fieldInner`, `label`, `help`, `helpIcon`, `error` |
|
|
38
59
|
| Controles | `input`, `select`, `textarea`, `checkbox`, `radio`, `file` |
|
|
39
|
-
| Botones | `button`, `buttonSecondary`, `buttonDanger`, `buttonLink` |
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
60
|
+
| Botones | `button`, `buttonSecondary`, `buttonDanger`, `buttonLink`, `iconButton` |
|
|
61
|
+
| Navegación | `breadcrumb`, `breadcrumbLink`, `breadcrumbCurrent`, `breadcrumbSeparator`, `actionMenu`, `actionMenuItem`, `actionMenuDanger`, `kbd` |
|
|
62
|
+
| Superficies | `surface`, `surfaceRaised`, `toolbar`, `badge`, `badgePrimary`, `badgeSuccess`, `badgeDanger`, `badgeWarning` |
|
|
63
|
+
| Esqueletos | `skeleton`, `skeletonText`, `skeletonCircle`, `skeletonBlock` |
|
|
64
|
+
| Diálogos y drawers | `overlay`, `dialog`, `dialogSmall`, `dialogLarge`, `dialogHeader`, `dialogTitle`, `dialogBody`, `dialogFooter`, `drawer`, `drawerStart`, `drawerHeader`, `drawerTitle`, `drawerBody`, `drawerFooter` |
|
|
65
|
+
| Menús | `menu`, `menuList`, `menuItem`, `menuItemDanger`, `menuSeparator`, `menuLabel` |
|
|
66
|
+
| Paleta de comandos | `command`, `commandInput`, `commandList`, `commandGroup`, `commandItem`, `commandEmpty` |
|
|
67
|
+
| Avisos | `toast`, `toastSuccess`, `toastDanger`, `toastWarning`, `toastTitle`, `toastClose`, `toastRegion` |
|
|
68
|
+
| Tabla | `table`, `tableNumeric`, `tableSticky`, `tableSelect`, `tableResizer`, `tableEmpty`, `bulkBar`, `bulkCount` |
|
|
69
|
+
| Edición en línea | `editable` |
|
|
70
|
+
| Shell de aplicación | `shell`, `shellHeader`, `shellSidebar`, `shellMain` |
|
|
71
|
+
|
|
72
|
+
`customClass` **reemplaza** al token, para el caso puntual:
|
|
47
73
|
|
|
48
74
|
```js
|
|
49
75
|
import { getTheme, resetTheme, onThemeChange, classFor } from 'innoboxrr-form-core'
|
|
@@ -55,9 +81,57 @@ resetTheme() // vuelve a fábrica (sobre todo para pruebas)
|
|
|
55
81
|
onThemeChange(fn) // devuelve la función para dejar de escuchar
|
|
56
82
|
```
|
|
57
83
|
|
|
58
|
-
Los
|
|
59
|
-
|
|
60
|
-
|
|
84
|
+
Los paquetes de componentes se suscriben, así que **un `setTheme` en caliente
|
|
85
|
+
repinta lo que ya esté montado**.
|
|
86
|
+
|
|
87
|
+
## Piezas de escritorio
|
|
88
|
+
|
|
89
|
+
Diálogos, drawers, menús y avisos se apoyan en lo que ya hace el navegador, sin
|
|
90
|
+
librerías de interfaz: `<dialog>` con `showModal()` pone la capa superior, el
|
|
91
|
+
fondo inerte, el foco atrapado, Escape para cerrar y la devolución del foco; el
|
|
92
|
+
atributo `popover` pone el cierre al pulsar fuera. Estas hojas solo los dibujan.
|
|
93
|
+
Los componentes de Vue y React envuelven exactamente este marcado.
|
|
94
|
+
|
|
95
|
+
```html
|
|
96
|
+
<dialog class="fe-drawer">
|
|
97
|
+
<header class="fe-drawer-header">
|
|
98
|
+
<h2 class="fe-drawer-title">Nuevo producto</h2>
|
|
99
|
+
<button class="fe-icon-button" aria-label="Cerrar">…</button>
|
|
100
|
+
</header>
|
|
101
|
+
<div class="fe-drawer-body">…</div>
|
|
102
|
+
<footer class="fe-drawer-footer">…</footer>
|
|
103
|
+
</dialog>
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
- **Diálogo**: `fe-dialog`, con `fe-dialog-sm` o `fe-dialog-lg` para el ancho.
|
|
107
|
+
- **Drawer**: `fe-drawer` a la derecha; `fe-drawer-start` lo pega a la izquierda.
|
|
108
|
+
- **Paleta de comandos**: `<dialog class="fe-dialog fe-command">` con
|
|
109
|
+
`fe-command-input` y una `fe-command-list` de `fe-command-item`; el elemento
|
|
110
|
+
activo lleva `aria-selected="true"`.
|
|
111
|
+
- **Avisos**: una `fe-toast-region` con `popover="manual"`, para seguir encima
|
|
112
|
+
de un drawer abierto con `showModal()`.
|
|
113
|
+
- **Menús**: `fe-menu` con `popover`, colocado con Floating UI.
|
|
114
|
+
- **Tabla**: `fe-table-select` para la columna de casillas, `data-selected` en
|
|
115
|
+
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.
|
|
117
|
+
|
|
118
|
+
Un `<dialog>` cerrado está oculto porque el navegador le pone `display: none`;
|
|
119
|
+
por eso ninguna regla fija `display` fuera del estado `[open]`. Las capas que no
|
|
120
|
+
viven en la capa superior —la cabecera fija de una tabla, un overlay dibujado a
|
|
121
|
+
mano, los tooltips— siguen la escala `--fe-z-*`, nunca un número suelto.
|
|
122
|
+
|
|
123
|
+
## Iconos
|
|
124
|
+
|
|
125
|
+
Un nombre semántico y un mapa que decide de dónde sale el dibujo. Los valores son
|
|
126
|
+
nombres de Iconify (`coleccion:icono`):
|
|
127
|
+
|
|
128
|
+
```js
|
|
129
|
+
import { setIcons, iconFor } from 'innoboxrr-form-core'
|
|
130
|
+
|
|
131
|
+
setIcons({ plus: 'lucide:plus', delete: 'lucide:trash-2' })
|
|
132
|
+
iconFor('plus') // 'lucide:plus'
|
|
133
|
+
iconFor('mdi:home') // un nombre completo pasa tal cual
|
|
134
|
+
```
|
|
61
135
|
|
|
62
136
|
## Archivos
|
|
63
137
|
|
|
@@ -76,10 +150,6 @@ hay que meter en el `FormData`.
|
|
|
76
150
|
|
|
77
151
|
`validateFiles` es la misma función devolviendo una promesa, por compatibilidad.
|
|
78
152
|
|
|
79
|
-
La vista previa de lo que no es imagen es un `data:` URI. Antes era una URL de
|
|
80
|
-
`icon-library.com`: cada archivo disparaba una petición a un tercero que puede
|
|
81
|
-
caerse o cambiar.
|
|
82
|
-
|
|
83
153
|
## Zonas horarias
|
|
84
154
|
|
|
85
155
|
```js
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "innoboxrr-form-core",
|
|
3
|
-
"version": "2.
|
|
4
|
-
"description": "El nucleo agnostico de
|
|
3
|
+
"version": "2.4.0",
|
|
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",
|
|
7
7
|
"exports": {
|
package/src/components.css
CHANGED
|
@@ -104,7 +104,7 @@
|
|
|
104
104
|
[data-tooltip]::after {
|
|
105
105
|
content: attr(data-tooltip);
|
|
106
106
|
position: absolute;
|
|
107
|
-
z-index:
|
|
107
|
+
z-index: var(--fe-z-tooltip);
|
|
108
108
|
bottom: calc(100% + var(--fe-space-2));
|
|
109
109
|
left: 50%;
|
|
110
110
|
transform: translateX(-50%);
|
|
@@ -329,6 +329,38 @@
|
|
|
329
329
|
font-size: var(--fe-text-sm);
|
|
330
330
|
}
|
|
331
331
|
|
|
332
|
+
/* Un botón que solo lleva un icono: cerrar un diálogo, abrir el menú de una
|
|
333
|
+
fila. Cuadrado, para que el objetivo no dependa del ancho del glifo. */
|
|
334
|
+
.fe-icon-button {
|
|
335
|
+
display: inline-flex;
|
|
336
|
+
align-items: center;
|
|
337
|
+
justify-content: center;
|
|
338
|
+
width: var(--fe-control-height);
|
|
339
|
+
height: var(--fe-control-height);
|
|
340
|
+
padding: 0;
|
|
341
|
+
color: var(--fe-text-muted);
|
|
342
|
+
background: none;
|
|
343
|
+
border: 1px solid transparent;
|
|
344
|
+
border-radius: var(--fe-radius);
|
|
345
|
+
cursor: pointer;
|
|
346
|
+
transition: background var(--fe-transition), color var(--fe-transition);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
.fe-icon-button:hover:not(:disabled) {
|
|
350
|
+
color: var(--fe-text);
|
|
351
|
+
background: var(--fe-surface-hover);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
.fe-icon-button:focus-visible {
|
|
355
|
+
outline: 2px solid var(--fe-focus);
|
|
356
|
+
outline-offset: 2px;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
.fe-icon-button:disabled {
|
|
360
|
+
opacity: 0.55;
|
|
361
|
+
cursor: not-allowed;
|
|
362
|
+
}
|
|
363
|
+
|
|
332
364
|
/* El icono que va dentro del control, a la izquierda. Sustituye a
|
|
333
365
|
`uk-form-icon`, que además de la clase traía el componente de iconos de
|
|
334
366
|
UIkit. */
|
|
@@ -433,6 +465,22 @@
|
|
|
433
465
|
text-decoration: underline;
|
|
434
466
|
}
|
|
435
467
|
|
|
468
|
+
/* La tecla de un atajo, en un menú o en la paleta de comandos. */
|
|
469
|
+
.fe-kbd {
|
|
470
|
+
display: inline-flex;
|
|
471
|
+
align-items: center;
|
|
472
|
+
min-width: 1.25rem;
|
|
473
|
+
height: 1.25rem;
|
|
474
|
+
padding: 0 var(--fe-space-1);
|
|
475
|
+
font-family: var(--fe-font-mono);
|
|
476
|
+
font-size: var(--fe-text-xs);
|
|
477
|
+
color: var(--fe-text-muted);
|
|
478
|
+
background: var(--fe-surface-sunk);
|
|
479
|
+
border: 1px solid var(--fe-border);
|
|
480
|
+
border-bottom-width: 2px;
|
|
481
|
+
border-radius: var(--fe-radius-sm);
|
|
482
|
+
}
|
|
483
|
+
|
|
436
484
|
/* ============================================================
|
|
437
485
|
SUPERFICIES
|
|
438
486
|
============================================================ */
|
|
@@ -474,6 +522,30 @@
|
|
|
474
522
|
color: var(--fe-text-muted);
|
|
475
523
|
}
|
|
476
524
|
|
|
525
|
+
.fe-badge-primary {
|
|
526
|
+
background: var(--fe-primary-soft);
|
|
527
|
+
color: var(--fe-primary);
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
.fe-badge-success {
|
|
531
|
+
background: var(--fe-success-soft);
|
|
532
|
+
color: var(--fe-success);
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
.fe-badge-danger {
|
|
536
|
+
background: var(--fe-danger-soft);
|
|
537
|
+
color: var(--fe-danger);
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
.fe-badge-warning {
|
|
541
|
+
background: var(--fe-warning-soft);
|
|
542
|
+
color: var(--fe-warning);
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
/* ============================================================
|
|
546
|
+
ESQUELETOS
|
|
547
|
+
============================================================ */
|
|
548
|
+
|
|
477
549
|
/* Un esqueleto en vez de un spinner: mantiene la forma de lo que va a
|
|
478
550
|
llegar, así que la página no salta al cargar. */
|
|
479
551
|
.fe-skeleton {
|
|
@@ -488,6 +560,32 @@
|
|
|
488
560
|
animation: fe-skeleton 1.4s ease infinite;
|
|
489
561
|
}
|
|
490
562
|
|
|
563
|
+
/* Las tres formas que aparecen en una vista de administración: una línea de
|
|
564
|
+
texto, un avatar y un bloque. Sin ellas cada vista inventaba su altura. */
|
|
565
|
+
.fe-skeleton-text {
|
|
566
|
+
display: block;
|
|
567
|
+
width: 100%;
|
|
568
|
+
height: 0.875em;
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
.fe-skeleton-text + .fe-skeleton-text {
|
|
572
|
+
margin-top: var(--fe-space-2);
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
.fe-skeleton-circle {
|
|
576
|
+
display: inline-block;
|
|
577
|
+
width: 2.5rem;
|
|
578
|
+
aspect-ratio: 1;
|
|
579
|
+
border-radius: var(--fe-radius-full);
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
.fe-skeleton-block {
|
|
583
|
+
display: block;
|
|
584
|
+
width: 100%;
|
|
585
|
+
height: 6rem;
|
|
586
|
+
border-radius: var(--fe-radius);
|
|
587
|
+
}
|
|
588
|
+
|
|
491
589
|
@keyframes fe-skeleton {
|
|
492
590
|
0% {
|
|
493
591
|
background-position: 100% 50%;
|
|
@@ -497,35 +595,181 @@
|
|
|
497
595
|
}
|
|
498
596
|
}
|
|
499
597
|
|
|
598
|
+
/* ============================================================
|
|
599
|
+
DIALOGOS Y DRAWERS
|
|
600
|
+
============================================================ */
|
|
601
|
+
|
|
602
|
+
/*
|
|
603
|
+
* Sobre el elemento <dialog> del navegador, abierto con showModal():
|
|
604
|
+
*
|
|
605
|
+
* <dialog class="fe-dialog">
|
|
606
|
+
* <header class="fe-dialog-header">…</header>
|
|
607
|
+
* <div class="fe-dialog-body">…</div>
|
|
608
|
+
* <footer class="fe-dialog-footer">…</footer>
|
|
609
|
+
* </dialog>
|
|
610
|
+
*
|
|
611
|
+
* El navegador pone lo que antes había que programar: la capa superior sin
|
|
612
|
+
* z-index, el fondo inerte, el foco atrapado dentro, Escape para cerrar y la
|
|
613
|
+
* devolución del foco al cerrar. Aquí solo se dibuja.
|
|
614
|
+
*
|
|
615
|
+
* Nada de lo de aquí fija `display` en el estado cerrado: un <dialog> sin
|
|
616
|
+
* `open` está oculto porque el navegador le pone display: none, y una regla
|
|
617
|
+
* que lo pisara lo dejaría visible siempre.
|
|
618
|
+
*/
|
|
619
|
+
|
|
500
620
|
.fe-overlay {
|
|
501
621
|
position: fixed;
|
|
502
622
|
inset: 0;
|
|
503
|
-
|
|
623
|
+
z-index: var(--fe-z-overlay);
|
|
624
|
+
background: var(--fe-overlay);
|
|
504
625
|
}
|
|
505
626
|
|
|
506
627
|
.fe-dialog {
|
|
628
|
+
width: min(var(--fe-dialog-width), calc(100vw - 2 * var(--fe-space-4)));
|
|
629
|
+
max-height: 85vh;
|
|
630
|
+
padding: 0;
|
|
631
|
+
color: var(--fe-text);
|
|
507
632
|
background: var(--fe-surface-raised);
|
|
508
633
|
border: 1px solid var(--fe-border);
|
|
509
634
|
border-radius: var(--fe-radius-lg);
|
|
510
635
|
box-shadow: var(--fe-shadow-lg);
|
|
511
|
-
max-height: 85vh;
|
|
512
636
|
overflow: auto;
|
|
513
637
|
}
|
|
514
638
|
|
|
639
|
+
.fe-dialog[open] {
|
|
640
|
+
display: flex;
|
|
641
|
+
flex-direction: column;
|
|
642
|
+
animation: fe-dialog-in var(--fe-duration) var(--fe-ease-out);
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
.fe-dialog::backdrop,
|
|
646
|
+
.fe-drawer::backdrop {
|
|
647
|
+
background: var(--fe-overlay);
|
|
648
|
+
animation: fe-backdrop-in var(--fe-duration) var(--fe-ease-out);
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
.fe-dialog-sm {
|
|
652
|
+
--fe-dialog-width: 24rem;
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
.fe-dialog-lg {
|
|
656
|
+
--fe-dialog-width: 48rem;
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
.fe-dialog-header,
|
|
660
|
+
.fe-drawer-header {
|
|
661
|
+
display: flex;
|
|
662
|
+
align-items: center;
|
|
663
|
+
justify-content: space-between;
|
|
664
|
+
gap: var(--fe-space-3);
|
|
665
|
+
padding: var(--fe-space-4) var(--fe-space-5);
|
|
666
|
+
border-bottom: 1px solid var(--fe-border);
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
.fe-dialog-title,
|
|
670
|
+
.fe-drawer-title {
|
|
671
|
+
margin: 0;
|
|
672
|
+
font-size: var(--fe-text-lg);
|
|
673
|
+
font-weight: 600;
|
|
674
|
+
color: var(--fe-text);
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
.fe-dialog-body,
|
|
678
|
+
.fe-drawer-body {
|
|
679
|
+
padding: var(--fe-space-5);
|
|
680
|
+
overflow: auto;
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
.fe-dialog-footer,
|
|
684
|
+
.fe-drawer-footer {
|
|
685
|
+
display: flex;
|
|
686
|
+
flex-wrap: wrap;
|
|
687
|
+
align-items: center;
|
|
688
|
+
justify-content: flex-end;
|
|
689
|
+
gap: var(--fe-space-2);
|
|
690
|
+
padding: var(--fe-space-3) var(--fe-space-5);
|
|
691
|
+
border-top: 1px solid var(--fe-border);
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
/* Un drawer es un <dialog> pegado a un borde. El formulario de crear o
|
|
695
|
+
editar se abre aquí y la tabla sigue a la vista, detrás. */
|
|
515
696
|
.fe-drawer {
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
697
|
+
width: min(var(--fe-drawer-width), 100vw);
|
|
698
|
+
max-width: 100vw;
|
|
699
|
+
height: 100dvh;
|
|
700
|
+
max-height: none;
|
|
701
|
+
margin: 0 0 0 auto;
|
|
702
|
+
padding: 0;
|
|
703
|
+
color: var(--fe-text);
|
|
521
704
|
background: var(--fe-surface);
|
|
705
|
+
border: none;
|
|
522
706
|
border-left: 1px solid var(--fe-border);
|
|
523
707
|
box-shadow: var(--fe-shadow-lg);
|
|
708
|
+
overflow: hidden;
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
.fe-drawer[open] {
|
|
524
712
|
display: flex;
|
|
525
713
|
flex-direction: column;
|
|
526
|
-
|
|
714
|
+
animation: fe-drawer-in var(--fe-duration) var(--fe-ease-out);
|
|
527
715
|
}
|
|
528
716
|
|
|
717
|
+
.fe-drawer-body {
|
|
718
|
+
flex: 1 1 auto;
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
.fe-drawer-start {
|
|
722
|
+
margin: 0 auto 0 0;
|
|
723
|
+
border-left: none;
|
|
724
|
+
border-right: 1px solid var(--fe-border);
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
.fe-drawer-start[open] {
|
|
728
|
+
animation-name: fe-drawer-start-in;
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
@keyframes fe-dialog-in {
|
|
732
|
+
from {
|
|
733
|
+
opacity: 0;
|
|
734
|
+
transform: translateY(0.5rem) scale(0.98);
|
|
735
|
+
}
|
|
736
|
+
to {
|
|
737
|
+
opacity: 1;
|
|
738
|
+
transform: none;
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
@keyframes fe-drawer-in {
|
|
743
|
+
from {
|
|
744
|
+
transform: translateX(100%);
|
|
745
|
+
}
|
|
746
|
+
to {
|
|
747
|
+
transform: none;
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
@keyframes fe-drawer-start-in {
|
|
752
|
+
from {
|
|
753
|
+
transform: translateX(-100%);
|
|
754
|
+
}
|
|
755
|
+
to {
|
|
756
|
+
transform: none;
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
@keyframes fe-backdrop-in {
|
|
761
|
+
from {
|
|
762
|
+
opacity: 0;
|
|
763
|
+
}
|
|
764
|
+
to {
|
|
765
|
+
opacity: 1;
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
/* ============================================================
|
|
770
|
+
MENUS
|
|
771
|
+
============================================================ */
|
|
772
|
+
|
|
529
773
|
.fe-menu {
|
|
530
774
|
min-width: 11rem;
|
|
531
775
|
padding: var(--fe-space-1);
|
|
@@ -535,6 +779,29 @@
|
|
|
535
779
|
box-shadow: var(--fe-shadow);
|
|
536
780
|
}
|
|
537
781
|
|
|
782
|
+
/*
|
|
783
|
+
* Un menú que vive en la capa superior del navegador, con el atributo
|
|
784
|
+
* `popover`. El navegador ya se encarga de abrirlo, cerrarlo al pulsar fuera,
|
|
785
|
+
* cerrarlo con Escape y sacarlo por encima de todo; aquí solo hay que quitarle
|
|
786
|
+
* los estilos que trae de fábrica para que Floating UI pueda colocarlo.
|
|
787
|
+
*/
|
|
788
|
+
.fe-menu[popover] {
|
|
789
|
+
position: fixed;
|
|
790
|
+
inset: auto;
|
|
791
|
+
margin: 0;
|
|
792
|
+
overflow: visible;
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
.fe-menu[popover]:popover-open {
|
|
796
|
+
animation: fe-menu-in var(--fe-duration-fast) ease;
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
.fe-menu-list {
|
|
800
|
+
list-style: none;
|
|
801
|
+
margin: 0;
|
|
802
|
+
padding: 0;
|
|
803
|
+
}
|
|
804
|
+
|
|
538
805
|
.fe-menu-item {
|
|
539
806
|
display: flex;
|
|
540
807
|
align-items: center;
|
|
@@ -544,6 +811,7 @@
|
|
|
544
811
|
font-size: var(--fe-text-sm);
|
|
545
812
|
color: var(--fe-text);
|
|
546
813
|
text-align: left;
|
|
814
|
+
text-decoration: none;
|
|
547
815
|
background: none;
|
|
548
816
|
border: none;
|
|
549
817
|
border-radius: var(--fe-radius-sm);
|
|
@@ -555,17 +823,159 @@
|
|
|
555
823
|
background: var(--fe-surface-hover);
|
|
556
824
|
}
|
|
557
825
|
|
|
826
|
+
.fe-menu-item:focus-visible {
|
|
827
|
+
outline: 2px solid var(--fe-focus);
|
|
828
|
+
outline-offset: -2px;
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
.fe-menu-item-danger {
|
|
832
|
+
color: var(--fe-danger);
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
.fe-menu-item-danger:hover,
|
|
836
|
+
.fe-menu-item-danger[data-highlighted] {
|
|
837
|
+
background: var(--fe-danger-soft);
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
/* Un elemento que no se puede usar se ve y se explica, no desaparece: quien no
|
|
841
|
+
tiene permiso tiene que saber que la acción existe. */
|
|
842
|
+
.fe-menu-item:disabled,
|
|
843
|
+
.fe-menu-item[aria-disabled='true'] {
|
|
844
|
+
color: var(--fe-text-subtle);
|
|
845
|
+
background: none;
|
|
846
|
+
cursor: not-allowed;
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
.fe-menu-item .fe-kbd {
|
|
850
|
+
margin-left: auto;
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
.fe-menu-separator {
|
|
854
|
+
height: 1px;
|
|
855
|
+
margin: var(--fe-space-1) 0;
|
|
856
|
+
background: var(--fe-border);
|
|
857
|
+
border: none;
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
.fe-menu-label {
|
|
861
|
+
padding: var(--fe-space-2) var(--fe-space-3) var(--fe-space-1);
|
|
862
|
+
font-size: var(--fe-text-xs);
|
|
863
|
+
font-weight: 500;
|
|
864
|
+
letter-spacing: 0.05em;
|
|
865
|
+
text-transform: uppercase;
|
|
866
|
+
color: var(--fe-text-subtle);
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
@keyframes fe-menu-in {
|
|
870
|
+
from {
|
|
871
|
+
opacity: 0;
|
|
872
|
+
}
|
|
873
|
+
to {
|
|
874
|
+
opacity: 1;
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
/* ============================================================
|
|
879
|
+
PALETA DE COMANDOS
|
|
880
|
+
============================================================ */
|
|
881
|
+
|
|
882
|
+
/*
|
|
883
|
+
* Un <dialog class="fe-dialog fe-command"> con un buscador y una lista. Se
|
|
884
|
+
* abre arriba y no centrado: el ojo va a donde se escribe, y la lista crece
|
|
885
|
+
* hacia abajo sin mover el buscador.
|
|
886
|
+
*/
|
|
887
|
+
|
|
888
|
+
.fe-command {
|
|
889
|
+
--fe-dialog-width: var(--fe-command-width);
|
|
890
|
+
margin: 12vh auto auto;
|
|
891
|
+
max-height: 70vh;
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
.fe-command-input {
|
|
895
|
+
width: 100%;
|
|
896
|
+
min-height: calc(var(--fe-control-height) * 1.4);
|
|
897
|
+
padding: 0 var(--fe-space-5);
|
|
898
|
+
font-family: var(--fe-font);
|
|
899
|
+
font-size: var(--fe-text-lg);
|
|
900
|
+
color: var(--fe-text);
|
|
901
|
+
background: none;
|
|
902
|
+
border: none;
|
|
903
|
+
border-bottom: 1px solid var(--fe-border);
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
.fe-command-input:focus {
|
|
907
|
+
outline: none;
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
.fe-command-input::placeholder {
|
|
911
|
+
color: var(--fe-text-subtle);
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
.fe-command-list {
|
|
915
|
+
list-style: none;
|
|
916
|
+
margin: 0;
|
|
917
|
+
padding: var(--fe-space-2);
|
|
918
|
+
overflow: auto;
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
.fe-command-group {
|
|
922
|
+
padding: var(--fe-space-2) var(--fe-space-3) var(--fe-space-1);
|
|
923
|
+
font-size: var(--fe-text-xs);
|
|
924
|
+
font-weight: 500;
|
|
925
|
+
letter-spacing: 0.05em;
|
|
926
|
+
text-transform: uppercase;
|
|
927
|
+
color: var(--fe-text-subtle);
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
.fe-command-item {
|
|
931
|
+
display: flex;
|
|
932
|
+
align-items: center;
|
|
933
|
+
gap: var(--fe-space-3);
|
|
934
|
+
width: 100%;
|
|
935
|
+
padding: var(--fe-space-2) var(--fe-space-3);
|
|
936
|
+
font-size: var(--fe-text-base);
|
|
937
|
+
color: var(--fe-text);
|
|
938
|
+
text-align: left;
|
|
939
|
+
background: none;
|
|
940
|
+
border: none;
|
|
941
|
+
border-radius: var(--fe-radius);
|
|
942
|
+
cursor: pointer;
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
.fe-command-item[aria-selected='true'],
|
|
946
|
+
.fe-command-item[data-highlighted] {
|
|
947
|
+
background: var(--fe-primary-soft);
|
|
948
|
+
color: var(--fe-text);
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
.fe-command-item .fe-kbd {
|
|
952
|
+
margin-left: auto;
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
.fe-command-empty {
|
|
956
|
+
padding: var(--fe-space-6) var(--fe-space-4);
|
|
957
|
+
font-size: var(--fe-text-sm);
|
|
958
|
+
text-align: center;
|
|
959
|
+
color: var(--fe-text-muted);
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
/* ============================================================
|
|
963
|
+
AVISOS
|
|
964
|
+
============================================================ */
|
|
965
|
+
|
|
558
966
|
.fe-toast {
|
|
559
967
|
display: flex;
|
|
560
968
|
align-items: flex-start;
|
|
561
969
|
gap: var(--fe-space-3);
|
|
562
970
|
padding: var(--fe-space-3) var(--fe-space-4);
|
|
563
971
|
font-size: var(--fe-text-sm);
|
|
972
|
+
color: var(--fe-text);
|
|
564
973
|
background: var(--fe-surface-raised);
|
|
565
974
|
border: 1px solid var(--fe-border);
|
|
566
975
|
border-left: 3px solid var(--fe-primary);
|
|
567
976
|
border-radius: var(--fe-radius);
|
|
568
977
|
box-shadow: var(--fe-shadow);
|
|
978
|
+
animation: fe-toast-in var(--fe-duration) var(--fe-ease-out);
|
|
569
979
|
}
|
|
570
980
|
|
|
571
981
|
.fe-toast-danger {
|
|
@@ -576,6 +986,61 @@
|
|
|
576
986
|
border-left-color: var(--fe-success);
|
|
577
987
|
}
|
|
578
988
|
|
|
989
|
+
.fe-toast-warning {
|
|
990
|
+
border-left-color: var(--fe-warning);
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
.fe-toast-title {
|
|
994
|
+
display: block;
|
|
995
|
+
font-weight: 600;
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
.fe-toast-close {
|
|
999
|
+
margin-left: auto;
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
/*
|
|
1003
|
+
* La región donde se apilan los avisos. Va con el atributo popover="manual"
|
|
1004
|
+
* para vivir en la capa superior: un aviso que llega mientras hay un drawer
|
|
1005
|
+
* abierto con showModal() quedaría debajo del fondo inerte, y justo ahí es
|
|
1006
|
+
* donde se guarda un formulario.
|
|
1007
|
+
*/
|
|
1008
|
+
.fe-toast-region {
|
|
1009
|
+
position: fixed;
|
|
1010
|
+
right: var(--fe-space-4);
|
|
1011
|
+
bottom: var(--fe-space-4);
|
|
1012
|
+
z-index: var(--fe-z-toast);
|
|
1013
|
+
display: flex;
|
|
1014
|
+
flex-direction: column;
|
|
1015
|
+
gap: var(--fe-space-2);
|
|
1016
|
+
width: min(24rem, calc(100vw - 2 * var(--fe-space-4)));
|
|
1017
|
+
pointer-events: none;
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
.fe-toast-region[popover] {
|
|
1021
|
+
inset: auto var(--fe-space-4) var(--fe-space-4) auto;
|
|
1022
|
+
margin: 0;
|
|
1023
|
+
padding: 0;
|
|
1024
|
+
overflow: visible;
|
|
1025
|
+
background: transparent;
|
|
1026
|
+
border: none;
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
.fe-toast-region > * {
|
|
1030
|
+
pointer-events: auto;
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
@keyframes fe-toast-in {
|
|
1034
|
+
from {
|
|
1035
|
+
opacity: 0;
|
|
1036
|
+
transform: translateY(0.5rem);
|
|
1037
|
+
}
|
|
1038
|
+
to {
|
|
1039
|
+
opacity: 1;
|
|
1040
|
+
transform: none;
|
|
1041
|
+
}
|
|
1042
|
+
}
|
|
1043
|
+
|
|
579
1044
|
/* ============================================================
|
|
580
1045
|
TABLA
|
|
581
1046
|
============================================================ */
|
|
@@ -587,6 +1052,7 @@
|
|
|
587
1052
|
}
|
|
588
1053
|
|
|
589
1054
|
.fe-table th {
|
|
1055
|
+
position: relative;
|
|
590
1056
|
padding: var(--fe-space-2) var(--fe-space-3);
|
|
591
1057
|
font-size: var(--fe-text-xs);
|
|
592
1058
|
font-weight: 500;
|
|
@@ -618,18 +1084,202 @@
|
|
|
618
1084
|
text-align: right;
|
|
619
1085
|
}
|
|
620
1086
|
|
|
1087
|
+
/* Una columna ordenable lo dice antes de pulsarla. */
|
|
1088
|
+
.fe-table th[aria-sort] {
|
|
1089
|
+
cursor: pointer;
|
|
1090
|
+
user-select: none;
|
|
1091
|
+
}
|
|
1092
|
+
|
|
1093
|
+
.fe-table th[aria-sort='ascending'],
|
|
1094
|
+
.fe-table th[aria-sort='descending'] {
|
|
1095
|
+
color: var(--fe-text);
|
|
1096
|
+
}
|
|
1097
|
+
|
|
1098
|
+
/* La cabecera se queda arriba al desplazar un listado largo. */
|
|
1099
|
+
.fe-table-sticky thead th {
|
|
1100
|
+
position: sticky;
|
|
1101
|
+
top: 0;
|
|
1102
|
+
z-index: var(--fe-z-sticky);
|
|
1103
|
+
background: var(--fe-surface);
|
|
1104
|
+
}
|
|
1105
|
+
|
|
1106
|
+
/* La columna de las casillas de selección: tan estrecha como la casilla. */
|
|
1107
|
+
.fe-table-select {
|
|
1108
|
+
width: 1%;
|
|
1109
|
+
white-space: nowrap;
|
|
1110
|
+
}
|
|
1111
|
+
|
|
1112
|
+
/* El tirador para cambiar el ancho de una columna. */
|
|
1113
|
+
.fe-table-resizer {
|
|
1114
|
+
position: absolute;
|
|
1115
|
+
top: 0;
|
|
1116
|
+
right: 0;
|
|
1117
|
+
width: 6px;
|
|
1118
|
+
height: 100%;
|
|
1119
|
+
cursor: col-resize;
|
|
1120
|
+
user-select: none;
|
|
1121
|
+
touch-action: none;
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
.fe-table-resizer:hover,
|
|
1125
|
+
.fe-table-resizer[data-resizing='true'] {
|
|
1126
|
+
background: var(--fe-focus);
|
|
1127
|
+
}
|
|
1128
|
+
|
|
1129
|
+
/* Una tabla sin filas dice por qué, en el sitio de las filas. */
|
|
1130
|
+
.fe-table-empty {
|
|
1131
|
+
padding: var(--fe-space-6) var(--fe-space-4);
|
|
1132
|
+
text-align: center;
|
|
1133
|
+
color: var(--fe-text-muted);
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
/*
|
|
1137
|
+
* La barra que aparece al seleccionar filas: cuántas hay y qué se puede hacer
|
|
1138
|
+
* con todas a la vez. Sustituye a la barra de herramientas mientras dura la
|
|
1139
|
+
* selección, en el mismo sitio, para que la tabla no salte.
|
|
1140
|
+
*/
|
|
1141
|
+
.fe-bulk-bar {
|
|
1142
|
+
display: flex;
|
|
1143
|
+
flex-wrap: wrap;
|
|
1144
|
+
align-items: center;
|
|
1145
|
+
gap: var(--fe-space-3);
|
|
1146
|
+
padding: var(--fe-space-2) var(--fe-space-4);
|
|
1147
|
+
color: var(--fe-text);
|
|
1148
|
+
background: var(--fe-primary-soft);
|
|
1149
|
+
border-radius: var(--fe-radius);
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1152
|
+
.fe-bulk-count {
|
|
1153
|
+
font-size: var(--fe-text-sm);
|
|
1154
|
+
font-weight: 500;
|
|
1155
|
+
font-variant-numeric: tabular-nums;
|
|
1156
|
+
}
|
|
1157
|
+
|
|
1158
|
+
/* ============================================================
|
|
1159
|
+
EDICION EN LINEA
|
|
1160
|
+
============================================================ */
|
|
1161
|
+
|
|
1162
|
+
/* Un valor que se edita donde está. Se distingue del texto normal solo al
|
|
1163
|
+
pasar o enfocar, para que una tabla editable no parezca un formulario. */
|
|
1164
|
+
.fe-editable {
|
|
1165
|
+
display: inline-flex;
|
|
1166
|
+
align-items: center;
|
|
1167
|
+
gap: var(--fe-space-1);
|
|
1168
|
+
min-height: 1.5em;
|
|
1169
|
+
padding: 0 var(--fe-space-1);
|
|
1170
|
+
margin: 0 calc(-1 * var(--fe-space-1));
|
|
1171
|
+
border-radius: var(--fe-radius-sm);
|
|
1172
|
+
border-bottom: 1px dashed transparent;
|
|
1173
|
+
cursor: text;
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1176
|
+
.fe-editable:hover {
|
|
1177
|
+
border-bottom-color: var(--fe-border-strong);
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1180
|
+
.fe-editable:focus-visible {
|
|
1181
|
+
outline: 2px solid var(--fe-focus);
|
|
1182
|
+
outline-offset: 1px;
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
.fe-editable[data-saving='true'] {
|
|
1186
|
+
opacity: 0.6;
|
|
1187
|
+
cursor: progress;
|
|
1188
|
+
}
|
|
1189
|
+
|
|
1190
|
+
.fe-editable[data-invalid='true'] {
|
|
1191
|
+
border-bottom-color: var(--fe-danger);
|
|
1192
|
+
}
|
|
1193
|
+
|
|
1194
|
+
/* ============================================================
|
|
1195
|
+
SHELL DE APLICACION
|
|
1196
|
+
============================================================ */
|
|
1197
|
+
|
|
1198
|
+
/*
|
|
1199
|
+
* La forma de una aplicación de escritorio: cabecera, barra lateral y el área
|
|
1200
|
+
* de trabajo, que es lo único que cambia al navegar.
|
|
1201
|
+
*
|
|
1202
|
+
* <div class="fe-shell">
|
|
1203
|
+
* <header class="fe-shell-header">…</header>
|
|
1204
|
+
* <nav class="fe-shell-sidebar">…</nav>
|
|
1205
|
+
* <main class="fe-shell-main">…</main>
|
|
1206
|
+
* </div>
|
|
1207
|
+
*/
|
|
1208
|
+
|
|
1209
|
+
.fe-shell {
|
|
1210
|
+
display: grid;
|
|
1211
|
+
grid-template-columns: var(--fe-sidebar-width) minmax(0, 1fr);
|
|
1212
|
+
grid-template-rows: auto minmax(0, 1fr);
|
|
1213
|
+
min-height: 100dvh;
|
|
1214
|
+
color: var(--fe-text);
|
|
1215
|
+
background: var(--fe-bg);
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
.fe-shell-header {
|
|
1219
|
+
grid-column: 1 / -1;
|
|
1220
|
+
display: flex;
|
|
1221
|
+
align-items: center;
|
|
1222
|
+
gap: var(--fe-space-3);
|
|
1223
|
+
padding: var(--fe-space-2) var(--fe-space-4);
|
|
1224
|
+
background: var(--fe-surface);
|
|
1225
|
+
border-bottom: 1px solid var(--fe-border);
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
.fe-shell-sidebar {
|
|
1229
|
+
padding: var(--fe-space-3);
|
|
1230
|
+
overflow: auto;
|
|
1231
|
+
background: var(--fe-surface);
|
|
1232
|
+
border-right: 1px solid var(--fe-border);
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1235
|
+
.fe-shell-main {
|
|
1236
|
+
min-width: 0;
|
|
1237
|
+
padding: var(--fe-space-5);
|
|
1238
|
+
overflow: auto;
|
|
1239
|
+
}
|
|
1240
|
+
|
|
1241
|
+
/* En pantallas estrechas la barra lateral sale del flujo y se abre encima. */
|
|
1242
|
+
@media (max-width: 959px) {
|
|
1243
|
+
.fe-shell {
|
|
1244
|
+
grid-template-columns: minmax(0, 1fr);
|
|
1245
|
+
}
|
|
1246
|
+
|
|
1247
|
+
.fe-shell-sidebar {
|
|
1248
|
+
display: none;
|
|
1249
|
+
}
|
|
1250
|
+
|
|
1251
|
+
.fe-shell[data-sidebar-open='true'] .fe-shell-sidebar {
|
|
1252
|
+
display: block;
|
|
1253
|
+
position: fixed;
|
|
1254
|
+
inset: 0 auto 0 0;
|
|
1255
|
+
z-index: var(--fe-z-overlay);
|
|
1256
|
+
width: min(var(--fe-sidebar-width), 85vw);
|
|
1257
|
+
box-shadow: var(--fe-shadow-lg);
|
|
1258
|
+
}
|
|
1259
|
+
}
|
|
1260
|
+
|
|
621
1261
|
@media (prefers-reduced-motion: reduce) {
|
|
622
1262
|
.fe-skeleton {
|
|
623
1263
|
animation: none;
|
|
624
1264
|
}
|
|
625
1265
|
|
|
1266
|
+
.fe-dialog[open],
|
|
1267
|
+
.fe-drawer[open],
|
|
1268
|
+
.fe-dialog::backdrop,
|
|
1269
|
+
.fe-drawer::backdrop,
|
|
1270
|
+
.fe-menu[popover]:popover-open,
|
|
1271
|
+
.fe-toast {
|
|
1272
|
+
animation: none;
|
|
1273
|
+
}
|
|
1274
|
+
|
|
626
1275
|
.fe-input,
|
|
627
1276
|
.fe-select,
|
|
628
1277
|
.fe-textarea,
|
|
629
1278
|
.fe-button,
|
|
630
1279
|
.fe-button-secondary,
|
|
631
1280
|
.fe-button-danger,
|
|
632
|
-
.fe-button-link
|
|
1281
|
+
.fe-button-link,
|
|
1282
|
+
.fe-icon-button {
|
|
633
1283
|
transition: none;
|
|
634
1284
|
}
|
|
635
1285
|
}
|
package/src/icons.js
CHANGED
|
@@ -41,8 +41,12 @@ export const defaultIcons = {
|
|
|
41
41
|
hide: 'fa6-solid:eye-slash',
|
|
42
42
|
actions: 'fa6-solid:gears',
|
|
43
43
|
refresh: 'fa6-solid:rotate',
|
|
44
|
+
restore: 'fa6-solid:rotate-left',
|
|
44
45
|
search: 'fa6-solid:magnifying-glass',
|
|
45
46
|
filter: 'fa6-solid:filter',
|
|
47
|
+
more: 'fa6-solid:ellipsis',
|
|
48
|
+
external: 'fa6-solid:arrow-up-right-from-square',
|
|
49
|
+
logout: 'fa6-solid:right-from-bracket',
|
|
46
50
|
|
|
47
51
|
// ESTADO
|
|
48
52
|
help: 'fa6-solid:circle-question',
|
|
@@ -58,12 +62,35 @@ export const defaultIcons = {
|
|
|
58
62
|
up: 'fa6-solid:chevron-up',
|
|
59
63
|
down: 'fa6-solid:chevron-down',
|
|
60
64
|
close: 'fa6-solid:xmark',
|
|
65
|
+
home: 'fa6-solid:house',
|
|
66
|
+
menu: 'fa6-solid:bars',
|
|
67
|
+
sidebar: 'fa6-solid:table-columns',
|
|
68
|
+
command: 'fa6-solid:terminal',
|
|
69
|
+
settings: 'fa6-solid:gear',
|
|
70
|
+
|
|
71
|
+
// SELECCION Y ORDEN
|
|
72
|
+
check: 'fa6-solid:check',
|
|
73
|
+
minus: 'fa6-solid:minus',
|
|
74
|
+
sort: 'fa6-solid:sort',
|
|
75
|
+
sortUp: 'fa6-solid:sort-up',
|
|
76
|
+
sortDown: 'fa6-solid:sort-down',
|
|
61
77
|
|
|
62
78
|
// OBJETOS
|
|
63
79
|
box: 'fa6-solid:box',
|
|
64
80
|
users: 'fa6-solid:users',
|
|
65
81
|
gift: 'fa6-solid:gift',
|
|
66
82
|
file: 'fa6-solid:file',
|
|
83
|
+
media: 'fa6-solid:photo-film',
|
|
84
|
+
|
|
85
|
+
// EDICION
|
|
86
|
+
save: 'fa6-solid:floppy-disk',
|
|
87
|
+
copy: 'fa6-solid:clone',
|
|
88
|
+
drag: 'fa6-solid:grip-vertical',
|
|
89
|
+
|
|
90
|
+
// GRABACION
|
|
91
|
+
record: 'fa6-solid:microphone',
|
|
92
|
+
pause: 'fa6-solid:pause',
|
|
93
|
+
play: 'fa6-solid:play',
|
|
67
94
|
}
|
|
68
95
|
|
|
69
96
|
/** @type {IconMap} */
|
package/src/theme.js
CHANGED
|
@@ -52,6 +52,7 @@ export const defaultTheme = {
|
|
|
52
52
|
buttonSecondary: 'fe-button-secondary',
|
|
53
53
|
buttonDanger: 'fe-button-danger',
|
|
54
54
|
buttonLink: 'fe-button-link',
|
|
55
|
+
iconButton: 'fe-icon-button',
|
|
55
56
|
|
|
56
57
|
// NAVEGACION Y ACCIONES
|
|
57
58
|
breadcrumb: 'fe-breadcrumb',
|
|
@@ -61,25 +62,81 @@ export const defaultTheme = {
|
|
|
61
62
|
actionMenu: 'fe-action-menu',
|
|
62
63
|
actionMenuItem: 'fe-action-item',
|
|
63
64
|
actionMenuDanger: 'fe-action-danger',
|
|
65
|
+
kbd: 'fe-kbd',
|
|
64
66
|
|
|
65
67
|
// SUPERFICIES Y PIEZAS DE APLICACION
|
|
66
68
|
surface: 'fe-surface',
|
|
67
69
|
surfaceRaised: 'fe-surface-raised',
|
|
68
70
|
toolbar: 'fe-toolbar',
|
|
69
71
|
badge: 'fe-badge',
|
|
72
|
+
badgePrimary: 'fe-badge-primary',
|
|
73
|
+
badgeSuccess: 'fe-badge-success',
|
|
74
|
+
badgeDanger: 'fe-badge-danger',
|
|
75
|
+
badgeWarning: 'fe-badge-warning',
|
|
70
76
|
skeleton: 'fe-skeleton',
|
|
77
|
+
skeletonText: 'fe-skeleton-text',
|
|
78
|
+
skeletonCircle: 'fe-skeleton-circle',
|
|
79
|
+
skeletonBlock: 'fe-skeleton-block',
|
|
80
|
+
|
|
81
|
+
// DIALOGOS Y DRAWERS, sobre <dialog> y showModal()
|
|
71
82
|
overlay: 'fe-overlay',
|
|
72
83
|
dialog: 'fe-dialog',
|
|
84
|
+
dialogSmall: 'fe-dialog-sm',
|
|
85
|
+
dialogLarge: 'fe-dialog-lg',
|
|
86
|
+
dialogHeader: 'fe-dialog-header',
|
|
87
|
+
dialogTitle: 'fe-dialog-title',
|
|
88
|
+
dialogBody: 'fe-dialog-body',
|
|
89
|
+
dialogFooter: 'fe-dialog-footer',
|
|
73
90
|
drawer: 'fe-drawer',
|
|
91
|
+
drawerStart: 'fe-drawer-start',
|
|
92
|
+
drawerHeader: 'fe-drawer-header',
|
|
93
|
+
drawerTitle: 'fe-drawer-title',
|
|
94
|
+
drawerBody: 'fe-drawer-body',
|
|
95
|
+
drawerFooter: 'fe-drawer-footer',
|
|
96
|
+
|
|
97
|
+
// MENUS, sobre el atributo popover
|
|
74
98
|
menu: 'fe-menu',
|
|
99
|
+
menuList: 'fe-menu-list',
|
|
75
100
|
menuItem: 'fe-menu-item',
|
|
101
|
+
menuItemDanger: 'fe-menu-item-danger',
|
|
102
|
+
menuSeparator: 'fe-menu-separator',
|
|
103
|
+
menuLabel: 'fe-menu-label',
|
|
104
|
+
|
|
105
|
+
// PALETA DE COMANDOS
|
|
106
|
+
command: 'fe-command',
|
|
107
|
+
commandInput: 'fe-command-input',
|
|
108
|
+
commandList: 'fe-command-list',
|
|
109
|
+
commandGroup: 'fe-command-group',
|
|
110
|
+
commandItem: 'fe-command-item',
|
|
111
|
+
commandEmpty: 'fe-command-empty',
|
|
112
|
+
|
|
113
|
+
// AVISOS
|
|
76
114
|
toast: 'fe-toast',
|
|
77
115
|
toastDanger: 'fe-toast-danger',
|
|
78
116
|
toastSuccess: 'fe-toast-success',
|
|
117
|
+
toastWarning: 'fe-toast-warning',
|
|
118
|
+
toastTitle: 'fe-toast-title',
|
|
119
|
+
toastClose: 'fe-toast-close',
|
|
120
|
+
toastRegion: 'fe-toast-region',
|
|
79
121
|
|
|
80
122
|
// TABLA
|
|
81
123
|
table: 'fe-table',
|
|
82
124
|
tableNumeric: 'fe-numeric',
|
|
125
|
+
tableSticky: 'fe-table-sticky',
|
|
126
|
+
tableSelect: 'fe-table-select',
|
|
127
|
+
tableResizer: 'fe-table-resizer',
|
|
128
|
+
tableEmpty: 'fe-table-empty',
|
|
129
|
+
bulkBar: 'fe-bulk-bar',
|
|
130
|
+
bulkCount: 'fe-bulk-count',
|
|
131
|
+
|
|
132
|
+
// EDICION EN LINEA
|
|
133
|
+
editable: 'fe-editable',
|
|
134
|
+
|
|
135
|
+
// SHELL DE APLICACION
|
|
136
|
+
shell: 'fe-shell',
|
|
137
|
+
shellHeader: 'fe-shell-header',
|
|
138
|
+
shellSidebar: 'fe-shell-sidebar',
|
|
139
|
+
shellMain: 'fe-shell-main',
|
|
83
140
|
}
|
|
84
141
|
|
|
85
142
|
/** @type {Theme} */
|
package/src/tokens.css
CHANGED
|
@@ -51,8 +51,15 @@
|
|
|
51
51
|
--fe-warning: #8a6212;
|
|
52
52
|
--fe-warning-soft: #f8f0dd;
|
|
53
53
|
|
|
54
|
+
--fe-info: #1f6fb2;
|
|
55
|
+
--fe-info-soft: #e5f0f9;
|
|
56
|
+
|
|
54
57
|
--fe-focus: #4b5bd7;
|
|
55
58
|
|
|
59
|
+
/* Lo que queda detrás de un diálogo o un drawer abierto. Era un rgba
|
|
60
|
+
escrito dentro de .fe-overlay, igual en claro que en oscuro. */
|
|
61
|
+
--fe-overlay: rgba(16, 18, 27, 0.45);
|
|
62
|
+
|
|
56
63
|
/* ---------- FORMA ---------- */
|
|
57
64
|
|
|
58
65
|
--fe-radius-sm: 4px;
|
|
@@ -97,6 +104,30 @@
|
|
|
97
104
|
/* ---------- MOVIMIENTO ---------- */
|
|
98
105
|
|
|
99
106
|
--fe-transition: 120ms ease;
|
|
107
|
+
--fe-duration-fast: 120ms;
|
|
108
|
+
--fe-duration: 200ms;
|
|
109
|
+
/* Rápido al empezar y suave al llegar: lo que se abre tiene que sentirse
|
|
110
|
+
inmediato, no animado. */
|
|
111
|
+
--fe-ease-out: cubic-bezier(0.2, 0.8, 0.2, 1);
|
|
112
|
+
|
|
113
|
+
/* ---------- CAPAS ---------- */
|
|
114
|
+
|
|
115
|
+
/* Un orden y no un número por componente. Lo que se abre con showModal() o
|
|
116
|
+
con el atributo popover ya vive en la capa superior del navegador y no
|
|
117
|
+
necesita z-index; esto es para lo que no: la cabecera fija de una tabla,
|
|
118
|
+
un overlay dibujado a mano, los tooltips. */
|
|
119
|
+
--fe-z-sticky: 10;
|
|
120
|
+
--fe-z-dropdown: 40;
|
|
121
|
+
--fe-z-overlay: 50;
|
|
122
|
+
--fe-z-tooltip: 60;
|
|
123
|
+
--fe-z-toast: 70;
|
|
124
|
+
|
|
125
|
+
/* ---------- MEDIDAS DE APLICACION ---------- */
|
|
126
|
+
|
|
127
|
+
--fe-dialog-width: 32rem;
|
|
128
|
+
--fe-drawer-width: 32rem;
|
|
129
|
+
--fe-command-width: 40rem;
|
|
130
|
+
--fe-sidebar-width: 15rem;
|
|
100
131
|
}
|
|
101
132
|
|
|
102
133
|
/* La elección explícita de claro gana sobre un sistema en oscuro, de ahí el
|
|
@@ -133,8 +164,13 @@
|
|
|
133
164
|
--fe-warning: #d9ac53;
|
|
134
165
|
--fe-warning-soft: #2a2417;
|
|
135
166
|
|
|
167
|
+
--fe-info: #7cb3e6;
|
|
168
|
+
--fe-info-soft: #16222e;
|
|
169
|
+
|
|
136
170
|
--fe-focus: #8b95f0;
|
|
137
171
|
|
|
172
|
+
--fe-overlay: rgba(0, 0, 0, 0.6);
|
|
173
|
+
|
|
138
174
|
--fe-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4);
|
|
139
175
|
--fe-shadow: 0 4px 12px rgba(0, 0, 0, 0.45);
|
|
140
176
|
--fe-shadow-lg: 0 16px 40px rgba(0, 0, 0, 0.55);
|
|
@@ -173,8 +209,13 @@
|
|
|
173
209
|
--fe-warning: #d9ac53;
|
|
174
210
|
--fe-warning-soft: #2a2417;
|
|
175
211
|
|
|
212
|
+
--fe-info: #7cb3e6;
|
|
213
|
+
--fe-info-soft: #16222e;
|
|
214
|
+
|
|
176
215
|
--fe-focus: #8b95f0;
|
|
177
216
|
|
|
217
|
+
--fe-overlay: rgba(0, 0, 0, 0.6);
|
|
218
|
+
|
|
178
219
|
--fe-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4);
|
|
179
220
|
--fe-shadow: 0 4px 12px rgba(0, 0, 0, 0.45);
|
|
180
221
|
--fe-shadow-lg: 0 16px 40px rgba(0, 0, 0, 0.55);
|