@gv-tech/design-system 2.2.0 → 2.4.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 (261) hide show
  1. package/.release-please-manifest.json +1 -1
  2. package/CHANGELOG.md +20 -0
  3. package/dist/App.d.ts +1 -2
  4. package/dist/App.d.ts.map +1 -1
  5. package/dist/accordion.cjs.js +2 -0
  6. package/dist/accordion.cjs.js.map +1 -0
  7. package/dist/accordion.es.js +38 -0
  8. package/dist/accordion.es.js.map +1 -0
  9. package/dist/alert-dialog.cjs.js +2 -0
  10. package/dist/alert-dialog.cjs.js.map +1 -0
  11. package/dist/alert-dialog.es.js +64 -0
  12. package/dist/alert-dialog.es.js.map +1 -0
  13. package/dist/alert.cjs.js +2 -0
  14. package/dist/alert.cjs.js.map +1 -0
  15. package/dist/alert.es.js +32 -0
  16. package/dist/alert.es.js.map +1 -0
  17. package/dist/aspect-ratio.cjs.js +2 -0
  18. package/dist/aspect-ratio.cjs.js.map +1 -0
  19. package/dist/aspect-ratio.es.js +6 -0
  20. package/dist/aspect-ratio.es.js.map +1 -0
  21. package/dist/avatar.cjs.js +2 -0
  22. package/dist/avatar.cjs.js.map +1 -0
  23. package/dist/avatar.es.js +29 -0
  24. package/dist/avatar.es.js.map +1 -0
  25. package/dist/badge.cjs.js +2 -0
  26. package/dist/badge.cjs.js.map +1 -0
  27. package/dist/badge.es.js +26 -0
  28. package/dist/badge.es.js.map +1 -0
  29. package/dist/breadcrumb.cjs.js +2 -0
  30. package/dist/breadcrumb.cjs.js.map +1 -0
  31. package/dist/breadcrumb.es.js +68 -0
  32. package/dist/breadcrumb.es.js.map +1 -0
  33. package/dist/button.cjs.js +2 -0
  34. package/dist/button.cjs.js.map +1 -0
  35. package/dist/button.es.js +39 -0
  36. package/dist/button.es.js.map +1 -0
  37. package/dist/calendar.cjs.js +2 -0
  38. package/dist/calendar.cjs.js.map +1 -0
  39. package/dist/calendar.es.js +132 -0
  40. package/dist/calendar.es.js.map +1 -0
  41. package/dist/card.cjs.js +2 -0
  42. package/dist/card.cjs.js.map +1 -0
  43. package/dist/card.es.js +34 -0
  44. package/dist/card.es.js.map +1 -0
  45. package/dist/carousel.cjs.js +2 -0
  46. package/dist/carousel.cjs.js.map +1 -0
  47. package/dist/carousel.es.js +158 -0
  48. package/dist/carousel.es.js.map +1 -0
  49. package/dist/chart.cjs.js +8 -0
  50. package/dist/chart.cjs.js.map +1 -0
  51. package/dist/chart.es.js +187 -0
  52. package/dist/chart.es.js.map +1 -0
  53. package/dist/checkbox.cjs.js +2 -0
  54. package/dist/checkbox.cjs.js.map +1 -0
  55. package/dist/checkbox.es.js +20 -0
  56. package/dist/checkbox.es.js.map +1 -0
  57. package/dist/collapsible.cjs.js +2 -0
  58. package/dist/collapsible.cjs.js.map +1 -0
  59. package/dist/collapsible.es.js +8 -0
  60. package/dist/collapsible.es.js.map +1 -0
  61. package/dist/command.cjs.js +2 -0
  62. package/dist/command.cjs.js.map +1 -0
  63. package/dist/command.es.js +86 -0
  64. package/dist/command.es.js.map +1 -0
  65. package/dist/components/docs/Sidebar.d.ts +2 -1
  66. package/dist/components/docs/Sidebar.d.ts.map +1 -1
  67. package/dist/components/ui/command.d.ts.map +1 -1
  68. package/dist/components/ui/theme-provider.d.ts +4 -0
  69. package/dist/components/ui/theme-provider.d.ts.map +1 -0
  70. package/dist/components/ui/theme-provider.test.d.ts +2 -0
  71. package/dist/components/ui/theme-provider.test.d.ts.map +1 -0
  72. package/dist/context-menu.cjs.js +2 -0
  73. package/dist/context-menu.cjs.js.map +1 -0
  74. package/dist/context-menu.es.js +121 -0
  75. package/dist/context-menu.es.js.map +1 -0
  76. package/dist/design-system.css +1 -1
  77. package/dist/dialog.cjs.js +2 -0
  78. package/dist/dialog.cjs.js.map +1 -0
  79. package/dist/dialog.es.js +65 -0
  80. package/dist/dialog.es.js.map +1 -0
  81. package/dist/drawer.cjs.js +2 -0
  82. package/dist/drawer.cjs.js.map +1 -0
  83. package/dist/drawer.es.js +54 -0
  84. package/dist/drawer.es.js.map +1 -0
  85. package/dist/dropdown-menu.cjs.js +2 -0
  86. package/dist/dropdown-menu.cjs.js.map +1 -0
  87. package/dist/dropdown-menu.es.js +123 -0
  88. package/dist/dropdown-menu.es.js.map +1 -0
  89. package/dist/form.cjs.js +2 -0
  90. package/dist/form.cjs.js.map +1 -0
  91. package/dist/form.es.js +83 -0
  92. package/dist/form.es.js.map +1 -0
  93. package/dist/hover-card.cjs.js +2 -0
  94. package/dist/hover-card.cjs.js.map +1 -0
  95. package/dist/hover-card.es.js +23 -0
  96. package/dist/hover-card.es.js.map +1 -0
  97. package/dist/index.cjs.js +1 -7
  98. package/dist/index.cjs.js.map +1 -1
  99. package/dist/index.d.ts +1 -0
  100. package/dist/index.d.ts.map +1 -1
  101. package/dist/index.es.js +285 -2446
  102. package/dist/index.es.js.map +1 -1
  103. package/dist/input.cjs.js +2 -0
  104. package/dist/input.cjs.js.map +1 -0
  105. package/dist/input.es.js +22 -0
  106. package/dist/input.es.js.map +1 -0
  107. package/dist/label.cjs.js +2 -0
  108. package/dist/label.cjs.js.map +1 -0
  109. package/dist/label.es.js +9 -0
  110. package/dist/label.es.js.map +1 -0
  111. package/dist/menubar.cjs.js +2 -0
  112. package/dist/menubar.cjs.js.map +1 -0
  113. package/dist/menubar.es.js +161 -0
  114. package/dist/menubar.es.js.map +1 -0
  115. package/dist/navigation-menu.cjs.js +2 -0
  116. package/dist/navigation-menu.cjs.js.map +1 -0
  117. package/dist/navigation-menu.es.js +96 -0
  118. package/dist/navigation-menu.es.js.map +1 -0
  119. package/dist/pages/GettingStarted.d.ts.map +1 -1
  120. package/dist/pages/components/ThemeToggleDocs.d.ts.map +1 -1
  121. package/dist/pagination.cjs.js +2 -0
  122. package/dist/pagination.cjs.js.map +1 -0
  123. package/dist/pagination.es.js +60 -0
  124. package/dist/pagination.es.js.map +1 -0
  125. package/dist/popover.cjs.js +2 -0
  126. package/dist/popover.cjs.js.map +1 -0
  127. package/dist/popover.es.js +24 -0
  128. package/dist/popover.es.js.map +1 -0
  129. package/dist/progress.cjs.js +2 -0
  130. package/dist/progress.cjs.js.map +1 -0
  131. package/dist/progress.es.js +24 -0
  132. package/dist/progress.es.js.map +1 -0
  133. package/dist/radio-group.cjs.js +2 -0
  134. package/dist/radio-group.cjs.js.map +1 -0
  135. package/dist/radio-group.es.js +23 -0
  136. package/dist/radio-group.es.js.map +1 -0
  137. package/dist/registry/command.json +1 -1
  138. package/dist/registry/index.json +14 -0
  139. package/dist/registry/search.json +1 -1
  140. package/dist/registry/search.test.json +1 -1
  141. package/dist/registry/theme-provider.json +13 -0
  142. package/dist/registry/theme-provider.test.json +13 -0
  143. package/dist/resizable.cjs.js +2 -0
  144. package/dist/resizable.cjs.js.map +1 -0
  145. package/dist/resizable.es.js +34 -0
  146. package/dist/resizable.es.js.map +1 -0
  147. package/dist/scroll-area.cjs.js +2 -0
  148. package/dist/scroll-area.cjs.js.map +1 -0
  149. package/dist/scroll-area.es.js +30 -0
  150. package/dist/scroll-area.es.js.map +1 -0
  151. package/dist/search.cjs.js +2 -0
  152. package/dist/search.cjs.js.map +1 -0
  153. package/dist/search.es.js +60 -0
  154. package/dist/search.es.js.map +1 -0
  155. package/dist/select.cjs.js +2 -0
  156. package/dist/select.cjs.js.map +1 -0
  157. package/dist/select.es.js +100 -0
  158. package/dist/select.es.js.map +1 -0
  159. package/dist/separator.cjs.js +2 -0
  160. package/dist/separator.cjs.js.map +1 -0
  161. package/dist/separator.es.js +18 -0
  162. package/dist/separator.es.js.map +1 -0
  163. package/dist/sheet.cjs.js +2 -0
  164. package/dist/sheet.cjs.js.map +1 -0
  165. package/dist/sheet.es.js +64 -0
  166. package/dist/sheet.es.js.map +1 -0
  167. package/dist/skeleton.cjs.js +2 -0
  168. package/dist/skeleton.cjs.js.map +1 -0
  169. package/dist/skeleton.es.js +9 -0
  170. package/dist/skeleton.es.js.map +1 -0
  171. package/dist/slider.cjs.js +2 -0
  172. package/dist/slider.cjs.js.map +1 -0
  173. package/dist/slider.es.js +20 -0
  174. package/dist/slider.es.js.map +1 -0
  175. package/dist/sonner.cjs.js +2 -0
  176. package/dist/sonner.cjs.js.map +1 -0
  177. package/dist/sonner.es.js +25 -0
  178. package/dist/sonner.es.js.map +1 -0
  179. package/dist/switch.cjs.js +2 -0
  180. package/dist/switch.cjs.js.map +1 -0
  181. package/dist/switch.es.js +27 -0
  182. package/dist/switch.es.js.map +1 -0
  183. package/dist/table.cjs.js +2 -0
  184. package/dist/table.cjs.js.map +1 -0
  185. package/dist/table.es.js +70 -0
  186. package/dist/table.es.js.map +1 -0
  187. package/dist/tabs.cjs.js +2 -0
  188. package/dist/tabs.cjs.js.map +1 -0
  189. package/dist/tabs.es.js +46 -0
  190. package/dist/tabs.es.js.map +1 -0
  191. package/dist/textarea.cjs.js +2 -0
  192. package/dist/textarea.cjs.js.map +1 -0
  193. package/dist/textarea.es.js +21 -0
  194. package/dist/textarea.es.js.map +1 -0
  195. package/dist/theme/tokens.d.ts +46 -0
  196. package/dist/theme/tokens.d.ts.map +1 -1
  197. package/dist/theme-provider.cjs.js +2 -0
  198. package/dist/theme-provider.cjs.js.map +1 -0
  199. package/dist/theme-provider.es.js +9 -0
  200. package/dist/theme-provider.es.js.map +1 -0
  201. package/dist/theme-toggle-CCUkxY6o.mjs +181 -0
  202. package/dist/theme-toggle-CCUkxY6o.mjs.map +1 -0
  203. package/dist/theme-toggle-Dc_nm_32.js +2 -0
  204. package/dist/theme-toggle-Dc_nm_32.js.map +1 -0
  205. package/dist/theme-toggle.cjs.js +2 -0
  206. package/dist/theme-toggle.cjs.js.map +1 -0
  207. package/dist/theme-toggle.es.js +9 -0
  208. package/dist/theme-toggle.es.js.map +1 -0
  209. package/dist/toast.cjs.js +2 -0
  210. package/dist/toast.cjs.js.map +1 -0
  211. package/dist/toast.es.js +70 -0
  212. package/dist/toast.es.js.map +1 -0
  213. package/dist/toaster-BjPc-lId.js +2 -0
  214. package/dist/toaster-BjPc-lId.js.map +1 -0
  215. package/dist/toaster-Bk6a4gIz.mjs +120 -0
  216. package/dist/toaster-Bk6a4gIz.mjs.map +1 -0
  217. package/dist/toaster.cjs.js +2 -0
  218. package/dist/toaster.cjs.js.map +1 -0
  219. package/dist/toaster.es.js +7 -0
  220. package/dist/toaster.es.js.map +1 -0
  221. package/dist/toggle-group.cjs.js +2 -0
  222. package/dist/toggle-group.cjs.js.map +1 -0
  223. package/dist/toggle-group.es.js +33 -0
  224. package/dist/toggle-group.es.js.map +1 -0
  225. package/dist/toggle.cjs.js +2 -0
  226. package/dist/toggle.cjs.js.map +1 -0
  227. package/dist/toggle.es.js +29 -0
  228. package/dist/toggle.es.js.map +1 -0
  229. package/dist/tooltip.cjs.js +2 -0
  230. package/dist/tooltip.cjs.js.map +1 -0
  231. package/dist/tooltip.es.js +23 -0
  232. package/dist/tooltip.es.js.map +1 -0
  233. package/dist/utils-C9QGdMaH.mjs +8 -0
  234. package/dist/utils-C9QGdMaH.mjs.map +1 -0
  235. package/dist/utils-CUFNKXRW.js +2 -0
  236. package/dist/utils-CUFNKXRW.js.map +1 -0
  237. package/dist/{vendor-BLvpSabH.mjs → vendor-CCQzmGyD.mjs} +1131 -1160
  238. package/dist/vendor-CCQzmGyD.mjs.map +1 -0
  239. package/dist/{vendor-n4WFhtJT.js → vendor-CIyDEr7H.js} +12 -12
  240. package/dist/vendor-CIyDEr7H.js.map +1 -0
  241. package/package.json +251 -5
  242. package/scripts/sync-exports.ts +52 -0
  243. package/scripts/sync-tokens.ts +73 -0
  244. package/scripts/{validate.js → validate.ts} +14 -8
  245. package/src/App.tsx +64 -27
  246. package/src/components/docs/ComponentShowcase.tsx +5 -5
  247. package/src/components/docs/Sidebar.tsx +3 -2
  248. package/src/components/ui/command.tsx +3 -1
  249. package/src/components/ui/search.test.tsx +2 -0
  250. package/src/components/ui/search.tsx +3 -3
  251. package/src/components/ui/theme-provider.test.tsx +47 -0
  252. package/src/components/ui/theme-provider.tsx +12 -0
  253. package/src/globals.css +22 -0
  254. package/src/index.ts +1 -0
  255. package/src/pages/ColorTokensDocs.tsx +4 -4
  256. package/src/pages/GettingStarted.tsx +43 -10
  257. package/src/pages/components/ThemeToggleDocs.tsx +155 -8
  258. package/src/theme/tokens.ts +60 -38
  259. package/vite.config.ts +27 -4
  260. package/dist/vendor-BLvpSabH.mjs.map +0 -1
  261. package/dist/vendor-n4WFhtJT.js.map +0 -1
