koori-ui 1.0.5 → 1.0.6

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 CHANGED
@@ -3,7 +3,7 @@
3
3
  </p>
4
4
 
5
5
  <p align="center">
6
- Soft glass UI components built on <a href="https://www.radix-ui.com">Radix UI</a> for React&nbsp;19
6
+ Comprehensive glassmorphism component library built on <a href="https://www.radix-ui.com">Radix UI</a> for React&nbsp;19
7
7
  </p>
8
8
 
9
9
  <p align="center">
@@ -16,228 +16,243 @@
16
16
 
17
17
  ## Features
18
18
 
19
- - 🪟 **Glassmorphism design system** — translucent surfaces, blur, and layered depth
20
- - ♿ **Accessible** — built on Radix UI primitives
21
- - 🌲 **Tree-shakeable** — only import what you use
22
- - **React 19 ready** — RSC-safe, concurrent rendering compatible
23
- - 🎨 **Themeable** — override CSS custom properties to match your brand
24
- - 📦 **Tiny footprint** — ESM + CJS, ~7 KB gzipped
19
+ - 🪟 **27+ components** — General, Layout, Form, Navigation, Data Display, Feedback
20
+ - ♿ **Accessible** — built on Radix UI primitives with keyboard nav and ARIA
21
+ - 🌗 **Dark / Light / System** — `KooriProvider` with localStorage persistence and no FOUC
22
+ - 🎨 **4 color presets** — Slate, Zinc, Neutral, Violet via `data-theme`
23
+ - 🤖 **MCP server** — search component docs from Claude Code
24
+ - **React 19 ready** — RSC-safe (`"use client"` banner auto-injected)
25
+ - 📦 **Dual ESM + CJS** — tree-shakeable, TypeScript declarations included
25
26
 
26
27
  ---
27
28
 
28
- ## Installation
29
+ ## Quick Start
29
30
 
30
31
  ```bash
31
- npm install koori-ui
32
+ npx create-koori-app my-app
33
+ cd my-app && npm run dev
32
34
  ```
33
35
 
34
- > **Peer dependencies:** `react >= 19` and `react-dom >= 19`
36
+ Or install manually:
37
+
38
+ ```bash
39
+ npm install koori-ui
40
+ ```
35
41
 
36
42
  ---
37
43
 
38
- ## Quick Start
44
+ ## Setup
39
45
 
40
- Import the styles **once** in your app's entry point:
46
+ ### 1. Import styles
41
47
 
42
48
  ```tsx
49
+ // app/layout.tsx (or your entry point)
43
50
  import "koori-ui/styles.css";
44
51
  ```
45
52
 
46
- Then use the components:
53
+ ### 2. Wrap with KooriProvider
54
+
55
+ `KooriProvider` handles dark/light mode, color scheme, localStorage persistence, and prevents flash-of-unstyled-content.
47
56
 
48
57
  ```tsx
49
- import { GlassPanel, GlassButton, GlassInput } from "koori-ui";
58
+ import { KooriProvider } from "koori-ui";
50
59
 
51
- export default function App() {
60
+ export default function RootLayout({ children }: { children: React.ReactNode }) {
52
61
  return (
53
- <div style={{ background: "#0B0F19", minHeight: "100vh", padding: 40 }}>
54
- <GlassPanel className="max-w-md mx-auto space-y-4">
55
- <h1 className="text-xl font-bold text-white">Welcome</h1>
56
- <GlassInput placeholder="Enter your email" />
57
- <GlassButton variant="primary">Get Started</GlassButton>
58
- </GlassPanel>
59
- </div>
62
+ <html lang="en" suppressHydrationWarning>
63
+ <body>
64
+ <KooriProvider defaultTheme="dark">
65
+ {children}
66
+ </KooriProvider>
67
+ </body>
68
+ </html>
60
69
  );
61
70
  }
62
71
  ```
63
72
 
