@gv-tech/design-system 2.1.1 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/.release-please-manifest.json +1 -1
  2. package/CHANGELOG.md +24 -0
  3. package/dist/components/ui/theme-provider.d.ts +4 -0
  4. package/dist/components/ui/theme-provider.d.ts.map +1 -0
  5. package/dist/components/ui/theme-provider.test.d.ts +2 -0
  6. package/dist/components/ui/theme-provider.test.d.ts.map +1 -0
  7. package/dist/components/ui/theme-toggle.test.d.ts +2 -0
  8. package/dist/components/ui/theme-toggle.test.d.ts.map +1 -0
  9. package/dist/design-system.css +1 -1
  10. package/dist/hooks/use-theme.d.ts +52 -0
  11. package/dist/hooks/use-theme.d.ts.map +1 -0
  12. package/dist/hooks/use-theme.test.d.ts +2 -0
  13. package/dist/hooks/use-theme.test.d.ts.map +1 -0
  14. package/dist/index.cjs.js +2 -2
  15. package/dist/index.cjs.js.map +1 -1
  16. package/dist/index.d.ts +2 -0
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.es.js +736 -723
  19. package/dist/index.es.js.map +1 -1
  20. package/dist/pages/GettingStarted.d.ts.map +1 -1
  21. package/dist/pages/components/ThemeToggleDocs.d.ts.map +1 -1
  22. package/dist/registry/alert-dialog.test.json +1 -1
  23. package/dist/registry/index.json +21 -0
  24. package/dist/registry/theme-provider.json +13 -0
  25. package/dist/registry/theme-provider.test.json +13 -0
  26. package/dist/registry/theme-toggle.json +1 -1
  27. package/dist/registry/theme-toggle.test.json +13 -0
  28. package/dist/{vendor-BLvpSabH.mjs → vendor-Bcg_ARLM.mjs} +1111 -1140
  29. package/dist/vendor-Bcg_ARLM.mjs.map +1 -0
  30. package/dist/{vendor-n4WFhtJT.js → vendor-BrqPND3G.js} +12 -12
  31. package/dist/vendor-BrqPND3G.js.map +1 -0
  32. package/package.json +3 -2
  33. package/scripts/validate.js +1 -0
  34. package/src/App.tsx +2 -2
  35. package/src/components/ui/alert-dialog.test.tsx +2 -0
  36. package/src/components/ui/theme-provider.test.tsx +47 -0
  37. package/src/components/ui/theme-provider.tsx +12 -0
  38. package/src/components/ui/theme-toggle.test.tsx +49 -0
  39. package/src/components/ui/theme-toggle.tsx +1 -1
  40. package/src/hooks/use-theme.test.tsx +27 -0
  41. package/src/hooks/use-theme.ts +15 -0
  42. package/src/index.ts +2 -0
  43. package/src/pages/GettingStarted.tsx +37 -6
  44. package/src/pages/components/ThemeToggleDocs.tsx +187 -13
  45. package/vite.config.ts +2 -1
  46. package/dist/vendor-BLvpSabH.mjs.map +0 -1
  47. package/dist/vendor-n4WFhtJT.js.map +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gv-tech/design-system",
3
- "version": "2.1.1",
3
+ "version": "2.3.0",
4
4
  "description": "Garcia Ventures react design system",
5
5
  "repository": "git@github.com:Garcia-Ventures/gvtech-design.git",
6
6
  "license": "MIT",
@@ -99,7 +99,6 @@
99
99
  "date-fns": "^4.1.0",
100
100
  "embla-carousel-react": "^8.6.0",
101
101
  "lucide-react": "^0.563.0",
102
- "next-themes": "^0.4.6",
103
102
  "react-day-picker": "^9.13.2",
104
103
  "react-hook-form": "^7.71.1",
105
104
  "react-icons": "^5.5.0",
@@ -131,6 +130,7 @@
131
130
  "husky": "^9.1.7",
132
131
  "jsdom": "^27.4.0",
133
132
  "lint-staged": "^16.2.7",
133
+ "next-themes": "^0.4.6",
134
134
  "postcss": "^8.5.6",
135
135
  "prettier": "^3.8.1",
136
136
  "prettier-plugin-organize-imports": "^4.3.0",
@@ -145,6 +145,7 @@
145
145
  "vitest": "^4.0.18"
146
146
  },
