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 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;
@@ -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 };
@@ -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
+ }