@gv-tech/design-system 2.2.0 → 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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gv-tech/design-system",
3
- "version": "2.2.0",
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",
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 */}
@@ -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
+ }
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';
@@ -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
  />
@@ -47,10 +47,107 @@ export function ThemeToggleDocs() {
47
47
  </div>
48
48
  </ComponentShowcase>
49
49
 
50
- <div className="space-y-4">
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">
51
146
  <h3 className="text-xl font-semibold">useTheme Hook</h3>
52
147
  <p className="text-sm text-muted-foreground">
53
- The `useTheme` hook provides access to the current theme and the active design tokens.
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>.
54
151
  </p>
55
152
  <div className="rounded-md border bg-muted p-4">
56
153
  <pre className="text-xs">
@@ -58,11 +155,12 @@ export function ThemeToggleDocs() {
58
155
  {`import { useTheme } from '@gv-tech/design-system';
59
156
 
60
157
  export function MyComponent() {
61
- const { theme, setTheme, tokens } = useTheme();
158
+ const { theme, setTheme, resolvedTheme, tokens } = useTheme();
62
159
 
63
160
  return (
64
161
  <div style={{ backgroundColor: tokens.background }}>
65
162
  <p>Current theme: {theme}</p>
163
+ <p>Resolved theme: {resolvedTheme}</p>
66
164
  <button onClick={() => setTheme('dark')}>Dark Mode</button>
67
165
  </div>
68
166
  );
@@ -70,8 +168,40 @@ export function MyComponent() {
70
168
  </code>
71
169
  </pre>
72
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
+ />
73
202
  </div>
74
203
 
204
+ {/* ThemeToggle Props Section */}
75
205
  <div className="space-y-4">
76
206
  <h3 className="text-xl font-semibold">ThemeToggle Props</h3>
77
207
  <PropsTable
@@ -106,23 +236,29 @@ export function MyComponent() {
106
236
  />
107
237
  </div>
108
238
 
239
+ {/* Integration Section */}
109
240
  <div className="mt-12 space-y-6">
110
241
  <div>
111
242
  <h3 className="text-xl font-semibold">Integration</h3>
112
243
  <p className="mt-2 text-muted-foreground">
113
- The `ThemeToggle` component is built to be flexible and works seamlessly with `next-themes` by default, but
114
- 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.
115
247
  </p>
116
248
  </div>
117
249
 
118
250
  <div className="grid gap-6 md:grid-cols-2">
119
251
  <div className="rounded-lg border bg-muted/50 p-6">
120
- <h4 className="font-medium text-foreground">With next-themes</h4>
252
+ <h4 className="font-medium text-foreground">With ThemeProvider (Recommended)</h4>
121
253
  <p className="mt-1 text-sm text-muted-foreground">
122
- 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.
123
257
  </p>
124
258
  <pre className="mt-4 overflow-x-auto rounded-md bg-background p-4 text-xs">
125
- <code>{`<ThemeProvider attribute="class">
259
+ <code>{`import { ThemeProvider, ThemeToggle } from '@gv-tech/design-system';
260
+
261
+ <ThemeProvider>
126
262
  <ThemeToggle />
127
263
  </ThemeProvider>`}</code>
128
264
  </pre>
@@ -143,6 +279,17 @@ export function MyComponent() {
143
279
  </pre>
144
280
  </div>
145
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>
146
293
  </div>
147
294
  </ComponentSection>
148
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) {