147
147
  "peerDependencies": {
148
+ "next-themes": "^0.4.0",
148
149
  "prop-types": "^15.8.0",
149
150
  "react": "^18 || ^19",
150
151
  "react-dom": "^18 || ^19",
@@ -15,6 +15,7 @@ const steps = [
15
15
  cmd: fix ? 'yarn lint:fix' : 'yarn lint',
16
16
  },
17
17
  { name: 'TypeScript type check', cmd: 'npx tsc --noEmit' },
18
+ { name: 'Test (vitest)', cmd: 'yarn test:ci' },
18
19
  { name: 'Build (vite)', cmd: 'yarn build' },
19
20
  ];
20
21
 
package/src/App.tsx CHANGED
@@ -1,4 +1,3 @@
1
- import { ThemeProvider } from 'next-themes';
2
1
  import * as React from 'react';
3
2
  import { Footer, Sidebar } from './components/docs';
4
3
  import { navItems } from './components/docs/Sidebar';
@@ -21,6 +20,7 @@ import {
21
20
  SearchTrigger,
22
21
  } from './components/ui/search';
23
22
  import { Toaster as SonnerToaster } from './components/ui/sonner';
23
+ import { ThemeProvider } from './components/ui/theme-provider';
24
24
  import { ThemeToggle } from './components/ui/theme-toggle';
25
25
  import { Toaster } from './components/ui/toaster';
26
26
  import { TooltipProvider } from './components/ui/tooltip';
@@ -205,7 +205,7 @@ function App() {
205
205
  };
206
206
 