64
- ---
65
-
66
- ## Components
67
-
68
- ### GlassPanel
69
-
70
- A container wrapper with glassmorphism styling.
73
+ ### 3. Use the theme hook
71
74
 
72
75
  ```tsx
73
- <GlassPanel variant="elevated">
74
- {/* content */}
75
- </GlassPanel>
76
- ```
76
+ "use client";
77
+ import { useKooriTheme, GlassButton } from "koori-ui";
77
78
 
78
- | Prop | Type | Default | Description |
79
- |------|------|---------|-------------|
80
- | `variant` | `"default" \| "subtle" \| "elevated"` | `"default"` | Glass intensity |
81
- | `className` | `string` | | Additional classes |
82
-
83
- ---
84
-
85
- ### GlassCard
86
-
87
- A card with optional `Header`, `Body`, and `Footer` sub-components.
88
-
89
- ```tsx
90
- import {
91
- GlassCard,
92
- GlassCardHeader,
93
- GlassCardBody,
94
- GlassCardFooter,
95
- } from "koori-ui";
96
-
97
- <GlassCard>
98
- <GlassCardHeader>Title</GlassCardHeader>
99
- <GlassCardBody>Content goes here.</GlassCardBody>
100
- <GlassCardFooter>
101
- <GlassButton>Action</GlassButton>
102
- </GlassCardFooter>
103
- </GlassCard>
79
+ export function ThemeToggle() {
80
+ const { theme, setTheme } = useKooriTheme();
81
+ return (
82
+ <GlassButton onClick={() => setTheme(theme === "dark" ? "light" : "dark")}>
83
+ Toggle Theme
84
+ </GlassButton>
85
+ );
86
+ }
104
87
  ```
105
88
 
106
- | Prop | Type | Default | Description |
107
- |------|------|---------|-------------|
108
- | `variant` | `"default" \| "subtle" \| "elevated"` | `"default"` | Glass intensity |
89
+ | `KooriProvider` prop | Type | Default | Description |
90
+ |---|---|---|---|
91
+ | `defaultTheme` | `"light" \| "dark" \| "system"` | `"system"` | Initial theme |
92
+ | `defaultColorScheme` | `"default" \| "slate" \| "zinc" \| "neutral" \| "violet"` | `"default"` | Initial color preset |
109
93
 
110
94
  ---
111
95
 
112
- ### GlassButton
113
-
114
- A button with hover glow and variants.
115
-
116
- ```tsx
117
- <GlassButton variant="primary" size="lg">Submit</GlassButton>
118
- ```
96
+ ## Components
119
97
 
