@smicolon/fasla-ui 0.2.2

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 +141 -0
  2. package/bin/fasla-ui.mjs +54 -0
  3. package/dist/index.d.ts +5 -0
  4. package/dist/index.js +241 -0
  5. package/dist/lib/utils.d.ts +9 -0
  6. package/dist/lib/utils.js +9 -0
  7. package/dist/motion/index.d.ts +33 -0
  8. package/dist/motion/index.js +59 -0
  9. package/dist/registry/index.d.ts +17 -0
  10. package/dist/registry/index.js +145 -0
  11. package/dist/tokens/index.d.ts +55 -0
  12. package/dist/tokens/index.js +34 -0
  13. package/package.json +97 -0
  14. package/registry/blocks/app-shell/AppShell.tsx +66 -0
  15. package/registry/blocks/app-shell/index.ts +1 -0
  16. package/registry/blocks/data-table/DataTable.tsx +292 -0
  17. package/registry/blocks/data-table/index.ts +7 -0
  18. package/registry/blocks/empty-state/EmptyState.test.tsx +120 -0
  19. package/registry/blocks/empty-state/EmptyState.tsx +164 -0
  20. package/registry/blocks/empty-state/index.ts +6 -0
  21. package/registry/blocks/form-section/FormSection.tsx +140 -0
  22. package/registry/blocks/form-section/index.ts +8 -0
  23. package/registry/blocks/navbar/Navbar.tsx +190 -0
  24. package/registry/blocks/navbar/index.ts +16 -0
  25. package/registry/blocks/page-header/PageHeader.tsx +64 -0
  26. package/registry/blocks/page-header/index.ts +1 -0
  27. package/registry/blocks/sidebar/Sidebar.tsx +202 -0
  28. package/registry/blocks/sidebar/index.ts +16 -0
  29. package/registry/blocks/stats-card/StatsCard.tsx +134 -0
  30. package/registry/blocks/stats-card/index.ts +6 -0
  31. package/registry/effects/animated-gradient/animated-gradient.tsx +136 -0
  32. package/registry/effects/animated-gradient/index.ts +6 -0
  33. package/registry/effects/border-beam/border-beam.tsx +132 -0
  34. package/registry/effects/border-beam/index.ts +6 -0
  35. package/registry/effects/glow-card/glow-card.tsx +145 -0
  36. package/registry/effects/glow-card/index.ts +6 -0
  37. package/registry/effects/shimmer-button/index.ts +1 -0
  38. package/registry/effects/shimmer-button/shimmer-button.tsx +91 -0
  39. package/registry/effects/spotlight/index.ts +6 -0
  40. package/registry/effects/spotlight/spotlight.tsx +162 -0
  41. package/registry/effects/text-reveal/index.ts +6 -0
  42. package/registry/effects/text-reveal/text-reveal.tsx +139 -0
  43. package/registry/effects/typewriter-text/index.ts +6 -0
  44. package/registry/effects/typewriter-text/typewriter-text.tsx +220 -0
  45. package/registry/ui/avatar/avatar.tsx +135 -0
  46. package/registry/ui/avatar/index.ts +1 -0
  47. package/registry/ui/badge/badge.test.tsx +51 -0
  48. package/registry/ui/badge/badge.tsx +39 -0
  49. package/registry/ui/badge/index.ts +1 -0
  50. package/registry/ui/button/button.test.tsx +87 -0
  51. package/registry/ui/button/button.tsx +88 -0
  52. package/registry/ui/button/index.ts +1 -0
  53. package/registry/ui/card/card.test.tsx +119 -0
  54. package/registry/ui/card/card.tsx +75 -0
  55. package/registry/ui/card/index.ts +8 -0
  56. package/registry/ui/checkbox/checkbox.tsx +113 -0
  57. package/registry/ui/checkbox/index.ts +1 -0
  58. package/registry/ui/combobox/combobox.tsx +410 -0
  59. package/registry/ui/combobox/index.ts +1 -0
  60. package/registry/ui/input/index.ts +1 -0
  61. package/registry/ui/input/input.test.tsx +78 -0
  62. package/registry/ui/input/input.tsx +76 -0
  63. package/registry/ui/select/index.ts +1 -0
  64. package/registry/ui/select/select.tsx +94 -0
  65. package/registry/ui/skeleton/index.ts +7 -0
  66. package/registry/ui/skeleton/skeleton.test.tsx +104 -0
  67. package/registry/ui/skeleton/skeleton.tsx +88 -0
  68. package/registry/ui/switch/index.ts +1 -0
  69. package/registry/ui/switch/switch.tsx +89 -0
  70. package/registry/ui/tabs/index.ts +10 -0
  71. package/registry/ui/tabs/tabs.tsx +150 -0
  72. package/registry/ui/textarea/index.ts +1 -0
  73. package/registry/ui/textarea/textarea.tsx +73 -0
  74. package/registry.json +247 -0