207
207
  return (
208
- <ThemeProvider attribute="class" defaultTheme="system" enableSystem>
208
+ <ThemeProvider>
209
209
  <TooltipProvider>
210
210
  <div className="flex h-screen bg-background">
211
211
  {/* Sidebar */}
@@ -50,6 +50,7 @@ describe('AlertDialog', () => {
50
50
  <AlertDialogContent>
51
51
  <AlertDialogHeader>
52
52
  <AlertDialogTitle>Are you sure?</AlertDialogTitle>
53
+ <AlertDialogDescription>This action cannot be undone.</AlertDialogDescription>
53
54
  </AlertDialogHeader>
54
55
  <AlertDialogFooter>
55
56
  <AlertDialogCancel>Cancel</AlertDialogCancel>
@@ -72,6 +73,7 @@ describe('AlertDialog', () => {
72
73
  <AlertDialogContent>
73
74
  <AlertDialogHeader>
74
75
  <AlertDialogTitle>Are you sure?</AlertDialogTitle>
76
+ <AlertDialogDescription>This action cannot be undone.</AlertDialogDescription>
75
77
  </AlertDialogHeader>
76
78
  <AlertDialogFooter>
77
79
  <AlertDialogAction>Continue</AlertDialogAction>
@@ -0,0 +1,47 @@
1
+ import { ThemeProvider } from '@/components/ui/theme-provider';
2
+ import { render, screen } from '@testing-library/react';
3
+ import { describe, expect, it } from 'vitest';
4
+
5
+ describe('ThemeProvider', () => {
6
+ it('renders children correctly', () => {
7
+ render(
8
+ <ThemeProvider>
9
+ <div data-testid="child">Hello</div>
10
+ </ThemeProvider>,
11
+ );
12
+ expect(screen.getByTestId('child')).toBeInTheDocument();
13
+ expect(screen.getByTestId('child')).toHaveTextContent('Hello');
14
+ });
15
+
16
+ it('applies class attribute to html element by default', () => {
17
+ render(
18
+ <ThemeProvider>
19
+ <div>Content</div>
20
+ </ThemeProvider>,
21
+ );
22
+ // next-themes applies the attribute to the html element;
23
+ // in jsdom the attribute should be set to 'class' by default
24
+ const html = document.documentElement;
25
+ // The attribute prop controls how the theme class is toggled.
26
+ // We verify the provider renders without error, which confirms the defaults are valid.
27
+ expect(html).toBeDefined();
28
+ });
29
+
30
+ it('allows overriding default props', () => {
31
+ render(
32
+ <ThemeProvider defaultTheme="dark" enableSystem={false}>
33
+ <div data-testid="child">Dark Mode</div>
34
+ </ThemeProvider>,
35
+ );
36
+ expect(screen.getByTestId('child')).toBeInTheDocument();
37
+ });
38
+
39
+ it('passes additional next-themes props through', () => {
40
+ render(
41
+ <ThemeProvider storageKey="my-app-theme" themes={['light', 'dark', 'ocean']}>
42
+ <div data-testid="child">Custom themes</div>
43
+ </ThemeProvider>,
44
+ );
45
+ expect(screen.getByTestId('child')).toBeInTheDocument();
46
+ });
47
+ });
@@ -0,0 +1,12 @@
1
+ import type { ThemeProviderProps as NextThemesProviderProps } from 'next-themes';
2
+ import { ThemeProvider as NextThemesProvider } from 'next-themes';
3
+
4
+ export type ThemeProviderProps = NextThemesProviderProps;
5
+
6
+ export function ThemeProvider({ children, ...props }: ThemeProviderProps) {
7
+ return (
8
+ <NextThemesProvider attribute="class" defaultTheme="system" enableSystem {...props}>
9
+ {children}
10
+ </NextThemesProvider>
11
+ );
12
+ }
@@ -0,0 +1,49 @@
1
+ import { ThemeToggle } from '@/components/ui/theme-toggle';
2
+ import { render, screen } from '@testing-library/react';
3
+ import userEvent from '@testing-library/user-event';
4
+ import { ThemeProvider } from 'next-themes';
5
+ import { describe, expect, it, vi } from 'vitest';
6
+
7
+ // Mock the useTheme hook to control its return values
8
+ vi.mock('@/hooks/use-theme', async () => {
9
+ const actual = await vi.importActual('@/hooks/use-theme');
10
+ return {
11
+ ...actual,
12
+ useTheme: () => ({
13
+ theme: 'light',
14
+ setTheme: vi.fn(),
15
+ resolvedTheme: 'light',
16
+ tokens: {},
17
+ }),
18
+ };
19
+ });
20
+
21
+ describe('ThemeToggle', () => {
22
+ it('renders binary toggle by default', () => {
23
+ render(
24
+ <ThemeProvider>
25
+ <ThemeToggle />
26
+ </ThemeProvider>,
27
+ );
28
+ // Use role button which is accessible
29
+ const button = screen.getByRole('button', { name: /toggle theme/i });
30
+ expect(button).toBeInTheDocument();
31
+ });
32
+
33
+ it('renders ternary toggle with dropdown', async () => {
34
+ const user = userEvent.setup();
35
+ render(
36
+ <ThemeProvider>
37
+ <ThemeToggle variant="ternary" />
38
+ </ThemeProvider>,
39
+ );
40
+ const button = screen.getByRole('button'); // Dropdown trigger
41
+ expect(button).toBeInTheDocument();
42
+
43
+ // Open dropdown
44
+ await user.click(button);
45
+ expect(await screen.findByText('Light')).toBeInTheDocument();
46
+ expect(screen.getByText('Dark')).toBeInTheDocument();
47
+ expect(screen.getByText('System')).toBeInTheDocument();
48
+ });
49
+ });
@@ -5,9 +5,9 @@ import {
5
5
  DropdownMenuItem,
6
6
  DropdownMenuTrigger,
7
7
  } from '@/components/ui/dropdown-menu';
8
+ import { useTheme } from '@/hooks/use-theme';
8
9
  import { cn } from '@/lib/utils';
9
10
  import { Moon, Sun, SunMoon } from 'lucide-react';
10
- import { useTheme } from 'next-themes';
11
11
 
12
12
  export interface ThemeToggleProps {
13
13
  /**
@@ -0,0 +1,27 @@
1
+ import { useTheme } from '@/hooks/use-theme';
2
+ import { theme } from '@/theme/tokens';
3
+ import { renderHook } from '@testing-library/react';
4
+ import { ThemeProvider } from 'next-themes';
5
+ import { describe, expect, it } from 'vitest';
6
+
7
+ describe('useTheme', () => {
8
+ it('returns default light tokens when no theme is set', () => {
9
+ const { result } = renderHook(() => useTheme(), {
10
+ wrapper: ({ children }) => <ThemeProvider>{children}</ThemeProvider>,
11
+ });
12
+
13
+ expect(result.current.tokens).toEqual(theme.light);
14
+ });
15
+
16
+ it('returns dark tokens when theme is dark', () => {
17
+ const { result } = renderHook(() => useTheme(), {
18
+ wrapper: ({ children }) => (
19
+ <ThemeProvider defaultTheme="dark" enableSystem={false}>
20
+ {children}
21
+ </ThemeProvider>
22
+ ),
23
+ });
24
+
25
+ expect(result.current.tokens).toEqual(theme.dark);
26
+ });
27
+ });
@@ -0,0 +1,15 @@
1
+ import { theme } from '@/theme/tokens';
2
+ import { useTheme as useNextTheme } from 'next-themes';
3
+
4
+ export function useTheme() {
5
+ const context = useNextTheme();
6
+ const { resolvedTheme } = context;
7
+
8
+ // Default to light theme tokens if resolvedTheme is undefined or invalid
9
+ const activeTokens = resolvedTheme === 'dark' ? theme.dark : theme.light;
10
+
11
+ return {
12
+ ...context,
13
+ tokens: activeTokens,
14
+ };
15
+ }
package/src/index.ts CHANGED
@@ -45,6 +45,7 @@ export * from './components/ui/switch';
45
45
  export * from './components/ui/table';
46
46
  export * from './components/ui/tabs';
47
47
  export * from './components/ui/textarea';
48
+ export * from './components/ui/theme-provider';
48
49
  export * from './components/ui/theme-toggle';
49
50
  export * from './components/ui/toast';
50
51
  export { Toaster as ToasterToast } from './components/ui/toaster';
@@ -53,4 +54,5 @@ export * from './components/ui/toggle-group';
53
54
  export * from './components/ui/tooltip';
54
55
 
55
56
  // Hooks
57
+ export * from './hooks/use-theme';
56
58
  export * from './hooks/use-toast';
@@ -133,10 +133,34 @@ export function InstallationPage() {
133
133
  <CodeBlock
134
134
  code={`{
135
135
  "react": "^18 || ^19",
136
- "react-dom": "^18 || ^19"
136
+ "react-dom": "^18 || ^19",
137
+ "next-themes": "^0.4.0"
137
138
  }`}
138
139
  language="json"
139
140
  />
141
+ <p className="text-sm text-muted-foreground">
142
+ <code className="text-sm bg-muted px-1.5 py-0.5 rounded">next-themes</code> is required for the design
143
+ system's <code className="text-sm bg-muted px-1.5 py-0.5 rounded">ThemeProvider</code>,{' '}
144
+ <code className="text-sm bg-muted px-1.5 py-0.5 rounded">ThemeToggle</code>, and{' '}
145
+ <code className="text-sm bg-muted px-1.5 py-0.5 rounded">useTheme</code> to work. Install it alongside the
146
+ design system:
147
+ </p>
148
+ <Tabs defaultValue="npm" className="w-full">
149
+ <TabsList>
150
+ <TabsTrigger value="npm">npm</TabsTrigger>
151
+ <TabsTrigger value="yarn">yarn</TabsTrigger>
152
+ <TabsTrigger value="pnpm">pnpm</TabsTrigger>
153
+ </TabsList>
154
+ <TabsContent value="npm" className="mt-4">
155
+ <CodeBlock code="npm install next-themes" language="bash" />
156
+ </TabsContent>
157
+ <TabsContent value="yarn" className="mt-4">
158
+ <CodeBlock code="yarn add next-themes" language="bash" />
159
+ </TabsContent>
160
+ <TabsContent value="pnpm" className="mt-4">
161
+ <CodeBlock code="pnpm add next-themes" language="bash" />
162
+ </TabsContent>
163
+ </Tabs>
140
164
  </section>
141
165
 
142
166
  <section className="space-y-4">
@@ -253,15 +277,22 @@ module.exports = {
253
277
 
254
278
  <section className="space-y-4">
255
279
  <h2 className="text-2xl font-semibold tracking-tight">Start Using Components</h2>
256
- <p className="text-muted-foreground">Now you can import and use components from the design system:</p>
280
+ <p className="text-muted-foreground">
281
+ Wrap your app with <code className="text-sm bg-muted px-1.5 py-0.5 rounded">ThemeProvider</code> and start
282
+ importing components:
283
+ </p>
257
284
  <CodeBlock
258
- code={`import { Button } from '@gv-tech/design-system';
285
+ code={`import { ThemeProvider, ThemeToggle, Button } from '@gv-tech/design-system';
286
+ import '@gv-tech/design-system/style.css';
259
287
 
260
288
  export default function App() {
261
289
  return (
262
- <Button variant="default">
263
- Click me
264
- </Button>
290
+ <ThemeProvider>
291
+ <div>
292
+ <ThemeToggle variant="ternary" />
293
+ <Button variant="default">Click me</Button>
294
+ </div>
295
+ </ThemeProvider>
265
296
  );
266
297
  }`}
267
298
  />
@@ -30,23 +30,178 @@ export function ThemeToggleDocs() {
30
30
  </ComponentShowcase>
31
31
 
32
32
  <ComponentShowcase
33
- title="Custom State Integration"
34
- description="You can control the theme externally by passing customTheme and onThemeChange props."
33
+ title="Controlled Mode"
34
+ description="You can control the theme externally by passing customTheme and onThemeChange props. This is useful for testing or when using a different theme provider."
35
35
  code={`const [theme, setTheme] = useState('light');
36
36
 
37
37
  <ThemeToggle
38
38
  customTheme={theme}
39
- onThemeChange={(newTheme) => setTheme(newTheme)}
39
+ onThemeChange={setTheme}
40
40
  />
41
41
 
42
42
  <p>Current Theme: {theme}</p>`}
43
43
  >
44
44
  <div className="flex flex-col items-center gap-4">
45
- <ThemeToggle customTheme={customTheme} onThemeChange={(newTheme) => setCustomTheme(newTheme)} />
45
+ <ThemeToggle customTheme={customTheme} onThemeChange={setCustomTheme} />
46
46
  <p className="text-sm font-medium">Current Selection: {customTheme}</p>
47
47
  </div>
48
48
  </ComponentShowcase>
49
49
 
50
+ {/* ThemeProvider Section */}
51
+ <div className="mt-12 space-y-6">
52
+ <div>
53
+ <h3 className="text-xl font-semibold">ThemeProvider</h3>
54
+ <p className="mt-2 text-muted-foreground">
55
+ The design system exports a pre-configured{' '}
56
+ <code className="text-sm bg-muted px-1.5 py-0.5 rounded">ThemeProvider</code> that wraps{' '}
57
+ <code className="text-sm bg-muted px-1.5 py-0.5 rounded">next-themes</code> with sensible defaults. Wrap
58
+ your application with it to enable theme switching for all design system components.
59
+ </p>
60
+ </div>
61
+
62
+ <div className="rounded-md border bg-muted p-4">
63
+ <pre className="text-xs">
64
+ <code>
65
+ {`import { ThemeProvider, ThemeToggle } from '@gv-tech/design-system';
66
+ import '@gv-tech/design-system/style.css';
67
+
68
+ function App() {
69
+ return (
70
+ <ThemeProvider>
71
+ <ThemeToggle variant="ternary" />
72
+ {/* Your app content */}
73
+ </ThemeProvider>
74
+ );
75
+ }`}
76
+ </code>
77
+ </pre>
78
+ </div>
79
+
80
+ <div className="space-y-4">
81
+ <h4 className="font-medium text-foreground">Defaults</h4>
82
+ <p className="text-sm text-muted-foreground">
83
+ Out of the box, <code className="text-sm bg-muted px-1.5 py-0.5 rounded">ThemeProvider</code> applies these
84
+ defaults. You can override any of them by passing the corresponding prop.
85
+ </p>
86
+ <div className="rounded-md border">
87
+ <table className="w-full text-sm">
88
+ <thead>
89
+ <tr className="border-b bg-muted/50">
90
+ <th className="p-3 text-left font-medium">Prop</th>
91
+ <th className="p-3 text-left font-medium">Default</th>
92
+ <th className="p-3 text-left font-medium">Description</th>
93
+ </tr>
94
+ </thead>
95
+ <tbody>
96
+ <tr className="border-b">
97
+ <td className="p-3">
98
+ <code className="text-xs bg-muted px-1 py-0.5 rounded">attribute</code>
99
+ </td>
100
+ <td className="p-3">
101
+ <code className="text-xs bg-muted px-1 py-0.5 rounded">"class"</code>
102
+ </td>
103
+ <td className="p-3 text-muted-foreground">Applies the theme as a CSS class on the HTML element</td>
104
+ </tr>
105
+ <tr className="border-b">
106
+ <td className="p-3">
107
+ <code className="text-xs bg-muted px-1 py-0.5 rounded">defaultTheme</code>
108
+ </td>
109
+ <td className="p-3">
110
+ <code className="text-xs bg-muted px-1 py-0.5 rounded">"system"</code>
111
+ </td>
112
+ <td className="p-3 text-muted-foreground">Respects the user's operating system preference</td>
113
+ </tr>
114
+ <tr>
115
+ <td className="p-3">
116
+ <code className="text-xs bg-muted px-1 py-0.5 rounded">enableSystem</code>
117
+ </td>
118
+ <td className="p-3">
119
+ <code className="text-xs bg-muted px-1 py-0.5 rounded">true</code>
120
+ </td>
121
+ <td className="p-3 text-muted-foreground">Enables automatic detection of the OS color scheme</td>
122
+ </tr>
123
+ </tbody>
124
+ </table>
125
+ </div>
126
+ </div>
127
+
128
+ <div className="rounded-md border bg-muted p-4">
129
+ <p className="text-xs font-medium text-muted-foreground mb-2">Overriding defaults:</p>
130
+ <pre className="text-xs">
131
+ <code>
132
+ {`<ThemeProvider
133
+ defaultTheme="dark"
134
+ storageKey="my-app-theme"
135
+ themes={['light', 'dark', 'ocean']}
136
+ >
137
+ <App />
138
+ </ThemeProvider>`}
139
+ </code>
140
+ </pre>
141
+ </div>
142
+ </div>
143
+
144
+ {/* useTheme Section */}
145
+ <div className="mt-12 space-y-4">
146
+ <h3 className="text-xl font-semibold">useTheme Hook</h3>
147
+ <p className="text-sm text-muted-foreground">
148
+ The <code className="text-sm bg-muted px-1.5 py-0.5 rounded">useTheme</code> hook provides access to the
149
+ current theme, theme controls, and the active design tokens. It must be used within a{' '}
150
+ <code className="text-sm bg-muted px-1.5 py-0.5 rounded">ThemeProvider</code>.
151
+ </p>
152
+ <div className="rounded-md border bg-muted p-4">
153
+ <pre className="text-xs">
154
+ <code>
155
+ {`import { useTheme } from '@gv-tech/design-system';
156
+
157
+ export function MyComponent() {
158
+ const { theme, setTheme, resolvedTheme, tokens } = useTheme();
159
+
160
+ return (
161
+ <div style={{ backgroundColor: tokens.background }}>
162
+ <p>Current theme: {theme}</p>
163
+ <p>Resolved theme: {resolvedTheme}</p>
164
+ <button onClick={() => setTheme('dark')}>Dark Mode</button>
165
+ </div>
166
+ );
167
+ }`}
168
+ </code>
169
+ </pre>
170
+ </div>
171
+
172
+ <PropsTable
173
+ props={[
174
+ {
175
+ name: 'theme',
176
+ type: 'string',
177
+ required: false,
178
+ description: 'The current theme name ("light", "dark", or "system").',
179
+ },
180
+ {
181
+ name: 'setTheme',
182
+ type: '(theme: string) => void',
183
+ required: false,
184
+ description: 'Function to programmatically change the theme.',
185
+ },
186
+ {
187
+ name: 'resolvedTheme',
188
+ type: 'string',
189
+ required: false,
190
+ description:
191
+ 'The resolved theme ("light" or "dark"). Useful when theme is "system" and you need the actual value.',
192
+ },
193
+ {
194
+ name: 'tokens',
195
+ type: 'ThemeTokens',
196
+ required: false,
197
+ description:
198
+ 'The active color tokens for the current resolved theme (light or dark). Contains background, foreground, primary, and other design token values.',
199
+ },
200
+ ]}
201
+ />
202
+ </div>
203
+
204
+ {/* ThemeToggle Props Section */}
50
205
  <div className="space-y-4">
51
206
  <h3 className="text-xl font-semibold">ThemeToggle Props</h3>
52
207
  <PropsTable
@@ -81,41 +236,60 @@ export function ThemeToggleDocs() {
81
236
  />
82
237
  </div>
83
238
 
239
+ {/* Integration Section */}
84
240
  <div className="mt-12 space-y-6">
85
241
  <div>
86
242
  <h3 className="text-xl font-semibold">Integration</h3>
87
243
  <p className="mt-2 text-muted-foreground">
88
- The `ThemeToggle` component is built to be flexible and works seamlessly with `next-themes` by default, but
89
- it can also be used in a fully controlled manner with any theme provider or custom state.
244
+ The <code className="text-sm bg-muted px-1.5 py-0.5 rounded">ThemeToggle</code> component works seamlessly
245
+ with the design system's <code className="text-sm bg-muted px-1.5 py-0.5 rounded">ThemeProvider</code>. It
246
+ can also be used in a fully controlled manner with any theme provider or custom state.
90
247
  </p>
91
248
  </div>
92
249
 
93
250
  <div className="grid gap-6 md:grid-cols-2">
94
251
  <div className="rounded-lg border bg-muted/50 p-6">
95
- <h4 className="font-medium text-foreground">With next-themes</h4>
252
+ <h4 className="font-medium text-foreground">With ThemeProvider (Recommended)</h4>
96
253
  <p className="mt-1 text-sm text-muted-foreground">
97
- Simply drop the component anywhere. It will automatically detect the `ThemeProvider` and handle switching.
254
+ Wrap your app with the design system's{' '}
255
+ <code className="text-xs bg-muted px-1 py-0.5 rounded">ThemeProvider</code> and drop in the toggle.
256
+ Everything connects automatically.
98
257
  </p>
99
258
  <pre className="mt-4 overflow-x-auto rounded-md bg-background p-4 text-xs">
100
- <code>{`<ThemeProvider attribute="class">
259
+ <code>{`import { ThemeProvider, ThemeToggle } from '@gv-tech/design-system';
260
+
261
+ <ThemeProvider>
101
262
  <ThemeToggle />
102
263
  </ThemeProvider>`}</code>
103
264
  </pre>
104
265
  </div>
105
266
 
106
267
  <div className="rounded-lg border bg-muted/50 p-6">
107
- <h4 className="font-medium text-foreground">Custom Provider</h4>
268
+ <h4 className="font-medium text-foreground">Controlled / Custom State</h4>
108
269
  <p className="mt-1 text-sm text-muted-foreground">
109
270
  Pass your own theme state and change handler to integrate with custom logic or external storage.
110
271
  </p>
111
272
  <pre className="mt-4 overflow-x-auto rounded-md bg-background p-4 text-xs">
112
- <code>{`<ThemeToggle
113
- customTheme={myTheme}
114
- onThemeChange={(t) => updateMyTheme(t)}
273
+ <code>{`const [theme, setTheme] = useState("light")
274
+
275
+ <ThemeToggle
276
+ customTheme={theme}
277
+ onThemeChange={setTheme}
115
278
  />`}</code>
116
279
  </pre>
117
280
  </div>
118
281
  </div>
282
+
283
+ <div className="rounded-lg border border-amber-500/30 bg-amber-500/5 p-6">
284
+ <h4 className="font-medium text-amber-600 dark:text-amber-400">⚠️ Important: Shared Context</h4>
285
+ <p className="mt-1 text-sm text-muted-foreground">
286
+ The design system marks <code className="text-xs bg-muted px-1 py-0.5 rounded">next-themes</code> as a{' '}
287
+ <strong>peer dependency</strong>, meaning it uses the same instance as your project. This ensures that{' '}
288
+ <code className="text-xs bg-muted px-1 py-0.5 rounded">useTheme</code>,{' '}
289
+ <code className="text-xs bg-muted px-1 py-0.5 rounded">ThemeToggle</code>, and your own components all share
290
+ the same theme context — no duplicate providers needed.
291
+ </p>
292
+ </div>
119
293
  </div>
120
294
  </ComponentSection>
121
295
  );
package/vite.config.ts CHANGED
@@ -27,13 +27,14 @@ export default defineConfig({
27
27
  }
28
28
  : undefined,
29
29
  rollupOptions: {
30
- external: isLibrary ? ['react', 'react-dom', 'prop-types'] : [],
30
+ external: isLibrary ? ['react', 'react-dom', 'prop-types', 'next-themes'] : [],
31
31
  output: {
32
32
  globals: isLibrary
33
33
  ? {
34
34
  react: 'React',
35
35
  'react-dom': 'ReactDOM',
36
36
  'prop-types': 'PropTypes',
37
+ 'next-themes': 'NextThemes',
37
38
  }
38
39
  : {},
39
40
  manualChunks(id) {