@ekoru/ui 0.1.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) 2025 Ekoru
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,272 @@
1
+ # @ekoru/ui
2
+
3
+ > Professional React component library for the Ekoru sustainable marketplace ecosystem.
4
+
5
+ [![npm version](https://img.shields.io/npm/v/@ekoru/ui.svg)](https://www.npmjs.com/package/@ekoru/ui)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://opensource.org/licenses/MIT)
7
+
8
+ ## ๐ŸŒฑ About
9
+
10
+ Ekoru UI is a comprehensive design system built with sustainability and user experience in mind. It provides a set of accessible, customizable, and beautiful React components for building modern web applications.
11
+
12
+ ## โœจ Features
13
+
14
+ - ๐ŸŽจ **Beautiful Design** - Carefully crafted components with a sustainable aesthetic
15
+ - โ™ฟ **Accessible** - WCAG 2.1 compliant components
16
+ - ๐ŸŽฏ **TypeScript** - Full type safety out of the box
17
+ - ๐ŸŽญ **Customizable** - Easy theming with Tailwind CSS
18
+ - ๐Ÿ“ฆ **Tree-shakeable** - Only bundle what you use
19
+ - ๐Ÿงช **Well tested** - Comprehensive test coverage
20
+ - ๐Ÿ“š **Documented** - Storybook documentation for all components
21
+
22
+ ## ๐Ÿ“ฆ Installation
23
+
24
+ ```bash
25
+ npm install @ekoru/ui
26
+ # or
27
+ pnpm add @ekoru/ui
28
+ # or
29
+ yarn add @ekoru/ui
30
+ ```
31
+
32
+ ## ๐Ÿš€ Quick Start
33
+
34
+ ```tsx
35
+ import { Button } from '@ekoru/ui';
36
+ import '@ekoru/ui/styles';
37
+
38
+ export default function App() {
39
+ return (
40
+ <Button variant="primary" onClick={() => console.log('clicked')}>
41
+ Click me
42
+ </Button>
43
+ );
44
+ }
45
+ ```
46
+
47
+ ## ๐Ÿ“– Usage
48
+
49
+ ### Importing Styles
50
+
51
+ Make sure to import the styles in your main app file:
52
+
53
+ ```tsx
54
+ // app.tsx or main.tsx
55
+ import '@ekoru/ui/styles';
56
+ ```
57
+
58
+ ### Using Components
59
+
60
+ ```tsx
61
+ import { Button, Card, Input } from '@ekoru/ui';
62
+
63
+ function MyComponent() {
64
+ return (
65
+ <Card>
66
+ <h2>Welcome to Ekoru</h2>
67
+ <Input placeholder="Enter your email" />
68
+ <Button variant="primary" size="lg">
69
+ Get Started
70
+ </Button>
71
+ </Card>
72
+ );
73
+ }
74
+ ```
75
+
76
+ ### Customizing Theme
77
+
78
+ You can customize the theme by extending your Tailwind config:
79
+
80
+ ```js
81
+ // tailwind.config.js
82
+ module.exports = {
83
+ content: [
84
+ './src/**/*.{js,jsx,ts,tsx}',
85
+ './node_modules/@ekoru/ui/dist/**/*.{js,mjs}',
86
+ ],
87
+ theme: {
88
+ extend: {
89
+ colors: {
90
+ primary: {
91
+ // Your custom colors
92
+ },
93
+ },
94
+ },
95
+ },
96
+ };
97
+ ```
98
+
99
+ ## ๐ŸŽจ Components
100
+
101
+ ### Button
102
+
103
+ A versatile button component with multiple variants and sizes.
104
+
105
+ ```tsx
106
+ <Button variant="primary" size="md" isLoading={false}>
107
+ Click me
108
+ </Button>
109
+ ```
110
+
111
+ **Variants:** `primary` | `secondary` | `outline` | `ghost` | `success` | `warning` | `error`
112
+
113
+ **Sizes:** `sm` | `md` | `lg`
114
+
115
+ ### More components coming soon!
116
+
117
+ - Input
118
+ - Card
119
+ - Modal
120
+ - Select
121
+ - Checkbox
122
+ - Radio
123
+ - Toast
124
+ - And many more...
125
+
126
+ ## ๐Ÿ› ๏ธ Development
127
+
128
+ ### Prerequisites
129
+
130
+ - Node.js >= 18
131
+ - pnpm >= 8
132
+
133
+ ### Setup
134
+
135
+ ```bash
136
+ # Clone the repository
137
+ git clone https://github.com/ekoru/ekoru-ui.git
138
+ cd ekoru-ui
139
+
140
+ # Install dependencies
141
+ pnpm install
142
+
143
+ # Start Storybook
144
+ pnpm storybook
145
+
146
+ # Run tests
147
+ pnpm test
148
+
149
+ # Run tests in watch mode
150
+ pnpm test:watch
151
+
152
+ # Build the library
153
+ pnpm build
154
+ ```
155
+
156
+ ### Project Structure
157
+
158
+ ```
159
+ ekoru-ui/
160
+ โ”œโ”€โ”€ src/
161
+ โ”‚ โ”œโ”€โ”€ components/ # React components
162
+ โ”‚ โ”œโ”€โ”€ utils/ # Utility functions
163
+ โ”‚ โ”œโ”€โ”€ styles/ # Global styles
164
+ โ”‚ โ””โ”€โ”€ index.ts # Main entry point
165
+ โ”œโ”€โ”€ test/ # Test utilities
166
+ โ”œโ”€โ”€ .storybook/ # Storybook configuration
167
+ โ””โ”€โ”€ dist/ # Build output (generated)
168
+ ```
169
+
170
+ ### Creating a New Component
171
+
172
+ 1. Create component folder in `src/components/`
173
+ 2. Create component file: `ComponentName.tsx`
174
+ 3. Create test file: `ComponentName.test.tsx`
175
+ 4. Create stories file: `ComponentName.stories.tsx`
176
+ 5. Export from `index.ts`
177
+
178
+ Example:
179
+
180
+ ```tsx
181
+ // src/components/MyComponent/MyComponent.tsx
182
+ import { cn } from '@/utils/cn';
183
+
184
+ export interface MyComponentProps {
185
+ className?: string;
186
+ children: React.ReactNode;
187
+ }
188
+
189
+ export const MyComponent = ({ className, children }: MyComponentProps) => {
190
+ return <div className={cn('my-component', className)}>{children}</div>;
191
+ };
192
+ ```
193
+
194
+ ### Running Tests
195
+
196
+ ```bash
197
+ # Run all tests
198
+ pnpm test
199
+
200
+ # Run tests in watch mode
201
+ pnpm test:watch
202
+
203
+ # Generate coverage report
204
+ pnpm test:coverage
205
+
206
+ # Run tests with UI
207
+ pnpm test:ui
208
+ ```
209
+
210
+ ### Building
211
+
212
+ ```bash
213
+ # Build for production
214
+ pnpm build
215
+
216
+ # Build CSS
217
+ pnpm build:css
218
+
219
+ # Type check
220
+ pnpm type-check
221
+ ```
222
+
223
+ ## ๐Ÿค Contributing
224
+
225
+ We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
226
+
227
+ ### Development Workflow
228
+
229
+ 1. Fork the repository
230
+ 2. Create a feature branch: `git checkout -b feature/my-feature`
231
+ 3. Make your changes
232
+ 4. Run tests: `pnpm test`
233
+ 5. Create a changeset: `pnpm changeset`
234
+ 6. Commit your changes: `git commit -m "feat: add new feature"`
235
+ 7. Push to your fork: `git push origin feature/my-feature`
236
+ 8. Open a Pull Request
237
+
238
+ ## ๐Ÿ“ Versioning
239
+
240
+ We use [Changesets](https://github.com/changesets/changesets) for version management.
241
+
242
+ To create a changeset:
243
+
244
+ ```bash
245
+ pnpm changeset
246
+ ```
247
+
248
+ Follow the prompts to describe your changes.
249
+
250
+ ## ๐Ÿ“„ License
251
+
252
+ MIT ยฉ [Ekoru](https://ekoru.cl)
253
+
254
+ ## ๐ŸŒ Links
255
+
256
+ - [Documentation](https://ui.ekoru.cl)
257
+ - [Storybook](https://storybook.ekoru.cl)
258
+ - [GitHub](https://github.com/ekoru/ekoru-ui)
259
+ - [npm](https://www.npmjs.com/package/@ekoru/ui)
260
+
261
+ ## ๐Ÿ’š Support
262
+
263
+ If you like this project, please consider:
264
+
265
+ - โญ Starring the repository
266
+ - ๐Ÿ› Reporting bugs
267
+ - ๐Ÿ’ก Suggesting new features
268
+ - ๐Ÿค Contributing to the codebase
269
+
270
+ ---
271
+
272
+ Made with ๐Ÿ’š by the Ekoru team for a more sustainable future.
@@ -0,0 +1,36 @@
1
+ import * as class_variance_authority_types from 'class-variance-authority/types';
2
+ import * as React from 'react';
3
+ import { VariantProps } from 'class-variance-authority';
4
+ import { ClassValue } from 'clsx';
5
+
6
+ declare const buttonVariants: (props?: ({
7
+ variant?: "primary" | "secondary" | "outline" | "ghost" | "success" | "warning" | "error" | null | undefined;
8
+ size?: "sm" | "md" | "lg" | null | undefined;
9
+ fullWidth?: boolean | null | undefined;
10
+ } & class_variance_authority_types.ClassProp) | undefined) => string;
11
+ interface ButtonProps extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'onDrag' | 'onDragEnd' | 'onDragStart' | 'onAnimationStart' | 'onAnimationEnd'>, VariantProps<typeof buttonVariants> {
12
+ /**
13
+ * If true, the button will show a loading spinner
14
+ */
15
+ isLoading?: boolean;
16
+ /**
17
+ * Icon to display before the button text
18
+ */
19
+ leftIcon?: React.ReactNode;
20
+ /**
21
+ * Icon to display after the button text
22
+ */
23
+ rightIcon?: React.ReactNode;
24
+ }
25
+ declare const Button: React.ForwardRefExoticComponent<ButtonProps & React.RefAttributes<HTMLButtonElement>>;
26
+
27
+ /**
28
+ * Utility function to merge Tailwind CSS classes
29
+ * Combines clsx for conditional classes and twMerge for proper Tailwind merging
30
+ *
31
+ * @example
32
+ * cn('px-2 py-1', condition && 'bg-blue-500', 'hover:bg-blue-600')
33
+ */
34
+ declare function cn(...inputs: ClassValue[]): string;
35
+
36
+ export { Button, type ButtonProps, buttonVariants, cn };
@@ -0,0 +1,36 @@
1
+ import * as class_variance_authority_types from 'class-variance-authority/types';
2
+ import * as React from 'react';
3
+ import { VariantProps } from 'class-variance-authority';
4
+ import { ClassValue } from 'clsx';
5
+
6
+ declare const buttonVariants: (props?: ({
7
+ variant?: "primary" | "secondary" | "outline" | "ghost" | "success" | "warning" | "error" | null | undefined;
8
+ size?: "sm" | "md" | "lg" | null | undefined;
9
+ fullWidth?: boolean | null | undefined;
10
+ } & class_variance_authority_types.ClassProp) | undefined) => string;
11
+ interface ButtonProps extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'onDrag' | 'onDragEnd' | 'onDragStart' | 'onAnimationStart' | 'onAnimationEnd'>, VariantProps<typeof buttonVariants> {
12
+ /**
13
+ * If true, the button will show a loading spinner
14
+ */
15
+ isLoading?: boolean;
16
+ /**
17
+ * Icon to display before the button text
18
+ */
19
+ leftIcon?: React.ReactNode;
20
+ /**
21
+ * Icon to display after the button text
22
+ */
23
+ rightIcon?: React.ReactNode;
24
+ }
25
+ declare const Button: React.ForwardRefExoticComponent<ButtonProps & React.RefAttributes<HTMLButtonElement>>;
26
+
27
+ /**
28
+ * Utility function to merge Tailwind CSS classes
29
+ * Combines clsx for conditional classes and twMerge for proper Tailwind merging
30
+ *
31
+ * @example
32
+ * cn('px-2 py-1', condition && 'bg-blue-500', 'hover:bg-blue-600')
33
+ */
34
+ declare function cn(...inputs: ClassValue[]): string;
35
+
36
+ export { Button, type ButtonProps, buttonVariants, cn };
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ 'use strict';var c=require('react'),classVarianceAuthority=require('class-variance-authority'),clsx=require('clsx'),tailwindMerge=require('tailwind-merge'),react=require('motion/react'),jsxRuntime=require('react/jsx-runtime');function _interopNamespace(e){if(e&&e.__esModule)return e;var n=Object.create(null);if(e){Object.keys(e).forEach(function(k){if(k!=='default'){var d=Object.getOwnPropertyDescriptor(e,k);Object.defineProperty(n,k,d.get?d:{enumerable:true,get:function(){return e[k]}});}})}n.default=e;return Object.freeze(n)}var c__namespace=/*#__PURE__*/_interopNamespace(c);function o(...r){return tailwindMerge.twMerge(clsx.clsx(r))}var m=classVarianceAuthority.cva("inline-flex items-center justify-center rounded-lg font-medium transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",{variants:{variant:{primary:"border-2 border-primary bg-primary text-white hover:bg-primary/90 active:bg-primary/80 shadow-md",secondary:"border-2 border-secondary bg-secondary text-white hover:bg-secondary/90 active:bg-secondary/80",outline:"border-2 border-primary text-primary hover:bg-primary/5 hover:text-accent-foreground active:bg-primary/10",ghost:"hover:bg-muted active:bg-muted/80 text-foreground",success:"border-2 border-success bg-success text-white hover:bg-success/90 active:bg-success/80 shadow-md",warning:"border-2 border-warning bg-warning text-white hover:bg-warning/90 active:bg-warning/80 shadow-md",error:"border-2 border-error bg-error text-white hover:bg-error/90 active:bg-error/80 shadow-md"},size:{sm:"h-9 px-3 text-sm",md:"h-11 px-6 text-base",lg:"h-14 px-8 text-lg"},fullWidth:{true:"w-full"}},defaultVariants:{variant:"primary",size:"md"}}),l=c__namespace.forwardRef(({className:r,variant:p,size:d,fullWidth:u,isLoading:t,leftIcon:i,rightIcon:s,children:b,disabled:g,...f},y)=>{let h=react.motion.button;return jsxRuntime.jsxs(h,{className:o(m({variant:p,size:d,fullWidth:u,className:r})),ref:y,disabled:g||t,whileHover:{scale:1.02,y:-2},whileTap:{scale:.96,y:0},transition:{type:"spring",stiffness:400,damping:17},...f,children:[jsxRuntime.jsxs(react.AnimatePresence,{mode:"wait",children:[t&&jsxRuntime.jsxs(react.motion.svg,{initial:{opacity:0,scale:.8},animate:{opacity:1,scale:1},exit:{opacity:0,scale:.8},transition:{duration:.2},className:"mr-2 h-4 w-4 animate-spin",xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 24 24",children:[jsxRuntime.jsx("circle",{className:"opacity-25",cx:"12",cy:"12",r:"10",stroke:"currentColor",strokeWidth:"4"}),jsxRuntime.jsx("path",{className:"opacity-75",fill:"currentColor",d:"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"})]},"spinner"),!t&&i&&jsxRuntime.jsx(react.motion.span,{initial:{opacity:0,scale:.8},animate:{opacity:1,scale:1},exit:{opacity:0,scale:.8},transition:{duration:.2},className:"mr-2",children:i},"leftIcon")]}),b,!t&&s&&jsxRuntime.jsx("span",{className:"ml-2",children:s})]})});l.displayName="Button";
2
+ exports.Button=l;exports.buttonVariants=m;exports.cn=o;//# sourceMappingURL=index.js.map
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/cn.ts","../src/components/Button/Button.tsx"],"names":["cn","inputs","twMerge","clsx","buttonVariants","cva","Button","c","className","variant","size","fullWidth","isLoading","leftIcon","rightIcon","children","disabled","props","ref","MotionButton","motion","jsxs","AnimatePresence","jsx"],"mappings":"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","file":"index.js","sourcesContent":["import { type ClassValue, clsx } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\n/**\n * Utility function to merge Tailwind CSS classes\n * Combines clsx for conditional classes and twMerge for proper Tailwind merging\n * \n * @example\n * cn('px-2 py-1', condition && 'bg-blue-500', 'hover:bg-blue-600')\n */\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n","import * as React from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { cn } from '@/utils/cn';\nimport { motion, AnimatePresence } from 'motion/react';\n\nconst buttonVariants = cva(\n 'inline-flex items-center justify-center rounded-lg font-medium transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50',\n {\n variants: {\n variant: {\n primary:\n 'border-2 border-primary bg-primary text-white hover:bg-primary/90 active:bg-primary/80 shadow-md',\n secondary:\n 'border-2 border-secondary bg-secondary text-white hover:bg-secondary/90 active:bg-secondary/80',\n outline:\n 'border-2 border-primary text-primary hover:bg-primary/5 hover:text-accent-foreground active:bg-primary/10',\n ghost: 'hover:bg-muted active:bg-muted/80 text-foreground',\n success:\n 'border-2 border-success bg-success text-white hover:bg-success/90 active:bg-success/80 shadow-md',\n warning:\n 'border-2 border-warning bg-warning text-white hover:bg-warning/90 active:bg-warning/80 shadow-md',\n error:\n 'border-2 border-error bg-error text-white hover:bg-error/90 active:bg-error/80 shadow-md',\n },\n size: {\n sm: 'h-9 px-3 text-sm',\n md: 'h-11 px-6 text-base',\n lg: 'h-14 px-8 text-lg',\n },\n fullWidth: {\n true: 'w-full',\n },\n },\n defaultVariants: {\n variant: 'primary',\n size: 'md',\n },\n }\n);\n\nexport interface ButtonProps\n extends\n Omit<\n React.ButtonHTMLAttributes<HTMLButtonElement>,\n | 'onDrag'\n | 'onDragEnd'\n | 'onDragStart'\n | 'onAnimationStart'\n | 'onAnimationEnd'\n >,\n VariantProps<typeof buttonVariants> {\n /**\n * If true, the button will show a loading spinner\n */\n isLoading?: boolean;\n /**\n * Icon to display before the button text\n */\n leftIcon?: React.ReactNode;\n /**\n * Icon to display after the button text\n */\n rightIcon?: React.ReactNode;\n}\n\nconst Button = React.forwardRef<HTMLButtonElement, ButtonProps>(\n (\n {\n className,\n variant,\n size,\n fullWidth,\n isLoading,\n leftIcon,\n rightIcon,\n children,\n disabled,\n ...props\n },\n ref\n ) => {\n const MotionButton = motion.button;\n\n return (\n <MotionButton\n className={cn(buttonVariants({ variant, size, fullWidth, className }))}\n ref={ref}\n disabled={disabled || isLoading}\n whileHover={{ scale: 1.02, y: -2 }}\n whileTap={{ scale: 0.96, y: 0 }}\n transition={{ type: 'spring', stiffness: 400, damping: 17 }}\n {...props}\n >\n <AnimatePresence mode=\"wait\">\n {isLoading && (\n <motion.svg\n key=\"spinner\"\n initial={{ opacity: 0, scale: 0.8 }}\n animate={{ opacity: 1, scale: 1 }}\n exit={{ opacity: 0, scale: 0.8 }}\n transition={{ duration: 0.2 }}\n className=\"mr-2 h-4 w-4 animate-spin\"\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n >\n <circle\n className=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n strokeWidth=\"4\"\n />\n <path\n className=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n />\n </motion.svg>\n )}\n {!isLoading && leftIcon && (\n <motion.span\n key=\"leftIcon\"\n initial={{ opacity: 0, scale: 0.8 }}\n animate={{ opacity: 1, scale: 1 }}\n exit={{ opacity: 0, scale: 0.8 }}\n transition={{ duration: 0.2 }}\n className=\"mr-2\"\n >\n {leftIcon}\n </motion.span>\n )}\n </AnimatePresence>\n {children}\n {!isLoading && rightIcon && <span className=\"ml-2\">{rightIcon}</span>}\n </MotionButton>\n );\n }\n);\n\nButton.displayName = 'Button';\n\nexport { Button, buttonVariants };\n"]}
package/dist/index.mjs ADDED
@@ -0,0 +1,3 @@
1
+ import*as c from'react';import {cva}from'class-variance-authority';import {clsx}from'clsx';import {twMerge}from'tailwind-merge';import {motion,AnimatePresence}from'motion/react';import {jsxs,jsx}from'react/jsx-runtime';function o(...r){return twMerge(clsx(r))}var m=cva("inline-flex items-center justify-center rounded-lg font-medium transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",{variants:{variant:{primary:"border-2 border-primary bg-primary text-white hover:bg-primary/90 active:bg-primary/80 shadow-md",secondary:"border-2 border-secondary bg-secondary text-white hover:bg-secondary/90 active:bg-secondary/80",outline:"border-2 border-primary text-primary hover:bg-primary/5 hover:text-accent-foreground active:bg-primary/10",ghost:"hover:bg-muted active:bg-muted/80 text-foreground",success:"border-2 border-success bg-success text-white hover:bg-success/90 active:bg-success/80 shadow-md",warning:"border-2 border-warning bg-warning text-white hover:bg-warning/90 active:bg-warning/80 shadow-md",error:"border-2 border-error bg-error text-white hover:bg-error/90 active:bg-error/80 shadow-md"},size:{sm:"h-9 px-3 text-sm",md:"h-11 px-6 text-base",lg:"h-14 px-8 text-lg"},fullWidth:{true:"w-full"}},defaultVariants:{variant:"primary",size:"md"}}),l=c.forwardRef(({className:r,variant:p,size:d,fullWidth:u,isLoading:t,leftIcon:i,rightIcon:s,children:b,disabled:g,...f},y)=>{let h=motion.button;return jsxs(h,{className:o(m({variant:p,size:d,fullWidth:u,className:r})),ref:y,disabled:g||t,whileHover:{scale:1.02,y:-2},whileTap:{scale:.96,y:0},transition:{type:"spring",stiffness:400,damping:17},...f,children:[jsxs(AnimatePresence,{mode:"wait",children:[t&&jsxs(motion.svg,{initial:{opacity:0,scale:.8},animate:{opacity:1,scale:1},exit:{opacity:0,scale:.8},transition:{duration:.2},className:"mr-2 h-4 w-4 animate-spin",xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 24 24",children:[jsx("circle",{className:"opacity-25",cx:"12",cy:"12",r:"10",stroke:"currentColor",strokeWidth:"4"}),jsx("path",{className:"opacity-75",fill:"currentColor",d:"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"})]},"spinner"),!t&&i&&jsx(motion.span,{initial:{opacity:0,scale:.8},animate:{opacity:1,scale:1},exit:{opacity:0,scale:.8},transition:{duration:.2},className:"mr-2",children:i},"leftIcon")]}),b,!t&&s&&jsx("span",{className:"ml-2",children:s})]})});l.displayName="Button";
2
+ export{l as Button,m as buttonVariants,o as cn};//# sourceMappingURL=index.mjs.map
3
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/cn.ts","../src/components/Button/Button.tsx"],"names":["cn","inputs","twMerge","clsx","buttonVariants","cva","Button","className","variant","size","fullWidth","isLoading","leftIcon","rightIcon","children","disabled","props","ref","MotionButton","motion","jsxs","AnimatePresence","jsx"],"mappings":"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","file":"index.mjs","sourcesContent":["import { type ClassValue, clsx } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\n/**\n * Utility function to merge Tailwind CSS classes\n * Combines clsx for conditional classes and twMerge for proper Tailwind merging\n * \n * @example\n * cn('px-2 py-1', condition && 'bg-blue-500', 'hover:bg-blue-600')\n */\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n","import * as React from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { cn } from '@/utils/cn';\nimport { motion, AnimatePresence } from 'motion/react';\n\nconst buttonVariants = cva(\n 'inline-flex items-center justify-center rounded-lg font-medium transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50',\n {\n variants: {\n variant: {\n primary:\n 'border-2 border-primary bg-primary text-white hover:bg-primary/90 active:bg-primary/80 shadow-md',\n secondary:\n 'border-2 border-secondary bg-secondary text-white hover:bg-secondary/90 active:bg-secondary/80',\n outline:\n 'border-2 border-primary text-primary hover:bg-primary/5 hover:text-accent-foreground active:bg-primary/10',\n ghost: 'hover:bg-muted active:bg-muted/80 text-foreground',\n success:\n 'border-2 border-success bg-success text-white hover:bg-success/90 active:bg-success/80 shadow-md',\n warning:\n 'border-2 border-warning bg-warning text-white hover:bg-warning/90 active:bg-warning/80 shadow-md',\n error:\n 'border-2 border-error bg-error text-white hover:bg-error/90 active:bg-error/80 shadow-md',\n },\n size: {\n sm: 'h-9 px-3 text-sm',\n md: 'h-11 px-6 text-base',\n lg: 'h-14 px-8 text-lg',\n },\n fullWidth: {\n true: 'w-full',\n },\n },\n defaultVariants: {\n variant: 'primary',\n size: 'md',\n },\n }\n);\n\nexport interface ButtonProps\n extends\n Omit<\n React.ButtonHTMLAttributes<HTMLButtonElement>,\n | 'onDrag'\n | 'onDragEnd'\n | 'onDragStart'\n | 'onAnimationStart'\n | 'onAnimationEnd'\n >,\n VariantProps<typeof buttonVariants> {\n /**\n * If true, the button will show a loading spinner\n */\n isLoading?: boolean;\n /**\n * Icon to display before the button text\n */\n leftIcon?: React.ReactNode;\n /**\n * Icon to display after the button text\n */\n rightIcon?: React.ReactNode;\n}\n\nconst Button = React.forwardRef<HTMLButtonElement, ButtonProps>(\n (\n {\n className,\n variant,\n size,\n fullWidth,\n isLoading,\n leftIcon,\n rightIcon,\n children,\n disabled,\n ...props\n },\n ref\n ) => {\n const MotionButton = motion.button;\n\n return (\n <MotionButton\n className={cn(buttonVariants({ variant, size, fullWidth, className }))}\n ref={ref}\n disabled={disabled || isLoading}\n whileHover={{ scale: 1.02, y: -2 }}\n whileTap={{ scale: 0.96, y: 0 }}\n transition={{ type: 'spring', stiffness: 400, damping: 17 }}\n {...props}\n >\n <AnimatePresence mode=\"wait\">\n {isLoading && (\n <motion.svg\n key=\"spinner\"\n initial={{ opacity: 0, scale: 0.8 }}\n animate={{ opacity: 1, scale: 1 }}\n exit={{ opacity: 0, scale: 0.8 }}\n transition={{ duration: 0.2 }}\n className=\"mr-2 h-4 w-4 animate-spin\"\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n >\n <circle\n className=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n strokeWidth=\"4\"\n />\n <path\n className=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n />\n </motion.svg>\n )}\n {!isLoading && leftIcon && (\n <motion.span\n key=\"leftIcon\"\n initial={{ opacity: 0, scale: 0.8 }}\n animate={{ opacity: 1, scale: 1 }}\n exit={{ opacity: 0, scale: 0.8 }}\n transition={{ duration: 0.2 }}\n className=\"mr-2\"\n >\n {leftIcon}\n </motion.span>\n )}\n </AnimatePresence>\n {children}\n {!isLoading && rightIcon && <span className=\"ml-2\">{rightIcon}</span>}\n </MotionButton>\n );\n }\n);\n\nButton.displayName = 'Button';\n\nexport { Button, buttonVariants };\n"]}
@@ -0,0 +1 @@
1
+ *,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }/*! tailwindcss v3.4.19 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}:host,html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:Inter,system-ui,sans-serif;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}:root{--primary:101 163 13;--primary-dark:63 98 18;--primary-hover:132 204 22;--primary-active:77 124 15;--secondary:34 211 238;--secondary-dark:14 116 144;--secondary-hover:103 232 249;--accent:245 158 11;--accent-hover:251 191 36;--danger:239 68 68;--danger-hover:248 113 113;--success:34 197 94;--warning:234 179 8;--info:59 130 246;--background:253 255 252;--background-secondary:249 250 251;--background-tertiary:243 244 246;--surface:255 255 255;--surface-elevated:255 255 255;--surface-hover:249 250 251;--surface-active:243 244 246;--item:101 163 13;--item-hover:230 230 230;--foreground:31 41 55;--foreground-secondary:75 85 99;--foreground-tertiary:156 163 175;--foreground-muted:209 213 219;--border:168 168 168;--border-light:243 244 246;--border-strong:209 213 219;--border-focus:132 204 22;--navbar-bg:217 249 157;--navbar-hover:190 242 100;--navbar-text:255 255 255;--navbar-border:229 231 235;--sidebar-bg:249 250 251;--sidebar-hover:243 244 246;--sidebar-active:217 249 157;--sidebar-text:31 41 55;--sidebar-border:229 231 235;--footer-bg:217 249 157;--footer-text:31 41 55;--footer-border:229 231 235;--modal-bg:255 255 255;--modal-overlay:0 0 0;--modal-border:229 231 235;--input-bg:255 255 255;--input-border:209 213 219;--input-border-hover:156 163 175;--input-border-focus:132 204 22;--input-text:31 41 55;--input-placeholder:156 163 175;--input-disabled:243 244 246;--shadow-sm:0 1px 2px 0 rgba(0,0,0,.05);--shadow-md:0 4px 6px -1px rgba(0,0,0,.1);--shadow-lg:0 10px 15px -3px rgba(0,0,0,.1);--shadow-xl:0 20px 25px -5px rgba(0,0,0,.1)}*{box-sizing:border-box}body{background-color:rgb(var(--background));color:rgb(var(--foreground));font-feature-settings:"rlig" 1,"calt" 1}.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}.absolute{position:absolute}.relative{position:relative}.inset-0{inset:0}.left-3{left:.75rem}.right-3{right:.75rem}.top-1\/2{top:50%}.z-10{z-index:10}.mx-auto{margin-left:auto;margin-right:auto}.mb-3{margin-bottom:.75rem}.ml-2{margin-left:.5rem}.mr-2{margin-right:.5rem}.mt-1{margin-top:.25rem}.block{display:block}.inline-block{display:inline-block}.flex{display:flex}.inline-flex{display:inline-flex}.h-11{height:2.75rem}.h-14{height:3.5rem}.h-3{height:.75rem}.h-4{height:1rem}.h-5{height:1.25rem}.h-9{height:2.25rem}.w-1\/2{width:50%}.w-1\/3{width:33.333333%}.w-2\/3{width:66.666667%}.w-3{width:.75rem}.w-4{width:1rem}.w-5{width:1.25rem}.w-\[95\%\]{width:95%}.w-full{width:100%}.max-w-md{max-width:28rem}.flex-1{flex:1 1 0%}.-translate-y-1\/2{--tw-translate-y:-50%}.-translate-y-1\/2,.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes spin{to{transform:rotate(1turn)}}.animate-spin{animation:spin 1s linear infinite}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.justify-center{justify-content:center}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-6{gap:1.5rem}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.5rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem*var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem*var(--tw-space-y-reverse))}.space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1.5rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem*var(--tw-space-y-reverse))}.space-y-8>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(2rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(2rem*var(--tw-space-y-reverse))}.overflow-hidden{overflow:hidden}.rounded-full{border-radius:9999px}.rounded-lg,.rounded-xl{border-radius:.75rem}.border-2{border-width:2px}.border-border{border-color:rgb(var(--border))}.border-error{border-color:rgb(var(--danger))}.border-primary{border-color:rgb(var(--primary))}.border-secondary{border-color:rgb(var(--secondary))}.border-success{border-color:rgb(var(--success))}.border-transparent{border-color:transparent}.border-warning{border-color:rgb(var(--warning))}.bg-background{background-color:rgb(var(--background))}.bg-blue-500{--tw-bg-opacity:1;background-color:rgb(59 130 246/var(--tw-bg-opacity,1))}.bg-error{background-color:rgb(var(--danger))}.bg-gray-600{--tw-bg-opacity:1;background-color:rgb(75 85 99/var(--tw-bg-opacity,1))}.bg-primary{background-color:rgb(var(--primary))}.bg-secondary{background-color:rgb(var(--secondary))}.bg-success{background-color:rgb(var(--success))}.bg-transparent{background-color:transparent}.bg-warning{background-color:rgb(var(--warning))}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity,1))}.bg-white\/50{background-color:hsla(0,0%,100%,.5)}.bg-gradient-to-br{background-image:linear-gradient(to bottom right,var(--tw-gradient-stops))}.bg-gradient-to-r{background-image:linear-gradient(to right,var(--tw-gradient-stops))}.from-green-50{--tw-gradient-from:#f0fdf4 var(--tw-gradient-from-position);--tw-gradient-to:rgba(240,253,244,0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.from-primary-dark{--tw-gradient-from:rgb(var(--primary-dark)) var(--tw-gradient-from-position);--tw-gradient-to:rgb(var(--primary-dark)/0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.from-secondary-dark{--tw-gradient-from:rgb(var(--secondary-dark)) var(--tw-gradient-from-position);--tw-gradient-to:rgb(var(--secondary-dark)/0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.from-transparent{--tw-gradient-from:transparent var(--tw-gradient-from-position);--tw-gradient-to:transparent var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.via-primary{--tw-gradient-to:rgb(var(--primary)/0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),rgb(var(--primary)) var(--tw-gradient-via-position),var(--tw-gradient-to)}.via-secondary{--tw-gradient-to:rgb(var(--secondary)/0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),rgb(var(--secondary)) var(--tw-gradient-via-position),var(--tw-gradient-to)}.via-white\/10{--tw-gradient-to:hsla(0,0%,100%,0) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),hsla(0,0%,100%,.1) var(--tw-gradient-via-position),var(--tw-gradient-to)}.to-blue-50{--tw-gradient-to:#eff6ff var(--tw-gradient-to-position)}.to-primary-dark{--tw-gradient-to:rgb(var(--primary-dark)) var(--tw-gradient-to-position)}.to-secondary-dark{--tw-gradient-to:rgb(var(--secondary-dark)) var(--tw-gradient-to-position)}.to-transparent{--tw-gradient-to:transparent var(--tw-gradient-to-position)}.p-4{padding:1rem}.p-6{padding:1.5rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.px-8{padding-left:2rem;padding-right:2rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.pl-10{padding-left:2.5rem}.pl-3{padding-left:.75rem}.pr-10{padding-right:2.5rem}.pr-3{padding-right:.75rem}.text-center{text-align:center}.text-2xl{font-size:1.5rem;line-height:2rem}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-light{font-weight:300}.font-medium{font-weight:500}.font-semibold{font-weight:600}.leading-snug{line-height:1.375}.tracking-tight{letter-spacing:-.025em}.text-error{color:rgb(var(--danger))}.text-foreground{color:rgb(var(--foreground))}.text-primary{color:rgb(var(--primary))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}.opacity-25{opacity:.25}.opacity-75{opacity:.75}.shadow-lg{--tw-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1);--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color)}.shadow-lg,.shadow-md{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-md{--tw-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1);--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color)}.shadow-white\/50{--tw-shadow-color:hsla(0,0%,100%,.5);--tw-shadow:var(--tw-shadow-colored)}.outline{outline-style:solid}.blur{--tw-blur:blur(8px);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.backdrop-blur{--tw-backdrop-blur:blur(8px);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-200{transition-duration:.2s}.hover\:bg-blue-600:hover{--tw-bg-opacity:1;background-color:rgb(37 99 235/var(--tw-bg-opacity,1))}.hover\:bg-error\/90:hover{background-color:rgb(var(--danger)/.9)}.hover\:bg-primary\/5:hover{background-color:rgb(var(--primary)/.05)}.hover\:bg-primary\/90:hover{background-color:rgb(var(--primary)/.9)}.hover\:bg-secondary\/90:hover{background-color:rgb(var(--secondary)/.9)}.hover\:bg-success\/90:hover{background-color:rgb(var(--success)/.9)}.hover\:bg-warning\/90:hover{background-color:rgb(var(--warning)/.9)}.focus\:border-error:focus{border-color:rgb(var(--danger))}.focus\:border-primary-active:focus{border-color:rgb(var(--primary-active))}.focus\:bg-primary\/5:focus{background-color:rgb(var(--primary)/.05)}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring-2:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.focus\:ring-error\/20:focus{--tw-ring-color:rgb(var(--danger)/0.2)}.focus\:ring-primary\/20:focus{--tw-ring-color:rgb(var(--primary)/0.2)}.focus\:ring-offset-2:focus{--tw-ring-offset-width:2px}.focus-visible\:outline-none:focus-visible{outline:2px solid transparent;outline-offset:2px}.focus-visible\:ring-2:focus-visible{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.focus-visible\:ring-ring:focus-visible{--tw-ring-color:rgb(var(--border-focus))}.focus-visible\:ring-offset-2:focus-visible{--tw-ring-offset-width:2px}.active\:bg-error\/80:active{background-color:rgb(var(--danger)/.8)}.active\:bg-primary\/10:active{background-color:rgb(var(--primary)/.1)}.active\:bg-primary\/80:active{background-color:rgb(var(--primary)/.8)}.active\:bg-secondary\/80:active{background-color:rgb(var(--secondary)/.8)}.active\:bg-success\/80:active{background-color:rgb(var(--success)/.8)}.active\:bg-warning\/80:active{background-color:rgb(var(--warning)/.8)}.disabled\:pointer-events-none:disabled{pointer-events:none}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-50:disabled{opacity:.5}@media (min-width:640px){.sm\:text-base{font-size:1rem;line-height:1.5rem}.sm\:text-lg{font-size:1.125rem;line-height:1.75rem}}@media (min-width:768px){.md\:gap-3{gap:.75rem}.md\:p-5{padding:1.25rem}.md\:text-2xl{font-size:1.5rem;line-height:2rem}.md\:text-lg{font-size:1.125rem;line-height:1.75rem}.md\:leading-normal{line-height:1.5}}
package/package.json ADDED
@@ -0,0 +1,123 @@
1
+ {
2
+ "name": "@ekoru/ui",
3
+ "version": "0.1.0",
4
+ "description": "Ekoru Design System - Professional React component library",
5
+ "author": "Ignacio <ignacio@ekoru.cl>",
6
+ "license": "MIT",
7
+ "homepage": "https://github.com/ekoru/ekoru-ui#readme",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/ekoru/ekoru-ui.git"
11
+ },
12
+ "bugs": {
13
+ "url": "https://github.com/ekoru/ekoru-ui/issues"
14
+ },
15
+ "keywords": [
16
+ "react",
17
+ "components",
18
+ "ui",
19
+ "design-system",
20
+ "ekoru",
21
+ "typescript",
22
+ "tailwind",
23
+ "sustainability"
24
+ ],
25
+ "main": "./dist/index.js",
26
+ "module": "./dist/index.mjs",
27
+ "types": "./dist/index.d.ts",
28
+ "exports": {
29
+ ".": {
30
+ "types": "./dist/index.d.ts",
31
+ "import": "./dist/index.mjs",
32
+ "require": "./dist/index.js"
33
+ },
34
+ "./styles": "./dist/styles.css",
35
+ "./package.json": "./package.json"
36
+ },
37
+ "files": [
38
+ "dist",
39
+ "README.md",
40
+ "LICENSE",
41
+ "CHANGELOG.md"
42
+ ],
43
+ "sideEffects": [
44
+ "**/*.css"
45
+ ],
46
+ "peerDependencies": {
47
+ "react": "^18.0.0",
48
+ "react-dom": "^18.0.0"
49
+ },
50
+ "dependencies": {
51
+ "class-variance-authority": "^0.7.0",
52
+ "clsx": "^2.1.0",
53
+ "lucide-react": "^0.562.0",
54
+ "motion": "^12.27.1",
55
+ "tailwind-merge": "^2.2.0"
56
+ },
57
+ "devDependencies": {
58
+ "@changesets/cli": "^2.27.1",
59
+ "@storybook/addon-essentials": "^7.6.6",
60
+ "@storybook/addon-interactions": "^7.6.6",
61
+ "@storybook/addon-links": "^7.6.6",
62
+ "@storybook/blocks": "^7.6.6",
63
+ "@storybook/react": "^7.6.6",
64
+ "@storybook/react-vite": "^7.6.6",
65
+ "@storybook/testing-library": "^0.2.2",
66
+ "@storybook/theming": "^7.6.6",
67
+ "@testing-library/jest-dom": "^6.1.5",
68
+ "@testing-library/react": "^14.1.2",
69
+ "@testing-library/user-event": "^14.5.1",
70
+ "@types/node": "^20.10.6",
71
+ "@types/react": "^18.2.46",
72
+ "@types/react-dom": "^18.2.18",
73
+ "@typescript-eslint/eslint-plugin": "^6.17.0",
74
+ "@typescript-eslint/parser": "^6.17.0",
75
+ "@vitejs/plugin-react": "^4.2.1",
76
+ "@vitest/ui": "^1.1.1",
77
+ "autoprefixer": "^10.4.16",
78
+ "eslint": "^8.56.0",
79
+ "eslint-config-prettier": "^9.1.0",
80
+ "eslint-plugin-react": "^7.33.2",
81
+ "eslint-plugin-react-hooks": "^4.6.0",
82
+ "eslint-plugin-storybook": "^0.6.15",
83
+ "jsdom": "^23.0.1",
84
+ "postcss": "^8.4.32",
85
+ "prettier": "^3.1.1",
86
+ "react": "^18.2.0",
87
+ "react-dom": "^18.2.0",
88
+ "storybook": "^7.6.6",
89
+ "storybook-dark-mode": "^4.0.2",
90
+ "tailwindcss": "^3.4.0",
91
+ "tsup": "^8.0.1",
92
+ "typescript": "^5.3.3",
93
+ "vite": "^5.0.10",
94
+ "vitest": "^1.1.1"
95
+ },
96
+ "publishConfig": {
97
+ "access": "public",
98
+ "registry": "https://registry.npmjs.org/"
99
+ },
100
+ "engines": {
101
+ "node": ">=18.0.0",
102
+ "pnpm": ">=8.0.0"
103
+ },
104
+ "scripts": {
105
+ "dev": "tsup --watch",
106
+ "build": "tsup && tailwindcss -i ./src/styles/globals.css -o ./dist/styles.css --minify",
107
+ "build:css": "tailwindcss -i ./src/styles/globals.css -o ./dist/styles.css --minify",
108
+ "type-check": "tsc --noEmit",
109
+ "lint": "eslint src --ext .ts,.tsx --max-warnings 0",
110
+ "lint:fix": "eslint src --ext .ts,.tsx --fix",
111
+ "format": "prettier --write \"src/**/*.{ts,tsx,json,md}\"",
112
+ "format:check": "prettier --check \"src/**/*.{ts,tsx,json,md}\"",
113
+ "test": "vitest run",
114
+ "test:watch": "vitest",
115
+ "test:coverage": "vitest run --coverage",
116
+ "test:ui": "vitest --ui",
117
+ "storybook": "storybook dev -p 6006",
118
+ "build-storybook": "storybook build",
119
+ "release": "pnpm changeset publish",
120
+ "version": "pnpm changeset version",
121
+ "clean": "rm -rf dist node_modules .turbo storybook-static"
122
+ }
123
+ }