120
- | Prop | Type | Default | Description |
121
- |------|------|---------|-------------|
122
- | `variant` | `"default" \| "primary"` | `"default"` | Visual style |
123
- | `size` | `"sm" \| "md" \| "lg"` | `"md"` | Size preset |
98
+ ### General
99
+
100
+ | Component | Description |
101
+ |---|---|
102
+ | `GlassButton` | Button with `variant` (default/primary) and `size` (sm/md/lg) |
103
+ | `GlassBadge` | Pill badge — variants: default, primary, success, warning, danger |
104
+ | `GlassH1` `GlassH2` `GlassH3` `GlassH4` | Heading elements |
105
+ | `GlassText` | Paragraph — `size` (sm/md/lg), `muted` prop |
106
+ | `GlassCode` | Inline code snippet with glass background |
107
+ | `GlassLink` | Anchor with primary color and hover underline |
108
+ | `GlassBlockquote` | Blockquote with primary left border |
109
+
110
+ ### Layout
111
+
112
+ | Component | Description |
113
+ |---|---|
114
+ | `GlassPanel` | Foundational container — variants: default, subtle, elevated |
115
+ | `GlassCard` + `GlassCardHeader` / `GlassCardBody` / `GlassCardFooter` | Structured card |
116
+ | `GlassSeparator` | Horizontal or vertical divider (`orientation` prop) |
117
+
118
+ ### Form
119
+
120
+ | Component | Description |
121
+ |---|---|
122
+ | `GlassInput` | Text input, all native types supported |
123
+ | `GlassTextarea` | Multi-line input (`rows` prop) |
124
+ | `GlassCheckbox` | Accessible checkbox with optional `label` |
125
+ | `GlassSwitch` | Toggle switch with optional `label` |
126
+ | `GlassRadioGroup` + `GlassRadioItem` | Radio group powered by Radix UI |
127
+ | `GlassSelect` + sub-components | Dropdown select powered by Radix UI |
128
+ | `GlassSlider` | Range slider powered by Radix UI |
129
+
130
+ ### Navigation
131
+
132
+ | Component | Description |
133
+ |---|---|
134
+ | `GlassTabs` + `GlassTabsList` / `GlassTabsTrigger` / `GlassTabsContent` | Tabbed interface |
135
+ | `GlassBreadcrumb` + `GlassBreadcrumbItem` / `GlassBreadcrumbSeparator` | Navigation breadcrumb |
136
+ | `GlassDropdownMenu` + sub-components | Context menu powered by Radix UI |
137
+
138
+ ### Data Display
139
+
140
+ | Component | Description |
141
+ |---|---|
142
+ | `GlassAvatar` + `GlassAvatarImage` / `GlassAvatarFallback` | Avatar with image fallback |
143
+ | `GlassTable` + `GlassThead` / `GlassTbody` / `GlassTr` / `GlassTh` / `GlassTd` | Data table |
144
+ | `GlassStatCard` | KPI card with `value`, `label`, `trend`, `icon` props |
145
+ | `GlassAreaChart` / `GlassBarChart` | Recharts wrappers with glass tooltips |
146
+
147
+ ### Feedback
148
+
149
+ | Component | Description |
150
+ |---|---|
151
+ | `GlassAlert` | Alert with variants: info, success, warning, error |
152
+ | `GlassDialog` + sub-components | Modal dialog powered by Radix UI |
153
+ | `GlassPopover` + sub-components | Floating panel powered by Radix UI |
154
+ | `GlassTooltip` + sub-components | Tooltip powered by Radix UI |
155
+ | `GlassToast` + `GlassToaster` | Toast notifications powered by Radix UI |
156
+ | `GlassProgress` | Progress bar — variants: default, success, warning, error |
157
+ | `GlassSkeleton` | Animated loading placeholder |
124
158
 
125
159
  ---
126
160
 
127
- ### GlassInput
128
-
129
- A styled text input with subtle focus ring.
130
-
131
- ```tsx
132
- <GlassInput placeholder="Search..." type="email" />
133
- ```
134
-
135
- Supports all native `<input>` props. Works controlled and uncontrolled.
136
-
137
- ---
161
+ ## Theming
138
162
 
139
- ### GlassDialog
163
+ ### Color presets
140
164
 
141
- An accessible modal dialog powered by Radix UI.
165
+ Apply a preset via `KooriProvider` or directly on `<html>`:
142
166
 
143
167
  ```tsx
144
- import {
145
- GlassDialog,
146
- GlassDialogTrigger,
147
- GlassDialogContent,
148
- GlassDialogTitle,
149
- GlassDialogDescription,
150
- GlassDialogClose,
151
- } from "koori-ui";
152
-
153
- <GlassDialog>
154
- <GlassDialogTrigger asChild>
155
- <GlassButton>Open</GlassButton>
156
- </GlassDialogTrigger>
157
- <GlassDialogContent>
158
- <GlassDialogTitle>Confirm</GlassDialogTitle>
159
- <GlassDialogDescription>Are you sure?</GlassDialogDescription>
160
- <GlassDialogClose asChild>
161
- <GlassButton>Close</GlassButton>
162
- </GlassDialogClose>
163
- </GlassDialogContent>
164
- </GlassDialog>
168
+ <KooriProvider defaultColorScheme="violet">...</KooriProvider>
169
+ // or
170
+ <html data-theme="slate">
165
171
  ```
