@motor-hero/ui-kit 0.5.1

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 (74) hide show
  1. package/README.md +52 -0
  2. package/dist/components/auth-card.d.ts +10 -0
  3. package/dist/components/auth-card.d.ts.map +1 -0
  4. package/dist/components/confirm-dialog.d.ts +15 -0
  5. package/dist/components/confirm-dialog.d.ts.map +1 -0
  6. package/dist/components/data-table-wrapper.d.ts +16 -0
  7. package/dist/components/data-table-wrapper.d.ts.map +1 -0
  8. package/dist/components/empty-state.d.ts +11 -0
  9. package/dist/components/empty-state.d.ts.map +1 -0
  10. package/dist/components/form-dialog.d.ts +14 -0
  11. package/dist/components/form-dialog.d.ts.map +1 -0
  12. package/dist/components/form-field.d.ts +12 -0
  13. package/dist/components/form-field.d.ts.map +1 -0
  14. package/dist/components/mobile-card-list.d.ts +12 -0
  15. package/dist/components/mobile-card-list.d.ts.map +1 -0
  16. package/dist/components/mode-toggle.d.ts +2 -0
  17. package/dist/components/mode-toggle.d.ts.map +1 -0
  18. package/dist/components/page-header.d.ts +10 -0
  19. package/dist/components/page-header.d.ts.map +1 -0
  20. package/dist/components/pagination.d.ts +10 -0
  21. package/dist/components/pagination.d.ts.map +1 -0
  22. package/dist/components/responsive-data-view.d.ts +14 -0
  23. package/dist/components/responsive-data-view.d.ts.map +1 -0
  24. package/dist/components/search-input.d.ts +7 -0
  25. package/dist/components/search-input.d.ts.map +1 -0
  26. package/dist/components/stat-card.d.ts +11 -0
  27. package/dist/components/stat-card.d.ts.map +1 -0
  28. package/dist/components/status-dot.d.ts +8 -0
  29. package/dist/components/status-dot.d.ts.map +1 -0
  30. package/dist/components/table-skeleton.d.ts +7 -0
  31. package/dist/components/table-skeleton.d.ts.map +1 -0
  32. package/dist/components/theme-provider.d.ts +14 -0
  33. package/dist/components/theme-provider.d.ts.map +1 -0
  34. package/dist/components/toaster.d.ts +5 -0
  35. package/dist/components/toaster.d.ts.map +1 -0
  36. package/dist/hooks/use-disclosure.d.ts +8 -0
  37. package/dist/hooks/use-disclosure.d.ts.map +1 -0
  38. package/dist/hooks/use-toast.d.ts +5 -0
  39. package/dist/hooks/use-toast.d.ts.map +1 -0
  40. package/dist/index.cjs +620 -0
  41. package/dist/index.cjs.map +1 -0
  42. package/dist/index.d.ts +23 -0
  43. package/dist/index.d.ts.map +1 -0
  44. package/dist/index.js +561 -0
  45. package/dist/index.js.map +1 -0
  46. package/dist/lib/api-error.d.ts +2 -0
  47. package/dist/lib/api-error.d.ts.map +1 -0
  48. package/dist/lib/utils.d.ts +3 -0
  49. package/dist/lib/utils.d.ts.map +1 -0
  50. package/dist/styles.css +45 -0
  51. package/package.json +80 -0
  52. package/src/components/auth-card.tsx +25 -0
  53. package/src/components/confirm-dialog.tsx +58 -0
  54. package/src/components/data-table-wrapper.tsx +65 -0
  55. package/src/components/empty-state.tsx +22 -0
  56. package/src/components/form-dialog.tsx +48 -0
  57. package/src/components/form-field.tsx +26 -0
  58. package/src/components/mobile-card-list.tsx +54 -0
  59. package/src/components/mode-toggle.tsx +47 -0
  60. package/src/components/page-header.tsx +22 -0
  61. package/src/components/pagination.tsx +31 -0
  62. package/src/components/responsive-data-view.tsx +31 -0
  63. package/src/components/search-input.tsx +36 -0
  64. package/src/components/stat-card.tsx +35 -0
  65. package/src/components/status-dot.tsx +16 -0
  66. package/src/components/table-skeleton.tsx +20 -0
  67. package/src/components/theme-provider.tsx +69 -0
  68. package/src/components/toaster.tsx +31 -0
  69. package/src/hooks/use-disclosure.ts +9 -0
  70. package/src/hooks/use-toast.ts +30 -0
  71. package/src/index.ts +29 -0
  72. package/src/lib/api-error.ts +7 -0
  73. package/src/lib/utils.ts +6 -0
  74. package/src/styles.css +45 -0
