@marcoschwartz/lite-ui 0.24.11 → 0.24.13
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 +84 -12
- package/dist/index.d.mts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +2 -71
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2 -71
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -19,23 +19,21 @@ A lightweight, modern UI component library built with React, TypeScript, and Tai
|
|
|
19
19
|
npm install @marcoschwartz/lite-ui
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
-
### Setup
|
|
22
|
+
### Setup for Next.js (Required)
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
> ⚠️ **Important:** You must include `ColorSchemeScript` in your layout to prevent dark mode flashing (FOUC).
|
|
25
25
|
|
|
26
26
|
```tsx
|
|
27
|
-
// app/layout.tsx
|
|
27
|
+
// app/layout.tsx
|
|
28
|
+
import { ThemeProvider, ColorSchemeScript } from '@marcoschwartz/lite-ui';
|
|
28
29
|
import '@marcoschwartz/lite-ui/styles.css';
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
2. **Wrap your app with ThemeProvider** (recommended):
|
|
32
|
-
|
|
33
|
-
```tsx
|
|
34
|
-
import { ThemeProvider } from '@marcoschwartz/lite-ui';
|
|
35
30
|
|
|
36
31
|
export default function RootLayout({ children }) {
|
|
37
32
|
return (
|
|
38
|
-
<html lang="en">
|
|
33
|
+
<html lang="en" suppressHydrationWarning>
|
|
34
|
+
<head>
|
|
35
|
+
<ColorSchemeScript defaultColorMode="system" />
|
|
36
|
+
</head>
|
|
39
37
|
<body>
|
|
40
38
|
<ThemeProvider defaultTheme="default" defaultColorMode="system">
|
|
41
39
|
{children}
|
|
@@ -46,7 +44,36 @@ export default function RootLayout({ children }) {
|
|
|
46
44
|
}
|
|
47
45
|
```
|
|
48
46
|
|
|
49
|
-
|
|
47
|
+
**Key points:**
|
|
48
|
+
- `ColorSchemeScript` must be in `<head>` - it prevents flash by setting colors before React hydrates
|
|
49
|
+
- `suppressHydrationWarning` on `<html>` is required to avoid React warnings
|
|
50
|
+
- `defaultColorMode` should match between `ColorSchemeScript` and `ThemeProvider`
|
|
51
|
+
|
|
52
|
+
### Setup for Vite/Other React Apps
|
|
53
|
+
|
|
54
|
+
```tsx
|
|
55
|
+
// main.tsx
|
|
56
|
+
import '@marcoschwartz/lite-ui/styles.css';
|
|
57
|
+
import { ThemeProvider } from '@marcoschwartz/lite-ui';
|
|
58
|
+
|
|
59
|
+
ReactDOM.createRoot(document.getElementById('root')!).render(
|
|
60
|
+
<ThemeProvider defaultTheme="default" defaultColorMode="system">
|
|
61
|
+
<App />
|
|
62
|
+
</ThemeProvider>
|
|
63
|
+
);
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
For Vite apps, add the theme script to your `index.html`:
|
|
67
|
+
|
|
68
|
+
```html
|
|
69
|
+
<head>
|
|
70
|
+
<script>
|
|
71
|
+
(function(){try{var d=document.documentElement,c=localStorage.getItem('lite-ui-color-mode')||'system',r=c;if(c==='system'||!c)r=matchMedia('(prefers-color-scheme:dark)').matches?'dark':'light';d.setAttribute('data-color-mode',r);d.style.colorScheme=r;if(r==='dark'){d.classList.add('dark');d.style.backgroundColor='hsl(0,0%,3.9%)';d.style.color='hsl(0,0%,98%)'}else{d.classList.remove('dark');d.style.backgroundColor='hsl(0,0%,100%)';d.style.color='hsl(0,0%,3.9%)'}}catch(e){}})();
|
|
72
|
+
</script>
|
|
73
|
+
</head>
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Start using components:
|
|
50
77
|
|
|
51
78
|
```tsx
|
|
52
79
|
import { Button, Card, TextInput } from '@marcoschwartz/lite-ui';
|
|
@@ -99,7 +126,29 @@ export default function Page() {
|
|
|
99
126
|
|
|
100
127
|
## 🌙 Dark Mode
|
|
101
128
|
|
|
102
|
-
Lite UI includes built-in dark mode support with three color modes
|
|
129
|
+
Lite UI includes built-in dark mode support with three color modes.
|
|
130
|
+
|
|
131
|
+
### Preventing Flash (FOUC)
|
|
132
|
+
|
|
133
|
+
To prevent the flash of wrong colors on page load, you **must** use `ColorSchemeScript`:
|
|
134
|
+
|
|
135
|
+
```tsx
|
|
136
|
+
// app/layout.tsx
|
|
137
|
+
import { ColorSchemeScript, ThemeProvider } from '@marcoschwartz/lite-ui';
|
|
138
|
+
|
|
139
|
+
<html lang="en" suppressHydrationWarning>
|
|
140
|
+
<head>
|
|
141
|
+
<ColorSchemeScript defaultColorMode="system" />
|
|
142
|
+
</head>
|
|
143
|
+
<body>
|
|
144
|
+
<ThemeProvider defaultColorMode="system">
|
|
145
|
+
{children}
|
|
146
|
+
</ThemeProvider>
|
|
147
|
+
</body>
|
|
148
|
+
</html>
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Toggling Dark Mode
|
|
103
152
|
|
|
104
153
|
```tsx
|
|
105
154
|
import { useTheme } from '@marcoschwartz/lite-ui';
|
|
@@ -117,6 +166,29 @@ function ThemeToggle() {
|
|
|
117
166
|
}
|
|
118
167
|
```
|
|
119
168
|
|
|
169
|
+
## ⬆️ Upgrading from v0.24.7 or earlier
|
|
170
|
+
|
|
171
|
+
If you're upgrading from an earlier version, update your `layout.tsx`:
|
|
172
|
+
|
|
173
|
+
```diff
|
|
174
|
+
- import { ThemeProvider, themeScript } from '@marcoschwartz/lite-ui';
|
|
175
|
+
+ import { ThemeProvider, ColorSchemeScript } from '@marcoschwartz/lite-ui';
|
|
176
|
+
|
|
177
|
+
<html lang="en" suppressHydrationWarning>
|
|
178
|
+
<head>
|
|
179
|
+
- <script
|
|
180
|
+
- dangerouslySetInnerHTML={{ __html: themeScript }}
|
|
181
|
+
- suppressHydrationWarning
|
|
182
|
+
- />
|
|
183
|
+
+ <ColorSchemeScript defaultColorMode="system" />
|
|
184
|
+
</head>
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
The new `ColorSchemeScript` component:
|
|
188
|
+
- Sets CSS custom properties inline (prevents flash even if CSS loads slowly)
|
|
189
|
+
- Cleaner API than the old `themeScript` string
|
|
190
|
+
- Supports `nonce` prop for Content Security Policy
|
|
191
|
+
|
|
120
192
|
## 🎭 Theming
|
|
121
193
|
|
|
122
194
|
Switch between built-in themes or create your own:
|
package/dist/index.d.mts
CHANGED
|
@@ -1347,8 +1347,10 @@ declare function getColorSchemeScriptString(defaultColorMode?: 'light' | 'dark'
|
|
|
1347
1347
|
* Theme initialization script that runs before React hydration
|
|
1348
1348
|
* This prevents flickering by setting the theme before the page renders
|
|
1349
1349
|
* Must be inlined in the HTML <head> as a blocking script
|
|
1350
|
+
*
|
|
1351
|
+
* @deprecated Use ColorSchemeScript component instead for better Next.js integration
|
|
1350
1352
|
*/
|
|
1351
|
-
declare const themeScript = "
|
|
1353
|
+
declare const themeScript = "(function(){try{var d=document.documentElement,s=d.style,t=localStorage.getItem('lite-ui-theme')||'default',c=localStorage.getItem('lite-ui-color-mode'),r=c;if(!c||c==='system')r=matchMedia('(prefers-color-scheme:dark)').matches?'dark':'light';d.setAttribute('data-theme',t);d.setAttribute('data-color-mode',r);s.colorScheme=r;if(r==='dark'){d.classList.add('dark');s.setProperty('--background','0 0% 3.9%');s.setProperty('--foreground','0 0% 98%');s.setProperty('--card','0 0% 5.9%');s.setProperty('--card-foreground','0 0% 98%');s.setProperty('--popover','0 0% 5.9%');s.setProperty('--popover-foreground','0 0% 98%');s.setProperty('--muted','0 0% 14.9%');s.setProperty('--muted-foreground','0 0% 63.9%');s.setProperty('--border','0 0% 25%');s.setProperty('--input','0 0% 25%');s.setProperty('--primary','217 91% 60%');s.setProperty('--secondary','0 0% 14.9%');s.setProperty('--accent','0 0% 14.9%');s.backgroundColor='hsl(0,0%,3.9%)';s.color='hsl(0,0%,98%)'}else{d.classList.remove('dark');s.backgroundColor='hsl(0,0%,100%)';s.color='hsl(0,0%,3.9%)'}d.setAttribute('data-theme-initialized','true')}catch(e){document.documentElement.setAttribute('data-theme-initialized','true')}})()";
|
|
1352
1354
|
declare function getThemeScript(): string;
|
|
1353
1355
|
|
|
1354
1356
|
interface IconProps {
|
package/dist/index.d.ts
CHANGED
|
@@ -1347,8 +1347,10 @@ declare function getColorSchemeScriptString(defaultColorMode?: 'light' | 'dark'
|
|
|
1347
1347
|
* Theme initialization script that runs before React hydration
|
|
1348
1348
|
* This prevents flickering by setting the theme before the page renders
|
|
1349
1349
|
* Must be inlined in the HTML <head> as a blocking script
|
|
1350
|
+
*
|
|
1351
|
+
* @deprecated Use ColorSchemeScript component instead for better Next.js integration
|
|
1350
1352
|
*/
|
|
1351
|
-
declare const themeScript = "
|
|
1353
|
+
declare const themeScript = "(function(){try{var d=document.documentElement,s=d.style,t=localStorage.getItem('lite-ui-theme')||'default',c=localStorage.getItem('lite-ui-color-mode'),r=c;if(!c||c==='system')r=matchMedia('(prefers-color-scheme:dark)').matches?'dark':'light';d.setAttribute('data-theme',t);d.setAttribute('data-color-mode',r);s.colorScheme=r;if(r==='dark'){d.classList.add('dark');s.setProperty('--background','0 0% 3.9%');s.setProperty('--foreground','0 0% 98%');s.setProperty('--card','0 0% 5.9%');s.setProperty('--card-foreground','0 0% 98%');s.setProperty('--popover','0 0% 5.9%');s.setProperty('--popover-foreground','0 0% 98%');s.setProperty('--muted','0 0% 14.9%');s.setProperty('--muted-foreground','0 0% 63.9%');s.setProperty('--border','0 0% 25%');s.setProperty('--input','0 0% 25%');s.setProperty('--primary','217 91% 60%');s.setProperty('--secondary','0 0% 14.9%');s.setProperty('--accent','0 0% 14.9%');s.backgroundColor='hsl(0,0%,3.9%)';s.color='hsl(0,0%,98%)'}else{d.classList.remove('dark');s.backgroundColor='hsl(0,0%,100%)';s.color='hsl(0,0%,3.9%)'}d.setAttribute('data-theme-initialized','true')}catch(e){document.documentElement.setAttribute('data-theme-initialized','true')}})()";
|
|
1352
1354
|
declare function getThemeScript(): string;
|
|
1353
1355
|
|
|
1354
1356
|
interface IconProps {
|
package/dist/index.js
CHANGED
|
@@ -9109,36 +9109,7 @@ var CalendarHeatmap = ({
|
|
|
9109
9109
|
// src/theme/ColorSchemeScript.tsx
|
|
9110
9110
|
var import_jsx_runtime121 = require("react/jsx-runtime");
|
|
9111
9111
|
function getColorSchemeScript(defaultColorMode, localStorageKey) {
|
|
9112
|
-
return `
|
|
9113
|
-
(function(){
|
|
9114
|
-
try {
|
|
9115
|
-
var d = document.documentElement;
|
|
9116
|
-
var stored = localStorage.getItem('${localStorageKey}');
|
|
9117
|
-
var mode = stored || '${defaultColorMode}';
|
|
9118
|
-
var resolved = mode;
|
|
9119
|
-
|
|
9120
|
-
if (mode === 'system' || !mode) {
|
|
9121
|
-
resolved = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
|
9122
|
-
}
|
|
9123
|
-
|
|
9124
|
-
d.setAttribute('data-color-mode', resolved);
|
|
9125
|
-
d.style.colorScheme = resolved;
|
|
9126
|
-
|
|
9127
|
-
if (resolved === 'dark') {
|
|
9128
|
-
d.classList.add('dark');
|
|
9129
|
-
d.style.backgroundColor = 'hsl(0,0%,3.9%)';
|
|
9130
|
-
d.style.color = 'hsl(0,0%,98%)';
|
|
9131
|
-
} else {
|
|
9132
|
-
d.classList.remove('dark');
|
|
9133
|
-
d.style.backgroundColor = 'hsl(0,0%,100%)';
|
|
9134
|
-
d.style.color = 'hsl(0,0%,3.9%)';
|
|
9135
|
-
}
|
|
9136
|
-
|
|
9137
|
-
// Mark as initialized to prevent FOUC
|
|
9138
|
-
d.setAttribute('data-theme-initialized', 'true');
|
|
9139
|
-
} catch(e) {}
|
|
9140
|
-
})();
|
|
9141
|
-
`.trim();
|
|
9112
|
+
return `(function(){try{var d=document.documentElement,s=d.style,c=localStorage.getItem('${localStorageKey}')||'${defaultColorMode}',r=c;if(c==='system'||!c)r=matchMedia('(prefers-color-scheme:dark)').matches?'dark':'light';d.setAttribute('data-color-mode',r);s.colorScheme=r;if(r==='dark'){d.classList.add('dark');s.setProperty('--background','0 0% 3.9%');s.setProperty('--foreground','0 0% 98%');s.setProperty('--card','0 0% 5.9%');s.setProperty('--card-foreground','0 0% 98%');s.setProperty('--popover','0 0% 5.9%');s.setProperty('--popover-foreground','0 0% 98%');s.setProperty('--muted','0 0% 14.9%');s.setProperty('--muted-foreground','0 0% 63.9%');s.setProperty('--border','0 0% 25%');s.setProperty('--input','0 0% 25%');s.setProperty('--primary','217 91% 60%');s.setProperty('--secondary','0 0% 14.9%');s.setProperty('--accent','0 0% 14.9%');s.backgroundColor='hsl(0,0%,3.9%)';s.color='hsl(0,0%,98%)'}else{d.classList.remove('dark');s.backgroundColor='hsl(0,0%,100%)';s.color='hsl(0,0%,3.9%)'}d.setAttribute('data-theme-initialized','true')}catch(e){}})()`;
|
|
9142
9113
|
}
|
|
9143
9114
|
function ColorSchemeScript({
|
|
9144
9115
|
defaultColorMode = "system",
|
|
@@ -9160,47 +9131,7 @@ function getColorSchemeScriptString(defaultColorMode = "system", localStorageKey
|
|
|
9160
9131
|
}
|
|
9161
9132
|
|
|
9162
9133
|
// src/utils/theme-script.ts
|
|
9163
|
-
var themeScript = `
|
|
9164
|
-
(function() {
|
|
9165
|
-
try {
|
|
9166
|
-
// Get stored preferences
|
|
9167
|
-
var storedTheme = localStorage.getItem('lite-ui-theme') || 'default';
|
|
9168
|
-
var storedColorMode = localStorage.getItem('lite-ui-color-mode');
|
|
9169
|
-
|
|
9170
|
-
// Determine color mode (system, light, or dark)
|
|
9171
|
-
var colorMode = storedColorMode;
|
|
9172
|
-
if (!colorMode || colorMode === 'system') {
|
|
9173
|
-
colorMode = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
|
9174
|
-
}
|
|
9175
|
-
|
|
9176
|
-
// Set attributes before render
|
|
9177
|
-
var html = document.documentElement;
|
|
9178
|
-
html.setAttribute('data-theme', storedTheme);
|
|
9179
|
-
html.setAttribute('data-color-mode', colorMode);
|
|
9180
|
-
|
|
9181
|
-
// Set color-scheme for browser UI elements (scrollbars, form controls)
|
|
9182
|
-
html.style.colorScheme = colorMode;
|
|
9183
|
-
|
|
9184
|
-
// Add dark class for Tailwind
|
|
9185
|
-
if (colorMode === 'dark') {
|
|
9186
|
-
html.classList.add('dark');
|
|
9187
|
-
// Set critical inline styles as fallback before CSS loads
|
|
9188
|
-
html.style.backgroundColor = 'hsl(0 0% 3.9%)';
|
|
9189
|
-
html.style.color = 'hsl(0 0% 98%)';
|
|
9190
|
-
} else {
|
|
9191
|
-
html.classList.remove('dark');
|
|
9192
|
-
html.style.backgroundColor = 'hsl(0 0% 100%)';
|
|
9193
|
-
html.style.color = 'hsl(0 0% 3.9%)';
|
|
9194
|
-
}
|
|
9195
|
-
|
|
9196
|
-
// Mark as initialized to prevent FOUC
|
|
9197
|
-
html.setAttribute('data-theme-initialized', 'true');
|
|
9198
|
-
} catch (e) {
|
|
9199
|
-
// Ensure page shows even on error
|
|
9200
|
-
document.documentElement.setAttribute('data-theme-initialized', 'true');
|
|
9201
|
-
}
|
|
9202
|
-
})();
|
|
9203
|
-
`;
|
|
9134
|
+
var themeScript = `(function(){try{var d=document.documentElement,s=d.style,t=localStorage.getItem('lite-ui-theme')||'default',c=localStorage.getItem('lite-ui-color-mode'),r=c;if(!c||c==='system')r=matchMedia('(prefers-color-scheme:dark)').matches?'dark':'light';d.setAttribute('data-theme',t);d.setAttribute('data-color-mode',r);s.colorScheme=r;if(r==='dark'){d.classList.add('dark');s.setProperty('--background','0 0% 3.9%');s.setProperty('--foreground','0 0% 98%');s.setProperty('--card','0 0% 5.9%');s.setProperty('--card-foreground','0 0% 98%');s.setProperty('--popover','0 0% 5.9%');s.setProperty('--popover-foreground','0 0% 98%');s.setProperty('--muted','0 0% 14.9%');s.setProperty('--muted-foreground','0 0% 63.9%');s.setProperty('--border','0 0% 25%');s.setProperty('--input','0 0% 25%');s.setProperty('--primary','217 91% 60%');s.setProperty('--secondary','0 0% 14.9%');s.setProperty('--accent','0 0% 14.9%');s.backgroundColor='hsl(0,0%,3.9%)';s.color='hsl(0,0%,98%)'}else{d.classList.remove('dark');s.backgroundColor='hsl(0,0%,100%)';s.color='hsl(0,0%,3.9%)'}d.setAttribute('data-theme-initialized','true')}catch(e){document.documentElement.setAttribute('data-theme-initialized','true')}})()`;
|
|
9204
9135
|
function getThemeScript() {
|
|
9205
9136
|
return themeScript;
|
|
9206
9137
|
}
|