@marcoschwartz/lite-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/README.md ADDED
@@ -0,0 +1,208 @@
1
+ # Lite UI
2
+
3
+ A lightweight UI component library built with Tailwind CSS and React.
4
+
5
+ ## Features
6
+
7
+ - Built with TypeScript
8
+ - Styled with Tailwind CSS
9
+ - Tree-shakeable ESM and CJS builds
10
+ - Live development with hot module reloading
11
+ - Server Component compatible (works in Next.js App Router and other RSC frameworks)
12
+ - Components are framework-agnostic React components
13
+ - Built-in theming system with multiple pre-built themes
14
+
15
+ ## Development
16
+
17
+ ### Quick Start
18
+
19
+ Run the library build watcher and demo app simultaneously:
20
+
21
+ ```bash
22
+ npm run dev:all
23
+ ```
24
+
25
+ This single command will:
26
+ 1. Start the UI library build in watch mode (auto-rebuilds on changes)
27
+ 2. Start the Next.js demo app on http://localhost:3000
28
+ 3. Automatically reflect changes from the library in the demo app
29
+
30
+ ### Individual Commands
31
+
32
+ Build the library once:
33
+ ```bash
34
+ npm run build
35
+ ```
36
+
37
+ Build the library in watch mode:
38
+ ```bash
39
+ npm run dev
40
+ ```
41
+
42
+ Run the demo app only:
43
+ ```bash
44
+ cd demo && npm run dev
45
+ ```
46
+
47
+ ## Components
48
+
49
+ ### Button
50
+
51
+ A versatile button component with multiple variants and sizes.
52
+
53
+ #### Variants
54
+ - `primary` (default) - Blue button
55
+ - `secondary` - Gray button
56
+ - `success` - Green button
57
+ - `danger` - Red button
58
+ - `warning` - Yellow button
59
+ - `info` - Cyan button
60
+
61
+ #### Sizes
62
+ - `sm` - Small
63
+ - `md` (default) - Medium
64
+ - `lg` - Large
65
+ - `xl` - Extra Large
66
+
67
+ #### Usage
68
+
69
+ **In Server Components (Next.js App Router):**
70
+ ```tsx
71
+ // app/page.tsx (Server Component)
72
+ import { Button } from 'lite-ui';
73
+
74
+ export default function Page() {
75
+ return (
76
+ <div>
77
+ <Button variant="primary" size="md">
78
+ Static Button (Server Rendered)
79
+ </Button>
80
+ </div>
81
+ );
82
+ }
83
+ ```
84
+
85
+ **In Client Components (with interactivity):**
86
+ ```tsx
87
+ // app/components/InteractiveButton.tsx
88
+ "use client";
89
+
90
+ import { Button } from 'lite-ui';
91
+
92
+ export function InteractiveButton() {
93
+ return (
94
+ <Button variant="success" onClick={() => alert('Clicked!')}>
95
+ Click Me
96
+ </Button>
97
+ );
98
+ }
99
+ ```
100
+
101
+ **In any React app:**
102
+ ```tsx
103
+ import { Button } from 'lite-ui';
104
+
105
+ function App() {
106
+ return (
107
+ <div>
108
+ <Button variant="primary" size="md">
109
+ Click Me
110
+ </Button>
111
+
112
+ <Button variant="success" size="lg" onClick={() => alert('Success!')}>
113
+ Submit
114
+ </Button>
115
+
116
+ <Button variant="danger" disabled>
117
+ Disabled
118
+ </Button>
119
+ </div>
120
+ );
121
+ }
122
+ ```
123
+
124
+ ## Structure
125
+
126
+ ```
127
+ lite-ui-js/
128
+ ├── src/ # UI library source code
129
+ │ ├── components/ # React components
130
+ │ └── index.ts # Main export file
131
+ ├── demo/ # Next.js demo application
132
+ ├── dist/ # Built library (generated)
133
+ └── dev.sh # Development script
134
+ ```
135
+
136
+ ## Theming
137
+
138
+ Lite UI includes a built-in theming system that allows you to easily switch between different visual styles.
139
+
140
+ ### Available Themes
141
+
142
+ 1. **Default** - Vibrant colors, shadows, and smooth animations
143
+ 2. **Minimalistic** - Flat design, subtle colors, minimal effects
144
+
145
+ ### Usage
146
+
147
+ **Wrap your app with ThemeProvider:**
148
+ ```tsx
149
+ import { ThemeProvider } from 'lite-ui';
150
+
151
+ function App() {
152
+ return (
153
+ <ThemeProvider defaultTheme="default">
154
+ {/* your app */}
155
+ </ThemeProvider>
156
+ );
157
+ }
158
+ ```
159
+
160
+ **Switch themes dynamically:**
161
+ ```tsx
162
+ "use client";
163
+
164
+ import { useTheme, Button } from 'lite-ui';
165
+
166
+ function ThemeSwitcher() {
167
+ const { themeName, setTheme } = useTheme();
168
+
169
+ return (
170
+ <div>
171
+ <p>Current theme: {themeName}</p>
172
+ <Button onClick={() => setTheme('default')}>Default Theme</Button>
173
+ <Button onClick={() => setTheme('minimalistic')}>Minimalistic Theme</Button>
174
+ </div>
175
+ );
176
+ }
177
+ ```
178
+
179
+ **Components work without ThemeProvider:**
180
+ If you don't wrap your app in a ThemeProvider, components will automatically use the default theme.
181
+
182
+ ### Creating Custom Themes
183
+
184
+ You can create custom themes by extending the theme configuration:
185
+
186
+ ```tsx
187
+ import { themes, ThemeProvider } from 'lite-ui';
188
+
189
+ const customTheme = {
190
+ ...themes.default,
191
+ name: 'custom',
192
+ button: {
193
+ ...themes.default.button,
194
+ variants: {
195
+ ...themes.default.button.variants,
196
+ primary: 'bg-purple-600 hover:bg-purple-700 text-white',
197
+ },
198
+ },
199
+ };
200
+ ```
201
+
202
+ ## Technology Stack
203
+
204
+ - **React 19** - UI framework
205
+ - **TypeScript** - Type safety
206
+ - **Tailwind CSS v4** - Styling
207
+ - **tsup** - Build tool
208
+ - **Next.js 15** - Demo app framework
@@ -0,0 +1,87 @@
1
+ import React from 'react';
2
+ import * as react_jsx_runtime from 'react/jsx-runtime';
3
+
4
+ interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
5
+ variant?: 'primary' | 'secondary' | 'success' | 'danger' | 'warning' | 'info';
6
+ size?: 'sm' | 'md' | 'lg' | 'xl';
7
+ children: React.ReactNode;
8
+ }
9
+ declare const Button: React.FC<ButtonProps>;
10
+
11
+ interface SelectOption {
12
+ value: string;
13
+ label: string;
14
+ }
15
+ interface SelectProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'size' | 'onChange' | 'defaultValue'> {
16
+ options: SelectOption[];
17
+ size?: 'sm' | 'md' | 'lg' | 'xl';
18
+ placeholder?: string;
19
+ disabled?: boolean;
20
+ value?: string;
21
+ defaultValue?: string;
22
+ onChange?: (value: string) => void;
23
+ }
24
+ declare const Select: React.FC<SelectProps>;
25
+
26
+ type ThemeName = 'default' | 'minimalistic';
27
+ interface ButtonTheme {
28
+ primary: string;
29
+ secondary: string;
30
+ success: string;
31
+ danger: string;
32
+ warning: string;
33
+ info: string;
34
+ }
35
+ interface SelectTheme {
36
+ base: string;
37
+ sizes: {
38
+ sm: string;
39
+ md: string;
40
+ lg: string;
41
+ xl: string;
42
+ };
43
+ disabled: string;
44
+ }
45
+ interface Theme {
46
+ name: ThemeName;
47
+ button: {
48
+ base: string;
49
+ variants: ButtonTheme;
50
+ sizes: {
51
+ sm: string;
52
+ md: string;
53
+ lg: string;
54
+ xl: string;
55
+ };
56
+ disabled: string;
57
+ };
58
+ select: SelectTheme;
59
+ }
60
+ declare const themes: Record<ThemeName, Theme>;
61
+
62
+ type ColorMode = 'light' | 'dark' | 'system';
63
+ interface ThemeContextValue {
64
+ theme: Theme;
65
+ themeName: ThemeName;
66
+ setTheme: (themeName: ThemeName) => void;
67
+ colorMode: ColorMode;
68
+ setColorMode: (mode: ColorMode) => void;
69
+ resolvedColorMode: 'light' | 'dark';
70
+ }
71
+ declare function useTheme(): ThemeContextValue;
72
+ interface ThemeProviderProps {
73
+ children: React.ReactNode;
74
+ defaultTheme?: ThemeName;
75
+ defaultColorMode?: ColorMode;
76
+ }
77
+ declare function ThemeProvider({ children, defaultTheme, defaultColorMode }: ThemeProviderProps): react_jsx_runtime.JSX.Element;
78
+
79
+ /**
80
+ * Theme initialization script that runs before React hydration
81
+ * This prevents flickering by setting the theme before the page renders
82
+ * Must be inlined in the HTML <head> as a blocking script
83
+ */
84
+ declare const themeScript = "\n(function() {\n try {\n // Get stored preferences\n const storedTheme = localStorage.getItem('lite-ui-theme') || 'default';\n const storedColorMode = localStorage.getItem('lite-ui-color-mode');\n\n // Determine color mode (system, light, or dark)\n let colorMode = storedColorMode;\n if (!colorMode || colorMode === 'system') {\n colorMode = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';\n }\n\n // Set attributes before render\n document.documentElement.setAttribute('data-theme', storedTheme);\n document.documentElement.setAttribute('data-color-mode', colorMode);\n\n // Add dark class for Tailwind\n if (colorMode === 'dark') {\n document.documentElement.classList.add('dark');\n } else {\n document.documentElement.classList.remove('dark');\n }\n } catch (e) {\n console.error('Failed to initialize theme:', e);\n }\n})();\n";
85
+ declare function getThemeScript(): string;
86
+
87
+ export { Button, type ButtonProps, type ButtonTheme, type ColorMode, Select, type SelectOption, type SelectProps, type SelectTheme, type Theme, type ThemeName, ThemeProvider, getThemeScript, themeScript, themes, useTheme };
@@ -0,0 +1,87 @@
1
+ import React from 'react';
2
+ import * as react_jsx_runtime from 'react/jsx-runtime';
3
+
4
+ interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
5
+ variant?: 'primary' | 'secondary' | 'success' | 'danger' | 'warning' | 'info';
6
+ size?: 'sm' | 'md' | 'lg' | 'xl';
7
+ children: React.ReactNode;
8
+ }
9
+ declare const Button: React.FC<ButtonProps>;
10
+
11
+ interface SelectOption {
12
+ value: string;
13
+ label: string;
14
+ }
15
+ interface SelectProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'size' | 'onChange' | 'defaultValue'> {
16
+ options: SelectOption[];
17
+ size?: 'sm' | 'md' | 'lg' | 'xl';
18
+ placeholder?: string;
19
+ disabled?: boolean;
20
+ value?: string;
21
+ defaultValue?: string;
22
+ onChange?: (value: string) => void;
23
+ }
24
+ declare const Select: React.FC<SelectProps>;
25
+
26
+ type ThemeName = 'default' | 'minimalistic';
27
+ interface ButtonTheme {
28
+ primary: string;
29
+ secondary: string;
30
+ success: string;
31
+ danger: string;
32
+ warning: string;
33
+ info: string;
34
+ }
35
+ interface SelectTheme {
36
+ base: string;
37
+ sizes: {
38
+ sm: string;
39
+ md: string;
40
+ lg: string;
41
+ xl: string;
42
+ };
43
+ disabled: string;
44
+ }
45
+ interface Theme {
46
+ name: ThemeName;
47
+ button: {
48
+ base: string;
49
+ variants: ButtonTheme;
50
+ sizes: {
51
+ sm: string;
52
+ md: string;
53
+ lg: string;
54
+ xl: string;
55
+ };
56
+ disabled: string;
57
+ };
58
+ select: SelectTheme;
59
+ }
60
+ declare const themes: Record<ThemeName, Theme>;
61
+
62
+ type ColorMode = 'light' | 'dark' | 'system';
63
+ interface ThemeContextValue {
64
+ theme: Theme;
65
+ themeName: ThemeName;
66
+ setTheme: (themeName: ThemeName) => void;
67
+ colorMode: ColorMode;
68
+ setColorMode: (mode: ColorMode) => void;
69
+ resolvedColorMode: 'light' | 'dark';
70
+ }
71
+ declare function useTheme(): ThemeContextValue;
72
+ interface ThemeProviderProps {
73
+ children: React.ReactNode;
74
+ defaultTheme?: ThemeName;
75
+ defaultColorMode?: ColorMode;
76
+ }
77
+ declare function ThemeProvider({ children, defaultTheme, defaultColorMode }: ThemeProviderProps): react_jsx_runtime.JSX.Element;
78
+
79
+ /**
80
+ * Theme initialization script that runs before React hydration
81
+ * This prevents flickering by setting the theme before the page renders
82
+ * Must be inlined in the HTML <head> as a blocking script
83
+ */
84
+ declare const themeScript = "\n(function() {\n try {\n // Get stored preferences\n const storedTheme = localStorage.getItem('lite-ui-theme') || 'default';\n const storedColorMode = localStorage.getItem('lite-ui-color-mode');\n\n // Determine color mode (system, light, or dark)\n let colorMode = storedColorMode;\n if (!colorMode || colorMode === 'system') {\n colorMode = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';\n }\n\n // Set attributes before render\n document.documentElement.setAttribute('data-theme', storedTheme);\n document.documentElement.setAttribute('data-color-mode', colorMode);\n\n // Add dark class for Tailwind\n if (colorMode === 'dark') {\n document.documentElement.classList.add('dark');\n } else {\n document.documentElement.classList.remove('dark');\n }\n } catch (e) {\n console.error('Failed to initialize theme:', e);\n }\n})();\n";
85
+ declare function getThemeScript(): string;
86
+
87
+ export { Button, type ButtonProps, type ButtonTheme, type ColorMode, Select, type SelectOption, type SelectProps, type SelectTheme, type Theme, type ThemeName, ThemeProvider, getThemeScript, themeScript, themes, useTheme };
package/dist/index.js ADDED
@@ -0,0 +1,358 @@
1
+ "use client";
2
+ "use strict";
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+
21
+ // src/index.ts
22
+ var index_exports = {};
23
+ __export(index_exports, {
24
+ Button: () => Button,
25
+ Select: () => Select,
26
+ ThemeProvider: () => ThemeProvider,
27
+ getThemeScript: () => getThemeScript,
28
+ themeScript: () => themeScript,
29
+ themes: () => themes,
30
+ useTheme: () => useTheme
31
+ });
32
+ module.exports = __toCommonJS(index_exports);
33
+
34
+ // src/theme/ThemeProvider.tsx
35
+ var import_react = require("react");
36
+
37
+ // src/theme/themes.ts
38
+ var themes = {
39
+ default: {
40
+ name: "default",
41
+ button: {
42
+ base: "font-semibold rounded-lg transition-all duration-150 focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 active:scale-95",
43
+ variants: {
44
+ primary: "bg-blue-600 hover:bg-blue-700 active:bg-blue-800 text-white shadow-sm hover:shadow-md dark:bg-blue-500 dark:hover:bg-blue-600 dark:active:bg-blue-700",
45
+ secondary: "bg-gray-600 hover:bg-gray-700 active:bg-gray-800 text-white shadow-sm hover:shadow-md dark:bg-gray-500 dark:hover:bg-gray-600 dark:active:bg-gray-700",
46
+ success: "bg-green-600 hover:bg-green-700 active:bg-green-800 text-white shadow-sm hover:shadow-md dark:bg-green-500 dark:hover:bg-green-600 dark:active:bg-green-700",
47
+ danger: "bg-red-600 hover:bg-red-700 active:bg-red-800 text-white shadow-sm hover:shadow-md dark:bg-red-500 dark:hover:bg-red-600 dark:active:bg-red-700",
48
+ warning: "bg-yellow-500 hover:bg-yellow-600 active:bg-yellow-700 text-white shadow-sm hover:shadow-md dark:bg-yellow-400 dark:hover:bg-yellow-500 dark:active:bg-yellow-600",
49
+ info: "bg-cyan-600 hover:bg-cyan-700 active:bg-cyan-800 text-white shadow-sm hover:shadow-md dark:bg-cyan-500 dark:hover:bg-cyan-600 dark:active:bg-cyan-700"
50
+ },
51
+ sizes: {
52
+ sm: "px-3 py-1.5 text-sm",
53
+ md: "px-4 py-2 text-base",
54
+ lg: "px-6 py-3 text-lg",
55
+ xl: "px-8 py-4 text-xl"
56
+ },
57
+ disabled: "opacity-50 cursor-not-allowed hover:shadow-sm active:scale-100"
58
+ },
59
+ select: {
60
+ base: "w-full appearance-none rounded-lg border border-gray-300 bg-white text-gray-900 transition-all duration-150 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent shadow-sm hover:border-gray-400 pr-10 cursor-pointer dark:bg-gray-800 dark:border-gray-600 dark:text-gray-100 dark:hover:border-gray-500",
61
+ sizes: {
62
+ sm: "px-3 py-1.5 text-sm",
63
+ md: "px-4 py-2.5 text-base",
64
+ lg: "px-4 py-3 text-lg",
65
+ xl: "px-5 py-4 text-xl"
66
+ },
67
+ disabled: "opacity-50 cursor-not-allowed bg-gray-50 dark:bg-gray-900"
68
+ }
69
+ },
70
+ minimalistic: {
71
+ name: "minimalistic",
72
+ button: {
73
+ base: "font-normal rounded-none transition-colors duration-200 focus:outline-none border-2",
74
+ variants: {
75
+ primary: "bg-transparent border-white text-white hover:bg-white hover:text-black",
76
+ secondary: "bg-transparent border-gray-400 text-gray-400 hover:bg-gray-400 hover:text-black",
77
+ success: "bg-transparent border-green-400 text-green-400 hover:bg-green-400 hover:text-black",
78
+ danger: "bg-transparent border-red-400 text-red-400 hover:bg-red-400 hover:text-black",
79
+ warning: "bg-transparent border-yellow-400 text-yellow-400 hover:bg-yellow-400 hover:text-black",
80
+ info: "bg-transparent border-blue-400 text-blue-400 hover:bg-blue-400 hover:text-black"
81
+ },
82
+ sizes: {
83
+ sm: "px-4 py-2 text-sm uppercase tracking-wide",
84
+ md: "px-6 py-3 text-base uppercase tracking-wide",
85
+ lg: "px-8 py-4 text-lg uppercase tracking-wider",
86
+ xl: "px-10 py-5 text-xl uppercase tracking-wider"
87
+ },
88
+ disabled: "opacity-30 cursor-not-allowed hover:bg-transparent"
89
+ },
90
+ select: {
91
+ base: "w-full appearance-none rounded-none border-2 border-white bg-transparent text-white transition-colors duration-200 focus:outline-none pr-10 cursor-pointer placeholder:text-gray-500",
92
+ sizes: {
93
+ sm: "px-4 py-2 text-sm uppercase tracking-wide",
94
+ md: "px-4 py-3 text-base uppercase tracking-wide",
95
+ lg: "px-4 py-4 text-lg uppercase tracking-wider",
96
+ xl: "px-5 py-5 text-xl uppercase tracking-wider"
97
+ },
98
+ disabled: "opacity-30 cursor-not-allowed"
99
+ }
100
+ }
101
+ };
102
+
103
+ // src/theme/ThemeProvider.tsx
104
+ var import_jsx_runtime = require("react/jsx-runtime");
105
+ var ThemeContext = (0, import_react.createContext)(void 0);
106
+ function useTheme() {
107
+ const context = (0, import_react.useContext)(ThemeContext);
108
+ if (!context) {
109
+ throw new Error("useTheme must be used within a ThemeProvider");
110
+ }
111
+ return context;
112
+ }
113
+ function ThemeProvider({
114
+ children,
115
+ defaultTheme = "default",
116
+ defaultColorMode = "system"
117
+ }) {
118
+ const [mounted, setMounted] = (0, import_react.useState)(false);
119
+ const [themeName, setThemeNameState] = (0, import_react.useState)(defaultTheme);
120
+ const [colorMode, setColorModeState] = (0, import_react.useState)(defaultColorMode);
121
+ const [resolvedColorMode, setResolvedColorMode] = (0, import_react.useState)("light");
122
+ (0, import_react.useEffect)(() => {
123
+ setMounted(true);
124
+ const storedTheme = localStorage.getItem("lite-ui-theme");
125
+ const storedColorMode = localStorage.getItem("lite-ui-color-mode");
126
+ const currentColorMode = document.documentElement.getAttribute("data-color-mode");
127
+ if (storedTheme) setThemeNameState(storedTheme);
128
+ if (storedColorMode) setColorModeState(storedColorMode);
129
+ if (currentColorMode) setResolvedColorMode(currentColorMode);
130
+ }, []);
131
+ const theme = themes[themeName];
132
+ const setTheme = (newThemeName) => {
133
+ setThemeNameState(newThemeName);
134
+ if (typeof window !== "undefined") {
135
+ localStorage.setItem("lite-ui-theme", newThemeName);
136
+ document.documentElement.setAttribute("data-theme", newThemeName);
137
+ }
138
+ };
139
+ const setColorMode = (mode) => {
140
+ if (typeof window === "undefined") return;
141
+ setColorModeState(mode);
142
+ localStorage.setItem("lite-ui-color-mode", mode);
143
+ let resolved;
144
+ if (mode === "system") {
145
+ resolved = window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
146
+ } else {
147
+ resolved = mode;
148
+ }
149
+ setResolvedColorMode(resolved);
150
+ document.documentElement.setAttribute("data-color-mode", resolved);
151
+ if (resolved === "dark") {
152
+ document.documentElement.classList.add("dark");
153
+ } else {
154
+ document.documentElement.classList.remove("dark");
155
+ }
156
+ };
157
+ (0, import_react.useEffect)(() => {
158
+ if (!mounted) return;
159
+ const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
160
+ const handleChange = (e) => {
161
+ if (colorMode === "system") {
162
+ const resolved = e.matches ? "dark" : "light";
163
+ setResolvedColorMode(resolved);
164
+ document.documentElement.setAttribute("data-color-mode", resolved);
165
+ if (resolved === "dark") {
166
+ document.documentElement.classList.add("dark");
167
+ } else {
168
+ document.documentElement.classList.remove("dark");
169
+ }
170
+ }
171
+ };
172
+ mediaQuery.addEventListener("change", handleChange);
173
+ return () => mediaQuery.removeEventListener("change", handleChange);
174
+ }, [mounted, colorMode]);
175
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ThemeContext.Provider, { value: {
176
+ theme,
177
+ themeName,
178
+ setTheme,
179
+ colorMode,
180
+ setColorMode,
181
+ resolvedColorMode
182
+ }, children });
183
+ }
184
+
185
+ // src/components/Button.tsx
186
+ var import_jsx_runtime2 = require("react/jsx-runtime");
187
+ var Button = ({
188
+ variant = "primary",
189
+ size = "md",
190
+ className = "",
191
+ children,
192
+ disabled,
193
+ ...props
194
+ }) => {
195
+ const { theme } = useTheme();
196
+ const baseStyles = theme.button.base;
197
+ const variantStyles = theme.button.variants[variant];
198
+ const sizeStyles = theme.button.sizes[size];
199
+ const disabledStyles = disabled ? theme.button.disabled : "";
200
+ const classes = `${baseStyles} ${variantStyles} ${sizeStyles} ${disabledStyles} ${className}`.trim();
201
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
202
+ "button",
203
+ {
204
+ className: classes,
205
+ disabled,
206
+ ...props,
207
+ children
208
+ }
209
+ );
210
+ };
211
+
212
+ // src/components/Select.tsx
213
+ var import_react2 = require("react");
214
+ var import_jsx_runtime3 = require("react/jsx-runtime");
215
+ var Select = ({
216
+ options,
217
+ size = "md",
218
+ placeholder,
219
+ className = "",
220
+ disabled,
221
+ value: controlledValue,
222
+ defaultValue,
223
+ onChange,
224
+ ...props
225
+ }) => {
226
+ const { theme, themeName } = useTheme();
227
+ const [isOpen, setIsOpen] = (0, import_react2.useState)(false);
228
+ const [internalValue, setInternalValue] = (0, import_react2.useState)(defaultValue || "");
229
+ const dropdownRef = (0, import_react2.useRef)(null);
230
+ const value = controlledValue !== void 0 ? controlledValue : internalValue;
231
+ const selectedOption = options.find((opt) => opt.value === value);
232
+ const displayText = selectedOption ? selectedOption.label : placeholder || "Select...";
233
+ (0, import_react2.useEffect)(() => {
234
+ const handleClickOutside = (event) => {
235
+ if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
236
+ setIsOpen(false);
237
+ }
238
+ };
239
+ if (isOpen) {
240
+ document.addEventListener("mousedown", handleClickOutside);
241
+ return () => document.removeEventListener("mousedown", handleClickOutside);
242
+ }
243
+ }, [isOpen]);
244
+ const handleSelect = (optionValue) => {
245
+ if (disabled) return;
246
+ setInternalValue(optionValue);
247
+ onChange?.(optionValue);
248
+ setIsOpen(false);
249
+ };
250
+ const handleToggle = () => {
251
+ if (!disabled) {
252
+ setIsOpen(!isOpen);
253
+ }
254
+ };
255
+ const baseStyles = theme.select.base;
256
+ const sizeStyles = theme.select.sizes[size];
257
+ const disabledStyles = disabled ? theme.select.disabled : "";
258
+ const buttonClasses = `${baseStyles} ${sizeStyles} ${disabledStyles} ${className}`.trim();
259
+ const iconColor = themeName === "minimalistic" ? disabled ? "text-gray-600" : "text-white" : disabled ? "text-gray-400" : "text-gray-500";
260
+ const dropdownBaseStyles = themeName === "minimalistic" ? "bg-black border-2 border-white" : "bg-white border border-gray-300 shadow-lg dark:bg-gray-800 dark:border-gray-600";
261
+ const optionBaseStyles = themeName === "minimalistic" ? "text-white hover:bg-white hover:text-black transition-colors duration-200" : "text-gray-900 hover:bg-blue-50 transition-colors duration-150 dark:text-gray-100 dark:hover:bg-gray-700";
262
+ const optionSizeStyles = {
263
+ sm: "px-4 py-2 text-sm",
264
+ md: "px-4 py-2.5 text-base",
265
+ lg: "px-4 py-3 text-lg",
266
+ xl: "px-5 py-4 text-xl"
267
+ }[size];
268
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "relative inline-block w-full", ref: dropdownRef, ...props, children: [
269
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
270
+ "button",
271
+ {
272
+ type: "button",
273
+ className: buttonClasses,
274
+ onClick: handleToggle,
275
+ disabled,
276
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: !selectedOption && placeholder ? "opacity-50" : "", children: displayText })
277
+ }
278
+ ),
279
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "pointer-events-none absolute inset-y-0 right-0 flex items-center pr-4", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
280
+ "svg",
281
+ {
282
+ className: `h-5 w-5 transition-transform duration-200 ${iconColor} ${isOpen ? "rotate-180" : ""}`,
283
+ xmlns: "http://www.w3.org/2000/svg",
284
+ viewBox: "0 0 20 20",
285
+ fill: "currentColor",
286
+ "aria-hidden": "true",
287
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
288
+ "path",
289
+ {
290
+ fillRule: "evenodd",
291
+ d: "M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z",
292
+ clipRule: "evenodd"
293
+ }
294
+ )
295
+ }
296
+ ) }),
297
+ isOpen && !disabled && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
298
+ "div",
299
+ {
300
+ className: `absolute z-50 w-full mt-1 ${dropdownBaseStyles} rounded-lg overflow-hidden`,
301
+ style: { maxHeight: "300px", overflowY: "auto" },
302
+ children: options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
303
+ "div",
304
+ {
305
+ className: `${optionBaseStyles} ${optionSizeStyles} cursor-pointer ${value === option.value ? themeName === "minimalistic" ? "bg-white text-black" : "bg-blue-100 dark:bg-blue-900" : ""}`,
306
+ onClick: () => handleSelect(option.value),
307
+ children: option.label
308
+ },
309
+ option.value
310
+ ))
311
+ }
312
+ )
313
+ ] });
314
+ };
315
+
316
+ // src/utils/theme-script.ts
317
+ var themeScript = `
318
+ (function() {
319
+ try {
320
+ // Get stored preferences
321
+ const storedTheme = localStorage.getItem('lite-ui-theme') || 'default';
322
+ const storedColorMode = localStorage.getItem('lite-ui-color-mode');
323
+
324
+ // Determine color mode (system, light, or dark)
325
+ let colorMode = storedColorMode;
326
+ if (!colorMode || colorMode === 'system') {
327
+ colorMode = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
328
+ }
329
+
330
+ // Set attributes before render
331
+ document.documentElement.setAttribute('data-theme', storedTheme);
332
+ document.documentElement.setAttribute('data-color-mode', colorMode);
333
+
334
+ // Add dark class for Tailwind
335
+ if (colorMode === 'dark') {
336
+ document.documentElement.classList.add('dark');
337
+ } else {
338
+ document.documentElement.classList.remove('dark');
339
+ }
340
+ } catch (e) {
341
+ console.error('Failed to initialize theme:', e);
342
+ }
343
+ })();
344
+ `;
345
+ function getThemeScript() {
346
+ return themeScript;
347
+ }
348
+ // Annotate the CommonJS export names for ESM import in node:
349
+ 0 && (module.exports = {
350
+ Button,
351
+ Select,
352
+ ThemeProvider,
353
+ getThemeScript,
354
+ themeScript,
355
+ themes,
356
+ useTheme
357
+ });
358
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/theme/ThemeProvider.tsx","../src/theme/themes.ts","../src/components/Button.tsx","../src/components/Select.tsx","../src/utils/theme-script.ts"],"sourcesContent":["export { Button } from './components/Button';\nexport type { ButtonProps } from './components/Button';\n\nexport { Select } from './components/Select';\nexport type { SelectProps, SelectOption } from './components/Select';\n\nexport { ThemeProvider, useTheme } from './theme/ThemeProvider';\nexport type { ColorMode } from './theme/ThemeProvider';\nexport { themes } from './theme/themes';\nexport type { ThemeName, Theme, ButtonTheme, SelectTheme } from './theme/themes';\n\nexport { themeScript, getThemeScript } from './utils/theme-script';\n","\"use client\";\n\nimport React, { createContext, useContext, useState, useEffect } from 'react';\nimport { themes, ThemeName, Theme } from './themes';\n\nexport type ColorMode = 'light' | 'dark' | 'system';\n\ninterface ThemeContextValue {\n theme: Theme;\n themeName: ThemeName;\n setTheme: (themeName: ThemeName) => void;\n colorMode: ColorMode;\n setColorMode: (mode: ColorMode) => void;\n resolvedColorMode: 'light' | 'dark';\n}\n\nconst ThemeContext = createContext<ThemeContextValue | undefined>(undefined);\n\nexport function useTheme() {\n const context = useContext(ThemeContext);\n if (!context) {\n throw new Error('useTheme must be used within a ThemeProvider');\n }\n return context;\n}\n\ninterface ThemeProviderProps {\n children: React.ReactNode;\n defaultTheme?: ThemeName;\n defaultColorMode?: ColorMode;\n}\n\nexport function ThemeProvider({\n children,\n defaultTheme = 'default',\n defaultColorMode = 'system'\n}: ThemeProviderProps) {\n const [mounted, setMounted] = useState(false);\n\n // Initialize from defaults (will sync with actual values after mount)\n const [themeName, setThemeNameState] = useState<ThemeName>(defaultTheme);\n const [colorMode, setColorModeState] = useState<ColorMode>(defaultColorMode);\n const [resolvedColorMode, setResolvedColorMode] = useState<'light' | 'dark'>('light');\n\n // Sync with actual values after mount to avoid hydration mismatch\n useEffect(() => {\n setMounted(true);\n\n // Read actual values from localStorage and DOM\n const storedTheme = localStorage.getItem('lite-ui-theme') as ThemeName;\n const storedColorMode = localStorage.getItem('lite-ui-color-mode') as ColorMode;\n const currentColorMode = document.documentElement.getAttribute('data-color-mode') as 'light' | 'dark';\n\n if (storedTheme) setThemeNameState(storedTheme);\n if (storedColorMode) setColorModeState(storedColorMode);\n if (currentColorMode) setResolvedColorMode(currentColorMode);\n }, []);\n\n const theme = themes[themeName];\n\n // Update theme\n const setTheme = (newThemeName: ThemeName) => {\n setThemeNameState(newThemeName);\n if (typeof window !== 'undefined') {\n localStorage.setItem('lite-ui-theme', newThemeName);\n document.documentElement.setAttribute('data-theme', newThemeName);\n }\n };\n\n // Update color mode\n const setColorMode = (mode: ColorMode) => {\n if (typeof window === 'undefined') return;\n\n setColorModeState(mode);\n localStorage.setItem('lite-ui-color-mode', mode);\n\n let resolved: 'light' | 'dark';\n if (mode === 'system') {\n resolved = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';\n } else {\n resolved = mode;\n }\n\n setResolvedColorMode(resolved);\n document.documentElement.setAttribute('data-color-mode', resolved);\n\n if (resolved === 'dark') {\n document.documentElement.classList.add('dark');\n } else {\n document.documentElement.classList.remove('dark');\n }\n };\n\n // Listen for system theme changes\n useEffect(() => {\n if (!mounted) return;\n\n const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');\n\n const handleChange = (e: MediaQueryListEvent) => {\n if (colorMode === 'system') {\n const resolved = e.matches ? 'dark' : 'light';\n setResolvedColorMode(resolved);\n document.documentElement.setAttribute('data-color-mode', resolved);\n\n if (resolved === 'dark') {\n document.documentElement.classList.add('dark');\n } else {\n document.documentElement.classList.remove('dark');\n }\n }\n };\n\n mediaQuery.addEventListener('change', handleChange);\n return () => mediaQuery.removeEventListener('change', handleChange);\n }, [mounted, colorMode]);\n\n return (\n <ThemeContext.Provider value={{\n theme,\n themeName,\n setTheme,\n colorMode,\n setColorMode,\n resolvedColorMode\n }}>\n {children}\n </ThemeContext.Provider>\n );\n}\n","export type ThemeName = 'default' | 'minimalistic';\n\nexport interface ButtonTheme {\n primary: string;\n secondary: string;\n success: string;\n danger: string;\n warning: string;\n info: string;\n}\n\nexport interface SelectTheme {\n base: string;\n sizes: {\n sm: string;\n md: string;\n lg: string;\n xl: string;\n };\n disabled: string;\n}\n\nexport interface Theme {\n name: ThemeName;\n button: {\n base: string;\n variants: ButtonTheme;\n sizes: {\n sm: string;\n md: string;\n lg: string;\n xl: string;\n };\n disabled: string;\n };\n select: SelectTheme;\n}\n\nexport const themes: Record<ThemeName, Theme> = {\n default: {\n name: 'default',\n button: {\n base: 'font-semibold rounded-lg transition-all duration-150 focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 active:scale-95',\n variants: {\n primary: 'bg-blue-600 hover:bg-blue-700 active:bg-blue-800 text-white shadow-sm hover:shadow-md dark:bg-blue-500 dark:hover:bg-blue-600 dark:active:bg-blue-700',\n secondary: 'bg-gray-600 hover:bg-gray-700 active:bg-gray-800 text-white shadow-sm hover:shadow-md dark:bg-gray-500 dark:hover:bg-gray-600 dark:active:bg-gray-700',\n success: 'bg-green-600 hover:bg-green-700 active:bg-green-800 text-white shadow-sm hover:shadow-md dark:bg-green-500 dark:hover:bg-green-600 dark:active:bg-green-700',\n danger: 'bg-red-600 hover:bg-red-700 active:bg-red-800 text-white shadow-sm hover:shadow-md dark:bg-red-500 dark:hover:bg-red-600 dark:active:bg-red-700',\n warning: 'bg-yellow-500 hover:bg-yellow-600 active:bg-yellow-700 text-white shadow-sm hover:shadow-md dark:bg-yellow-400 dark:hover:bg-yellow-500 dark:active:bg-yellow-600',\n info: 'bg-cyan-600 hover:bg-cyan-700 active:bg-cyan-800 text-white shadow-sm hover:shadow-md dark:bg-cyan-500 dark:hover:bg-cyan-600 dark:active:bg-cyan-700',\n },\n sizes: {\n sm: 'px-3 py-1.5 text-sm',\n md: 'px-4 py-2 text-base',\n lg: 'px-6 py-3 text-lg',\n xl: 'px-8 py-4 text-xl',\n },\n disabled: 'opacity-50 cursor-not-allowed hover:shadow-sm active:scale-100',\n },\n select: {\n base: 'w-full appearance-none rounded-lg border border-gray-300 bg-white text-gray-900 transition-all duration-150 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent shadow-sm hover:border-gray-400 pr-10 cursor-pointer dark:bg-gray-800 dark:border-gray-600 dark:text-gray-100 dark:hover:border-gray-500',\n sizes: {\n sm: 'px-3 py-1.5 text-sm',\n md: 'px-4 py-2.5 text-base',\n lg: 'px-4 py-3 text-lg',\n xl: 'px-5 py-4 text-xl',\n },\n disabled: 'opacity-50 cursor-not-allowed bg-gray-50 dark:bg-gray-900',\n },\n },\n minimalistic: {\n name: 'minimalistic',\n button: {\n base: 'font-normal rounded-none transition-colors duration-200 focus:outline-none border-2',\n variants: {\n primary: 'bg-transparent border-white text-white hover:bg-white hover:text-black',\n secondary: 'bg-transparent border-gray-400 text-gray-400 hover:bg-gray-400 hover:text-black',\n success: 'bg-transparent border-green-400 text-green-400 hover:bg-green-400 hover:text-black',\n danger: 'bg-transparent border-red-400 text-red-400 hover:bg-red-400 hover:text-black',\n warning: 'bg-transparent border-yellow-400 text-yellow-400 hover:bg-yellow-400 hover:text-black',\n info: 'bg-transparent border-blue-400 text-blue-400 hover:bg-blue-400 hover:text-black',\n },\n sizes: {\n sm: 'px-4 py-2 text-sm uppercase tracking-wide',\n md: 'px-6 py-3 text-base uppercase tracking-wide',\n lg: 'px-8 py-4 text-lg uppercase tracking-wider',\n xl: 'px-10 py-5 text-xl uppercase tracking-wider',\n },\n disabled: 'opacity-30 cursor-not-allowed hover:bg-transparent',\n },\n select: {\n base: 'w-full appearance-none rounded-none border-2 border-white bg-transparent text-white transition-colors duration-200 focus:outline-none pr-10 cursor-pointer placeholder:text-gray-500',\n sizes: {\n sm: 'px-4 py-2 text-sm uppercase tracking-wide',\n md: 'px-4 py-3 text-base uppercase tracking-wide',\n lg: 'px-4 py-4 text-lg uppercase tracking-wider',\n xl: 'px-5 py-5 text-xl uppercase tracking-wider',\n },\n disabled: 'opacity-30 cursor-not-allowed',\n },\n },\n};\n","\"use client\";\n\nimport React from 'react';\nimport { useTheme } from '../theme/ThemeProvider';\n\nexport interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n variant?: 'primary' | 'secondary' | 'success' | 'danger' | 'warning' | 'info';\n size?: 'sm' | 'md' | 'lg' | 'xl';\n children: React.ReactNode;\n}\n\nexport const Button: React.FC<ButtonProps> = ({\n variant = 'primary',\n size = 'md',\n className = '',\n children,\n disabled,\n ...props\n}) => {\n const { theme } = useTheme();\n\n const baseStyles = theme.button.base;\n const variantStyles = theme.button.variants[variant];\n const sizeStyles = theme.button.sizes[size];\n const disabledStyles = disabled ? theme.button.disabled : '';\n\n const classes = `${baseStyles} ${variantStyles} ${sizeStyles} ${disabledStyles} ${className}`.trim();\n\n return (\n <button\n className={classes}\n disabled={disabled}\n {...props}\n >\n {children}\n </button>\n );\n};\n","\"use client\";\n\nimport React, { useState, useRef, useEffect } from 'react';\nimport { useTheme } from '../theme/ThemeProvider';\n\nexport interface SelectOption {\n value: string;\n label: string;\n}\n\nexport interface SelectProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'size' | 'onChange' | 'defaultValue'> {\n options: SelectOption[];\n size?: 'sm' | 'md' | 'lg' | 'xl';\n placeholder?: string;\n disabled?: boolean;\n value?: string;\n defaultValue?: string;\n onChange?: (value: string) => void;\n}\n\nexport const Select: React.FC<SelectProps> = ({\n options,\n size = 'md',\n placeholder,\n className = '',\n disabled,\n value: controlledValue,\n defaultValue,\n onChange,\n ...props\n}) => {\n const { theme, themeName } = useTheme();\n const [isOpen, setIsOpen] = useState(false);\n const [internalValue, setInternalValue] = useState(defaultValue || '');\n const dropdownRef = useRef<HTMLDivElement>(null);\n\n // Use controlled value if provided, otherwise use internal state\n const value = controlledValue !== undefined ? controlledValue : internalValue;\n\n // Find the selected option\n const selectedOption = options.find(opt => opt.value === value);\n const displayText = selectedOption ? selectedOption.label : placeholder || 'Select...';\n\n // Close dropdown when clicking outside\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {\n setIsOpen(false);\n }\n };\n\n if (isOpen) {\n document.addEventListener('mousedown', handleClickOutside);\n return () => document.removeEventListener('mousedown', handleClickOutside);\n }\n }, [isOpen]);\n\n const handleSelect = (optionValue: string) => {\n if (disabled) return;\n\n setInternalValue(optionValue);\n onChange?.(optionValue);\n setIsOpen(false);\n };\n\n const handleToggle = () => {\n if (!disabled) {\n setIsOpen(!isOpen);\n }\n };\n\n const baseStyles = theme.select.base;\n const sizeStyles = theme.select.sizes[size];\n const disabledStyles = disabled ? theme.select.disabled : '';\n\n const buttonClasses = `${baseStyles} ${sizeStyles} ${disabledStyles} ${className}`.trim();\n\n // Icon color based on theme\n const iconColor = themeName === 'minimalistic'\n ? (disabled ? 'text-gray-600' : 'text-white')\n : (disabled ? 'text-gray-400' : 'text-gray-500');\n\n // Dropdown menu styles based on theme\n const dropdownBaseStyles = themeName === 'minimalistic'\n ? 'bg-black border-2 border-white'\n : 'bg-white border border-gray-300 shadow-lg dark:bg-gray-800 dark:border-gray-600';\n\n const optionBaseStyles = themeName === 'minimalistic'\n ? 'text-white hover:bg-white hover:text-black transition-colors duration-200'\n : 'text-gray-900 hover:bg-blue-50 transition-colors duration-150 dark:text-gray-100 dark:hover:bg-gray-700';\n\n const optionSizeStyles = {\n sm: 'px-4 py-2 text-sm',\n md: 'px-4 py-2.5 text-base',\n lg: 'px-4 py-3 text-lg',\n xl: 'px-5 py-4 text-xl',\n }[size];\n\n return (\n <div className=\"relative inline-block w-full\" ref={dropdownRef} {...props}>\n {/* Custom button that looks like select */}\n <button\n type=\"button\"\n className={buttonClasses}\n onClick={handleToggle}\n disabled={disabled}\n >\n <span className={!selectedOption && placeholder ? 'opacity-50' : ''}>\n {displayText}\n </span>\n </button>\n\n {/* Chevron icon */}\n <div className=\"pointer-events-none absolute inset-y-0 right-0 flex items-center pr-4\">\n <svg\n className={`h-5 w-5 transition-transform duration-200 ${iconColor} ${isOpen ? 'rotate-180' : ''}`}\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n fillRule=\"evenodd\"\n d=\"M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z\"\n clipRule=\"evenodd\"\n />\n </svg>\n </div>\n\n {/* Custom dropdown menu */}\n {isOpen && !disabled && (\n <div\n className={`absolute z-50 w-full mt-1 ${dropdownBaseStyles} rounded-lg overflow-hidden`}\n style={{ maxHeight: '300px', overflowY: 'auto' }}\n >\n {options.map((option) => (\n <div\n key={option.value}\n className={`${optionBaseStyles} ${optionSizeStyles} cursor-pointer ${\n value === option.value ? (themeName === 'minimalistic' ? 'bg-white text-black' : 'bg-blue-100 dark:bg-blue-900') : ''\n }`}\n onClick={() => handleSelect(option.value)}\n >\n {option.label}\n </div>\n ))}\n </div>\n )}\n </div>\n );\n};\n","/**\n * Theme initialization script that runs before React hydration\n * This prevents flickering by setting the theme before the page renders\n * Must be inlined in the HTML <head> as a blocking script\n */\n\nexport const themeScript = `\n(function() {\n try {\n // Get stored preferences\n const storedTheme = localStorage.getItem('lite-ui-theme') || 'default';\n const storedColorMode = localStorage.getItem('lite-ui-color-mode');\n\n // Determine color mode (system, light, or dark)\n let colorMode = storedColorMode;\n if (!colorMode || colorMode === 'system') {\n colorMode = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';\n }\n\n // Set attributes before render\n document.documentElement.setAttribute('data-theme', storedTheme);\n document.documentElement.setAttribute('data-color-mode', colorMode);\n\n // Add dark class for Tailwind\n if (colorMode === 'dark') {\n document.documentElement.classList.add('dark');\n } else {\n document.documentElement.classList.remove('dark');\n }\n } catch (e) {\n console.error('Failed to initialize theme:', e);\n }\n})();\n`;\n\nexport function getThemeScript() {\n return themeScript;\n}\n"],"mappings":"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","names":["import_jsx_runtime","import_react","import_jsx_runtime"]}
package/dist/index.mjs ADDED
@@ -0,0 +1,326 @@
1
+ "use client";
2
+
3
+ // src/theme/ThemeProvider.tsx
4
+ import { createContext, useContext, useState, useEffect } from "react";
5
+
6
+ // src/theme/themes.ts
7
+ var themes = {
8
+ default: {
9
+ name: "default",
10
+ button: {
11
+ base: "font-semibold rounded-lg transition-all duration-150 focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 active:scale-95",
12
+ variants: {
13
+ primary: "bg-blue-600 hover:bg-blue-700 active:bg-blue-800 text-white shadow-sm hover:shadow-md dark:bg-blue-500 dark:hover:bg-blue-600 dark:active:bg-blue-700",
14
+ secondary: "bg-gray-600 hover:bg-gray-700 active:bg-gray-800 text-white shadow-sm hover:shadow-md dark:bg-gray-500 dark:hover:bg-gray-600 dark:active:bg-gray-700",
15
+ success: "bg-green-600 hover:bg-green-700 active:bg-green-800 text-white shadow-sm hover:shadow-md dark:bg-green-500 dark:hover:bg-green-600 dark:active:bg-green-700",
16
+ danger: "bg-red-600 hover:bg-red-700 active:bg-red-800 text-white shadow-sm hover:shadow-md dark:bg-red-500 dark:hover:bg-red-600 dark:active:bg-red-700",
17
+ warning: "bg-yellow-500 hover:bg-yellow-600 active:bg-yellow-700 text-white shadow-sm hover:shadow-md dark:bg-yellow-400 dark:hover:bg-yellow-500 dark:active:bg-yellow-600",
18
+ info: "bg-cyan-600 hover:bg-cyan-700 active:bg-cyan-800 text-white shadow-sm hover:shadow-md dark:bg-cyan-500 dark:hover:bg-cyan-600 dark:active:bg-cyan-700"
19
+ },
20
+ sizes: {
21
+ sm: "px-3 py-1.5 text-sm",
22
+ md: "px-4 py-2 text-base",
23
+ lg: "px-6 py-3 text-lg",
24
+ xl: "px-8 py-4 text-xl"
25
+ },
26
+ disabled: "opacity-50 cursor-not-allowed hover:shadow-sm active:scale-100"
27
+ },
28
+ select: {
29
+ base: "w-full appearance-none rounded-lg border border-gray-300 bg-white text-gray-900 transition-all duration-150 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent shadow-sm hover:border-gray-400 pr-10 cursor-pointer dark:bg-gray-800 dark:border-gray-600 dark:text-gray-100 dark:hover:border-gray-500",
30
+ sizes: {
31
+ sm: "px-3 py-1.5 text-sm",
32
+ md: "px-4 py-2.5 text-base",
33
+ lg: "px-4 py-3 text-lg",
34
+ xl: "px-5 py-4 text-xl"
35
+ },
36
+ disabled: "opacity-50 cursor-not-allowed bg-gray-50 dark:bg-gray-900"
37
+ }
38
+ },
39
+ minimalistic: {
40
+ name: "minimalistic",
41
+ button: {
42
+ base: "font-normal rounded-none transition-colors duration-200 focus:outline-none border-2",
43
+ variants: {
44
+ primary: "bg-transparent border-white text-white hover:bg-white hover:text-black",
45
+ secondary: "bg-transparent border-gray-400 text-gray-400 hover:bg-gray-400 hover:text-black",
46
+ success: "bg-transparent border-green-400 text-green-400 hover:bg-green-400 hover:text-black",
47
+ danger: "bg-transparent border-red-400 text-red-400 hover:bg-red-400 hover:text-black",
48
+ warning: "bg-transparent border-yellow-400 text-yellow-400 hover:bg-yellow-400 hover:text-black",
49
+ info: "bg-transparent border-blue-400 text-blue-400 hover:bg-blue-400 hover:text-black"
50
+ },
51
+ sizes: {
52
+ sm: "px-4 py-2 text-sm uppercase tracking-wide",
53
+ md: "px-6 py-3 text-base uppercase tracking-wide",
54
+ lg: "px-8 py-4 text-lg uppercase tracking-wider",
55
+ xl: "px-10 py-5 text-xl uppercase tracking-wider"
56
+ },
57
+ disabled: "opacity-30 cursor-not-allowed hover:bg-transparent"
58
+ },
59
+ select: {
60
+ base: "w-full appearance-none rounded-none border-2 border-white bg-transparent text-white transition-colors duration-200 focus:outline-none pr-10 cursor-pointer placeholder:text-gray-500",
61
+ sizes: {
62
+ sm: "px-4 py-2 text-sm uppercase tracking-wide",
63
+ md: "px-4 py-3 text-base uppercase tracking-wide",
64
+ lg: "px-4 py-4 text-lg uppercase tracking-wider",
65
+ xl: "px-5 py-5 text-xl uppercase tracking-wider"
66
+ },
67
+ disabled: "opacity-30 cursor-not-allowed"
68
+ }
69
+ }
70
+ };
71
+
72
+ // src/theme/ThemeProvider.tsx
73
+ import { jsx } from "react/jsx-runtime";
74
+ var ThemeContext = createContext(void 0);
75
+ function useTheme() {
76
+ const context = useContext(ThemeContext);
77
+ if (!context) {
78
+ throw new Error("useTheme must be used within a ThemeProvider");
79
+ }
80
+ return context;
81
+ }
82
+ function ThemeProvider({
83
+ children,
84
+ defaultTheme = "default",
85
+ defaultColorMode = "system"
86
+ }) {
87
+ const [mounted, setMounted] = useState(false);
88
+ const [themeName, setThemeNameState] = useState(defaultTheme);
89
+ const [colorMode, setColorModeState] = useState(defaultColorMode);
90
+ const [resolvedColorMode, setResolvedColorMode] = useState("light");
91
+ useEffect(() => {
92
+ setMounted(true);
93
+ const storedTheme = localStorage.getItem("lite-ui-theme");
94
+ const storedColorMode = localStorage.getItem("lite-ui-color-mode");
95
+ const currentColorMode = document.documentElement.getAttribute("data-color-mode");
96
+ if (storedTheme) setThemeNameState(storedTheme);
97
+ if (storedColorMode) setColorModeState(storedColorMode);
98
+ if (currentColorMode) setResolvedColorMode(currentColorMode);
99
+ }, []);
100
+ const theme = themes[themeName];
101
+ const setTheme = (newThemeName) => {
102
+ setThemeNameState(newThemeName);
103
+ if (typeof window !== "undefined") {
104
+ localStorage.setItem("lite-ui-theme", newThemeName);
105
+ document.documentElement.setAttribute("data-theme", newThemeName);
106
+ }
107
+ };
108
+ const setColorMode = (mode) => {
109
+ if (typeof window === "undefined") return;
110
+ setColorModeState(mode);
111
+ localStorage.setItem("lite-ui-color-mode", mode);
112
+ let resolved;
113
+ if (mode === "system") {
114
+ resolved = window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
115
+ } else {
116
+ resolved = mode;
117
+ }
118
+ setResolvedColorMode(resolved);
119
+ document.documentElement.setAttribute("data-color-mode", resolved);
120
+ if (resolved === "dark") {
121
+ document.documentElement.classList.add("dark");
122
+ } else {
123
+ document.documentElement.classList.remove("dark");
124
+ }
125
+ };
126
+ useEffect(() => {
127
+ if (!mounted) return;
128
+ const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
129
+ const handleChange = (e) => {
130
+ if (colorMode === "system") {
131
+ const resolved = e.matches ? "dark" : "light";
132
+ setResolvedColorMode(resolved);
133
+ document.documentElement.setAttribute("data-color-mode", resolved);
134
+ if (resolved === "dark") {
135
+ document.documentElement.classList.add("dark");
136
+ } else {
137
+ document.documentElement.classList.remove("dark");
138
+ }
139
+ }
140
+ };
141
+ mediaQuery.addEventListener("change", handleChange);
142
+ return () => mediaQuery.removeEventListener("change", handleChange);
143
+ }, [mounted, colorMode]);
144
+ return /* @__PURE__ */ jsx(ThemeContext.Provider, { value: {
145
+ theme,
146
+ themeName,
147
+ setTheme,
148
+ colorMode,
149
+ setColorMode,
150
+ resolvedColorMode
151
+ }, children });
152
+ }
153
+
154
+ // src/components/Button.tsx
155
+ import { jsx as jsx2 } from "react/jsx-runtime";
156
+ var Button = ({
157
+ variant = "primary",
158
+ size = "md",
159
+ className = "",
160
+ children,
161
+ disabled,
162
+ ...props
163
+ }) => {
164
+ const { theme } = useTheme();
165
+ const baseStyles = theme.button.base;
166
+ const variantStyles = theme.button.variants[variant];
167
+ const sizeStyles = theme.button.sizes[size];
168
+ const disabledStyles = disabled ? theme.button.disabled : "";
169
+ const classes = `${baseStyles} ${variantStyles} ${sizeStyles} ${disabledStyles} ${className}`.trim();
170
+ return /* @__PURE__ */ jsx2(
171
+ "button",
172
+ {
173
+ className: classes,
174
+ disabled,
175
+ ...props,
176
+ children
177
+ }
178
+ );
179
+ };
180
+
181
+ // src/components/Select.tsx
182
+ import { useState as useState2, useRef, useEffect as useEffect2 } from "react";
183
+ import { jsx as jsx3, jsxs } from "react/jsx-runtime";
184
+ var Select = ({
185
+ options,
186
+ size = "md",
187
+ placeholder,
188
+ className = "",
189
+ disabled,
190
+ value: controlledValue,
191
+ defaultValue,
192
+ onChange,
193
+ ...props
194
+ }) => {
195
+ const { theme, themeName } = useTheme();
196
+ const [isOpen, setIsOpen] = useState2(false);
197
+ const [internalValue, setInternalValue] = useState2(defaultValue || "");
198
+ const dropdownRef = useRef(null);
199
+ const value = controlledValue !== void 0 ? controlledValue : internalValue;
200
+ const selectedOption = options.find((opt) => opt.value === value);
201
+ const displayText = selectedOption ? selectedOption.label : placeholder || "Select...";
202
+ useEffect2(() => {
203
+ const handleClickOutside = (event) => {
204
+ if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
205
+ setIsOpen(false);
206
+ }
207
+ };
208
+ if (isOpen) {
209
+ document.addEventListener("mousedown", handleClickOutside);
210
+ return () => document.removeEventListener("mousedown", handleClickOutside);
211
+ }
212
+ }, [isOpen]);
213
+ const handleSelect = (optionValue) => {
214
+ if (disabled) return;
215
+ setInternalValue(optionValue);
216
+ onChange?.(optionValue);
217
+ setIsOpen(false);
218
+ };
219
+ const handleToggle = () => {
220
+ if (!disabled) {
221
+ setIsOpen(!isOpen);
222
+ }
223
+ };
224
+ const baseStyles = theme.select.base;
225
+ const sizeStyles = theme.select.sizes[size];
226
+ const disabledStyles = disabled ? theme.select.disabled : "";
227
+ const buttonClasses = `${baseStyles} ${sizeStyles} ${disabledStyles} ${className}`.trim();
228
+ const iconColor = themeName === "minimalistic" ? disabled ? "text-gray-600" : "text-white" : disabled ? "text-gray-400" : "text-gray-500";
229
+ const dropdownBaseStyles = themeName === "minimalistic" ? "bg-black border-2 border-white" : "bg-white border border-gray-300 shadow-lg dark:bg-gray-800 dark:border-gray-600";
230
+ const optionBaseStyles = themeName === "minimalistic" ? "text-white hover:bg-white hover:text-black transition-colors duration-200" : "text-gray-900 hover:bg-blue-50 transition-colors duration-150 dark:text-gray-100 dark:hover:bg-gray-700";
231
+ const optionSizeStyles = {
232
+ sm: "px-4 py-2 text-sm",
233
+ md: "px-4 py-2.5 text-base",
234
+ lg: "px-4 py-3 text-lg",
235
+ xl: "px-5 py-4 text-xl"
236
+ }[size];
237
+ return /* @__PURE__ */ jsxs("div", { className: "relative inline-block w-full", ref: dropdownRef, ...props, children: [
238
+ /* @__PURE__ */ jsx3(
239
+ "button",
240
+ {
241
+ type: "button",
242
+ className: buttonClasses,
243
+ onClick: handleToggle,
244
+ disabled,
245
+ children: /* @__PURE__ */ jsx3("span", { className: !selectedOption && placeholder ? "opacity-50" : "", children: displayText })
246
+ }
247
+ ),
248
+ /* @__PURE__ */ jsx3("div", { className: "pointer-events-none absolute inset-y-0 right-0 flex items-center pr-4", children: /* @__PURE__ */ jsx3(
249
+ "svg",
250
+ {
251
+ className: `h-5 w-5 transition-transform duration-200 ${iconColor} ${isOpen ? "rotate-180" : ""}`,
252
+ xmlns: "http://www.w3.org/2000/svg",
253
+ viewBox: "0 0 20 20",
254
+ fill: "currentColor",
255
+ "aria-hidden": "true",
256
+ children: /* @__PURE__ */ jsx3(
257
+ "path",
258
+ {
259
+ fillRule: "evenodd",
260
+ d: "M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z",
261
+ clipRule: "evenodd"
262
+ }
263
+ )
264
+ }
265
+ ) }),
266
+ isOpen && !disabled && /* @__PURE__ */ jsx3(
267
+ "div",
268
+ {
269
+ className: `absolute z-50 w-full mt-1 ${dropdownBaseStyles} rounded-lg overflow-hidden`,
270
+ style: { maxHeight: "300px", overflowY: "auto" },
271
+ children: options.map((option) => /* @__PURE__ */ jsx3(
272
+ "div",
273
+ {
274
+ className: `${optionBaseStyles} ${optionSizeStyles} cursor-pointer ${value === option.value ? themeName === "minimalistic" ? "bg-white text-black" : "bg-blue-100 dark:bg-blue-900" : ""}`,
275
+ onClick: () => handleSelect(option.value),
276
+ children: option.label
277
+ },
278
+ option.value
279
+ ))
280
+ }
281
+ )
282
+ ] });
283
+ };
284
+
285
+ // src/utils/theme-script.ts
286
+ var themeScript = `
287
+ (function() {
288
+ try {
289
+ // Get stored preferences
290
+ const storedTheme = localStorage.getItem('lite-ui-theme') || 'default';
291
+ const storedColorMode = localStorage.getItem('lite-ui-color-mode');
292
+
293
+ // Determine color mode (system, light, or dark)
294
+ let colorMode = storedColorMode;
295
+ if (!colorMode || colorMode === 'system') {
296
+ colorMode = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
297
+ }
298
+
299
+ // Set attributes before render
300
+ document.documentElement.setAttribute('data-theme', storedTheme);
301
+ document.documentElement.setAttribute('data-color-mode', colorMode);
302
+
303
+ // Add dark class for Tailwind
304
+ if (colorMode === 'dark') {
305
+ document.documentElement.classList.add('dark');
306
+ } else {
307
+ document.documentElement.classList.remove('dark');
308
+ }
309
+ } catch (e) {
310
+ console.error('Failed to initialize theme:', e);
311
+ }
312
+ })();
313
+ `;
314
+ function getThemeScript() {
315
+ return themeScript;
316
+ }
317
+ export {
318
+ Button,
319
+ Select,
320
+ ThemeProvider,
321
+ getThemeScript,
322
+ themeScript,
323
+ themes,
324
+ useTheme
325
+ };
326
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/theme/ThemeProvider.tsx","../src/theme/themes.ts","../src/components/Button.tsx","../src/components/Select.tsx","../src/utils/theme-script.ts"],"sourcesContent":["\"use client\";\n\nimport React, { createContext, useContext, useState, useEffect } from 'react';\nimport { themes, ThemeName, Theme } from './themes';\n\nexport type ColorMode = 'light' | 'dark' | 'system';\n\ninterface ThemeContextValue {\n theme: Theme;\n themeName: ThemeName;\n setTheme: (themeName: ThemeName) => void;\n colorMode: ColorMode;\n setColorMode: (mode: ColorMode) => void;\n resolvedColorMode: 'light' | 'dark';\n}\n\nconst ThemeContext = createContext<ThemeContextValue | undefined>(undefined);\n\nexport function useTheme() {\n const context = useContext(ThemeContext);\n if (!context) {\n throw new Error('useTheme must be used within a ThemeProvider');\n }\n return context;\n}\n\ninterface ThemeProviderProps {\n children: React.ReactNode;\n defaultTheme?: ThemeName;\n defaultColorMode?: ColorMode;\n}\n\nexport function ThemeProvider({\n children,\n defaultTheme = 'default',\n defaultColorMode = 'system'\n}: ThemeProviderProps) {\n const [mounted, setMounted] = useState(false);\n\n // Initialize from defaults (will sync with actual values after mount)\n const [themeName, setThemeNameState] = useState<ThemeName>(defaultTheme);\n const [colorMode, setColorModeState] = useState<ColorMode>(defaultColorMode);\n const [resolvedColorMode, setResolvedColorMode] = useState<'light' | 'dark'>('light');\n\n // Sync with actual values after mount to avoid hydration mismatch\n useEffect(() => {\n setMounted(true);\n\n // Read actual values from localStorage and DOM\n const storedTheme = localStorage.getItem('lite-ui-theme') as ThemeName;\n const storedColorMode = localStorage.getItem('lite-ui-color-mode') as ColorMode;\n const currentColorMode = document.documentElement.getAttribute('data-color-mode') as 'light' | 'dark';\n\n if (storedTheme) setThemeNameState(storedTheme);\n if (storedColorMode) setColorModeState(storedColorMode);\n if (currentColorMode) setResolvedColorMode(currentColorMode);\n }, []);\n\n const theme = themes[themeName];\n\n // Update theme\n const setTheme = (newThemeName: ThemeName) => {\n setThemeNameState(newThemeName);\n if (typeof window !== 'undefined') {\n localStorage.setItem('lite-ui-theme', newThemeName);\n document.documentElement.setAttribute('data-theme', newThemeName);\n }\n };\n\n // Update color mode\n const setColorMode = (mode: ColorMode) => {\n if (typeof window === 'undefined') return;\n\n setColorModeState(mode);\n localStorage.setItem('lite-ui-color-mode', mode);\n\n let resolved: 'light' | 'dark';\n if (mode === 'system') {\n resolved = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';\n } else {\n resolved = mode;\n }\n\n setResolvedColorMode(resolved);\n document.documentElement.setAttribute('data-color-mode', resolved);\n\n if (resolved === 'dark') {\n document.documentElement.classList.add('dark');\n } else {\n document.documentElement.classList.remove('dark');\n }\n };\n\n // Listen for system theme changes\n useEffect(() => {\n if (!mounted) return;\n\n const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');\n\n const handleChange = (e: MediaQueryListEvent) => {\n if (colorMode === 'system') {\n const resolved = e.matches ? 'dark' : 'light';\n setResolvedColorMode(resolved);\n document.documentElement.setAttribute('data-color-mode', resolved);\n\n if (resolved === 'dark') {\n document.documentElement.classList.add('dark');\n } else {\n document.documentElement.classList.remove('dark');\n }\n }\n };\n\n mediaQuery.addEventListener('change', handleChange);\n return () => mediaQuery.removeEventListener('change', handleChange);\n }, [mounted, colorMode]);\n\n return (\n <ThemeContext.Provider value={{\n theme,\n themeName,\n setTheme,\n colorMode,\n setColorMode,\n resolvedColorMode\n }}>\n {children}\n </ThemeContext.Provider>\n );\n}\n","export type ThemeName = 'default' | 'minimalistic';\n\nexport interface ButtonTheme {\n primary: string;\n secondary: string;\n success: string;\n danger: string;\n warning: string;\n info: string;\n}\n\nexport interface SelectTheme {\n base: string;\n sizes: {\n sm: string;\n md: string;\n lg: string;\n xl: string;\n };\n disabled: string;\n}\n\nexport interface Theme {\n name: ThemeName;\n button: {\n base: string;\n variants: ButtonTheme;\n sizes: {\n sm: string;\n md: string;\n lg: string;\n xl: string;\n };\n disabled: string;\n };\n select: SelectTheme;\n}\n\nexport const themes: Record<ThemeName, Theme> = {\n default: {\n name: 'default',\n button: {\n base: 'font-semibold rounded-lg transition-all duration-150 focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 active:scale-95',\n variants: {\n primary: 'bg-blue-600 hover:bg-blue-700 active:bg-blue-800 text-white shadow-sm hover:shadow-md dark:bg-blue-500 dark:hover:bg-blue-600 dark:active:bg-blue-700',\n secondary: 'bg-gray-600 hover:bg-gray-700 active:bg-gray-800 text-white shadow-sm hover:shadow-md dark:bg-gray-500 dark:hover:bg-gray-600 dark:active:bg-gray-700',\n success: 'bg-green-600 hover:bg-green-700 active:bg-green-800 text-white shadow-sm hover:shadow-md dark:bg-green-500 dark:hover:bg-green-600 dark:active:bg-green-700',\n danger: 'bg-red-600 hover:bg-red-700 active:bg-red-800 text-white shadow-sm hover:shadow-md dark:bg-red-500 dark:hover:bg-red-600 dark:active:bg-red-700',\n warning: 'bg-yellow-500 hover:bg-yellow-600 active:bg-yellow-700 text-white shadow-sm hover:shadow-md dark:bg-yellow-400 dark:hover:bg-yellow-500 dark:active:bg-yellow-600',\n info: 'bg-cyan-600 hover:bg-cyan-700 active:bg-cyan-800 text-white shadow-sm hover:shadow-md dark:bg-cyan-500 dark:hover:bg-cyan-600 dark:active:bg-cyan-700',\n },\n sizes: {\n sm: 'px-3 py-1.5 text-sm',\n md: 'px-4 py-2 text-base',\n lg: 'px-6 py-3 text-lg',\n xl: 'px-8 py-4 text-xl',\n },\n disabled: 'opacity-50 cursor-not-allowed hover:shadow-sm active:scale-100',\n },\n select: {\n base: 'w-full appearance-none rounded-lg border border-gray-300 bg-white text-gray-900 transition-all duration-150 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent shadow-sm hover:border-gray-400 pr-10 cursor-pointer dark:bg-gray-800 dark:border-gray-600 dark:text-gray-100 dark:hover:border-gray-500',\n sizes: {\n sm: 'px-3 py-1.5 text-sm',\n md: 'px-4 py-2.5 text-base',\n lg: 'px-4 py-3 text-lg',\n xl: 'px-5 py-4 text-xl',\n },\n disabled: 'opacity-50 cursor-not-allowed bg-gray-50 dark:bg-gray-900',\n },\n },\n minimalistic: {\n name: 'minimalistic',\n button: {\n base: 'font-normal rounded-none transition-colors duration-200 focus:outline-none border-2',\n variants: {\n primary: 'bg-transparent border-white text-white hover:bg-white hover:text-black',\n secondary: 'bg-transparent border-gray-400 text-gray-400 hover:bg-gray-400 hover:text-black',\n success: 'bg-transparent border-green-400 text-green-400 hover:bg-green-400 hover:text-black',\n danger: 'bg-transparent border-red-400 text-red-400 hover:bg-red-400 hover:text-black',\n warning: 'bg-transparent border-yellow-400 text-yellow-400 hover:bg-yellow-400 hover:text-black',\n info: 'bg-transparent border-blue-400 text-blue-400 hover:bg-blue-400 hover:text-black',\n },\n sizes: {\n sm: 'px-4 py-2 text-sm uppercase tracking-wide',\n md: 'px-6 py-3 text-base uppercase tracking-wide',\n lg: 'px-8 py-4 text-lg uppercase tracking-wider',\n xl: 'px-10 py-5 text-xl uppercase tracking-wider',\n },\n disabled: 'opacity-30 cursor-not-allowed hover:bg-transparent',\n },\n select: {\n base: 'w-full appearance-none rounded-none border-2 border-white bg-transparent text-white transition-colors duration-200 focus:outline-none pr-10 cursor-pointer placeholder:text-gray-500',\n sizes: {\n sm: 'px-4 py-2 text-sm uppercase tracking-wide',\n md: 'px-4 py-3 text-base uppercase tracking-wide',\n lg: 'px-4 py-4 text-lg uppercase tracking-wider',\n xl: 'px-5 py-5 text-xl uppercase tracking-wider',\n },\n disabled: 'opacity-30 cursor-not-allowed',\n },\n },\n};\n","\"use client\";\n\nimport React from 'react';\nimport { useTheme } from '../theme/ThemeProvider';\n\nexport interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n variant?: 'primary' | 'secondary' | 'success' | 'danger' | 'warning' | 'info';\n size?: 'sm' | 'md' | 'lg' | 'xl';\n children: React.ReactNode;\n}\n\nexport const Button: React.FC<ButtonProps> = ({\n variant = 'primary',\n size = 'md',\n className = '',\n children,\n disabled,\n ...props\n}) => {\n const { theme } = useTheme();\n\n const baseStyles = theme.button.base;\n const variantStyles = theme.button.variants[variant];\n const sizeStyles = theme.button.sizes[size];\n const disabledStyles = disabled ? theme.button.disabled : '';\n\n const classes = `${baseStyles} ${variantStyles} ${sizeStyles} ${disabledStyles} ${className}`.trim();\n\n return (\n <button\n className={classes}\n disabled={disabled}\n {...props}\n >\n {children}\n </button>\n );\n};\n","\"use client\";\n\nimport React, { useState, useRef, useEffect } from 'react';\nimport { useTheme } from '../theme/ThemeProvider';\n\nexport interface SelectOption {\n value: string;\n label: string;\n}\n\nexport interface SelectProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'size' | 'onChange' | 'defaultValue'> {\n options: SelectOption[];\n size?: 'sm' | 'md' | 'lg' | 'xl';\n placeholder?: string;\n disabled?: boolean;\n value?: string;\n defaultValue?: string;\n onChange?: (value: string) => void;\n}\n\nexport const Select: React.FC<SelectProps> = ({\n options,\n size = 'md',\n placeholder,\n className = '',\n disabled,\n value: controlledValue,\n defaultValue,\n onChange,\n ...props\n}) => {\n const { theme, themeName } = useTheme();\n const [isOpen, setIsOpen] = useState(false);\n const [internalValue, setInternalValue] = useState(defaultValue || '');\n const dropdownRef = useRef<HTMLDivElement>(null);\n\n // Use controlled value if provided, otherwise use internal state\n const value = controlledValue !== undefined ? controlledValue : internalValue;\n\n // Find the selected option\n const selectedOption = options.find(opt => opt.value === value);\n const displayText = selectedOption ? selectedOption.label : placeholder || 'Select...';\n\n // Close dropdown when clicking outside\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {\n setIsOpen(false);\n }\n };\n\n if (isOpen) {\n document.addEventListener('mousedown', handleClickOutside);\n return () => document.removeEventListener('mousedown', handleClickOutside);\n }\n }, [isOpen]);\n\n const handleSelect = (optionValue: string) => {\n if (disabled) return;\n\n setInternalValue(optionValue);\n onChange?.(optionValue);\n setIsOpen(false);\n };\n\n const handleToggle = () => {\n if (!disabled) {\n setIsOpen(!isOpen);\n }\n };\n\n const baseStyles = theme.select.base;\n const sizeStyles = theme.select.sizes[size];\n const disabledStyles = disabled ? theme.select.disabled : '';\n\n const buttonClasses = `${baseStyles} ${sizeStyles} ${disabledStyles} ${className}`.trim();\n\n // Icon color based on theme\n const iconColor = themeName === 'minimalistic'\n ? (disabled ? 'text-gray-600' : 'text-white')\n : (disabled ? 'text-gray-400' : 'text-gray-500');\n\n // Dropdown menu styles based on theme\n const dropdownBaseStyles = themeName === 'minimalistic'\n ? 'bg-black border-2 border-white'\n : 'bg-white border border-gray-300 shadow-lg dark:bg-gray-800 dark:border-gray-600';\n\n const optionBaseStyles = themeName === 'minimalistic'\n ? 'text-white hover:bg-white hover:text-black transition-colors duration-200'\n : 'text-gray-900 hover:bg-blue-50 transition-colors duration-150 dark:text-gray-100 dark:hover:bg-gray-700';\n\n const optionSizeStyles = {\n sm: 'px-4 py-2 text-sm',\n md: 'px-4 py-2.5 text-base',\n lg: 'px-4 py-3 text-lg',\n xl: 'px-5 py-4 text-xl',\n }[size];\n\n return (\n <div className=\"relative inline-block w-full\" ref={dropdownRef} {...props}>\n {/* Custom button that looks like select */}\n <button\n type=\"button\"\n className={buttonClasses}\n onClick={handleToggle}\n disabled={disabled}\n >\n <span className={!selectedOption && placeholder ? 'opacity-50' : ''}>\n {displayText}\n </span>\n </button>\n\n {/* Chevron icon */}\n <div className=\"pointer-events-none absolute inset-y-0 right-0 flex items-center pr-4\">\n <svg\n className={`h-5 w-5 transition-transform duration-200 ${iconColor} ${isOpen ? 'rotate-180' : ''}`}\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n fillRule=\"evenodd\"\n d=\"M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z\"\n clipRule=\"evenodd\"\n />\n </svg>\n </div>\n\n {/* Custom dropdown menu */}\n {isOpen && !disabled && (\n <div\n className={`absolute z-50 w-full mt-1 ${dropdownBaseStyles} rounded-lg overflow-hidden`}\n style={{ maxHeight: '300px', overflowY: 'auto' }}\n >\n {options.map((option) => (\n <div\n key={option.value}\n className={`${optionBaseStyles} ${optionSizeStyles} cursor-pointer ${\n value === option.value ? (themeName === 'minimalistic' ? 'bg-white text-black' : 'bg-blue-100 dark:bg-blue-900') : ''\n }`}\n onClick={() => handleSelect(option.value)}\n >\n {option.label}\n </div>\n ))}\n </div>\n )}\n </div>\n );\n};\n","/**\n * Theme initialization script that runs before React hydration\n * This prevents flickering by setting the theme before the page renders\n * Must be inlined in the HTML <head> as a blocking script\n */\n\nexport const themeScript = `\n(function() {\n try {\n // Get stored preferences\n const storedTheme = localStorage.getItem('lite-ui-theme') || 'default';\n const storedColorMode = localStorage.getItem('lite-ui-color-mode');\n\n // Determine color mode (system, light, or dark)\n let colorMode = storedColorMode;\n if (!colorMode || colorMode === 'system') {\n colorMode = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';\n }\n\n // Set attributes before render\n document.documentElement.setAttribute('data-theme', storedTheme);\n document.documentElement.setAttribute('data-color-mode', colorMode);\n\n // Add dark class for Tailwind\n if (colorMode === 'dark') {\n document.documentElement.classList.add('dark');\n } else {\n document.documentElement.classList.remove('dark');\n }\n } catch (e) {\n console.error('Failed to initialize theme:', e);\n }\n})();\n`;\n\nexport function getThemeScript() {\n return themeScript;\n}\n"],"mappings":"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","names":["jsx","useState","useEffect","jsx","useState","useEffect"]}
package/package.json ADDED
@@ -0,0 +1,66 @@
1
+ {
2
+ "name": "@marcoschwartz/lite-ui",
3
+ "version": "0.1.0",
4
+ "description": "A lightweight UI component library built with Tailwind CSS",
5
+ "author": "Marco Schwartz",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/marcoschwartz/lite-ui.git"
10
+ },
11
+ "homepage": "https://github.com/marcoschwartz/lite-ui#readme",
12
+ "bugs": {
13
+ "url": "https://github.com/marcoschwartz/lite-ui/issues"
14
+ },
15
+ "main": "./dist/index.js",
16
+ "module": "./dist/index.mjs",
17
+ "types": "./dist/index.d.ts",
18
+ "exports": {
19
+ ".": {
20
+ "types": "./dist/index.d.ts",
21
+ "import": "./dist/index.mjs",
22
+ "require": "./dist/index.js"
23
+ },
24
+ "./styles.css": "./dist/styles.css"
25
+ },
26
+ "files": [
27
+ "dist",
28
+ "README.md",
29
+ "LICENSE"
30
+ ],
31
+ "scripts": {
32
+ "build": "tsup",
33
+ "dev": "npm run build -- --watch",
34
+ "dev:all": "./dev.sh",
35
+ "clean": "rm -rf dist",
36
+ "prepublishOnly": "npm run clean && npm run build"
37
+ },
38
+ "peerDependencies": {
39
+ "react": ">=18",
40
+ "react-dom": ">=18"
41
+ },
42
+ "devDependencies": {
43
+ "@types/react": "^19",
44
+ "@types/react-dom": "^19",
45
+ "react": "^19",
46
+ "react-dom": "^19",
47
+ "tailwindcss": "^4",
48
+ "tsup": "^8.0.0",
49
+ "typescript": "^5"
50
+ },
51
+ "keywords": [
52
+ "react",
53
+ "ui",
54
+ "components",
55
+ "tailwind",
56
+ "tailwindcss",
57
+ "react-components",
58
+ "ui-library",
59
+ "design-system",
60
+ "dark-mode",
61
+ "theming"
62
+ ],
63
+ "publishConfig": {
64
+ "access": "public"
65
+ }
66
+ }