@@ -0,0 +1,20 @@
1
+ interface TableSkeletonProps {
2
+ rows?: number
3
+ columns?: number
4
+ }
5
+
6
+ export function TableSkeleton({ rows = 5, columns = 4 }: TableSkeletonProps) {
7
+ return (
8
+ <>
9
+ {Array.from({ length: rows }).map((_, i) => (
10
+ <tr key={i} className="border-b transition-colors">
11
+ {Array.from({ length: columns }).map((_, j) => (
12
+ <td key={j} className="p-4 align-middle">
13
+ <div className="h-5 w-full animate-pulse rounded bg-muted" />
14
+ </td>
15
+ ))}
16
+ </tr>
17
+ ))}
18
+ </>
19
+ )
20
+ }
@@ -0,0 +1,69 @@
1
+ import { createContext, useContext, useEffect, useState } from "react"
2
+
3
+ type Theme = "dark" | "light" | "system"
4
+
5
+ type ThemeProviderProps = {
6
+ children: React.ReactNode
7
+ defaultTheme?: Theme
8
+ storageKey?: string
9
+ }
10
+
11
+ type ThemeProviderState = {
12
+ theme: Theme
13
+ setTheme: (theme: Theme) => void
14
+ }
15
+
16
+ const initialState: ThemeProviderState = {
17
+ theme: "system",
18
+ setTheme: () => null,
19
+ }
20
+
21
+ const ThemeProviderContext = createContext<ThemeProviderState>(initialState)
22
+
23
+ export function ThemeProvider({
24
+ children,
25
+ defaultTheme = "system",
26
+ storageKey = "ui-theme",
27
+ ...props
28
+ }: ThemeProviderProps) {
29
+ const [theme, setTheme] = useState<Theme>(
30
+ () => (localStorage.getItem(storageKey) as Theme) || defaultTheme
31
+ )
32
+
33
+ useEffect(() => {
34
+ const root = window.document.documentElement
35
+ root.classList.remove("light", "dark")
36
+ if (theme === "system") {
37
+ const systemTheme = window.matchMedia("(prefers-color-scheme: dark)").matches
38
+ ? "dark"
39
+ : "light"
40
+ root.classList.add(systemTheme)
41
+ return
42
+ }
43
+ root.classList.add(theme)
44
+ }, [theme])
45
+
46
+ const value = {
47
+ theme,
48
+ setTheme: (theme: Theme) => {
49
+ localStorage.setItem(storageKey, theme)
50
+ setTheme(theme)
51
+ },
52
+ }
53
+
54
+ return (
55
+ <ThemeProviderContext.Provider {...props} value={value}>
56
+ {children}
57
+ </ThemeProviderContext.Provider>
58
+ )
59
+ }
60
+
61
+ export function useTheme() {
62
+ const context = useContext(ThemeProviderContext)
63
+ if (context === undefined) {
64
+ throw new Error("useTheme must be used within a ThemeProvider")
65
+ }
66
+ return context
67
+ }
68
+
69
+ export type { Theme, ThemeProviderProps, ThemeProviderState }
@@ -0,0 +1,31 @@
1
+ import { useTheme } from "./theme-provider"
2
+ import { Toaster as Sonner } from "sonner"
3
+
4
+ type ToasterProps = React.ComponentProps<typeof Sonner>
5
+
6
+ export function Toaster(props: ToasterProps) {
7
+ const { theme = "system" } = useTheme()
8
+
9
+ return (
10
+ <Sonner
11
+ theme={theme as ToasterProps["theme"]}
12
+ className="toaster group"
13
+ toastOptions={{
14
+ classNames: {
15
+ toast:
16
+ "group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-md",
17
+ description: "group-[.toast]:text-muted-foreground",
18
+ actionButton:
19
+ "group-[.toast]:bg-primary group-[.toast]:text-primary-foreground",
20
+ cancelButton:
21
+ "group-[.toast]:bg-muted group-[.toast]:text-muted-foreground",
22
+ success:
23
+ "group-[.toaster]:!bg-background group-[.toaster]:!text-foreground group-[.toaster]:!border-success/40",
24
+ error:
25
+ "group-[.toaster]:!bg-background group-[.toaster]:!text-foreground group-[.toaster]:!border-destructive/40",
26
+ },
27
+ }}
28
+ {...props}
29
+ />
30
+ )
31
+ }
@@ -0,0 +1,9 @@
1
+ import { useCallback, useState } from "react"
2
+
3
+ export function useDisclosure(initial = false) {
4
+ const [open, setOpen] = useState(initial)
5
+ const onOpen = useCallback(() => setOpen(true), [])
6
+ const onClose = useCallback(() => setOpen(false), [])
7
+ const onToggle = useCallback(() => setOpen((v) => !v), [])
8
+ return { open, onOpen, onClose, onToggle, setOpen }
9
+ }
@@ -0,0 +1,30 @@
1
+ import { toast } from "sonner"
2
+ import { useCallback } from "react"
3
+
4
+ type ToastStatus = "success" | "error" | "info" | "warning"
5
+
6
+ export function useCustomToast() {
7
+ const showToast = useCallback(
8
+ (title: string, description?: string, status: ToastStatus = "success") => {
9
+ switch (status) {
10
+ case "success":
11
+ toast.success(title, { description })
12
+ break
13
+ case "error":
14
+ toast.error(title, { description })
15
+ break
16
+ case "info":
17
+ toast.info(title, { description })
18
+ break
19
+ case "warning":
20
+ toast.warning(title, { description })
21
+ break
22
+ }
23
+ },
24
+ [],
25
+ )
26
+
27
+ return showToast
28
+ }
29
+
30
+ export { toast }
package/src/index.ts ADDED
@@ -0,0 +1,29 @@
1
+ // Theme
2
+ export { ThemeProvider, useTheme } from "./components/theme-provider"
3
+ export type { Theme, ThemeProviderProps, ThemeProviderState } from "./components/theme-provider"
4
+
5
+ // Components
6
+ export { ModeToggle } from "./components/mode-toggle"
7
+ export { EmptyState } from "./components/empty-state"
8
+ export { ConfirmDialog } from "./components/confirm-dialog"
9
+ export { PageHeader } from "./components/page-header"
10
+ export { StatusDot } from "./components/status-dot"
11
+ export { FormField } from "./components/form-field"
12
+ export { FormDialogLayout } from "./components/form-dialog"
13
+ export { AuthCard } from "./components/auth-card"
14
+ export { Pagination } from "./components/pagination"
15
+ export { TableSkeleton } from "./components/table-skeleton"
16
+ export { SearchInput } from "./components/search-input"
17
+ export { StatCard } from "./components/stat-card"
18
+ export { DataTableWrapper } from "./components/data-table-wrapper"
19
+ export { MobileCardList } from "./components/mobile-card-list"
20
+ export { ResponsiveDataView } from "./components/responsive-data-view"
21
+ export { Toaster } from "./components/toaster"
22
+
23
+ // Utilities
24
+ export { cn } from "./lib/utils"
25
+ export { extractApiError } from "./lib/api-error"
26
+
27
+ // Hooks
28
+ export { useDisclosure } from "./hooks/use-disclosure"
29
+ export { useCustomToast, toast } from "./hooks/use-toast"
@@ -0,0 +1,7 @@
1
+ export function extractApiError(err: any, fallbackMessage = "Ocorreu um erro inesperado."): string {
2
+ const detail = err?.body?.detail || err?.message
3
+ if (Array.isArray(detail) && detail.length > 0) {
4
+ return detail[0].msg
5
+ }
6
+ return detail || fallbackMessage
7
+ }
@@ -0,0 +1,6 @@
1
+ import { type ClassValue, clsx } from "clsx"
2
+ import { twMerge } from "tailwind-merge"
3
+
4
+ export function cn(...inputs: ClassValue[]) {
5
+ return twMerge(clsx(inputs))
6
+ }
package/src/styles.css ADDED
@@ -0,0 +1,45 @@
1
+ /* @motor-hero/ui-kit - Zinc theme tokens */
2
+ :root {
3
+ --background: 0 0% 100%;
4
+ --foreground: 240 10% 3.9%;
5
+ --card: 0 0% 100%;
6
+ --card-foreground: 240 10% 3.9%;
7
+ --popover: 0 0% 100%;
8
+ --popover-foreground: 240 10% 3.9%;
9
+ --primary: 240 5.9% 10%;
10
+ --primary-foreground: 0 0% 98%;
11
+ --secondary: 240 4.8% 95.9%;
12
+ --secondary-foreground: 240 5.9% 10%;
13
+ --muted: 240 4.8% 95.9%;
14
+ --muted-foreground: 240 3.8% 46.1%;
15
+ --accent: 240 4.8% 95.9%;
16
+ --accent-foreground: 240 5.9% 10%;
17
+ --destructive: 0 84.2% 60.2%;
18
+ --destructive-foreground: 0 0% 98%;
19
+ --border: 240 5.9% 90%;
20
+ --input: 240 5.9% 90%;
21
+ --ring: 240 5.9% 10%;
22
+ --radius: 0.5rem;
23
+ }
24
+
25
+ .dark {
26
+ --background: 240 10% 3.9%;
27
+ --foreground: 0 0% 98%;
28
+ --card: 240 10% 3.9%;
29
+ --card-foreground: 0 0% 98%;
30
+ --popover: 240 10% 3.9%;
31
+ --popover-foreground: 0 0% 98%;
32
+ --primary: 0 0% 98%;
33
+ --primary-foreground: 240 5.9% 10%;
34
+ --secondary: 240 3.7% 15.9%;
35
+ --secondary-foreground: 0 0% 98%;
36
+ --muted: 240 3.7% 15.9%;
37
+ --muted-foreground: 240 5% 64.9%;
38
+ --accent: 240 3.7% 15.9%;
39
+ --accent-foreground: 0 0% 98%;
40
+ --destructive: 0 62.8% 30.6%;
41
+ --destructive-foreground: 0 0% 98%;
42
+ --border: 240 3.7% 15.9%;
43
+ --input: 240 3.7% 15.9%;
44
+ --ring: 240 4.9% 83.9%;
45
+ }