@neo-design/foundations 1.0.0-rc.4
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/LICENSE +21 -0
- package/README.md +18 -0
- package/css/alert.css +133 -0
- package/css/aspect-ratio.css +32 -0
- package/css/badge.css +57 -0
- package/css/banner.css +220 -0
- package/css/button-icon.css +14 -0
- package/css/button.css +174 -0
- package/css/checkbox.css +124 -0
- package/css/chips-group.css +26 -0
- package/css/chips.css +88 -0
- package/css/combobox.css +229 -0
- package/css/empty-state.css +149 -0
- package/css/index.css +36 -0
- package/css/link.css +39 -0
- package/css/menu.css +112 -0
- package/css/modal-dialog.css +204 -0
- package/css/modal-fullscreen.css +145 -0
- package/css/radio-button.css +132 -0
- package/css/select.css +181 -0
- package/css/snackbar.css +85 -0
- package/css/spinner.css +21 -0
- package/css/tabs.css +126 -0
- package/css/tag.css +38 -0
- package/css/text-field.css +224 -0
- package/css/toggle.css +53 -0
- package/css/tooltip.css +32 -0
- package/icon-aliases.mjs +57 -0
- package/icons/README.md +84 -0
- package/icons/icons.css +16 -0
- package/icons/index.json +843 -0
- package/icons/sprite.mjs +2 -0
- package/package.json +44 -0
- package/tokens/_brand.mjs +3 -0
- package/tokens/_primitives.mjs +44 -0
- package/tokens/_util.mjs +12 -0
- package/tokens/api-js.mjs +11 -0
- package/tokens/breakpoints.mjs +8 -0
- package/tokens/color-semantic.mjs +47 -0
- package/tokens/color.mjs +58 -0
- package/tokens/component-tokens.mjs +24 -0
- package/tokens/container.mjs +8 -0
- package/tokens/iconSize.mjs +18 -0
- package/tokens/neo-color.css +97 -0
- package/tokens/neo-foundations.css +250 -0
- package/tokens/radius.mjs +18 -0
- package/tokens/shadows.mjs +14 -0
- package/tokens/spacing.mjs +21 -0
- package/tokens/stroke.mjs +15 -0
- package/tokens/typography.mjs +59 -0
package/css/toggle.css
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/* packages/foundations/css/toggle.css — emitted without comments. The reasoning behind each decision lives in Neo's source repository. */
|
|
2
|
+
|
|
3
|
+
.toggle {
|
|
4
|
+
display: inline-flex;
|
|
5
|
+
align-items: center;
|
|
6
|
+
justify-content: center;
|
|
7
|
+
width: 48px;
|
|
8
|
+
height: 44px;
|
|
9
|
+
padding: 0;
|
|
10
|
+
border: none;
|
|
11
|
+
background: transparent;
|
|
12
|
+
cursor: pointer;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.toggle__track {
|
|
16
|
+
display: inline-flex;
|
|
17
|
+
align-items: center;
|
|
18
|
+
width: 48px;
|
|
19
|
+
height: 24px;
|
|
20
|
+
padding-inline: var(--neo-space-xs-rem);
|
|
21
|
+
border-radius: var(--neo-radius-pill);
|
|
22
|
+
background: var(--fill--base--strong);
|
|
23
|
+
transition: background 120ms ease-out;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.toggle__thumb {
|
|
27
|
+
width: 16px;
|
|
28
|
+
height: 16px;
|
|
29
|
+
border-radius: var(--neo-radius-pill);
|
|
30
|
+
background: var(--fill--base--default);
|
|
31
|
+
transition: transform 120ms ease-out;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.toggle[aria-checked="true"] .toggle__track { background: var(--fill--semantic--success--solid); }
|
|
35
|
+
.toggle[aria-checked="true"] .toggle__thumb { transform: translateX(var(--neo-switch-thumb-travel-rem)); }
|
|
36
|
+
|
|
37
|
+
.toggle:focus-visible { outline: none; }
|
|
38
|
+
.toggle:focus-visible .toggle__track {
|
|
39
|
+
box-shadow:
|
|
40
|
+
0 0 0 var(--neo-stroke-focus-ring-width) var(--focus--gap--default),
|
|
41
|
+
0 0 0 calc(2 * var(--neo-stroke-focus-ring-width)) var(--focus--ring--default);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.toggle:disabled { cursor: not-allowed; }
|
|
45
|
+
.toggle:disabled .toggle__track {
|
|
46
|
+
background: var(--fill--base--disabled);
|
|
47
|
+
border: var(--neo-stroke-xs) solid var(--border--base--disabled);
|
|
48
|
+
}
|
|
49
|
+
.toggle:disabled .toggle__thumb { background: var(--fill--base--medium); }
|
|
50
|
+
|
|
51
|
+
@media (prefers-reduced-motion: reduce) {
|
|
52
|
+
.toggle__track, .toggle__thumb { transition: none; }
|
|
53
|
+
}
|
package/css/tooltip.css
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/* packages/foundations/css/tooltip.css — emitted without comments. The reasoning behind each decision lives in Neo's source repository. */
|
|
2
|
+
|
|
3
|
+
.tooltip {
|
|
4
|
+
display: inline-block;
|
|
5
|
+
max-width: 40ch;
|
|
6
|
+
padding-inline: var(--neo-space-sm-rem);
|
|
7
|
+
padding-block: var(--neo-space-xs-rem);
|
|
8
|
+
border-radius: var(--neo-radius-xs);
|
|
9
|
+
background: var(--fill--semantic--info--solid);
|
|
10
|
+
color: var(--text--base--contrast);
|
|
11
|
+
font-size: var(--neo-type-body-md-regular-size-rem);
|
|
12
|
+
font-weight: var(--neo-type-body-md-regular-weight);
|
|
13
|
+
line-height: var(--neo-type-body-md-regular-line-height-rem);
|
|
14
|
+
position: relative;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.tooltip[hidden] { display: none; }
|
|
18
|
+
|
|
19
|
+
.tooltip::before {
|
|
20
|
+
content: none;
|
|
21
|
+
position: absolute;
|
|
22
|
+
border: 6px solid transparent;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.tooltip--top::before { content: ""; bottom: 100%; left: 50%; transform: translateX(-50%); border-bottom-color: var(--fill--semantic--info--solid); }
|
|
26
|
+
.tooltip--bottom::before { content: ""; top: 100%; left: 50%; transform: translateX(-50%); border-top-color: var(--fill--semantic--info--solid); }
|
|
27
|
+
.tooltip--left::before { content: ""; right: 100%; top: 50%; transform: translateY(-50%); border-right-color: var(--fill--semantic--info--solid); }
|
|
28
|
+
.tooltip--right::before { content: ""; left: 100%; top: 50%; transform: translateY(-50%); border-left-color: var(--fill--semantic--info--solid); }
|
|
29
|
+
.tooltip--top-start::before { content: ""; bottom: 100%; left: var(--neo-space-md-rem); border-bottom-color: var(--fill--semantic--info--solid); }
|
|
30
|
+
.tooltip--top-end::before { content: ""; bottom: 100%; right: var(--neo-space-md-rem); border-bottom-color: var(--fill--semantic--info--solid); }
|
|
31
|
+
.tooltip--bottom-start::before { content: ""; top: 100%; left: var(--neo-space-md-rem); border-top-color: var(--fill--semantic--info--solid); }
|
|
32
|
+
.tooltip--bottom-end::before { content: ""; top: 100%; right: var(--neo-space-md-rem); border-top-color: var(--fill--semantic--info--solid); }
|
package/icon-aliases.mjs
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// packages/foundations/icon-aliases.mjs — emitted without comments. The reasoning behind each decision lives in Neo's source repository.
|
|
2
|
+
|
|
3
|
+
export const approved = true;
|
|
4
|
+
export const appliedInFigma = '2026-09-06';
|
|
5
|
+
export const mirroredInCode = true;
|
|
6
|
+
export const mirroredOn = '2026-09-06';
|
|
7
|
+
|
|
8
|
+
export const SYSTEM = {
|
|
9
|
+
advertencia: 'warning', agregar: 'add', 'agregar-circulo': 'add-circle', alarma: 'alarm', ayuda: 'help',
|
|
10
|
+
'bandeja-entrada': 'inbox', 'bandeja-salida': 'outbox', bano: 'restroom', 'bano-mujeres': 'restroom-women',
|
|
11
|
+
billetera: 'wallet', bolsa: 'bag', bombilla: 'lightbulb', brujula: 'compass', buscar: 'search',
|
|
12
|
+
'buscar-circulo': 'search-circle', 'buzon-voz': 'voicemail', 'buzon-voz-silencio': 'voicemail-off',
|
|
13
|
+
calendario: 'calendar', 'calendario-agregar': 'calendar-add', campana: 'bell', 'campana-agregar': 'bell-add',
|
|
14
|
+
'campana-bloquear': 'bell-block', 'campana-silencio': 'bell-off', 'campana-timbrar': 'bell-ring', candado: 'lock',
|
|
15
|
+
carrito: 'cart', 'carrito-agregar': 'cart-add', 'carrito-verificar': 'cart-check', celular: 'mobile',
|
|
16
|
+
cerrar: 'close', 'cerrar-sesion': 'logout', 'chat-burbujas': 'chat', 'chat-escribiendo': 'chat-typing',
|
|
17
|
+
'chevron-abajo': 'chevron-down', 'chevron-arriba': 'chevron-up', 'chevron-derecha': 'chevron-right',
|
|
18
|
+
'chevron-izquierda': 'chevron-left', configuracion: 'settings', copiar: 'copy', corazon: 'heart',
|
|
19
|
+
'corazon-desactivar': 'heart-off', correo: 'mail', 'correo-enviar': 'mail-send', 'derivacion-out': 'referral-out',
|
|
20
|
+
descargar: 'download', diccionario: 'dictionary', editar: 'edit', enlace: 'link', 'enlace-roto': 'link-broken',
|
|
21
|
+
error: 'error', escaner: 'scanner', escudo: 'shield', 'escudo-verificar': 'shield-check', estrella: 'star',
|
|
22
|
+
'flecha-abajo': 'arrow-down', 'flecha-arriba': 'arrow-up', 'flecha-derecha': 'arrow-right',
|
|
23
|
+
'flecha-izquierda': 'arrow-left', 'grafico-baja': 'chart-down', imagen: 'image', informacion: 'info',
|
|
24
|
+
inicio: 'home', kebab: 'kebab', lista: 'list', 'lista-tareas': 'checklist', 'llamada-entrante': 'call-incoming',
|
|
25
|
+
'llamada-entrante-alt': 'call-incoming-alt', mapa: 'map', marcador: 'bookmark', 'media-anterior': 'media-previous',
|
|
26
|
+
'media-avanzar': 'media-forward', 'media-pausa': 'media-pause', 'media-reproducir': 'media-play',
|
|
27
|
+
'media-retroceder': 'media-rewind', 'media-siguiente': 'media-next', megafono: 'megaphone', menos: 'minus',
|
|
28
|
+
'menu-puntos': 'menu-dots', moneda: 'coin', 'nav-derecha': 'nav-right', 'nav-izquierda': 'nav-left',
|
|
29
|
+
navegar: 'navigate', 'navegar-desactivar': 'navigate-off', nube: 'cloud', 'nube-actualizar': 'cloud-refresh',
|
|
30
|
+
'nube-agregar': 'cloud-add', 'nube-alerta': 'cloud-alert', 'nube-bloquear': 'cloud-block',
|
|
31
|
+
'nube-compartir': 'cloud-share', 'nube-transferir': 'cloud-transfer', 'nube-verificar': 'cloud-check',
|
|
32
|
+
'nube-video': 'cloud-video', ojo: 'eye', 'ojo-oculto': 'eye-off', 'papelera-reciclaje': 'trash',
|
|
33
|
+
'portapapeles-agregar': 'clipboard-add', 'portapapeles-eliminar': 'clipboard-remove',
|
|
34
|
+
'portapapeles-verificar': 'clipboard-check', regalo: 'gift', 'reloj-circulo': 'clock', senal: 'signal',
|
|
35
|
+
'silla-ruedas': 'wheelchair', 'sincronizar-alerta': 'sync-alert', soporte: 'support', 'tarjeta-credito': 'credit-card',
|
|
36
|
+
telefono: 'phone', ubicacion: 'location', 'usuario-agregar': 'user-add', 'usuario-circulo': 'user-circle',
|
|
37
|
+
'usuario-id': 'user-id', 'usuario-perfil': 'user-profile', 'usuario-proteger': 'user-shield',
|
|
38
|
+
'usuario-verificar': 'user-check', verificar: 'check', 'verificar-cuadro': 'check-box', 'volumen-alto': 'volume-high',
|
|
39
|
+
'volumen-apagar': 'volume-off', 'volumen-bajar': 'volume-down', 'volumen-bajo': 'volume-low',
|
|
40
|
+
'volumen-mudo': 'volume-mute', wifi: 'wifi', 'wifi-desactivar': 'wifi-off',
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export const BRAND = {
|
|
44
|
+
ambulancia: 'ambulance', bienestar: 'wellness', brillos: 'sparkles', 'call-center': 'call-center', capsula: 'capsule',
|
|
45
|
+
chequeo: 'checkup', contacto: 'contact', conversacion: 'conversation', cruz: 'cross', desktop: 'desktop',
|
|
46
|
+
diente: 'tooth', dinero: 'money', 'donar-sangre': 'blood-donation', enfermero: 'nurse', estetoscopio: 'stethoscope',
|
|
47
|
+
garantia: 'warranty', 'gorro-enfermero': 'nurse-cap', 'gota-sangre': 'blood-drop', 'historial-medico': 'medical-record',
|
|
48
|
+
hospital: 'hospital', hospitalsymbol: 'hospital-symbol', 'maletin-medico': 'medical-bag', mascarilla: 'mask',
|
|
49
|
+
oido: 'ear', ojo: 'eye', pelota: 'ball', 'ritmo-cardiaco': 'heart-rate', salud: 'health', seguro: 'insurance',
|
|
50
|
+
'silla-ruedas': 'wheelchair', 'tarjeta-credito': 'credit-card', telemedicina: 'telemedicine',
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
export const ALIASES = Object.fromEntries([
|
|
55
|
+
...Object.entries(SYSTEM).map(([v, n]) => [`system-${v}`, `system-${n}`]),
|
|
56
|
+
...Object.entries(BRAND).map(([v, n]) => [`brand-${v}`, `brand-${n}`]),
|
|
57
|
+
].filter(([oldName, newName]) => oldName !== newName));
|
package/icons/README.md
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# Neo — Icons
|
|
2
|
+
|
|
3
|
+
167 icons in 3 families —`system`, `semantic` and `brand`, all three compared against the library—, generated from the Figma **Icons** library, which is the source of truth.
|
|
4
|
+
They are not edited by hand: they are regenerated from there.
|
|
5
|
+
|
|
6
|
+
**The set defines no colors of its own: it consumes the color variables of the token system.**
|
|
7
|
+
|
|
8
|
+
| Family | How many | What it is | Color |
|
|
9
|
+
|---|---|---|---|
|
|
10
|
+
| `system` | 125 | **interface** icons: actions, navigation, neutral states | `icon/base/default` by default — **can vary** within the `icon/base/*` base |
|
|
11
|
+
| `semantic` | 10 (5 + 5 `-inverse`) | **feedback** icons: info, alert, success, warning, error | already defined, `icon/semantic/*`. **Not modified** |
|
|
12
|
+
| `brand` | 32 | **brand identity** icons | its own duality, already defined. **Not modified** |
|
|
13
|
+
|
|
14
|
+
> The error state ships **two drawings**: `semantic-error` ("✕") and `semantic-alert` ("!"). Both are
|
|
15
|
+
> painted by `icon/semantic/error`. In the Figma library the first one is named `danger`; the package
|
|
16
|
+
> renames it to `error`, so `danger` is not an id you can use here.
|
|
17
|
+
|
|
18
|
+
## Usage
|
|
19
|
+
|
|
20
|
+
It needs the CSS vars on `:root` — the theme's `<CssBaseline/>` injects them, or the two CSS files in `tokens/` are loaded.
|
|
21
|
+
|
|
22
|
+
The sprite is injected once into the document, and each icon is then requested by its id
|
|
23
|
+
(`<family>-<name>`):
|
|
24
|
+
|
|
25
|
+
```html
|
|
26
|
+
<svg class="icon"><use href="#system-close"/></svg>
|
|
27
|
+
<svg class="icon icon--lg"><use href="#brand-health"/></svg>
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
```css
|
|
31
|
+
/* icons.css brings the base class and the sizes */
|
|
32
|
+
.icon /* 24px · color icon/base/default */
|
|
33
|
+
.icon--xs|sm|md|lg|xl
|
|
34
|
+
.icon--secondary|disabled|inverse
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Which can change color and which cannot
|
|
38
|
+
|
|
39
|
+
**Only the `system` ones.** They come in `icon/base/default` and can take another token **from the same
|
|
40
|
+
base family** as the context requires — `secondary` for lower hierarchy, `disabled` in a
|
|
41
|
+
disabled control, `contrast` on a dark background. The handoff says which one goes on each screen.
|
|
42
|
+
|
|
43
|
+
Since they are exported with `fill="currentColor"`, it is applied by setting `color` on the container:
|
|
44
|
+
|
|
45
|
+
```css
|
|
46
|
+
.mi-componente__icono { color: var(--icon--base--secondary); }
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
The `.icon--secondary|disabled|inverse` classes cover those cases.
|
|
50
|
+
|
|
51
|
+
> **`semantic` and `brand` are not recolored.** They carry their color inside on purpose: an error icon
|
|
52
|
+
> is red wherever it is, and the brand ones keep their duality. Neither `color` nor `currentColor`
|
|
53
|
+
> affects them — and changing them would break the meaning the icon conveys.
|
|
54
|
+
|
|
55
|
+
> A `system` icon **does not take semantic colors**: if something has to convey error or success, the
|
|
56
|
+
> right icon is the one from the `semantic` family, not a `system` painted red.
|
|
57
|
+
|
|
58
|
+
`index.json` lists the 167 icons by family, with their `viewBox` and their color type — useful to
|
|
59
|
+
populate a picker or validate names at build time.
|
|
60
|
+
|
|
61
|
+
## How they are consumed from the package
|
|
62
|
+
|
|
63
|
+
```js
|
|
64
|
+
import '@neo-design/foundations/icons.css';
|
|
65
|
+
import { sprite } from '@neo-design/foundations/sprite';
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
**The sprite is injected into the document and each icon is requested by id:**
|
|
69
|
+
|
|
70
|
+
```html
|
|
71
|
+
<svg class="icon"><use href="#system-add" /></svg>
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
**It is not referenced as a file** —`<use href="icons.svg#id">`— because the browser blocks it by
|
|
75
|
+
CORS. Injecting the sprite once, as high up the tree as possible, avoids the whole case. That is why
|
|
76
|
+
it ships as a string module and not as a file: `import { sprite }` resolves in any bundler and in
|
|
77
|
+
Node, with nothing to configure.
|
|
78
|
+
|
|
79
|
+
And the three families behave differently: **`system`** inherits the context's color (or the
|
|
80
|
+
`.icon` class sets it), **`semantic`** already carries it bound to its token and needs no class, and **`brand`** is
|
|
81
|
+
its own multicolor — it only accepts a size change. The integration guide repeats it with examples.
|
|
82
|
+
|
|
83
|
+
> **Only `icons.css`, `sprite` and `icons.json` are exported**, not the loose SVG files nor the
|
|
84
|
+
> sprite as a file: an `exports` map is an allowlist, and consumption is by sprite, not by file.
|
package/icons/icons.css
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/* packages/foundations/icons/icons.css — emitted without comments. The reasoning behind each decision lives in Neo's source repository. */
|
|
2
|
+
|
|
3
|
+
.icon { display: inline-flex; flex-shrink: 0; width: var(--neo-icon-size-md); height: var(--neo-icon-size-md); }
|
|
4
|
+
.icon--xs { width: var(--neo-icon-size-xs); height: var(--neo-icon-size-xs); }
|
|
5
|
+
.icon--sm { width: var(--neo-icon-size-sm); height: var(--neo-icon-size-sm); }
|
|
6
|
+
.icon--md { width: var(--neo-icon-size-md); height: var(--neo-icon-size-md); }
|
|
7
|
+
.icon--lg { width: var(--neo-icon-size-lg); height: var(--neo-icon-size-lg); }
|
|
8
|
+
.icon--xl { width: var(--neo-icon-size-xl); height: var(--neo-icon-size-xl); }
|
|
9
|
+
.icon--2xl { width: var(--neo-icon-size-2xl); height: var(--neo-icon-size-2xl); }
|
|
10
|
+
.icon--3xl { width: var(--neo-icon-size-3xl); height: var(--neo-icon-size-3xl); }
|
|
11
|
+
.icon--4xl { width: var(--neo-icon-size-4xl); height: var(--neo-icon-size-4xl); }
|
|
12
|
+
|
|
13
|
+
.icon { color: var(--icon--base--default); }
|
|
14
|
+
.icon--secondary { color: var(--icon--base--secondary); }
|
|
15
|
+
.icon--disabled { color: var(--icon--base--disabled); }
|
|
16
|
+
.icon--inverse { color: var(--icon--base--contrast); }
|