@@ -0,0 +1,119 @@
1
+ import { describe, it, expect, vi } from "vitest"
2
+ import { render, screen } from "@testing-library/react"
3
+ import {
4
+ Card,
5
+ CardHeader,
6
+ CardTitle,
7
+ CardDescription,
8
+ CardContent,
9
+ CardFooter,
10
+ } from "./card"
11
+
12
+ describe("Card", () => {
13
+ it("renders Card with children", () => {
14
+ render(<Card>Card content</Card>)
15
+ expect(screen.getByText("Card content")).toBeInTheDocument()
16
+ })
17
+
18
+ it("renders Card with correct base classes", () => {
19
+ render(<Card data-testid="card">Content</Card>)
20
+ const card = screen.getByTestId("card")
21
+ expect(card).toHaveClass("rounded-xl", "border", "bg-card", "shadow")
22
+ })
23
+
24
+ it("applies custom className to Card", () => {
25
+ render(<Card className="custom-class" data-testid="card">Content</Card>)
26
+ expect(screen.getByTestId("card")).toHaveClass("custom-class")
27
+ })
28
+
29
+ it("forwards ref to Card", () => {
30
+ const ref = vi.fn()
31
+ render(<Card ref={ref}>Content</Card>)
32
+ expect(ref).toHaveBeenCalled()
33
+ })
34
+ })
35
+
36
+ describe("CardHeader", () => {
37
+ it("renders CardHeader with children", () => {
38
+ render(<CardHeader>Header content</CardHeader>)
39
+ expect(screen.getByText("Header content")).toBeInTheDocument()
40
+ })
41
+
42
+ it("renders CardHeader with correct classes", () => {
43
+ render(<CardHeader data-testid="header">Header</CardHeader>)
44
+ expect(screen.getByTestId("header")).toHaveClass("flex", "flex-col", "p-6")
45
+ })
46
+
47
+ it("applies custom className to CardHeader", () => {
48
+ render(<CardHeader className="custom-class" data-testid="header">Header</CardHeader>)
49
+ expect(screen.getByTestId("header")).toHaveClass("custom-class")
50
+ })
51
+ })
52
+
53
+ describe("CardTitle", () => {
54
+ it("renders CardTitle with children", () => {
55
+ render(<CardTitle>My Title</CardTitle>)
56
+ expect(screen.getByText("My Title")).toBeInTheDocument()
57
+ })
58
+
59
+ it("renders CardTitle with correct classes", () => {
60
+ render(<CardTitle data-testid="title">Title</CardTitle>)
61
+ expect(screen.getByTestId("title")).toHaveClass("font-semibold", "leading-none")
62
+ })
63
+ })
64
+
65
+ describe("CardDescription", () => {
66
+ it("renders CardDescription with children", () => {
67
+ render(<CardDescription>Description text</CardDescription>)
68
+ expect(screen.getByText("Description text")).toBeInTheDocument()
69
+ })
70
+
71
+ it("renders CardDescription with correct classes", () => {
72
+ render(<CardDescription data-testid="desc">Description</CardDescription>)
73
+ expect(screen.getByTestId("desc")).toHaveClass("text-sm", "text-muted-foreground")
74
+ })
75
+ })
76
+
77
+ describe("CardContent", () => {
78
+ it("renders CardContent with children", () => {
79
+ render(<CardContent>Content here</CardContent>)
80
+ expect(screen.getByText("Content here")).toBeInTheDocument()
81
+ })
82
+
83
+ it("renders CardContent with correct classes", () => {
84
+ render(<CardContent data-testid="content">Content</CardContent>)
85
+ expect(screen.getByTestId("content")).toHaveClass("p-6", "pt-0")
86
+ })
87
+ })
88
+
89
+ describe("CardFooter", () => {
90
+ it("renders CardFooter with children", () => {
91
+ render(<CardFooter>Footer content</CardFooter>)
92
+ expect(screen.getByText("Footer content")).toBeInTheDocument()
93
+ })
94
+
95
+ it("renders CardFooter with correct classes", () => {
96
+ render(<CardFooter data-testid="footer">Footer</CardFooter>)
97
+ expect(screen.getByTestId("footer")).toHaveClass("flex", "items-center", "p-6", "pt-0")
98
+ })
99
+ })
100
+
101
+ describe("Full Card composition", () => {
102
+ it("renders a complete card with all parts", () => {
103
+ render(
104
+ <Card>
105
+ <CardHeader>
106
+ <CardTitle>Card Title</CardTitle>
107
+ <CardDescription>Card description</CardDescription>
108
+ </CardHeader>
109
+ <CardContent>Main content</CardContent>
110
+ <CardFooter>Footer actions</CardFooter>
111
+ </Card>
112
+ )
113
+
114
+ expect(screen.getByText("Card Title")).toBeInTheDocument()
115
+ expect(screen.getByText("Card description")).toBeInTheDocument()
116
+ expect(screen.getByText("Main content")).toBeInTheDocument()
117
+ expect(screen.getByText("Footer actions")).toBeInTheDocument()
118
+ })
119
+ })
@@ -0,0 +1,75 @@
1
+ import * as React from "react"
2
+ import { cn } from "../../../src/lib/utils"
3
+
4
+ const Card = React.forwardRef<
5
+ HTMLDivElement,
6
+ React.HTMLAttributes<HTMLDivElement>
7
+ >(({ className, ...props }, ref) => (
8
+ <div
9
+ ref={ref}
10
+ className={cn(
11
+ "rounded-xl border bg-card text-card-foreground shadow",
12
+ className
13
+ )}
14
+ {...props}
15
+ />
16
+ ))
17
+ Card.displayName = "Card"
18
+
19
+ const CardHeader = React.forwardRef<
20
+ HTMLDivElement,
21
+ React.HTMLAttributes<HTMLDivElement>
22
+ >(({ className, ...props }, ref) => (
23
+ <div
24
+ ref={ref}
25
+ className={cn("flex flex-col space-y-1.5 p-6", className)}
26
+ {...props}
27
+ />
28
+ ))
29
+ CardHeader.displayName = "CardHeader"
30
+
31
+ const CardTitle = React.forwardRef<
32
+ HTMLDivElement,
33
+ React.HTMLAttributes<HTMLDivElement>
34
+ >(({ className, ...props }, ref) => (
35
+ <div
36
+ ref={ref}
37
+ className={cn("font-semibold leading-none tracking-tight", className)}
38
+ {...props}
39
+ />
40
+ ))
41
+ CardTitle.displayName = "CardTitle"
42
+
43
+ const CardDescription = React.forwardRef<
44
+ HTMLDivElement,
45
+ React.HTMLAttributes<HTMLDivElement>
46
+ >(({ className, ...props }, ref) => (
47
+ <div
48
+ ref={ref}
49
+ className={cn("text-sm text-muted-foreground", className)}
50
+ {...props}
51
+ />
52
+ ))
53
+ CardDescription.displayName = "CardDescription"
54
+
55
+ const CardContent = React.forwardRef<
56
+ HTMLDivElement,
57
+ React.HTMLAttributes<HTMLDivElement>
58
+ >(({ className, ...props }, ref) => (
59
+ <div ref={ref} className={cn("p-6 pt-0", className)} {...props} />
60
+ ))
61
+ CardContent.displayName = "CardContent"
62
+
63
+ const CardFooter = React.forwardRef<
64
+ HTMLDivElement,
65
+ React.HTMLAttributes<HTMLDivElement>
66
+ >(({ className, ...props }, ref) => (
67
+ <div
68
+ ref={ref}
69
+ className={cn("flex items-center p-6 pt-0", className)}
70
+ {...props}
71
+ />
72
+ ))
73
+ CardFooter.displayName = "CardFooter"
74
+
75
+ export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent }
@@ -0,0 +1,8 @@
1
+ export {
2
+ Card,
3
+ CardHeader,
4
+ CardFooter,
5
+ CardTitle,
6
+ CardDescription,
7
+ CardContent,
8
+ } from "./card"
@@ -0,0 +1,113 @@
1
+ import * as React from "react"
2
+ import { cn } from "../../../src/lib/utils"
3
+
4
+ export interface CheckboxProps
5
+ extends Omit<React.InputHTMLAttributes<HTMLInputElement>, "type"> {
6
+ /** Label text */
7
+ label?: string
8
+ /** Description text */
9
+ description?: string
10
+ /** Error state */
11
+ error?: boolean
12
+ /** Indeterminate state */
13
+ indeterminate?: boolean
14
+ }
15
+
16
+ const Checkbox = React.forwardRef<HTMLInputElement, CheckboxProps>(
17
+ ({ className, label, description, error, indeterminate, id, ...props }, ref) => {
18
+ const inputRef = React.useRef<HTMLInputElement>(null)
19
+
20
+ React.useImperativeHandle(ref, () => inputRef.current!)
21
+
22
+ React.useEffect(() => {
23
+ if (inputRef.current) {
24
+ inputRef.current.indeterminate = indeterminate ?? false
25
+ }
26
+ }, [indeterminate])
27
+
28
+ const inputId = id || React.useId()
29
+
30
+ const checkbox = (
31
+ <div className="relative flex items-center">
32
+ <input
33
+ type="checkbox"
34
+ ref={inputRef}
35
+ id={inputId}
36
+ className="peer sr-only"
37
+ {...props}
38
+ />
39
+ <div
40
+ className={cn(
41
+ "flex h-4 w-4 shrink-0 items-center justify-center rounded-sm border transition-colors",
42
+ "peer-focus-visible:outline-none peer-focus-visible:ring-2 peer-focus-visible:ring-ring peer-focus-visible:ring-offset-2",
43
+ "peer-checked:border-primary peer-checked:bg-primary peer-checked:text-primary-foreground",
44
+ "peer-disabled:cursor-not-allowed peer-disabled:opacity-50",
45
+ error
46
+ ? "border-destructive peer-checked:border-destructive peer-checked:bg-destructive"
47
+ : "border-input",
48
+ className
49
+ )}
50
+ >
51
+ <svg
52
+ width="12"
53
+ height="12"
54
+ viewBox="0 0 24 24"
55
+ fill="none"
56
+ stroke="currentColor"
57
+ strokeWidth="3"
58
+ strokeLinecap="round"
59
+ strokeLinejoin="round"
60
+ className={cn(
61
+ "opacity-0 peer-checked:opacity-100",
62
+ indeterminate ? "hidden" : "block"
63
+ )}
64
+ >
65
+ <polyline points="20 6 9 17 4 12" />
66
+ </svg>
67
+ {indeterminate && (
68
+ <svg
69
+ width="12"
70
+ height="12"
71
+ viewBox="0 0 24 24"
72
+ fill="none"
73
+ stroke="currentColor"
74
+ strokeWidth="3"
75
+ strokeLinecap="round"
76
+ >
77
+ <line x1="5" y1="12" x2="19" y2="12" />
78
+ </svg>
79
+ )}
80
+ </div>
81
+ </div>
82
+ )
83
+
84
+ if (!label && !description) {
85
+ return checkbox
86
+ }
87
+
88
+ return (
89
+ <div className="flex items-start gap-3">
90
+ {checkbox}
91
+ <div className="grid gap-1 leading-none">
92
+ {label && (
93
+ <label
94
+ htmlFor={inputId}
95
+ className={cn(
96
+ "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
97
+ error && "text-destructive"
98
+ )}
99
+ >
100
+ {label}
101
+ </label>
102
+ )}
103
+ {description && (
104
+ <p className="text-xs text-muted-foreground">{description}</p>
105
+ )}
106
+ </div>
107
+ </div>
108
+ )
109
+ }
110
+ )
111
+ Checkbox.displayName = "Checkbox"
112
+
113
+ export { Checkbox }
@@ -0,0 +1 @@
1
+ export { Checkbox, type CheckboxProps } from "./checkbox"