innoboxrr-form-core 2.0.0 → 2.2.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/index.js +9 -0
- package/package.json +2 -1
- package/src/components.css +92 -0
- package/src/icons.js +151 -0
package/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "innoboxrr-form-core",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"description": "El nucleo agnostico de los formularios innoboxrr: tema, archivos y zonas horarias.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"exports": {
|
|
8
8
|
".": "./index.js",
|
|
9
9
|
"./theme": "./src/theme.js",
|
|
10
|
+
"./icons": "./src/icons.js",
|
|
10
11
|
"./files": "./src/files.js",
|
|
11
12
|
"./timezone": "./src/timezone.js",
|
|
12
13
|
"./styles": "./styles.css",
|
package/src/components.css
CHANGED
|
@@ -72,6 +72,98 @@
|
|
|
72
72
|
color: var(--fe-danger);
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
+
/* ============================================================
|
|
76
|
+
TOOLTIP
|
|
77
|
+
============================================================ */
|
|
78
|
+
|
|
79
|
+
/*
|
|
80
|
+
* Sin una linea de JavaScript.
|
|
81
|
+
*
|
|
82
|
+
* Los diez tooltips del ecosistema son texto plano —la ayuda de un campo,
|
|
83
|
+
* «This action is not authorized», «Buscar»—, asi que no hacen falta ni
|
|
84
|
+
* posicionamiento dinamico ni contenido rico. Antes los pintaba `uk-tooltip`,
|
|
85
|
+
* que es un componente de UIkit: para una cadena de ayuda arrastraba un
|
|
86
|
+
* framework entero.
|
|
87
|
+
*
|
|
88
|
+
* <span data-tooltip="Texto de ayuda">…</span>
|
|
89
|
+
* <span data-tooltip="Texto" data-tooltip-pos="right">…</span>
|
|
90
|
+
*
|
|
91
|
+
* Aparece con el raton y **tambien con el foco**, para que exista para quien
|
|
92
|
+
* navega con teclado. Un disparador que no sea enfocable de por si necesita
|
|
93
|
+
* `tabindex="0"`.
|
|
94
|
+
*
|
|
95
|
+
* Un lector de pantalla no anuncia el contenido de un `::after`: cuando el
|
|
96
|
+
* tooltip es la unica etiqueta —un icono suelto— hay que poner ademas un
|
|
97
|
+
* `aria-label` en el disparador. Es lo que hacen los componentes.
|
|
98
|
+
*/
|
|
99
|
+
|
|
100
|
+
[data-tooltip] {
|
|
101
|
+
position: relative;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
[data-tooltip]::after {
|
|
105
|
+
content: attr(data-tooltip);
|
|
106
|
+
position: absolute;
|
|
107
|
+
z-index: 60;
|
|
108
|
+
bottom: calc(100% + var(--fe-space-2));
|
|
109
|
+
left: 50%;
|
|
110
|
+
transform: translateX(-50%);
|
|
111
|
+
width: max-content;
|
|
112
|
+
max-width: 16rem;
|
|
113
|
+
padding: var(--fe-space-1) var(--fe-space-2);
|
|
114
|
+
font-family: var(--fe-font);
|
|
115
|
+
font-size: var(--fe-text-xs);
|
|
116
|
+
font-weight: 400;
|
|
117
|
+
line-height: 1.4;
|
|
118
|
+
white-space: normal;
|
|
119
|
+
text-align: left;
|
|
120
|
+
color: var(--fe-text-inverse);
|
|
121
|
+
background: var(--fe-text);
|
|
122
|
+
border-radius: var(--fe-radius-sm);
|
|
123
|
+
box-shadow: var(--fe-shadow);
|
|
124
|
+
opacity: 0;
|
|
125
|
+
visibility: hidden;
|
|
126
|
+
transition: opacity var(--fe-transition), visibility var(--fe-transition);
|
|
127
|
+
pointer-events: none;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
[data-tooltip]:hover::after,
|
|
131
|
+
[data-tooltip]:focus-visible::after {
|
|
132
|
+
opacity: 1;
|
|
133
|
+
visibility: visible;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/* Un tooltip vacio no debe dibujar una caja negra de dos pixeles. */
|
|
137
|
+
[data-tooltip='']::after {
|
|
138
|
+
content: none;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
[data-tooltip-pos='right']::after {
|
|
142
|
+
bottom: auto;
|
|
143
|
+
top: 50%;
|
|
144
|
+
left: calc(100% + var(--fe-space-2));
|
|
145
|
+
transform: translateY(-50%);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
[data-tooltip-pos='left']::after {
|
|
149
|
+
bottom: auto;
|
|
150
|
+
top: 50%;
|
|
151
|
+
left: auto;
|
|
152
|
+
right: calc(100% + var(--fe-space-2));
|
|
153
|
+
transform: translateY(-50%);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
[data-tooltip-pos='bottom']::after {
|
|
157
|
+
bottom: auto;
|
|
158
|
+
top: calc(100% + var(--fe-space-2));
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
@media (prefers-reduced-motion: reduce) {
|
|
162
|
+
[data-tooltip]::after {
|
|
163
|
+
transition: none;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
75
167
|
/* ============================================================
|
|
76
168
|
CONTROLES
|
|
77
169
|
============================================================ */
|
package/src/icons.js
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Los iconos del ecosistema: un nombre semantico, y un mapa que decide de
|
|
3
|
+
* donde sale el dibujo.
|
|
4
|
+
*
|
|
5
|
+
* Antes hacian falta tres dependencias para pintar un icono: `uikit` ponia el
|
|
6
|
+
* componente, `@fortawesome/fontawesome-free` los glifos y
|
|
7
|
+
* `uikit-custom-icons` hacia de puente registrando los de Font Awesome dentro
|
|
8
|
+
* del registro de UIkit. Por eso `icon: 'fa-plus'` funcionaba —porque alguien
|
|
9
|
+
* escribio el puente—, y por eso dejaba de funcionar en cuanto faltaba
|
|
10
|
+
* cualquiera de las tres.
|
|
11
|
+
*
|
|
12
|
+
* Ahora el componente recibe un nombre semantico (`plus`, `download`) y este
|
|
13
|
+
* mapa dice a que icono corresponde. Los valores son nombres de Iconify
|
|
14
|
+
* (`coleccion:icono`), que son 200.000 iconos de mas de 150 colecciones bajo
|
|
15
|
+
* un solo esquema.
|
|
16
|
+
*
|
|
17
|
+
* Cambiar el aspecto de todo el proyecto es cambiar el mapa:
|
|
18
|
+
*
|
|
19
|
+
* import { setIcons } from 'innoboxrr-form-core'
|
|
20
|
+
*
|
|
21
|
+
* setIcons({ plus: 'lucide:plus', download: 'lucide:download' })
|
|
22
|
+
*
|
|
23
|
+
* Y un nombre de Iconify se puede pasar directo cuando haga falta uno suelto:
|
|
24
|
+
* `iconFor('mdi:home')` devuelve `mdi:home`. El mapa es para lo que se repite,
|
|
25
|
+
* no una aduana.
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @typedef {Record<string, string>} IconMap
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
/** @type {IconMap} */
|
|
33
|
+
export const defaultIcons = {
|
|
34
|
+
// ACCIONES
|
|
35
|
+
plus: 'fa6-solid:plus',
|
|
36
|
+
download: 'fa6-solid:download',
|
|
37
|
+
upload: 'fa6-solid:upload',
|
|
38
|
+
edit: 'fa6-solid:pen',
|
|
39
|
+
delete: 'fa6-solid:trash',
|
|
40
|
+
show: 'fa6-solid:eye',
|
|
41
|
+
hide: 'fa6-solid:eye-slash',
|
|
42
|
+
actions: 'fa6-solid:gears',
|
|
43
|
+
refresh: 'fa6-solid:rotate',
|
|
44
|
+
search: 'fa6-solid:magnifying-glass',
|
|
45
|
+
filter: 'fa6-solid:filter',
|
|
46
|
+
|
|
47
|
+
// ESTADO
|
|
48
|
+
help: 'fa6-solid:circle-question',
|
|
49
|
+
warning: 'fa6-solid:triangle-exclamation',
|
|
50
|
+
error: 'fa6-solid:circle-exclamation',
|
|
51
|
+
success: 'fa6-solid:circle-check',
|
|
52
|
+
info: 'fa6-solid:circle-info',
|
|
53
|
+
locked: 'fa6-solid:lock',
|
|
54
|
+
|
|
55
|
+
// NAVEGACION
|
|
56
|
+
previous: 'fa6-solid:chevron-left',
|
|
57
|
+
next: 'fa6-solid:chevron-right',
|
|
58
|
+
up: 'fa6-solid:chevron-up',
|
|
59
|
+
down: 'fa6-solid:chevron-down',
|
|
60
|
+
close: 'fa6-solid:xmark',
|
|
61
|
+
|
|
62
|
+
// OBJETOS
|
|
63
|
+
box: 'fa6-solid:box',
|
|
64
|
+
users: 'fa6-solid:users',
|
|
65
|
+
gift: 'fa6-solid:gift',
|
|
66
|
+
file: 'fa6-solid:file',
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** @type {IconMap} */
|
|
70
|
+
let icons = { ...defaultIcons }
|
|
71
|
+
|
|
72
|
+
/** @type {Set<(icons: IconMap) => void>} */
|
|
73
|
+
const listeners = new Set()
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Ajusta el mapa. Se mezcla con el actual, asi que se puede cambiar un icono
|
|
77
|
+
* sin repetir los demas.
|
|
78
|
+
*
|
|
79
|
+
* @param {Partial<IconMap>} map
|
|
80
|
+
* @returns {IconMap}
|
|
81
|
+
*/
|
|
82
|
+
export function setIcons(map = {}) {
|
|
83
|
+
icons = { ...icons, ...map }
|
|
84
|
+
|
|
85
|
+
listeners.forEach((listener) => listener(icons))
|
|
86
|
+
|
|
87
|
+
return icons
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Devuelve el mapa completo, o el icono de un nombre.
|
|
92
|
+
*
|
|
93
|
+
* @param {string} [name]
|
|
94
|
+
* @returns {IconMap|string}
|
|
95
|
+
*/
|
|
96
|
+
export function getIcon(name) {
|
|
97
|
+
return name === undefined ? icons : (icons[name] ?? '')
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Resuelve un nombre a un icono de Iconify.
|
|
102
|
+
*
|
|
103
|
+
* Es lo que llaman los componentes. Acepta tres cosas:
|
|
104
|
+
*
|
|
105
|
+
* - un nombre del mapa → `plus` → `fa6-solid:plus`
|
|
106
|
+
* - un nombre de Iconify → `mdi:home` → `mdi:home`
|
|
107
|
+
* - cualquier otra cosa → se devuelve tal cual, para que el fallo se vea
|
|
108
|
+
*
|
|
109
|
+
* @param {string|null|undefined} name
|
|
110
|
+
* @returns {string}
|
|
111
|
+
*/
|
|
112
|
+
export function iconFor(name) {
|
|
113
|
+
if (! name) {
|
|
114
|
+
return ''
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (icons[name]) {
|
|
118
|
+
return icons[name]
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Ya viene con coleccion: es un nombre de Iconify y se pasa entero.
|
|
122
|
+
if (name.includes(':')) {
|
|
123
|
+
return name
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return name
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Vuelve a los valores de fabrica. Sobre todo para las pruebas: el mapa es
|
|
131
|
+
* estado de modulo y sin esto una prueba se filtraria a la siguiente.
|
|
132
|
+
*
|
|
133
|
+
* @returns {IconMap}
|
|
134
|
+
*/
|
|
135
|
+
export function resetIcons() {
|
|
136
|
+
icons = { ...defaultIcons }
|
|
137
|
+
|
|
138
|
+
listeners.forEach((listener) => listener(icons))
|
|
139
|
+
|
|
140
|
+
return icons
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* @param {(icons: IconMap) => void} listener
|
|
145
|
+
* @returns {() => void} para dejar de escuchar
|
|
146
|
+
*/
|
|
147
|
+
export function onIconChange(listener) {
|
|
148
|
+
listeners.add(listener)
|
|
149
|
+
|
|
150
|
+
return () => listeners.delete(listener)
|
|
151
|
+
}
|