@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,120 @@
1
+ import { describe, it, expect, vi } from "vitest"
2
+ import { render, screen, fireEvent } from "@testing-library/react"
3
+ import { EmptyState, EmptySearchResults, EmptyData } from "./EmptyState"
4
+
5
+ describe("EmptyState", () => {
6
+ it("renders with required title prop", () => {
7
+ render(<EmptyState title="No items found" />)
8
+ expect(screen.getByText("No items found")).toBeInTheDocument()
9
+ })
10
+
11
+ it("renders with description", () => {
12
+ render(
13
+ <EmptyState
14
+ title="No items"
15
+ description="Start by adding your first item"
16
+ />
17
+ )
18
+ expect(screen.getByText("Start by adding your first item")).toBeInTheDocument()
19
+ })
20
+
21
+ it("renders with icon", () => {
22
+ render(
23
+ <EmptyState
24
+ title="Empty"
25
+ icon={<span data-testid="icon">📭</span>}
26
+ />
27
+ )
28
+ expect(screen.getByTestId("icon")).toBeInTheDocument()
29
+ })
30
+
31
+ it("renders with action", () => {
32
+ render(
33
+ <EmptyState
34
+ title="No items"
35
+ action={<button>Add Item</button>}
36
+ />
37
+ )
38
+ expect(screen.getByRole("button", { name: "Add Item" })).toBeInTheDocument()
39
+ })
40
+
41
+ it("renders with secondary action", () => {
42
+ render(
43
+ <EmptyState
44
+ title="No items"
45
+ action={<button>Primary</button>}
46
+ secondaryAction={<button>Secondary</button>}
47
+ />
48
+ )
49
+ expect(screen.getByRole("button", { name: "Primary" })).toBeInTheDocument()
50
+ expect(screen.getByRole("button", { name: "Secondary" })).toBeInTheDocument()
51
+ })
52
+
53
+ it("renders with small size", () => {
54
+ render(<EmptyState title="Empty" size="sm" data-testid="empty" />)
55
+ expect(screen.getByTestId("empty")).toHaveClass("py-8")
56
+ })
57
+
58
+ it("renders with default size", () => {
59
+ render(<EmptyState title="Empty" size="default" data-testid="empty" />)
60
+ expect(screen.getByTestId("empty")).toHaveClass("py-12")
61
+ })
62
+
63
+ it("renders with large size", () => {
64
+ render(<EmptyState title="Empty" size="lg" data-testid="empty" />)
65
+ expect(screen.getByTestId("empty")).toHaveClass("py-16")
66
+ })
67
+
68
+ it("applies custom className", () => {
69
+ render(<EmptyState title="Empty" className="custom-class" data-testid="empty" />)
70
+ expect(screen.getByTestId("empty")).toHaveClass("custom-class")
71
+ })
72
+ })
73
+
74
+ describe("EmptySearchResults", () => {
75
+ it("renders with default no results message", () => {
76
+ render(<EmptySearchResults />)
77
+ expect(screen.getByText("No results found")).toBeInTheDocument()
78
+ })
79
+
80
+ it("renders with query in description", () => {
81
+ render(<EmptySearchResults query="test search" />)
82
+ expect(screen.getByText('No results for "test search". Try a different search term.')).toBeInTheDocument()
83
+ })
84
+
85
+ it("renders without query showing generic message", () => {
86
+ render(<EmptySearchResults />)
87
+ expect(screen.getByText("Try adjusting your search or filters.")).toBeInTheDocument()
88
+ })
89
+
90
+ it("renders search icon", () => {
91
+ const { container } = render(<EmptySearchResults />)
92
+ const svg = container.querySelector("svg")
93
+ expect(svg).toBeInTheDocument()
94
+ })
95
+ })
96
+
97
+ describe("EmptyData", () => {
98
+ it("renders with default resource name", () => {
99
+ render(<EmptyData />)
100
+ expect(screen.getByText("No items yet")).toBeInTheDocument()
101
+ expect(screen.getByText("Get started by creating your first item.")).toBeInTheDocument()
102
+ })
103
+
104
+ it("renders with custom resource name", () => {
105
+ render(<EmptyData resourceName="projects" />)
106
+ expect(screen.getByText("No projects yet")).toBeInTheDocument()
107
+ expect(screen.getByText("Get started by creating your first project.")).toBeInTheDocument()
108
+ })
109
+
110
+ it("renders with action passed through", () => {
111
+ render(<EmptyData action={<button>Create</button>} />)
112
+ expect(screen.getByRole("button", { name: "Create" })).toBeInTheDocument()
113
+ })
114
+
115
+ it("renders document icon", () => {
116
+ const { container } = render(<EmptyData />)
117
+ const svg = container.querySelector("svg")
118
+ expect(svg).toBeInTheDocument()
119
+ })
120
+ })
@@ -0,0 +1,164 @@
1
+ import * as React from "react"
2
+ import { cn } from "../../../src/lib/utils"
3
+
4
+ export interface EmptyStateProps extends React.HTMLAttributes<HTMLDivElement> {
5
+ /** Icon to display (should be a React element) */
6
+ icon?: React.ReactNode
7
+ /** Main title */
8
+ title: string
9
+ /** Description text */
10
+ description?: string
11
+ /** Primary action button/link */
12
+ action?: React.ReactNode
13
+ /** Secondary action */
14
+ secondaryAction?: React.ReactNode
15
+ /** Size variant */
16
+ size?: "sm" | "default" | "lg"
17
+ }
18
+
19
+ const sizeClasses = {
20
+ sm: {
21
+ container: "py-8",
22
+ icon: "[&_svg]:h-8 [&_svg]:w-8",
23
+ title: "text-base",
24
+ description: "text-sm",
25
+ },
26
+ default: {
27
+ container: "py-12",
28
+ icon: "[&_svg]:h-12 [&_svg]:w-12",
29
+ title: "text-lg",
30
+ description: "text-sm",
31
+ },
32
+ lg: {
33
+ container: "py-16",
34
+ icon: "[&_svg]:h-16 [&_svg]:w-16",
35
+ title: "text-xl",
36
+ description: "text-base",
37
+ },
38
+ }
39
+
40
+ /**
41
+ * Empty state component for displaying when there's no data.
42
+ * Provides contextual messaging and primary actions to guide users.
43
+ */
44
+ export function EmptyState({
45
+ icon,
46
+ title,
47
+ description,
48
+ action,
49
+ secondaryAction,
50
+ size = "default",
51
+ className,
52
+ ...props
53
+ }: EmptyStateProps) {
54
+ const sizes = sizeClasses[size]
55
+
56
+ return (
57
+ <div
58
+ className={cn(
59
+ "flex flex-col items-center justify-center text-center",
60
+ sizes.container,
61
+ className
62
+ )}
63
+ {...props}
64
+ >
65
+ {icon && (
66
+ <div
67
+ className={cn(
68
+ "mb-4 text-muted-foreground/50",
69
+ sizes.icon
70
+ )}
71
+ >
72
+ {icon}
73
+ </div>
74
+ )}
75
+ <h3 className={cn("font-semibold text-foreground", sizes.title)}>
76
+ {title}
77
+ </h3>
78
+ {description && (
79
+ <p
80
+ className={cn(
81
+ "mt-2 max-w-sm text-muted-foreground",
82
+ sizes.description
83
+ )}
84
+ >
85
+ {description}
86
+ </p>
87
+ )}
88
+ {(action || secondaryAction) && (
89
+ <div className="mt-6 flex flex-wrap items-center justify-center gap-3">
90
+ {action}
91
+ {secondaryAction}
92
+ </div>
93
+ )}
94
+ </div>
95
+ )
96
+ }
97
+
98
+ /** Pre-built empty state for no search results */
99
+ export function EmptySearchResults({
100
+ query,
101
+ onClear,
102
+ ...props
103
+ }: Omit<EmptyStateProps, "title" | "description"> & {
104
+ query?: string
105
+ onClear?: () => void
106
+ }) {
107
+ return (
108
+ <EmptyState
109
+ title="No results found"
110
+ description={
111
+ query
112
+ ? `No results for "${query}". Try a different search term.`
113
+ : "Try adjusting your search or filters."
114
+ }
115
+ icon={
116
+ <svg
117
+ xmlns="http://www.w3.org/2000/svg"
118
+ fill="none"
119
+ viewBox="0 0 24 24"
120
+ strokeWidth={1.5}
121
+ stroke="currentColor"
122
+ >
123
+ <path
124
+ strokeLinecap="round"
125
+ strokeLinejoin="round"
126
+ d="m21 21-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607Z"
127
+ />
128
+ </svg>
129
+ }
130
+ {...props}
131
+ />
132
+ )
133
+ }
134
+
135
+ /** Pre-built empty state for no data */
136
+ export function EmptyData({
137
+ resourceName = "items",
138
+ ...props
139
+ }: Omit<EmptyStateProps, "title" | "description"> & {
140
+ resourceName?: string
141
+ }) {
142
+ return (
143
+ <EmptyState
144
+ title={`No ${resourceName} yet`}
145
+ description={`Get started by creating your first ${resourceName.replace(/s$/, "")}.`}
146
+ icon={
147
+ <svg
148
+ xmlns="http://www.w3.org/2000/svg"
149
+ fill="none"
150
+ viewBox="0 0 24 24"
151
+ strokeWidth={1.5}
152
+ stroke="currentColor"
153
+ >
154
+ <path
155
+ strokeLinecap="round"
156
+ strokeLinejoin="round"
157
+ d="M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5a3.375 3.375 0 0 0-3.375-3.375H8.25m3.75 9v6m3-3H9m1.5-12H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Z"
158
+ />
159
+ </svg>
160
+ }
161
+ {...props}
162
+ />
163
+ )
164
+ }
@@ -0,0 +1,6 @@
1
+ export {
2
+ EmptyState,
3
+ EmptySearchResults,
4
+ EmptyData,
5
+ type EmptyStateProps,
6
+ } from "./EmptyState"
@@ -0,0 +1,140 @@
1
+ import * as React from "react"
2
+ import { cn } from "../../../src/lib/utils"
3
+
4
+ export interface FormSectionProps extends React.HTMLAttributes<HTMLDivElement> {
5
+ /** Section title */
6
+ title: string
7
+ /** Section description */
8
+ description?: string
9
+ /** Form fields content */
10
+ children: React.ReactNode
11
+ /** Whether to show a divider at the bottom */
12
+ divider?: boolean
13
+ }
14
+
15
+ /**
16
+ * Form section for grouping related form fields.
17
+ * Provides consistent spacing and typography for form organization.
18
+ */
19
+ export function FormSection({
20
+ title,
21
+ description,
22
+ children,
23
+ divider = true,
24
+ className,
25
+ ...props
26
+ }: FormSectionProps) {
27
+ return (
28
+ <div
29
+ className={cn(
30
+ "grid gap-6 pb-6",
31
+ divider && "border-b",
32
+ className
33
+ )}
34
+ {...props}
35
+ >
36
+ <div className="space-y-1">
37
+ <h3 className="text-base font-medium">{title}</h3>
38
+ {description && (
39
+ <p className="text-sm text-muted-foreground">{description}</p>
40
+ )}
41
+ </div>
42
+ <div className="grid gap-4">{children}</div>
43
+ </div>
44
+ )
45
+ }
46
+
47
+ export interface FormFieldProps extends React.HTMLAttributes<HTMLDivElement> {
48
+ /** Field label */
49
+ label: string
50
+ /** Field description/help text */
51
+ description?: string
52
+ /** Error message */
53
+ error?: string
54
+ /** Whether the field is required */
55
+ required?: boolean
56
+ /** The form input element */
57
+ children: React.ReactNode
58
+ /** HTML for attribute to connect label with input */
59
+ htmlFor?: string
60
+ }
61
+
62
+ /**
63
+ * Form field wrapper with label, description, and error handling.
64
+ */
65
+ export function FormField({
66
+ label,
67
+ description,
68
+ error,
69
+ required,
70
+ children,
71
+ htmlFor,
72
+ className,
73
+ ...props
74
+ }: FormFieldProps) {
75
+ return (
76
+ <div className={cn("space-y-2", className)} {...props}>
77
+ <label
78
+ htmlFor={htmlFor}
79
+ className={cn(
80
+ "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
81
+ error && "text-destructive"
82
+ )}
83
+ >
84
+ {label}
85
+ {required && <span className="ml-1 text-destructive">*</span>}
86
+ </label>
87
+ {children}
88
+ {description && !error && (
89
+ <p className="text-xs text-muted-foreground">{description}</p>
90
+ )}
91
+ {error && (
92
+ <p className="text-xs text-destructive" role="alert">
93
+ {error}
94
+ </p>
95
+ )}
96
+ </div>
97
+ )
98
+ }
99
+
100
+ export interface FormActionsProps extends React.HTMLAttributes<HTMLDivElement> {
101
+ /** Action buttons */
102
+ children: React.ReactNode
103
+ /** Alignment of actions */
104
+ align?: "left" | "right" | "center" | "between"
105
+ /** Whether to make it sticky at the bottom */
106
+ sticky?: boolean
107
+ }
108
+
109
+ const alignClasses = {
110
+ left: "justify-start",
111
+ right: "justify-end",
112
+ center: "justify-center",
113
+ between: "justify-between",
114
+ }
115
+
116
+ /**
117
+ * Form actions bar for submit/cancel buttons.
118
+ * Can be sticky at the bottom of the form.
119
+ */
120
+ export function FormActions({
121
+ children,
122
+ align = "right",
123
+ sticky = false,
124
+ className,
125
+ ...props
126
+ }: FormActionsProps) {
127
+ return (
128
+ <div
129
+ className={cn(
130
+ "flex items-center gap-3 pt-6",
131
+ alignClasses[align],
132
+ sticky && "sticky bottom-0 border-t bg-background py-4",
133
+ className
134
+ )}
135
+ {...props}
136
+ >
137
+ {children}
138
+ </div>
139
+ )
140
+ }
@@ -0,0 +1,8 @@
1
+ export {
2
+ FormSection,
3
+ FormField,
4
+ FormActions,
5
+ type FormSectionProps,
6
+ type FormFieldProps,
7
+ type FormActionsProps,
8
+ } from "./FormSection"
@@ -0,0 +1,190 @@
1
+ import * as React from "react"
2
+ import { cn } from "../../../src/lib/utils"
3
+
4
+ export interface NavbarProps extends React.HTMLAttributes<HTMLElement> {
5
+ /** Whether the navbar is sticky */
6
+ sticky?: boolean
7
+ /** Whether to show border at bottom */
8
+ bordered?: boolean
9
+ children: React.ReactNode
10
+ }
11
+
12
+ export function Navbar({
13
+ sticky = true,
14
+ bordered = true,
15
+ className,
16
+ children,
17
+ ...props
18
+ }: NavbarProps) {
19
+ return (
20
+ <nav
21
+ className={cn(
22
+ "z-50 flex h-14 w-full items-center bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60",
23
+ sticky && "sticky top-0",
24
+ bordered && "border-b",
25
+ className
26
+ )}
27
+ {...props}
28
+ >
29
+ <div className="container flex h-full items-center px-4">
30
+ {children}
31
+ </div>
32
+ </nav>
33
+ )
34
+ }
35
+
36
+ export interface NavbarBrandProps extends React.HTMLAttributes<HTMLDivElement> {
37
+ children: React.ReactNode
38
+ }
39
+
40
+ export function NavbarBrand({ className, children, ...props }: NavbarBrandProps) {
41
+ return (
42
+ <div
43
+ className={cn("flex items-center gap-2 font-semibold", className)}
44
+ {...props}
45
+ >
46
+ {children}
47
+ </div>
48
+ )
49
+ }
50
+
51
+ export interface NavbarContentProps extends React.HTMLAttributes<HTMLDivElement> {
52
+ /** Alignment of content */
53
+ align?: "start" | "center" | "end"
54
+ children: React.ReactNode
55
+ }
56
+
57
+ export function NavbarContent({
58
+ align = "start",
59
+ className,
60
+ children,
61
+ ...props
62
+ }: NavbarContentProps) {
63
+ return (
64
+ <div
65
+ className={cn(
66
+ "flex flex-1 items-center gap-4",
67
+ align === "start" && "justify-start",
68
+ align === "center" && "justify-center",
69
+ align === "end" && "justify-end",
70
+ className
71
+ )}
72
+ {...props}
73
+ >
74
+ {children}
75
+ </div>
76
+ )
77
+ }
78
+
79
+ export interface NavbarItemProps extends React.HTMLAttributes<HTMLDivElement> {
80
+ children: React.ReactNode
81
+ }
82
+
83
+ export function NavbarItem({ className, children, ...props }: NavbarItemProps) {
84
+ return (
85
+ <div className={cn("flex items-center", className)} {...props}>
86
+ {children}
87
+ </div>
88
+ )
89
+ }
90
+
91
+ export interface NavbarLinkProps
92
+ extends React.AnchorHTMLAttributes<HTMLAnchorElement> {
93
+ /** Whether link is active */
94
+ active?: boolean
95
+ children: React.ReactNode
96
+ }
97
+
98
+ export function NavbarLink({
99
+ active,
100
+ className,
101
+ children,
102
+ ...props
103
+ }: NavbarLinkProps) {
104
+ return (
105
+ <a
106
+ className={cn(
107
+ "text-sm font-medium transition-colors hover:text-foreground",
108
+ active ? "text-foreground" : "text-muted-foreground",
109
+ className
110
+ )}
111
+ {...props}
112
+ >
113
+ {children}
114
+ </a>
115
+ )
116
+ }
117
+
118
+ export interface NavbarMenuProps extends React.HTMLAttributes<HTMLDivElement> {
119
+ /** Whether to show on mobile */
120
+ mobileMenu?: boolean
121
+ children: React.ReactNode
122
+ }
123
+
124
+ export function NavbarMenu({
125
+ mobileMenu,
126
+ className,
127
+ children,
128
+ ...props
129
+ }: NavbarMenuProps) {
130
+ return (
131
+ <div
132
+ className={cn(
133
+ "flex items-center gap-6",
134
+ mobileMenu && "hidden md:flex",
135
+ className
136
+ )}
137
+ {...props}
138
+ >
139
+ {children}
140
+ </div>
141
+ )
142
+ }
143
+
144
+ export interface NavbarToggleProps
145
+ extends React.ButtonHTMLAttributes<HTMLButtonElement> {
146
+ /** Whether menu is open */
147
+ open?: boolean
148
+ }
149
+
150
+ export function NavbarToggle({
151
+ open,
152
+ className,
153
+ ...props
154
+ }: NavbarToggleProps) {
155
+ return (
156
+ <button
157
+ className={cn(
158
+ "flex h-9 w-9 items-center justify-center rounded-md md:hidden",
159
+ "hover:bg-accent hover:text-accent-foreground",
160
+ className
161
+ )}
162
+ aria-label={open ? "Close menu" : "Open menu"}
163
+ {...props}
164
+ >
165
+ <svg
166
+ width="20"
167
+ height="20"
168
+ viewBox="0 0 24 24"
169
+ fill="none"
170
+ stroke="currentColor"
171
+ strokeWidth="2"
172
+ strokeLinecap="round"
173
+ strokeLinejoin="round"
174
+ >
175
+ {open ? (
176
+ <>
177
+ <line x1="18" y1="6" x2="6" y2="18" />
178
+ <line x1="6" y1="6" x2="18" y2="18" />
179
+ </>
180
+ ) : (
181
+ <>
182
+ <line x1="4" y1="12" x2="20" y2="12" />
183
+ <line x1="4" y1="6" x2="20" y2="6" />
184
+ <line x1="4" y1="18" x2="20" y2="18" />
185
+ </>
186
+ )}
187
+ </svg>
188
+ </button>
189
+ )
190
+ }
@@ -0,0 +1,16 @@
1
+ export {
2
+ Navbar,
3
+ NavbarBrand,
4
+ NavbarContent,
5
+ NavbarItem,
6
+ NavbarLink,
7
+ NavbarMenu,
8
+ NavbarToggle,
9
+ type NavbarProps,
10
+ type NavbarBrandProps,
11
+ type NavbarContentProps,
12
+ type NavbarItemProps,
13
+ type NavbarLinkProps,
14
+ type NavbarMenuProps,
15
+ type NavbarToggleProps,
16
+ } from "./Navbar"