166
172
 
167
- ---
173
+ Available presets: `slate`, `zinc`, `neutral`, `violet`
168
174
 
169
- ### GlassChart (Recharts Component)
175
+ ### CSS custom properties
170
176
 
171
- Premium, automatically responsive glassmorphism wrappers for Recharts.
177
+ Override any token to match your brand:
172
178
 
173
- ```tsx
174
- import { GlassAreaChart, GlassBarChart } from "koori-ui";
175
-
176
- const chartData = [
177
- { name: "Jan", revenue: 4000, users: 2400 },
178
- { name: "Feb", revenue: 3000, users: 1398 },
179
- ];
180
-
181
- <GlassAreaChart
182
- data={chartData}
183
- index="name"
184
- categories={[{ key: "revenue", color: "var(--koori-primary)", name: "Revenue" }]}
185
- />
179
+ ```css
180
+ :root {
181
+ --koori-primary: #8b5cf6;
182
+ --koori-accent: #a78bfa;
183
+ }
186
184
  ```
187
185
 
188
- ---
186
+ | Token | Description |
187
+ |---|---|
188
+ | `--koori-bg` | Page background |
189
+ | `--koori-text` | Primary text |
190
+ | `--koori-muted` | Secondary/muted text |
191
+ | `--koori-primary` | Brand primary |
192
+ | `--koori-accent` | Brand accent |
193
+ | `--koori-success` / `--koori-warning` / `--koori-error` / `--koori-info` | Status colors |
194
+ | `--koori-radius-sm/md/lg/xl/full` | Border radius scale |
189
195
 
190
- ## 🤖 Model Context Protocol (MCP) & Copy-Paste Setup [SOON]
196
+ ### Glass CSS classes
191
197
 
192
- We are currently building **native MCP (Model Context Protocol)** support! Soon, you will be able to simply expose Koori UI to any agent and have it automatically scaffold React components for you.
198
+ Use directly when building custom components:
193
199
 
194
- We will also provide copy-pasteable Markdown recipes for every complex component directly in our documentation so your AI assistants can use them perfectly every time!
200
+ | Class | Description |
201
+ |---|---|
202
+ | `.glass` | Standard frosted glass |
203
+ | `.glass-subtle` | Lighter, more transparent |
204
+ | `.glass-elevated` | Strongest blur and drop shadow |
195
205
 
196
206
  ---
197
207
 
198
- ## Theming
208
+ ## MCP Server (Claude Code)
199
209
 
200
- Override CSS custom properties to customize the palette:
210
+ Search Koori UI component docs from within Claude Code:
201
211
 
202
- ```css
203
- :root {
204
- --koori-bg: #0b0f19;
205
- --koori-text: #e6eaf2;
206
- --koori-muted: #a1a7b3;
207
- --koori-primary: #6c8cff;
208
- }
212
+ ```bash
213
+ cd packages/mcp && npm run build
209
214
  ```
210
215
 
211
- For example, switch to a purple accent:
216
+ Add to `.claude/settings.json`:
212
217
 
213
- ```css
214
- :root {
215
- --koori-primary: #a78bfa;
218
+ ```json
219
+ {
220
+ "mcpServers": {
221
+ "koori-ui": {
222
+ "command": "node",
223
+ "args": ["./packages/mcp/dist/index.js"]
224
+ }
225
+ }
216
226
  }
217
227
  ```
218
228
 
229
+ Available tools: `list_components`, `get_component_docs`, `search_components`, `get_component_example`
230
+
219
231
  ---
220
232
 
221
- ## Glass CSS Classes
233
+ ## create-koori-app
222
234
 
223
- You can also use the raw CSS classes directly:
235
+ Scaffold a new project interactively:
224
236
 
225
- | Class | Description |
226
- |-------|-------------|
227
- | `.glass` | Standard frosted glass |
228
- | `.glass-subtle` | Lighter, more transparent |
229
- | `.glass-elevated` | Stronger blur + drop shadow |
237
+ ```bash
238
+ npx create-koori-app my-app
239
+ ```
240
+
241
+ Prompts for project name, default theme, and package manager. Outputs a Next.js app with `KooriProvider` pre-configured.
230
242
 
231
243
  ---
232
244
 
233
245
  ## Build
234
246
 
235
247
  ```bash
