intibank-ui 0.3.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/LICENSE +21 -0
- package/README.md +86 -0
- package/dist/index.cjs +187 -0
- package/dist/index.d.cts +65 -0
- package/dist/index.d.mts +65 -0
- package/dist/index.mjs +156 -0
- package/package.json +86 -0
- package/src/styles/semantic.css +101 -0
- package/src/styles/tokens.css +92 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 David Mario LC
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# intibank-ui
|
|
2
|
+
|
|
3
|
+
Librería de componentes de **Intibank**, un banco digital ficticio peruano con identidad visual inspirada en la cultura incaica (concepto central: _Inti_, el dios sol).
|
|
4
|
+
|
|
5
|
+
Es un proyecto de portafolio: una versión reducida pero completa de un design system real — tokens de color en dos capas, componentes accesibles sobre [Base UI](https://base-ui.com), documentación en Fumadocs y catálogo en Storybook.
|
|
6
|
+
|
|
7
|
+
> Intibank es un concepto propio. No está asociado a ninguna entidad financiera real.
|
|
8
|
+
|
|
9
|
+
## Instalación
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pnpm add intibank-ui
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Requiere React 19 o superior como peer dependency.
|
|
16
|
+
|
|
17
|
+
## Uso
|
|
18
|
+
|
|
19
|
+
Los componentes traen sus estilos vía Tailwind CSS v4. Importá los tokens en tu CSS de entrada:
|
|
20
|
+
|
|
21
|
+
```css
|
|
22
|
+
@import "tailwindcss";
|
|
23
|
+
@import "intibank-ui/styles/tokens.css";
|
|
24
|
+
@import "intibank-ui/styles/semantic.css";
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Tailwind v4 no escanea `node_modules` al detectar clases, así que hace falta señalarle el código de la librería para que genere las suyas. Esto aplica a **cualquier** consumidor, tanto instalando desde npm como enlazando el paquete desde un monorepo:
|
|
28
|
+
|
|
29
|
+
```css
|
|
30
|
+
@source "../node_modules/intibank-ui/dist";
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Ajustá la ruta relativa según dónde viva tu CSS de entrada. Si los componentes se renderizan sin estilos, casi siempre es este `@source` faltante.
|
|
34
|
+
|
|
35
|
+
Después, los componentes se usan directo:
|
|
36
|
+
|
|
37
|
+
```tsx
|
|
38
|
+
import { Button, Field, Input } from "intibank-ui";
|
|
39
|
+
|
|
40
|
+
export function Transferencia() {
|
|
41
|
+
return (
|
|
42
|
+
<form>
|
|
43
|
+
<Field.Root
|
|
44
|
+
name="monto"
|
|
45
|
+
validationMode="onBlur"
|
|
46
|
+
validate={(value) =>
|
|
47
|
+
Number(value) > 5000 ? "El monto excede tu límite diario" : null
|
|
48
|
+
}
|
|
49
|
+
>
|
|
50
|
+
<Field.Label>Monto a transferir</Field.Label>
|
|
51
|
+
<Input placeholder="S/ 0.00" />
|
|
52
|
+
<Field.Description>Máximo S/ 5,000 por operación</Field.Description>
|
|
53
|
+
<Field.Error />
|
|
54
|
+
</Field.Root>
|
|
55
|
+
|
|
56
|
+
<Button variant="primary">Transferir</Button>
|
|
57
|
+
</form>
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Componentes
|
|
63
|
+
|
|
64
|
+
| Componente | Descripción |
|
|
65
|
+
| ---------- | ----------- |
|
|
66
|
+
| `Button` | Acciones. Variantes `primary`, `secondary`, `destructive`, `outline`, `ghost`; tamaños `sm`, `default`, `lg`, `icon`. |
|
|
67
|
+
| `Field` | Envoltura de formularios: `Field.Root`, `Field.Label`, `Field.Description`, `Field.Error`. Conecta label, descripción accesible y estado de validación al control. |
|
|
68
|
+
| `Input` | Campo de texto. Tamaños `sm`, `default`, `lg`; estados deshabilitado e inválido. |
|
|
69
|
+
| `Card` | Superficie de contenido: `Card.Root`, `Card.Header`, `Card.Title`, `Card.Description`, `Card.Content`, `Card.Footer`. Cada pieza acepta `render` para decidir su tag (el nivel de heading de `Card.Title` lo elige la página, no el componente). |
|
|
70
|
+
| `Badge` | Estado de una transacción u operación. Variantes `neutral`, `primary`, `secondary`, `success`, `warning`, `destructive`, `outline`; tamaños `sm`, `default`. |
|
|
71
|
+
|
|
72
|
+
Los controles se componen dentro de `Field` y no reimplementan label ni mensajes de error. Cada componente exporta también sus variantes (`buttonVariants`, `inputVariants`, `badgeVariants`) por si necesitás las clases sin el componente.
|
|
73
|
+
|
|
74
|
+
## Design tokens
|
|
75
|
+
|
|
76
|
+
Sistema de dos capas: una **paleta base** con los valores crudos y una capa de **variables semánticas** que es la única que consumen los componentes. Si el color de marca cambia, se edita en un lugar y todo el sistema se actualiza.
|
|
77
|
+
|
|
78
|
+
La paleta base son cinco rampas: `inti` (dorado solar, primario), `terracota` (secundario), `noche` (índigo de marca), `piedra` (neutros fríos, superficies del modo oscuro) y `arena` (neutros cálidos, modo claro), más los semánticos de estado.
|
|
79
|
+
|
|
80
|
+
Las variables semánticas siguen la convención de shadcn/ui — `background`, `foreground`, `card`, `border`, `input`, `ring`, `muted`, `primary`, `secondary`, `accent`, `destructive`, `success`, `warning` — cada una con su `-foreground`. Los semánticos de estado suman un `-text` para cuando el color se usa como texto en vez de superficie: son roles con requisitos de contraste opuestos y no los cumple un valor único.
|
|
81
|
+
|
|
82
|
+
Modo oscuro con la clase `.dark` en un ancestro. Todos los pares de color cumplen WCAG AA.
|
|
83
|
+
|
|
84
|
+
## Licencia
|
|
85
|
+
|
|
86
|
+
MIT
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
//#region \0rolldown/runtime.js
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
11
|
+
key = keys[i];
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
13
|
+
get: ((k) => from[k]).bind(null, key),
|
|
14
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
20
|
+
value: mod,
|
|
21
|
+
enumerable: true
|
|
22
|
+
}) : target, mod));
|
|
23
|
+
//#endregion
|
|
24
|
+
let class_variance_authority = require("class-variance-authority");
|
|
25
|
+
let react = require("react");
|
|
26
|
+
react = __toESM(react, 1);
|
|
27
|
+
let clsx = require("clsx");
|
|
28
|
+
let tailwind_merge = require("tailwind-merge");
|
|
29
|
+
let react_jsx_runtime = require("react/jsx-runtime");
|
|
30
|
+
let _base_ui_react_button = require("@base-ui/react/button");
|
|
31
|
+
let _base_ui_react_use_render = require("@base-ui/react/use-render");
|
|
32
|
+
let _base_ui_react_field = require("@base-ui/react/field");
|
|
33
|
+
let _base_ui_react_input = require("@base-ui/react/input");
|
|
34
|
+
//#region src/lib/cn.ts
|
|
35
|
+
function cn(...inputs) {
|
|
36
|
+
return (0, tailwind_merge.twMerge)((0, clsx.clsx)(inputs));
|
|
37
|
+
}
|
|
38
|
+
//#endregion
|
|
39
|
+
//#region src/components/badge/badge.tsx
|
|
40
|
+
const badgeVariants = (0, class_variance_authority.cva)("inline-flex w-fit shrink-0 items-center justify-center gap-1 whitespace-nowrap rounded-full font-medium [&_svg]:pointer-events-none [&_svg]:size-3 [&_svg]:shrink-0", {
|
|
41
|
+
variants: {
|
|
42
|
+
variant: {
|
|
43
|
+
neutral: "bg-muted text-muted-foreground",
|
|
44
|
+
primary: "bg-primary text-primary-foreground",
|
|
45
|
+
secondary: "bg-secondary text-secondary-foreground",
|
|
46
|
+
success: "bg-success text-success-foreground",
|
|
47
|
+
warning: "bg-warning text-warning-foreground",
|
|
48
|
+
destructive: "bg-destructive text-destructive-foreground",
|
|
49
|
+
outline: "border border-border text-foreground"
|
|
50
|
+
},
|
|
51
|
+
size: {
|
|
52
|
+
sm: "h-5 px-2 text-[0.6875rem]",
|
|
53
|
+
default: "h-6 px-2.5 text-xs"
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
defaultVariants: {
|
|
57
|
+
variant: "neutral",
|
|
58
|
+
size: "default"
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
const Badge = react.forwardRef(({ className, variant, size, ...props }, ref) => {
|
|
62
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
63
|
+
ref,
|
|
64
|
+
className: cn(badgeVariants({
|
|
65
|
+
variant,
|
|
66
|
+
size
|
|
67
|
+
}), className),
|
|
68
|
+
...props
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
Badge.displayName = "Badge";
|
|
72
|
+
//#endregion
|
|
73
|
+
//#region src/components/button/button.tsx
|
|
74
|
+
const buttonVariants = (0, class_variance_authority.cva)("inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", {
|
|
75
|
+
variants: {
|
|
76
|
+
variant: {
|
|
77
|
+
primary: "bg-primary text-primary-foreground hover:bg-primary/90",
|
|
78
|
+
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/90",
|
|
79
|
+
destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
|
|
80
|
+
outline: "border border-input bg-transparent hover:bg-muted",
|
|
81
|
+
ghost: "hover:bg-muted"
|
|
82
|
+
},
|
|
83
|
+
size: {
|
|
84
|
+
sm: "h-8 px-3",
|
|
85
|
+
default: "h-10 px-4",
|
|
86
|
+
lg: "h-12 px-6",
|
|
87
|
+
icon: "size-10 p-0"
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
defaultVariants: {
|
|
91
|
+
variant: "primary",
|
|
92
|
+
size: "default"
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
const Button = react.forwardRef(({ className, variant, size, ...props }, ref) => {
|
|
96
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_base_ui_react_button.Button, {
|
|
97
|
+
ref,
|
|
98
|
+
className: cn(buttonVariants({
|
|
99
|
+
variant,
|
|
100
|
+
size
|
|
101
|
+
}), className),
|
|
102
|
+
...props
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
Button.displayName = "Button";
|
|
106
|
+
//#endregion
|
|
107
|
+
//#region src/components/card/card.tsx
|
|
108
|
+
function createCardPart(displayName, defaultTagName, baseClassName) {
|
|
109
|
+
const Part = react.forwardRef(({ className, render, ...props }, ref) => (0, _base_ui_react_use_render.useRender)({
|
|
110
|
+
render,
|
|
111
|
+
ref,
|
|
112
|
+
defaultTagName,
|
|
113
|
+
props: {
|
|
114
|
+
className: cn(baseClassName, className),
|
|
115
|
+
...props
|
|
116
|
+
}
|
|
117
|
+
}));
|
|
118
|
+
Part.displayName = displayName;
|
|
119
|
+
return Part;
|
|
120
|
+
}
|
|
121
|
+
const Card = {
|
|
122
|
+
Root: createCardPart("Card.Root", "div", "flex flex-col rounded-lg border border-border bg-card text-card-foreground shadow-sm"),
|
|
123
|
+
Header: createCardPart("Card.Header", "div", "flex flex-col gap-1.5 p-6"),
|
|
124
|
+
Title: createCardPart("Card.Title", "h3", "text-base font-semibold leading-none"),
|
|
125
|
+
Description: createCardPart("Card.Description", "p", "text-sm text-muted-foreground"),
|
|
126
|
+
Content: createCardPart("Card.Content", "div", "p-6 pt-0"),
|
|
127
|
+
Footer: createCardPart("Card.Footer", "div", "flex items-center gap-2 p-6 pt-0")
|
|
128
|
+
};
|
|
129
|
+
//#endregion
|
|
130
|
+
//#region src/components/field/field.tsx
|
|
131
|
+
const FieldRoot = react.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_base_ui_react_field.Field.Root, {
|
|
132
|
+
ref,
|
|
133
|
+
className: cn("flex w-full flex-col gap-1.5", className),
|
|
134
|
+
...props
|
|
135
|
+
}));
|
|
136
|
+
FieldRoot.displayName = "Field.Root";
|
|
137
|
+
const FieldLabel = react.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_base_ui_react_field.Field.Label, {
|
|
138
|
+
ref,
|
|
139
|
+
className: cn("text-sm font-medium text-foreground data-[disabled]:opacity-50", className),
|
|
140
|
+
...props
|
|
141
|
+
}));
|
|
142
|
+
FieldLabel.displayName = "Field.Label";
|
|
143
|
+
const FieldDescription = react.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_base_ui_react_field.Field.Description, {
|
|
144
|
+
ref,
|
|
145
|
+
className: cn("text-sm text-muted-foreground", className),
|
|
146
|
+
...props
|
|
147
|
+
}));
|
|
148
|
+
FieldDescription.displayName = "Field.Description";
|
|
149
|
+
const FieldError = react.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_base_ui_react_field.Field.Error, {
|
|
150
|
+
ref,
|
|
151
|
+
className: cn("text-sm text-destructive-text", className),
|
|
152
|
+
...props
|
|
153
|
+
}));
|
|
154
|
+
FieldError.displayName = "Field.Error";
|
|
155
|
+
const Field = {
|
|
156
|
+
Root: FieldRoot,
|
|
157
|
+
Label: FieldLabel,
|
|
158
|
+
Description: FieldDescription,
|
|
159
|
+
Error: FieldError
|
|
160
|
+
};
|
|
161
|
+
//#endregion
|
|
162
|
+
//#region src/components/input/input.tsx
|
|
163
|
+
const inputVariants = (0, class_variance_authority.cva)("flex w-full rounded-md border border-input bg-card text-foreground shadow-xs transition-colors placeholder:text-muted-foreground outline-none focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 data-[invalid]:border-destructive data-[invalid]:focus-visible:ring-destructive aria-invalid:border-destructive aria-invalid:focus-visible:ring-destructive", {
|
|
164
|
+
variants: { size: {
|
|
165
|
+
sm: "h-8 px-2.5 text-sm",
|
|
166
|
+
default: "h-10 px-3 text-sm",
|
|
167
|
+
lg: "h-12 px-4 text-base"
|
|
168
|
+
} },
|
|
169
|
+
defaultVariants: { size: "default" }
|
|
170
|
+
});
|
|
171
|
+
const Input = react.forwardRef(({ className, size, ...props }, ref) => {
|
|
172
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_base_ui_react_input.Input, {
|
|
173
|
+
ref,
|
|
174
|
+
className: cn(inputVariants({ size }), className),
|
|
175
|
+
...props
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
Input.displayName = "Input";
|
|
179
|
+
//#endregion
|
|
180
|
+
exports.Badge = Badge;
|
|
181
|
+
exports.Button = Button;
|
|
182
|
+
exports.Card = Card;
|
|
183
|
+
exports.Field = Field;
|
|
184
|
+
exports.Input = Input;
|
|
185
|
+
exports.badgeVariants = badgeVariants;
|
|
186
|
+
exports.buttonVariants = buttonVariants;
|
|
187
|
+
exports.inputVariants = inputVariants;
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { VariantProps } from "class-variance-authority";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { Button as Button$1 } from "@base-ui/react/button";
|
|
4
|
+
import { useRender } from "@base-ui/react/use-render";
|
|
5
|
+
import { Field as Field$1 } from "@base-ui/react/field";
|
|
6
|
+
import { Input as Input$1 } from "@base-ui/react/input";
|
|
7
|
+
//#region src/components/badge/badge.d.ts
|
|
8
|
+
declare const badgeVariants: (props?: ({
|
|
9
|
+
variant?: "primary" | "secondary" | "destructive" | "outline" | "neutral" | "success" | "warning" | null | undefined;
|
|
10
|
+
size?: "sm" | "default" | null | undefined;
|
|
11
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
12
|
+
interface BadgeProps extends React.ComponentPropsWithoutRef<"span">, VariantProps<typeof badgeVariants> {}
|
|
13
|
+
declare const Badge: React.ForwardRefExoticComponent<BadgeProps & React.RefAttributes<HTMLSpanElement>>;
|
|
14
|
+
//#endregion
|
|
15
|
+
//#region src/components/button/button.d.ts
|
|
16
|
+
declare const buttonVariants: (props?: ({
|
|
17
|
+
variant?: "primary" | "secondary" | "destructive" | "outline" | "ghost" | null | undefined;
|
|
18
|
+
size?: "sm" | "default" | "lg" | "icon" | null | undefined;
|
|
19
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
20
|
+
interface ButtonProps extends Omit<Button$1.Props, "className">, VariantProps<typeof buttonVariants> {
|
|
21
|
+
className?: string;
|
|
22
|
+
}
|
|
23
|
+
declare const Button: React.ForwardRefExoticComponent<Omit<ButtonProps, "ref"> & React.RefAttributes<HTMLElement>>;
|
|
24
|
+
//#endregion
|
|
25
|
+
//#region src/components/card/card.d.ts
|
|
26
|
+
interface CardPartProps extends Omit<useRender.ComponentProps<"div">, "ref"> {}
|
|
27
|
+
declare const Card: {
|
|
28
|
+
Root: React.ForwardRefExoticComponent<CardPartProps & React.RefAttributes<HTMLElement>>;
|
|
29
|
+
Header: React.ForwardRefExoticComponent<CardPartProps & React.RefAttributes<HTMLElement>>;
|
|
30
|
+
Title: React.ForwardRefExoticComponent<CardPartProps & React.RefAttributes<HTMLElement>>;
|
|
31
|
+
Description: React.ForwardRefExoticComponent<CardPartProps & React.RefAttributes<HTMLElement>>;
|
|
32
|
+
Content: React.ForwardRefExoticComponent<CardPartProps & React.RefAttributes<HTMLElement>>;
|
|
33
|
+
Footer: React.ForwardRefExoticComponent<CardPartProps & React.RefAttributes<HTMLElement>>;
|
|
34
|
+
};
|
|
35
|
+
//#endregion
|
|
36
|
+
//#region src/components/field/field.d.ts
|
|
37
|
+
interface FieldRootProps extends Omit<Field$1.Root.Props, "className"> {
|
|
38
|
+
className?: string;
|
|
39
|
+
}
|
|
40
|
+
interface FieldLabelProps extends Omit<Field$1.Label.Props, "className"> {
|
|
41
|
+
className?: string;
|
|
42
|
+
}
|
|
43
|
+
interface FieldDescriptionProps extends Omit<Field$1.Description.Props, "className"> {
|
|
44
|
+
className?: string;
|
|
45
|
+
}
|
|
46
|
+
interface FieldErrorProps extends Omit<Field$1.Error.Props, "className"> {
|
|
47
|
+
className?: string;
|
|
48
|
+
}
|
|
49
|
+
declare const Field: {
|
|
50
|
+
Root: React.ForwardRefExoticComponent<Omit<FieldRootProps, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
51
|
+
Label: React.ForwardRefExoticComponent<Omit<FieldLabelProps, "ref"> & React.RefAttributes<HTMLLabelElement>>;
|
|
52
|
+
Description: React.ForwardRefExoticComponent<Omit<FieldDescriptionProps, "ref"> & React.RefAttributes<HTMLParagraphElement>>;
|
|
53
|
+
Error: React.ForwardRefExoticComponent<Omit<FieldErrorProps, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
54
|
+
};
|
|
55
|
+
//#endregion
|
|
56
|
+
//#region src/components/input/input.d.ts
|
|
57
|
+
declare const inputVariants: (props?: ({
|
|
58
|
+
size?: "sm" | "default" | "lg" | null | undefined;
|
|
59
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
60
|
+
interface InputProps extends Omit<Input$1.Props, "className" | "size">, VariantProps<typeof inputVariants> {
|
|
61
|
+
className?: string;
|
|
62
|
+
}
|
|
63
|
+
declare const Input: React.ForwardRefExoticComponent<Omit<InputProps, "ref"> & React.RefAttributes<HTMLElement>>;
|
|
64
|
+
//#endregion
|
|
65
|
+
export { Badge, type BadgeProps, Button, type ButtonProps, Card, type CardPartProps, Field, type FieldDescriptionProps, type FieldErrorProps, type FieldLabelProps, type FieldRootProps, Input, type InputProps, badgeVariants, buttonVariants, inputVariants };
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { VariantProps } from "class-variance-authority";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { Button as Button$1 } from "@base-ui/react/button";
|
|
4
|
+
import { useRender } from "@base-ui/react/use-render";
|
|
5
|
+
import { Field as Field$1 } from "@base-ui/react/field";
|
|
6
|
+
import { Input as Input$1 } from "@base-ui/react/input";
|
|
7
|
+
//#region src/components/badge/badge.d.ts
|
|
8
|
+
declare const badgeVariants: (props?: ({
|
|
9
|
+
variant?: "primary" | "secondary" | "destructive" | "outline" | "neutral" | "success" | "warning" | null | undefined;
|
|
10
|
+
size?: "sm" | "default" | null | undefined;
|
|
11
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
12
|
+
interface BadgeProps extends React.ComponentPropsWithoutRef<"span">, VariantProps<typeof badgeVariants> {}
|
|
13
|
+
declare const Badge: React.ForwardRefExoticComponent<BadgeProps & React.RefAttributes<HTMLSpanElement>>;
|
|
14
|
+
//#endregion
|
|
15
|
+
//#region src/components/button/button.d.ts
|
|
16
|
+
declare const buttonVariants: (props?: ({
|
|
17
|
+
variant?: "primary" | "secondary" | "destructive" | "outline" | "ghost" | null | undefined;
|
|
18
|
+
size?: "sm" | "default" | "lg" | "icon" | null | undefined;
|
|
19
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
20
|
+
interface ButtonProps extends Omit<Button$1.Props, "className">, VariantProps<typeof buttonVariants> {
|
|
21
|
+
className?: string;
|
|
22
|
+
}
|
|
23
|
+
declare const Button: React.ForwardRefExoticComponent<Omit<ButtonProps, "ref"> & React.RefAttributes<HTMLElement>>;
|
|
24
|
+
//#endregion
|
|
25
|
+
//#region src/components/card/card.d.ts
|
|
26
|
+
interface CardPartProps extends Omit<useRender.ComponentProps<"div">, "ref"> {}
|
|
27
|
+
declare const Card: {
|
|
28
|
+
Root: React.ForwardRefExoticComponent<CardPartProps & React.RefAttributes<HTMLElement>>;
|
|
29
|
+
Header: React.ForwardRefExoticComponent<CardPartProps & React.RefAttributes<HTMLElement>>;
|
|
30
|
+
Title: React.ForwardRefExoticComponent<CardPartProps & React.RefAttributes<HTMLElement>>;
|
|
31
|
+
Description: React.ForwardRefExoticComponent<CardPartProps & React.RefAttributes<HTMLElement>>;
|
|
32
|
+
Content: React.ForwardRefExoticComponent<CardPartProps & React.RefAttributes<HTMLElement>>;
|
|
33
|
+
Footer: React.ForwardRefExoticComponent<CardPartProps & React.RefAttributes<HTMLElement>>;
|
|
34
|
+
};
|
|
35
|
+
//#endregion
|
|
36
|
+
//#region src/components/field/field.d.ts
|
|
37
|
+
interface FieldRootProps extends Omit<Field$1.Root.Props, "className"> {
|
|
38
|
+
className?: string;
|
|
39
|
+
}
|
|
40
|
+
interface FieldLabelProps extends Omit<Field$1.Label.Props, "className"> {
|
|
41
|
+
className?: string;
|
|
42
|
+
}
|
|
43
|
+
interface FieldDescriptionProps extends Omit<Field$1.Description.Props, "className"> {
|
|
44
|
+
className?: string;
|
|
45
|
+
}
|
|
46
|
+
interface FieldErrorProps extends Omit<Field$1.Error.Props, "className"> {
|
|
47
|
+
className?: string;
|
|
48
|
+
}
|
|
49
|
+
declare const Field: {
|
|
50
|
+
Root: React.ForwardRefExoticComponent<Omit<FieldRootProps, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
51
|
+
Label: React.ForwardRefExoticComponent<Omit<FieldLabelProps, "ref"> & React.RefAttributes<HTMLLabelElement>>;
|
|
52
|
+
Description: React.ForwardRefExoticComponent<Omit<FieldDescriptionProps, "ref"> & React.RefAttributes<HTMLParagraphElement>>;
|
|
53
|
+
Error: React.ForwardRefExoticComponent<Omit<FieldErrorProps, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
54
|
+
};
|
|
55
|
+
//#endregion
|
|
56
|
+
//#region src/components/input/input.d.ts
|
|
57
|
+
declare const inputVariants: (props?: ({
|
|
58
|
+
size?: "sm" | "default" | "lg" | null | undefined;
|
|
59
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
60
|
+
interface InputProps extends Omit<Input$1.Props, "className" | "size">, VariantProps<typeof inputVariants> {
|
|
61
|
+
className?: string;
|
|
62
|
+
}
|
|
63
|
+
declare const Input: React.ForwardRefExoticComponent<Omit<InputProps, "ref"> & React.RefAttributes<HTMLElement>>;
|
|
64
|
+
//#endregion
|
|
65
|
+
export { Badge, type BadgeProps, Button, type ButtonProps, Card, type CardPartProps, Field, type FieldDescriptionProps, type FieldErrorProps, type FieldLabelProps, type FieldRootProps, Input, type InputProps, badgeVariants, buttonVariants, inputVariants };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { cva } from "class-variance-authority";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { clsx } from "clsx";
|
|
4
|
+
import { twMerge } from "tailwind-merge";
|
|
5
|
+
import { jsx } from "react/jsx-runtime";
|
|
6
|
+
import { Button as Button$1 } from "@base-ui/react/button";
|
|
7
|
+
import { useRender } from "@base-ui/react/use-render";
|
|
8
|
+
import { Field as Field$1 } from "@base-ui/react/field";
|
|
9
|
+
import { Input as Input$1 } from "@base-ui/react/input";
|
|
10
|
+
//#region src/lib/cn.ts
|
|
11
|
+
function cn(...inputs) {
|
|
12
|
+
return twMerge(clsx(inputs));
|
|
13
|
+
}
|
|
14
|
+
//#endregion
|
|
15
|
+
//#region src/components/badge/badge.tsx
|
|
16
|
+
const badgeVariants = cva("inline-flex w-fit shrink-0 items-center justify-center gap-1 whitespace-nowrap rounded-full font-medium [&_svg]:pointer-events-none [&_svg]:size-3 [&_svg]:shrink-0", {
|
|
17
|
+
variants: {
|
|
18
|
+
variant: {
|
|
19
|
+
neutral: "bg-muted text-muted-foreground",
|
|
20
|
+
primary: "bg-primary text-primary-foreground",
|
|
21
|
+
secondary: "bg-secondary text-secondary-foreground",
|
|
22
|
+
success: "bg-success text-success-foreground",
|
|
23
|
+
warning: "bg-warning text-warning-foreground",
|
|
24
|
+
destructive: "bg-destructive text-destructive-foreground",
|
|
25
|
+
outline: "border border-border text-foreground"
|
|
26
|
+
},
|
|
27
|
+
size: {
|
|
28
|
+
sm: "h-5 px-2 text-[0.6875rem]",
|
|
29
|
+
default: "h-6 px-2.5 text-xs"
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
defaultVariants: {
|
|
33
|
+
variant: "neutral",
|
|
34
|
+
size: "default"
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
const Badge = React.forwardRef(({ className, variant, size, ...props }, ref) => {
|
|
38
|
+
return /* @__PURE__ */ jsx("span", {
|
|
39
|
+
ref,
|
|
40
|
+
className: cn(badgeVariants({
|
|
41
|
+
variant,
|
|
42
|
+
size
|
|
43
|
+
}), className),
|
|
44
|
+
...props
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
Badge.displayName = "Badge";
|
|
48
|
+
//#endregion
|
|
49
|
+
//#region src/components/button/button.tsx
|
|
50
|
+
const buttonVariants = cva("inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", {
|
|
51
|
+
variants: {
|
|
52
|
+
variant: {
|
|
53
|
+
primary: "bg-primary text-primary-foreground hover:bg-primary/90",
|
|
54
|
+
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/90",
|
|
55
|
+
destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
|
|
56
|
+
outline: "border border-input bg-transparent hover:bg-muted",
|
|
57
|
+
ghost: "hover:bg-muted"
|
|
58
|
+
},
|
|
59
|
+
size: {
|
|
60
|
+
sm: "h-8 px-3",
|
|
61
|
+
default: "h-10 px-4",
|
|
62
|
+
lg: "h-12 px-6",
|
|
63
|
+
icon: "size-10 p-0"
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
defaultVariants: {
|
|
67
|
+
variant: "primary",
|
|
68
|
+
size: "default"
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
const Button = React.forwardRef(({ className, variant, size, ...props }, ref) => {
|
|
72
|
+
return /* @__PURE__ */ jsx(Button$1, {
|
|
73
|
+
ref,
|
|
74
|
+
className: cn(buttonVariants({
|
|
75
|
+
variant,
|
|
76
|
+
size
|
|
77
|
+
}), className),
|
|
78
|
+
...props
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
Button.displayName = "Button";
|
|
82
|
+
//#endregion
|
|
83
|
+
//#region src/components/card/card.tsx
|
|
84
|
+
function createCardPart(displayName, defaultTagName, baseClassName) {
|
|
85
|
+
const Part = React.forwardRef(({ className, render, ...props }, ref) => useRender({
|
|
86
|
+
render,
|
|
87
|
+
ref,
|
|
88
|
+
defaultTagName,
|
|
89
|
+
props: {
|
|
90
|
+
className: cn(baseClassName, className),
|
|
91
|
+
...props
|
|
92
|
+
}
|
|
93
|
+
}));
|
|
94
|
+
Part.displayName = displayName;
|
|
95
|
+
return Part;
|
|
96
|
+
}
|
|
97
|
+
const Card = {
|
|
98
|
+
Root: createCardPart("Card.Root", "div", "flex flex-col rounded-lg border border-border bg-card text-card-foreground shadow-sm"),
|
|
99
|
+
Header: createCardPart("Card.Header", "div", "flex flex-col gap-1.5 p-6"),
|
|
100
|
+
Title: createCardPart("Card.Title", "h3", "text-base font-semibold leading-none"),
|
|
101
|
+
Description: createCardPart("Card.Description", "p", "text-sm text-muted-foreground"),
|
|
102
|
+
Content: createCardPart("Card.Content", "div", "p-6 pt-0"),
|
|
103
|
+
Footer: createCardPart("Card.Footer", "div", "flex items-center gap-2 p-6 pt-0")
|
|
104
|
+
};
|
|
105
|
+
//#endregion
|
|
106
|
+
//#region src/components/field/field.tsx
|
|
107
|
+
const FieldRoot = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(Field$1.Root, {
|
|
108
|
+
ref,
|
|
109
|
+
className: cn("flex w-full flex-col gap-1.5", className),
|
|
110
|
+
...props
|
|
111
|
+
}));
|
|
112
|
+
FieldRoot.displayName = "Field.Root";
|
|
113
|
+
const FieldLabel = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(Field$1.Label, {
|
|
114
|
+
ref,
|
|
115
|
+
className: cn("text-sm font-medium text-foreground data-[disabled]:opacity-50", className),
|
|
116
|
+
...props
|
|
117
|
+
}));
|
|
118
|
+
FieldLabel.displayName = "Field.Label";
|
|
119
|
+
const FieldDescription = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(Field$1.Description, {
|
|
120
|
+
ref,
|
|
121
|
+
className: cn("text-sm text-muted-foreground", className),
|
|
122
|
+
...props
|
|
123
|
+
}));
|
|
124
|
+
FieldDescription.displayName = "Field.Description";
|
|
125
|
+
const FieldError = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(Field$1.Error, {
|
|
126
|
+
ref,
|
|
127
|
+
className: cn("text-sm text-destructive-text", className),
|
|
128
|
+
...props
|
|
129
|
+
}));
|
|
130
|
+
FieldError.displayName = "Field.Error";
|
|
131
|
+
const Field = {
|
|
132
|
+
Root: FieldRoot,
|
|
133
|
+
Label: FieldLabel,
|
|
134
|
+
Description: FieldDescription,
|
|
135
|
+
Error: FieldError
|
|
136
|
+
};
|
|
137
|
+
//#endregion
|
|
138
|
+
//#region src/components/input/input.tsx
|
|
139
|
+
const inputVariants = cva("flex w-full rounded-md border border-input bg-card text-foreground shadow-xs transition-colors placeholder:text-muted-foreground outline-none focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 data-[invalid]:border-destructive data-[invalid]:focus-visible:ring-destructive aria-invalid:border-destructive aria-invalid:focus-visible:ring-destructive", {
|
|
140
|
+
variants: { size: {
|
|
141
|
+
sm: "h-8 px-2.5 text-sm",
|
|
142
|
+
default: "h-10 px-3 text-sm",
|
|
143
|
+
lg: "h-12 px-4 text-base"
|
|
144
|
+
} },
|
|
145
|
+
defaultVariants: { size: "default" }
|
|
146
|
+
});
|
|
147
|
+
const Input = React.forwardRef(({ className, size, ...props }, ref) => {
|
|
148
|
+
return /* @__PURE__ */ jsx(Input$1, {
|
|
149
|
+
ref,
|
|
150
|
+
className: cn(inputVariants({ size }), className),
|
|
151
|
+
...props
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
Input.displayName = "Input";
|
|
155
|
+
//#endregion
|
|
156
|
+
export { Badge, Button, Card, Field, Input, badgeVariants, buttonVariants, inputVariants };
|
package/package.json
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "intibank-ui",
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"private": false,
|
|
5
|
+
"description": "Component library for Intibank, a fictional digital bank design system.",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": "David Mario LC <davidmariolc.dev@gmail.com>",
|
|
8
|
+
"homepage": "https://github.com/DavidMarioLC/intibank-design-system#readme",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/DavidMarioLC/intibank-design-system.git",
|
|
12
|
+
"directory": "packages/ui"
|
|
13
|
+
},
|
|
14
|
+
"bugs": {
|
|
15
|
+
"url": "https://github.com/DavidMarioLC/intibank-design-system/issues"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"design-system",
|
|
19
|
+
"react",
|
|
20
|
+
"components",
|
|
21
|
+
"ui",
|
|
22
|
+
"tailwindcss",
|
|
23
|
+
"base-ui",
|
|
24
|
+
"design-tokens"
|
|
25
|
+
],
|
|
26
|
+
"sideEffects": [
|
|
27
|
+
"**/*.css"
|
|
28
|
+
],
|
|
29
|
+
"type": "module",
|
|
30
|
+
"main": "./dist/index.cjs",
|
|
31
|
+
"module": "./dist/index.mjs",
|
|
32
|
+
"types": "./dist/index.d.mts",
|
|
33
|
+
"exports": {
|
|
34
|
+
".": {
|
|
35
|
+
"import": {
|
|
36
|
+
"types": "./dist/index.d.mts",
|
|
37
|
+
"default": "./dist/index.mjs"
|
|
38
|
+
},
|
|
39
|
+
"require": {
|
|
40
|
+
"types": "./dist/index.d.cts",
|
|
41
|
+
"default": "./dist/index.cjs"
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
"./styles/tokens.css": "./src/styles/tokens.css",
|
|
45
|
+
"./styles/semantic.css": "./src/styles/semantic.css"
|
|
46
|
+
},
|
|
47
|
+
"files": [
|
|
48
|
+
"dist",
|
|
49
|
+
"src/styles",
|
|
50
|
+
"README.md",
|
|
51
|
+
"LICENSE"
|
|
52
|
+
],
|
|
53
|
+
"peerDependencies": {
|
|
54
|
+
"react": ">=19",
|
|
55
|
+
"react-dom": ">=19"
|
|
56
|
+
},
|
|
57
|
+
"dependencies": {
|
|
58
|
+
"@base-ui/react": "^1.6.0",
|
|
59
|
+
"class-variance-authority": "^0.7.1",
|
|
60
|
+
"clsx": "^2.1.1",
|
|
61
|
+
"tailwind-merge": "^3.3.1"
|
|
62
|
+
},
|
|
63
|
+
"devDependencies": {
|
|
64
|
+
"@storybook/react-vite": "10.5.4",
|
|
65
|
+
"@testing-library/jest-dom": "^6.6.3",
|
|
66
|
+
"@testing-library/react": "^16.3.2",
|
|
67
|
+
"@testing-library/user-event": "^14.5.2",
|
|
68
|
+
"@types/react": "^19.0.0",
|
|
69
|
+
"@types/react-dom": "^19.0.0",
|
|
70
|
+
"jsdom": "^25.0.0",
|
|
71
|
+
"react": "^19.0.0",
|
|
72
|
+
"react-dom": "^19.0.0",
|
|
73
|
+
"storybook": "10.5.4",
|
|
74
|
+
"tailwindcss": "^4.3.3",
|
|
75
|
+
"tsdown": "^0.22.14",
|
|
76
|
+
"typescript": "^5.7.0",
|
|
77
|
+
"vitest": "^4.1.10",
|
|
78
|
+
"@intibank/tsconfig": "0.0.0"
|
|
79
|
+
},
|
|
80
|
+
"scripts": {
|
|
81
|
+
"build": "tsdown",
|
|
82
|
+
"dev": "tsdown --watch",
|
|
83
|
+
"test": "vitest run",
|
|
84
|
+
"lint": "tsc --noEmit"
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
@layer base {
|
|
2
|
+
:root {
|
|
3
|
+
/* Base surfaces */
|
|
4
|
+
--background: var(--color-arena-50);
|
|
5
|
+
--foreground: var(--color-noche-900);
|
|
6
|
+
|
|
7
|
+
--card: #ffffff;
|
|
8
|
+
--card-foreground: var(--color-noche-900);
|
|
9
|
+
|
|
10
|
+
--popover: #ffffff;
|
|
11
|
+
--popover-foreground: var(--color-noche-900);
|
|
12
|
+
|
|
13
|
+
/* Bordes y controles */
|
|
14
|
+
--border: var(--color-arena-200);
|
|
15
|
+
--input: var(--color-arena-300);
|
|
16
|
+
--ring: var(--color-inti-500);
|
|
17
|
+
|
|
18
|
+
/* Muted (fondos sutiles, texto secundario) */
|
|
19
|
+
--muted: var(--color-arena-100);
|
|
20
|
+
--muted-foreground: var(--color-arena-600);
|
|
21
|
+
|
|
22
|
+
/* Marca */
|
|
23
|
+
--primary: var(--color-inti-600);
|
|
24
|
+
--primary-foreground: var(--color-arena-50);
|
|
25
|
+
|
|
26
|
+
--secondary: var(--color-terracota-600);
|
|
27
|
+
--secondary-foreground: var(--color-arena-50);
|
|
28
|
+
|
|
29
|
+
--accent: var(--color-noche-900);
|
|
30
|
+
--accent-foreground: var(--color-arena-50);
|
|
31
|
+
|
|
32
|
+
/* Semánticos.
|
|
33
|
+
Cada uno viene en dos sabores porque los roles piden lo contrario:
|
|
34
|
+
el par `X` / `X-foreground` es una SUPERFICIE (fondo de botón, badge)
|
|
35
|
+
y se mide contra su propio texto; `X-text` es el color como TEXTO o
|
|
36
|
+
ícono sobre `background` y se mide contra el fondo de la página.
|
|
37
|
+
Un solo valor no puede cumplir ambos: al aclararlo para que se lea
|
|
38
|
+
sobre el fondo, deja de contrastar con el blanco que lleva encima. */
|
|
39
|
+
--destructive: var(--color-error-500);
|
|
40
|
+
--destructive-foreground: #ffffff;
|
|
41
|
+
--destructive-text: var(--color-error-600);
|
|
42
|
+
|
|
43
|
+
/* success-500 con blanco da 3.3:1 — el verde saturado necesita el 600. */
|
|
44
|
+
--success: var(--color-success-600);
|
|
45
|
+
--success-foreground: #ffffff;
|
|
46
|
+
--success-text: var(--color-success-600);
|
|
47
|
+
|
|
48
|
+
--warning: var(--color-warning-500);
|
|
49
|
+
--warning-foreground: var(--color-noche-900);
|
|
50
|
+
--warning-text: var(--color-warning-700);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/* El modo oscuro construye sus superficies sobre `piedra`, no sobre
|
|
54
|
+
`noche`: `noche` sigue siendo el índigo de marca, pero como fondo se
|
|
55
|
+
lee morado y le compite al dorado. Las superficies quedan casi neutras
|
|
56
|
+
y la identidad la carga `primary`. Los tonos saturados suben un escalón
|
|
57
|
+
respecto al modo claro para no perder visibilidad sobre fondo oscuro. */
|
|
58
|
+
.dark {
|
|
59
|
+
--background: var(--color-piedra-950);
|
|
60
|
+
--foreground: var(--color-piedra-50);
|
|
61
|
+
|
|
62
|
+
--card: var(--color-piedra-900);
|
|
63
|
+
--card-foreground: var(--color-piedra-50);
|
|
64
|
+
|
|
65
|
+
--popover: var(--color-piedra-900);
|
|
66
|
+
--popover-foreground: var(--color-piedra-50);
|
|
67
|
+
|
|
68
|
+
--border: var(--color-piedra-700);
|
|
69
|
+
--input: var(--color-piedra-600);
|
|
70
|
+
--ring: var(--color-inti-400);
|
|
71
|
+
|
|
72
|
+
--muted: var(--color-piedra-800);
|
|
73
|
+
/* piedra-400 daría 3.98:1 sobre el fondo — no alcanza para texto. */
|
|
74
|
+
--muted-foreground: var(--color-piedra-300);
|
|
75
|
+
|
|
76
|
+
--primary: var(--color-inti-500);
|
|
77
|
+
--primary-foreground: var(--color-piedra-950);
|
|
78
|
+
|
|
79
|
+
--secondary: var(--color-terracota-500);
|
|
80
|
+
--secondary-foreground: var(--color-piedra-950);
|
|
81
|
+
|
|
82
|
+
--accent: var(--color-inti-400);
|
|
83
|
+
--accent-foreground: var(--color-piedra-950);
|
|
84
|
+
|
|
85
|
+
/* Las superficies NO se aclaran en modo oscuro: un botón destructivo en
|
|
86
|
+
error-400 queda rosa pastel y se lee menos grave que el secundario, o
|
|
87
|
+
sea al revés de lo que la jerarquía de riesgo necesita. El que sube un
|
|
88
|
+
escalón es `X-text`, que sí se mide contra el fondo oscuro. */
|
|
89
|
+
--destructive: var(--color-error-500);
|
|
90
|
+
--destructive-foreground: #ffffff;
|
|
91
|
+
--destructive-text: var(--color-error-400);
|
|
92
|
+
|
|
93
|
+
--success: var(--color-success-600);
|
|
94
|
+
--success-foreground: #ffffff;
|
|
95
|
+
--success-text: var(--color-success-400);
|
|
96
|
+
|
|
97
|
+
--warning: var(--color-warning-500);
|
|
98
|
+
--warning-foreground: var(--color-noche-900);
|
|
99
|
+
--warning-text: var(--color-warning-400);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/* `static` evita que Tailwind elimine los shades que ningún selector del
|
|
2
|
+
monorepo referencia todavía (ej. inti-700) — tokens.css es la paleta
|
|
3
|
+
pública completa, no solo las utilidades usadas hoy. */
|
|
4
|
+
@theme static {
|
|
5
|
+
/* Inti (dorado/ámbar solar) — primario */
|
|
6
|
+
--color-inti-50: #fffbeb;
|
|
7
|
+
--color-inti-100: #fef3c7;
|
|
8
|
+
--color-inti-200: #fde68a;
|
|
9
|
+
--color-inti-300: #fcd34d;
|
|
10
|
+
--color-inti-400: #fbbf24;
|
|
11
|
+
--color-inti-500: #f59e0b;
|
|
12
|
+
--color-inti-600: #d97706;
|
|
13
|
+
--color-inti-700: #b45309;
|
|
14
|
+
--color-inti-800: #92400e;
|
|
15
|
+
--color-inti-900: #78350f;
|
|
16
|
+
--color-inti-950: #451a03;
|
|
17
|
+
|
|
18
|
+
/* Terracota (cerámica/textiles andinos) — secundario */
|
|
19
|
+
--color-terracota-50: #fef4ee;
|
|
20
|
+
--color-terracota-100: #fce6d4;
|
|
21
|
+
--color-terracota-200: #f8caa8;
|
|
22
|
+
--color-terracota-300: #f3a771;
|
|
23
|
+
--color-terracota-400: #ec7d3f;
|
|
24
|
+
--color-terracota-500: #de5c22;
|
|
25
|
+
--color-terracota-600: #c04517;
|
|
26
|
+
--color-terracota-700: #9a3412;
|
|
27
|
+
--color-terracota-800: #7c2d12;
|
|
28
|
+
--color-terracota-900: #672a14;
|
|
29
|
+
--color-terracota-950: #391207;
|
|
30
|
+
|
|
31
|
+
/* Noche (índigo profundo) — anclaje / confianza */
|
|
32
|
+
--color-noche-50: #f1f1fb;
|
|
33
|
+
--color-noche-100: #e3e3f6;
|
|
34
|
+
--color-noche-200: #c7c8ec;
|
|
35
|
+
--color-noche-300: #a3a3de;
|
|
36
|
+
--color-noche-400: #7a78cb;
|
|
37
|
+
--color-noche-500: #5b57b8;
|
|
38
|
+
--color-noche-600: #46409e;
|
|
39
|
+
--color-noche-700: #363080;
|
|
40
|
+
--color-noche-800: #2a2563;
|
|
41
|
+
--color-noche-900: #1e1b4b;
|
|
42
|
+
--color-noche-950: #0f0e2e;
|
|
43
|
+
|
|
44
|
+
/* Piedra (neutros fríos, dejo índigo) — superficies del modo oscuro.
|
|
45
|
+
`noche` es color de marca: saturado de más para usarse como fondo (un
|
|
46
|
+
bloque de noche-900 se lee como una losa morada, no como una superficie).
|
|
47
|
+
`piedra` es esa misma familia llevada a ~10% de saturación: se percibe
|
|
48
|
+
como neutro, pero emparenta con el índigo en vez de con un gris puro.
|
|
49
|
+
Rampa comprimida en el extremo oscuro a propósito — 950→600 son los
|
|
50
|
+
escalones de superficie y ahí los saltos tienen que ser finos. */
|
|
51
|
+
--color-piedra-50: #f4f4f7;
|
|
52
|
+
--color-piedra-100: #e4e4eb;
|
|
53
|
+
--color-piedra-200: #c2c2d1;
|
|
54
|
+
--color-piedra-300: #9494ad;
|
|
55
|
+
--color-piedra-400: #6e6e8f;
|
|
56
|
+
--color-piedra-500: #4d4d6b;
|
|
57
|
+
--color-piedra-600: #33334a;
|
|
58
|
+
--color-piedra-700: #292938;
|
|
59
|
+
--color-piedra-800: #1c1c29;
|
|
60
|
+
--color-piedra-900: #14141f;
|
|
61
|
+
--color-piedra-950: #0c0c12;
|
|
62
|
+
|
|
63
|
+
/* Arena (neutros cálidos) */
|
|
64
|
+
--color-arena-50: #fafaf9;
|
|
65
|
+
--color-arena-100: #f5f4f2;
|
|
66
|
+
--color-arena-200: #e7e4e0;
|
|
67
|
+
--color-arena-300: #d3cec7;
|
|
68
|
+
--color-arena-400: #a8a099;
|
|
69
|
+
--color-arena-500: #7d766e;
|
|
70
|
+
--color-arena-600: #5e5850;
|
|
71
|
+
--color-arena-700: #453f39;
|
|
72
|
+
--color-arena-800: #2e2a26;
|
|
73
|
+
--color-arena-900: #1c1a17;
|
|
74
|
+
--color-arena-950: #0f0d0b;
|
|
75
|
+
|
|
76
|
+
/* Semánticos base (convención estándar, sin tematizar).
|
|
77
|
+
El escalón 400 existe para el modo oscuro: sobre fondo casi negro el 500
|
|
78
|
+
no llega a 4.5:1 (error-500 da 4.04:1), así que el modo oscuro sube un
|
|
79
|
+
escalón en luminosidad igual que hacen los tonos de marca. */
|
|
80
|
+
--color-success-400: #4ade80;
|
|
81
|
+
--color-success-500: #16a34a;
|
|
82
|
+
--color-success-600: #15803d;
|
|
83
|
+
--color-error-400: #f87171;
|
|
84
|
+
--color-error-500: #dc2626;
|
|
85
|
+
--color-error-600: #b91c1c;
|
|
86
|
+
--color-warning-400: #facc15;
|
|
87
|
+
--color-warning-500: #eab308;
|
|
88
|
+
--color-warning-600: #ca8a04;
|
|
89
|
+
/* El amarillo no funciona como texto sobre fondo claro a ningún escalón
|
|
90
|
+
por debajo del 700: warning-600 sobre `background` da 2.81:1. */
|
|
91
|
+
--color-warning-700: #a16207;
|
|
92
|
+
}
|