@@ -25,6 +25,7 @@ export interface NavItem {
25
25
  interface SidebarProps {
26
26
  activeItem: string;
27
27
  onItemSelect: (id: string) => void;
28
+ className?: string;
28
29
  }
29
30
 
30
31
  const categoryConfig: Record<ComponentCategory, { label: string; icon: React.ReactNode }> = {
@@ -106,7 +107,7 @@ export const navItems: NavItem[] = [
106
107
  { id: 'theme-toggle', label: 'Theme Toggle', category: 'advanced' },
107
108
  ];
108
109
 
109
- export function Sidebar({ activeItem, onItemSelect }: SidebarProps) {
110
+ export function Sidebar({ activeItem, onItemSelect, className }: SidebarProps) {
110
111
  const categories = Object.keys(categoryConfig) as ComponentCategory[];
111
112
  const [expandedCategories, setExpandedCategories] = React.useState<string[]>(['getting-started', 'forms']);
112
113
 
@@ -119,7 +120,7 @@ export function Sidebar({ activeItem, onItemSelect }: SidebarProps) {
119
120
  }, [activeItem, expandedCategories]);
120
121
 
121
122
  return (
122
- <div className="w-64 border-r bg-muted/50 flex flex-col h-full">
123
+ <div className={cn('w-64 border-r bg-muted/50 flex flex-col h-full', className)}>
123
124
  <div className="p-4 border-b">
124
125
  <h2 className="font-semibold text-lg">GV Design System</h2>
125
126
  <p className="text-xs text-muted-foreground">v{version}</p>
@@ -5,7 +5,7 @@ import { Command as CommandPrimitive } from 'cmdk';
5
5
  import { Search } from 'lucide-react';
6
6
  import * as React from 'react';
7
7
 
8
- import { Dialog, DialogContent } from '@/components/ui/dialog';
8
+ import { Dialog, DialogContent, DialogDescription, DialogTitle } from '@/components/ui/dialog';
9
9
  import { cn } from '@/lib/utils';
10
10
 
11
11
  const Command = React.forwardRef<
@@ -27,6 +27,8 @@ const CommandDialog = ({ children, ...props }: DialogProps) => {
27
27
  return (
28
28
  <Dialog {...props}>
29
29
  <DialogContent className="overflow-hidden p-0">
30
+ <DialogTitle className="sr-only">Search</DialogTitle>
31
+ <DialogDescription className="sr-only">Search for documentation and components.</DialogDescription>
30
32
  <Command className="[&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:px-2 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5">
31
33
  {children}
32
34
  </Command>
@@ -9,6 +9,8 @@ vi.mock('@/components/ui/dialog', () => ({
9
9
  DialogContent: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
10
10
  DialogPortal: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
11
11
  DialogOverlay: () => null,
12
+ DialogTitle: ({ children }: { children: React.ReactNode }) => <h2>{children}</h2>,
13
+ DialogDescription: ({ children }: { children: React.ReactNode }) => <p>{children}</p>,
12
14
  }));
13
15
 
14
16
  describe('Search', () => {
@@ -70,8 +70,8 @@ export const SearchTrigger = React.forwardRef<HTMLButtonElement, SearchTriggerPr
70
70
  className={cn(
71
71
  'relative h-9 text-sm text-muted-foreground transition-all transition-colors',
72
72
  variant === 'default'
73
- ? 'w-full justify-start sm:pr-12 md:w-40 lg:w-64'
74
- : 'w-9 justify-center px-0 sm:w-24 sm:justify-start sm:px-3 sm:pr-12',
73
+ ? 'w-full justify-start pr-12'
74
+ : 'w-9 justify-center px-0 md:w-40 md:justify-start md:px-3 md:pr-12 lg:w-64',
75
75
  className,
76
76
  )}
77
77
  ref={ref}
@@ -79,7 +79,7 @@ export const SearchTrigger = React.forwardRef<HTMLButtonElement, SearchTriggerPr
79
79
  >
80
80
  <span className="inline-flex items-center gap-2">
81
81
  <SearchIcon className="h-4 w-4 shrink-0" />
82
- {variant === 'default' && <span className="truncate">{placeholder}</span>}
82
+ <span className={cn('truncate', variant === 'compact' && 'hidden md:inline')}>{placeholder}</span>
83
83
  </span>
84
84
  <kbd className="pointer-events-none absolute right-1.5 top-1.5 hidden h-6 select-none items-center gap-1 rounded border bg-muted px-1.5 font-mono text-[10px] font-medium opacity-100 sm:flex">
85
85
  <span className="text-xs">⌘</span>K
@@ -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/globals.css CHANGED
@@ -33,6 +33,7 @@
33
33
  }
34
34
 
35
35
  @layer base {
36
+ /* @tokens-start */
36
37
  :root {
37
38
  --background: 0 0% 96%;
38
39
  --foreground: 222 47% 11%;
@@ -59,6 +60,25 @@
59
60
  --brand-blue: 225 73% 57%;
60
61
  --brand-green: 151 66% 27%;
61
62
  --brand-floral-white: 40 100% 97%;
63
+ --neutral-white: 0 0% 100%;
64
+ --neutral-black: 0 0% 0%;
65
+ --neutral-gray50: 0 0% 96%;
66
+ --neutral-gray100: 0 0% 92%;
67
+ --neutral-gray200: 0 0% 89%;
68
+ --neutral-gray300: 0 0% 88%;
69
+ --neutral-gray400: 0 0% 70%;
70
+ --neutral-gray500: 215 16% 47%;
71
+ --neutral-gray600: 222 47% 11%;
72
+ --neutral-gray700: 0 0% 18%;
73
+ --neutral-gray800: 0 0% 15%;
74
+ --neutral-gray900: 0 0% 14%;
75
+ --neutral-gray950: 0 0% 11%;
76
+ --neutral-gray975: 0 0% 9%;
77
+ --neutral-gray990: 0 0% 6%;
78
+ --semantic-success: 93 28% 54%;
79
+ --semantic-success-dark: 96 44% 61%;
80
+ --semantic-destructive: 0 84.2% 60.2%;
81
+ --semantic-destructive-dark: 0 62.8% 30.6%;
62
82
  }
63
83
 
64
84
  .dark {
@@ -81,7 +101,9 @@
81
101
  --border: 0 0% 18%;
82
102
  --input: 0 0% 18%;
83
103
  --ring: 0 0% 90%;
104
+ --radius: 0.5rem;
84
105
  }
106
+ /* @tokens-end */
85
107
  }
86
108
 
87
109
  @layer base {
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';
@@ -7,8 +7,8 @@ export function ColorTokensDocs() {
7
7
  return (
8
8
  <div className="space-y-12">
9
9
  <div className="space-y-4">
10
- <h1 className="text-4xl font-extrabold tracking-tight">Color Tokens</h1>
11
- <p className="text-xl text-muted-foreground max-w-2xl">
10
+ <h1 className="text-3xl md:text-4xl font-extrabold tracking-tight">Color Tokens</h1>
11
+ <p className="text-lg md:text-xl text-muted-foreground max-w-2xl">
12
12
  The Garcia Ventures design system is built on a robust token architecture that ensures consistency,
13
13
  accessibility, and easy maintenance across all digital products.
14
14
  </p>
@@ -167,8 +167,8 @@ const MyComponent = () => {
167
167
 
168
168
  <section className="space-y-6">
169
169
  <h2 className="text-3xl font-bold tracking-tight">Semantic Tokens Reference</h2>
170
- <div className="rounded-xl border shadow-sm overflow-hidden">
171
- <Table>
170
+ <div className="rounded-xl border shadow-sm overflow-x-auto">
171
+ <Table className="min-w-[600px] md:min-w-full">
172
172
  <TableHeader>
173
173
  <TableRow className="bg-muted/50 hover:bg-muted/50">
174
174
  <TableHead className="w-[200px]">Token</TableHead>
@@ -6,8 +6,10 @@ export function GettingStartedPage() {
6
6
  return (
7
7
  <div className="space-y-8">
8
8
  <div className="space-y-2">
9
- <h1 className="text-4xl font-bold tracking-tight">GV Tech Design System</h1>
10
- <p className="text-xl text-muted-foreground">
9
+ <h1 className="text-3xl md:text-4xl font-bold tracking-tight text-center md:text-left">
10
+ GV Tech Design System
11
+ </h1>
12
+ <p className="text-lg md:text-xl text-muted-foreground text-center md:text-left">
11
13
  A comprehensive React component library built with shadcn/ui and Tailwind CSS.
12
14
  </p>
13
15
  </div>
@@ -100,8 +102,8 @@ export function InstallationPage() {
100
102
  return (
101
103
  <div className="space-y-8">
102
104
  <div className="space-y-2">
103
- <h1 className="text-3xl font-bold tracking-tight">Installation</h1>
104
- <p className="text-lg text-muted-foreground">
105
+ <h1 className="text-2xl md:text-3xl font-bold tracking-tight">Installation</h1>
106
+ <p className="text-base md:text-lg text-muted-foreground">
105
107
  Get started with the GV Tech Design System in your React project.
106
108
  </p>
107
109
  </div>
@@ -133,10 +135,34 @@ export function InstallationPage() {
133
135
  <CodeBlock
134
136
  code={`{
135
137
  "react": "^18 || ^19",
136
- "react-dom": "^18 || ^19"
138
+ "react-dom": "^18 || ^19",
139
+ "next-themes": "^0.4.0"
137
140
  }`}
138
141
  language="json"
139
142
  />
143
+ <p className="text-sm text-muted-foreground">
144
+ <code className="text-sm bg-muted px-1.5 py-0.5 rounded">next-themes</code> is required for the design
145
+ system's <code className="text-sm bg-muted px-1.5 py-0.5 rounded">ThemeProvider</code>,{' '}
146
+ <code className="text-sm bg-muted px-1.5 py-0.5 rounded">ThemeToggle</code>, and{' '}
147
+ <code className="text-sm bg-muted px-1.5 py-0.5 rounded">useTheme</code> to work. Install it alongside the
148
+ design system:
149
+ </p>
150
+ <Tabs defaultValue="npm" className="w-full">
151
+ <TabsList>
152
+ <TabsTrigger value="npm">npm</TabsTrigger>
153
+ <TabsTrigger value="yarn">yarn</TabsTrigger>
154
+ <TabsTrigger value="pnpm">pnpm</TabsTrigger>
155
+ </TabsList>
156
+ <TabsContent value="npm" className="mt-4">
157
+ <CodeBlock code="npm install next-themes" language="bash" />
158
+ </TabsContent>
159
+ <TabsContent value="yarn" className="mt-4">
160
+ <CodeBlock code="yarn add next-themes" language="bash" />
161
+ </TabsContent>
162
+ <TabsContent value="pnpm" className="mt-4">
163
+ <CodeBlock code="pnpm add next-themes" language="bash" />
164
+ </TabsContent>
165
+ </Tabs>
140
166
  </section>
141
167
 
142
168
  <section className="space-y-4">
@@ -253,15 +279,22 @@ module.exports = {
253
279
 
254
280
  <section className="space-y-4">
255
281
  <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>
282
+ <p className="text-muted-foreground">
283
+ Wrap your app with <code className="text-sm bg-muted px-1.5 py-0.5 rounded">ThemeProvider</code> and start
284
+ importing components:
285
+ </p>
257
286
  <CodeBlock
258
- code={`import { Button } from '@gv-tech/design-system';
287
+ code={`import { ThemeProvider, ThemeToggle, Button } from '@gv-tech/design-system';
288
+ import '@gv-tech/design-system/style.css';
259
289
 
260
290
  export default function App() {
261
291
  return (
262
- <Button variant="default">
263
- Click me
264
- </Button>
292
+ <ThemeProvider>
293
+ <div>
294
+ <ThemeToggle variant="ternary" />
295
+ <Button variant="default">Click me</Button>
296
+ </div>
297
+ </ThemeProvider>
265
298
  );
266
299
  }`}
267
300
  />
@@ -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
  );
@@ -9,51 +9,73 @@ export const palette = {
9
9
  green: 'hsl(151 66% 27%)', // #177245 (Stability)
10
10
  floralWhite: 'hsl(40 100% 97%)', // Light Neutral / Floral White
11
11
  },
12
- // Additional primitives can be added here
12
+ neutral: {
13
+ white: 'hsl(0 0% 100%)',
14
+ black: 'hsl(0 0% 0%)', // Pure Black
15
+ gray50: 'hsl(0 0% 96%)', // White Smoke
16
+ gray100: 'hsl(0 0% 92%)', // Gainsboro
17
+ gray200: 'hsl(0 0% 89%)', // Light Gray
18
+ gray300: 'hsl(0 0% 88%)', // French Gray
19
+ gray400: 'hsl(0 0% 70%)', // Silver
20
+ gray500: 'hsl(215 16% 47%)', // Steel Blue
21
+ gray600: 'hsl(222 47% 11%)', // Oxford Blue
22
+ gray700: 'hsl(0 0% 18%)', // Raisin Black
23
+ gray800: 'hsl(0 0% 15%)', // Jet
24
+ gray900: 'hsl(0 0% 14%)', // Eerie Black
25
+ gray950: 'hsl(0 0% 11%)', // Night (alt)
26
+ gray975: 'hsl(0 0% 9%)', // Night
27
+ gray990: 'hsl(0 0% 6%)', // Black (almost)
28
+ },
29
+ semantic: {
30
+ success: 'hsl(93 28% 54%)', // Asparagus / Pistachio
31
+ successDark: 'hsl(96 44% 61%)',
32
+ destructive: 'hsl(0 84.2% 60.2%)', // Vivid Red
33
+ destructiveDark: 'hsl(0 62.8% 30.6%)', // Blood Red
34
+ },
13
35
  } as const;
14
36
 
15
37
  export const theme = {
16
38
  light: {
17
- background: 'hsl(0 0% 96%)', // White Smoke
18
- foreground: 'hsl(222 47% 11%)', // Oxford Blue
19
- card: 'hsl(0 0% 100%)', // White
20
- cardForeground: 'hsl(222 47% 11%)', // Oxford Blue
21
- popover: 'hsl(0 0% 100%)', // White
22
- popoverForeground: 'hsl(222 47% 11%)', // Oxford Blue
23
- primary: palette.brand.blue, // Royal Blue (Intellect)
24
- primaryForeground: 'hsl(0 0% 100%)', // White
25
- secondary: 'hsl(93 28% 54%)', // Asparagus / Pistachio
26
- secondaryForeground: 'hsl(0 0% 100%)', // White
27
- muted: 'hsl(0 0% 92%)', // Gainsboro
28
- mutedForeground: 'hsl(215 16% 47%)', // Steel Blue
29
- accent: 'hsl(0 0% 88%)', // French Gray
30
- accentForeground: 'hsl(222 47% 11%)', // Oxford Blue
31
- destructive: 'hsl(0 84.2% 60.2%)', // Vivid Red
32
- destructiveForeground: 'hsl(0 0% 100%)', // White
33
- border: 'hsl(0 0% 89%)', // Light Gray
34
- input: 'hsl(0 0% 89%)', // Light Gray
35
- ring: 'hsl(222 47% 11%)', // Oxford Blue
39
+ background: palette.neutral.gray50,
40
+ foreground: palette.neutral.gray600,
41
+ card: palette.neutral.white,
42
+ cardForeground: palette.neutral.gray600,
43
+ popover: palette.neutral.white,
44
+ popoverForeground: palette.neutral.gray600,
45
+ primary: palette.brand.blue,
46
+ primaryForeground: palette.neutral.white,
47
+ secondary: palette.semantic.success,
48
+ secondaryForeground: palette.neutral.white,
49
+ muted: palette.neutral.gray100,
50
+ mutedForeground: palette.neutral.gray500,
51
+ accent: palette.neutral.gray300,
52
+ accentForeground: palette.neutral.gray600,
53
+ destructive: palette.semantic.destructive,
54
+ destructiveForeground: palette.neutral.white,
55
+ border: palette.neutral.gray200,
56
+ input: palette.neutral.gray200,
57
+ ring: palette.neutral.gray600,
36
58
  radius: '0.5rem',
37
59
  },
38
60
  dark: {
39
- background: 'hsl(0 0% 9%)', // Night
40
- foreground: 'hsl(0 0% 100%)', // White
41
- card: 'hsl(0 0% 14%)', // Eerie Black
42
- cardForeground: 'hsl(0 0% 100%)', // White
43
- popover: 'hsl(0 0% 11%)', // Night (alt)
44
- popoverForeground: 'hsl(0 0% 100%)', // White
45
- primary: 'hsl(227 96% 71%)', // Baby Blue
46
- primaryForeground: 'hsl(0 0% 9%)', // Night
47
- secondary: 'hsl(96 44% 61%)', // Celadon
48
- secondaryForeground: 'hsl(0 0% 9%)', // Night
49
- muted: 'hsl(0 0% 6%)', // Black
50
- mutedForeground: 'hsl(0 0% 70%)', // Silver
51
- accent: 'hsl(0 0% 15%)', // Jet
52
- accentForeground: 'hsl(0 0% 100%)', // White
53
- destructive: 'hsl(0 62.8% 30.6%)', // Blood Red
54
- destructiveForeground: 'hsl(0 0% 100%)', // White
55
- border: 'hsl(0 0% 18%)', // Raisin Black
56
- input: 'hsl(0 0% 18%)', // Raisin Black
61
+ background: palette.neutral.gray975,
62
+ foreground: palette.neutral.white,
63
+ card: palette.neutral.gray900,
64
+ cardForeground: palette.neutral.white,
65
+ popover: palette.neutral.gray950,
66
+ popoverForeground: palette.neutral.white,
67
+ primary: 'hsl(227 96% 71%)', // Keeping as specific HSL to match original
68
+ primaryForeground: palette.neutral.gray975,
69
+ secondary: palette.semantic.successDark,
70
+ secondaryForeground: palette.neutral.gray975,
71
+ muted: palette.neutral.gray990,
72
+ mutedForeground: palette.neutral.gray400,
73
+ accent: palette.neutral.gray800,
74
+ accentForeground: palette.neutral.white,
75
+ destructive: palette.semantic.destructiveDark,
76
+ destructiveForeground: palette.neutral.white,
77
+ border: palette.neutral.gray700,
78
+ input: palette.neutral.gray700,
57
79
  ring: 'hsl(0 0% 90%)', // Platinum
58
80
  radius: '0.5rem',
59
81
  },