236
- npm run build # CJS + ESM + DTS → dist/
248
+ npm run build # CJS + ESM + DTS + CSS → dist/
237
249
  npm run typecheck # tsc --noEmit
238
250
  npm run dev # watch mode
251
+ npm run release:patch # bump version, build, pack tarball
239
252
  ```
240
253
 
254
+ ---
255
+
241
256
  ## License
242
257
 
243
258
  MIT
package/dist/index.css CHANGED
@@ -1074,6 +1074,9 @@
1074
1074
  .italic {
1075
1075
  font-style: italic;
1076
1076
  }
1077
+ .underline {
1078
+ text-decoration-line: underline;
1079
+ }
1077
1080
  .underline-offset-4 {
1078
1081
  text-underline-offset: 4px;
1079
1082
  }
package/dist/index.js CHANGED
@@ -262,11 +262,14 @@ function GlassAreaChart({
262
262
  index
263
263
  }) {
264
264
  const [mounted, setMounted] = (0, import_react2.useState)(false);
265
- (0, import_react2.useEffect)(() => setMounted(true), []);
265
+ (0, import_react2.useEffect)(() => {
266
+ const raf = requestAnimationFrame(() => setMounted(true));
267
+ return () => cancelAnimationFrame(raf);
268
+ }, []);
266
269
  if (!mounted) {
267
270
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: cn("w-full", className), style: { height, minHeight: height } });
268
271
  }
269
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: cn("w-full", className), style: { height, minHeight: height, minWidth: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_recharts.ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_recharts.AreaChart, { data, margin: { top: 10, right: 10, left: 0, bottom: 0 }, children: [
272
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: cn("w-full", className), style: { height, minHeight: height, minWidth: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_recharts.ResponsiveContainer, { width: "100%", height: "100%", minWidth: 200, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_recharts.AreaChart, { data, margin: { top: 10, right: 10, left: 0, bottom: 0 }, children: [
270
273
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("defs", { children: categories.map((cat, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("linearGradient", { id: `grad-${cat.key}`, x1: "0", y1: "0", x2: "0", y2: "1", children: [
271
274
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("stop", { offset: "5%", stopColor: cat.color, stopOpacity: 0.3 }),
272
275
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("stop", { offset: "95%", stopColor: cat.color, stopOpacity: 0 })
@@ -318,11 +321,14 @@ function GlassBarChart({
318
321
  index
319
322
  }) {
320
323
  const [mounted, setMounted] = (0, import_react2.useState)(false);
321
- (0, import_react2.useEffect)(() => setMounted(true), []);
324
+ (0, import_react2.useEffect)(() => {
325
+ const raf = requestAnimationFrame(() => setMounted(true));
326
+ return () => cancelAnimationFrame(raf);
327
+ }, []);
322
328
  if (!mounted) {
323
329
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: cn("w-full", className), style: { height, minHeight: height } });
324
330
  }
325
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: cn("w-full", className), style: { height, minHeight: height, minWidth: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_recharts.ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_recharts.BarChart, { data, margin: { top: 10, right: 10, left: 0, bottom: 0 }, barSize: 32, children: [
331
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: cn("w-full", className), style: { height, minHeight: height, minWidth: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_recharts.ResponsiveContainer, { width: "100%", height: "100%", minWidth: 200, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_recharts.BarChart, { data, margin: { top: 10, right: 10, left: 0, bottom: 0 }, barSize: 32, children: [
326
332
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_recharts.CartesianGrid, { strokeDasharray: "3 3", vertical: false, stroke: "rgba(255,255,255,0.06)" }),
327
333
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
328
334
  import_recharts.XAxis,