@nikala-ui/core 0.10.1 → 0.11.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 (55) hide show
  1. package/package.json +1 -1
  2. package/registry/bubble.json +18 -0
  3. package/registry/button-group.json +20 -0
  4. package/registry/create-chat-scroll.json +13 -0
  5. package/registry/create-drop-zone.json +13 -0
  6. package/registry/create-pagination.json +13 -0
  7. package/registry/dropzone.json +21 -0
  8. package/registry/footer.json +18 -0
  9. package/registry/forgot-password-01.json +28 -0
  10. package/registry/hero-01.json +22 -0
  11. package/registry/index.json +331 -0
  12. package/registry/login-01.json +28 -0
  13. package/registry/marker.json +17 -0
  14. package/registry/marquee.json +17 -0
  15. package/registry/message.json +17 -0
  16. package/registry/navbar.json +19 -0
  17. package/registry/navigation-menu.json +22 -0
  18. package/registry/otp-verification-01.json +26 -0
  19. package/registry/pagination.json +22 -0
  20. package/registry/rating.json +19 -0
  21. package/registry/register-01.json +31 -0
  22. package/registry/review-card.json +23 -0
  23. package/registry/scroll-area.json +1 -1
  24. package/registry/sidebar.json +24 -0
  25. package/registry/spinner.json +1 -1
  26. package/registry/stat.json +19 -0
  27. package/registry/table.json +17 -0
  28. package/registry/timeline.json +18 -0
  29. package/registry/toggle-group.json +21 -0
  30. package/src/registry/blocks/forgot-password-01.tsx +141 -0
  31. package/src/registry/blocks/hero-01.tsx +28 -0
  32. package/src/registry/blocks/login-01.tsx +231 -0
  33. package/src/registry/blocks/otp-verification-01.tsx +170 -0
  34. package/src/registry/blocks/register-01.tsx +318 -0
  35. package/src/registry/components/ui/bubble.tsx +142 -0
  36. package/src/registry/components/ui/button-group.tsx +42 -0
  37. package/src/registry/components/ui/dropzone.tsx +189 -0
  38. package/src/registry/components/ui/footer.tsx +247 -0
  39. package/src/registry/components/ui/marker.tsx +102 -0
  40. package/src/registry/components/ui/marquee.tsx +118 -0
  41. package/src/registry/components/ui/message.tsx +168 -0
  42. package/src/registry/components/ui/navbar.tsx +368 -0
  43. package/src/registry/components/ui/navigation-menu.tsx +358 -0
  44. package/src/registry/components/ui/pagination.tsx +258 -0
  45. package/src/registry/components/ui/rating.tsx +185 -0
  46. package/src/registry/components/ui/review-card.tsx +195 -0
  47. package/src/registry/components/ui/scroll-area.tsx +2 -2
  48. package/src/registry/components/ui/sidebar.tsx +692 -0
  49. package/src/registry/components/ui/spinner.tsx +1 -1
  50. package/src/registry/components/ui/stat.tsx +245 -0
  51. package/src/registry/components/ui/table.tsx +160 -0
  52. package/src/registry/components/ui/timeline.tsx +350 -0
  53. package/src/registry/components/ui/toggle-group.tsx +203 -0
  54. package/src/registry/index.ts +3 -3
  55. package/src/registry/metadata.ts +141 -0
@@ -0,0 +1,368 @@
1
+ import {
2
+ createContext,
3
+ createSignal,
4
+ useContext,
5
+ splitProps,
6
+ Show,
7
+ type JSX,
8
+ type ParentComponent,
9
+ type Component,
10
+ type Accessor,
11
+ } from "solid-js";
12
+ import { cva, type VariantProps } from "class-variance-authority";
13
+ import { Menu, X } from "lucide-solid";
14
+ import { cn } from "@/lib/cn";
15
+
16
+ /* --- Navbar Context --- */
17
+ interface NavbarContextValue {
18
+ isOpen: Accessor<boolean>;
19
+ setIsOpen: (open: boolean) => void;
20
+ toggleMobileMenu: () => void;
21
+ }
22
+
23
+ const NavbarContext = createContext<NavbarContextValue>();
24
+
25
+ export function useNavbar() {
26
+ const context = useContext(NavbarContext);
27
+ if (!context) {
28
+ throw new Error("useNavbar must be used within a <Navbar /> component");
29
+ }
30
+ return context;
31
+ }
32
+
33
+ /* --- Root Navbar --- */
34
+ export const navbarVariants = cva(
35
+ "w-full transition-all duration-200 z-40",
36
+ {
37
+ variants: {
38
+ variant: {
39
+ default: "border-b border-border/60 bg-background/80 backdrop-blur-md",
40
+ floating: "my-3 rounded-lg border border-border/80 bg-background/90 backdrop-blur-md shadow-sm",
41
+ bordered: "border-b border-border bg-background",
42
+ transparent: "bg-transparent border-transparent",
43
+ },
44
+ isSticky: {
45
+ true: "sticky top-0",
46
+ false: "relative",
47
+ },
48
+ },
49
+ defaultVariants: {
50
+ variant: "default",
51
+ isSticky: true,
52
+ },
53
+ }
54
+ );
55
+
56
+ export interface NavbarProps
57
+ extends JSX.HTMLAttributes<HTMLElement>,
58
+ VariantProps<typeof navbarVariants> {
59
+ maxWidth?: "sm" | "md" | "lg" | "xl" | "2xl" | "full";
60
+ open?: boolean;
61
+ onOpenChange?: (open: boolean) => void;
62
+ }
63
+
64
+ export const Navbar: ParentComponent<NavbarProps> = (props) => {
65
+ const [local, rest] = splitProps(props, [
66
+ "class",
67
+ "variant",
68
+ "isSticky",
69
+ "maxWidth",
70
+ "open",
71
+ "onOpenChange",
72
+ "children",
73
+ ]);
74
+
75
+ const [internalOpen, setInternalOpen] = createSignal(false);
76
+ const isOpen = () => (local.open !== undefined ? local.open : internalOpen());
77
+
78
+ const setIsOpen = (open: boolean) => {
79
+ if (local.open === undefined) {
80
+ setInternalOpen(open);
81
+ }
82
+ local.onOpenChange?.(open);
83
+ };
84
+
85
+ const toggleMobileMenu = () => setIsOpen(!isOpen());
86
+
87
+ const maxWidthClass = () => {
88
+ switch (local.maxWidth) {
89
+ case "sm":
90
+ return "max-w-screen-sm";
91
+ case "md":
92
+ return "max-w-screen-md";
93
+ case "lg":
94
+ return "max-w-screen-lg";
95
+ case "xl":
96
+ return "max-w-screen-xl";
97
+ case "full":
98
+ return "max-w-full";
99
+ case "2xl":
100
+ default:
101
+ return "max-w-screen-2xl";
102
+ }
103
+ };
104
+
105
+ return (
106
+ <NavbarContext.Provider value={{ isOpen, setIsOpen, toggleMobileMenu }}>
107
+ <header
108
+ class={cn(
109
+ navbarVariants({
110
+ variant: local.variant,
111
+ isSticky: local.isSticky,
112
+ }),
113
+ local.variant === "floating" && cn("mx-auto", maxWidthClass()),
114
+ local.class
115
+ )}
116
+ {...rest}
117
+ >
118
+ <div class={cn("w-full", local.variant !== "floating" && cn("mx-auto", maxWidthClass()))}>
119
+ {local.children}
120
+ </div>
121
+ </header>
122
+ </NavbarContext.Provider>
123
+ );
124
+ };
125
+
126
+ /* --- Navbar Container (Top Flex Row) --- */
127
+ export interface NavbarContainerProps extends JSX.HTMLAttributes<HTMLDivElement> {
128
+ class?: string;
129
+ }
130
+
131
+ export const NavbarContainer: ParentComponent<NavbarContainerProps> = (props) => {
132
+ const [local, rest] = splitProps(props, ["class", "children"]);
133
+
134
+ return (
135
+ <div
136
+ class={cn(
137
+ "flex h-14 md:h-16 items-center justify-between px-4 sm:px-6 lg:px-8 gap-3 w-full",
138
+ local.class
139
+ )}
140
+ {...rest}
141
+ >
142
+ {local.children}
143
+ </div>
144
+ );
145
+ };
146
+
147
+ /* --- Navbar Brand / Logo Container --- */
148
+ export interface NavbarBrandProps extends JSX.AnchorHTMLAttributes<HTMLAnchorElement> {
149
+ class?: string;
150
+ }
151
+
152
+ export const NavbarBrand: ParentComponent<NavbarBrandProps> = (props) => {
153
+ const [local, rest] = splitProps(props, ["class", "children"]);
154
+
155
+ return (
156
+ <a
157
+ class={cn(
158
+ "flex items-center gap-2 font-bold text-foreground transition-opacity hover:opacity-90 cursor-pointer shrink-0",
159
+ local.class
160
+ )}
161
+ {...rest}
162
+ >
163
+ {local.children}
164
+ </a>
165
+ );
166
+ };
167
+
168
+ /* --- Navbar Content / Section --- */
169
+ export const navbarContentVariants = cva("flex items-center gap-1 sm:gap-2 h-full", {
170
+ variants: {
171
+ justify: {
172
+ start: "justify-start flex-1",
173
+ center: "justify-center flex-1",
174
+ end: "justify-end flex-1",
175
+ },
176
+ },
177
+ defaultVariants: {
178
+ justify: "center",
179
+ },
180
+ });
181
+
182
+ export interface NavbarContentProps
183
+ extends JSX.HTMLAttributes<HTMLDivElement>,
184
+ VariantProps<typeof navbarContentVariants> {
185
+ class?: string;
186
+ hideOnMobile?: boolean;
187
+ }
188
+
189
+ export const NavbarContent: ParentComponent<NavbarContentProps> = (props) => {
190
+ const [local, rest] = splitProps(props, ["class", "justify", "hideOnMobile", "children"]);
191
+
192
+ return (
193
+ <div
194
+ class={cn(
195
+ navbarContentVariants({ justify: local.justify }),
196
+ local.hideOnMobile !== false && "hidden md:flex",
197
+ local.class
198
+ )}
199
+ {...rest}
200
+ >
201
+ {local.children}
202
+ </div>
203
+ );
204
+ };
205
+
206
+ /* --- Navbar Item --- */
207
+ export interface NavbarItemProps extends JSX.HTMLAttributes<HTMLDivElement> {
208
+ class?: string;
209
+ isActive?: boolean;
210
+ }
211
+
212
+ export const NavbarItem: ParentComponent<NavbarItemProps> = (props) => {
213
+ const [local, rest] = splitProps(props, ["class", "isActive", "children"]);
214
+
215
+ return (
216
+ <div
217
+ class={cn(
218
+ "relative flex items-center h-full text-sm font-medium",
219
+ local.class
220
+ )}
221
+ {...rest}
222
+ >
223
+ {local.children}
224
+ <Show when={local.isActive}>
225
+ <div class="absolute -bottom-px left-0 right-0 h-0.5 bg-primary rounded-lg z-10" />
226
+ </Show>
227
+ </div>
228
+ );
229
+ };
230
+
231
+ /* --- Navbar Link --- */
232
+ export const navbarLinkVariants = cva(
233
+ "inline-flex h-9 items-center justify-center rounded-md px-3 text-sm font-medium transition-colors cursor-pointer select-none focus-visible:outline-hidden",
234
+ {
235
+ variants: {
236
+ variant: {
237
+ default:
238
+ "text-muted-foreground hover:bg-muted hover:text-foreground",
239
+ active:
240
+ "text-foreground font-semibold bg-muted/80",
241
+ ghost:
242
+ "text-foreground hover:text-primary",
243
+ },
244
+ },
245
+ defaultVariants: {
246
+ variant: "default",
247
+ },
248
+ }
249
+ );
250
+
251
+ export interface NavbarLinkProps
252
+ extends JSX.AnchorHTMLAttributes<HTMLAnchorElement>,
253
+ VariantProps<typeof navbarLinkVariants> {
254
+ class?: string;
255
+ isActive?: boolean;
256
+ }
257
+
258
+ export const NavbarLink: ParentComponent<NavbarLinkProps> = (props) => {
259
+ const [local, rest] = splitProps(props, ["class", "variant", "isActive", "children"]);
260
+
261
+ return (
262
+ <a
263
+ class={cn(
264
+ navbarLinkVariants({
265
+ variant: local.isActive ? "active" : local.variant,
266
+ }),
267
+ local.class
268
+ )}
269
+ {...rest}
270
+ >
271
+ {local.children}
272
+ </a>
273
+ );
274
+ };
275
+
276
+ /* --- Navbar Actions Container --- */
277
+ export interface NavbarActionsProps extends JSX.HTMLAttributes<HTMLDivElement> {
278
+ class?: string;
279
+ }
280
+
281
+ export const NavbarActions: ParentComponent<NavbarActionsProps> = (props) => {
282
+ const [local, rest] = splitProps(props, ["class", "children"]);
283
+
284
+ return (
285
+ <div class={cn("flex items-center gap-2 shrink-0", local.class)} {...rest}>
286
+ {local.children}
287
+ </div>
288
+ );
289
+ };
290
+
291
+ /* --- Navbar Mobile Toggle Button --- */
292
+ export interface NavbarMobileToggleProps extends JSX.ButtonHTMLAttributes<HTMLButtonElement> {
293
+ class?: string;
294
+ }
295
+
296
+ export const NavbarMobileToggle: Component<NavbarMobileToggleProps> = (props) => {
297
+ const [local, rest] = splitProps(props, ["class"]);
298
+ const { isOpen, toggleMobileMenu } = useNavbar();
299
+
300
+ return (
301
+ <button
302
+ type="button"
303
+ onClick={toggleMobileMenu}
304
+ aria-label="Toggle navigation menu"
305
+ aria-expanded={isOpen()}
306
+ class={cn(
307
+ "inline-flex md:hidden size-8 items-center justify-center rounded-md border border-border/60 bg-muted/30 text-muted-foreground hover:bg-muted hover:text-foreground transition-colors cursor-pointer focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring shrink-0",
308
+ local.class
309
+ )}
310
+ {...rest}
311
+ >
312
+ <Show when={isOpen()} fallback={<Menu class="size-4" />}>
313
+ <X class="size-4" />
314
+ </Show>
315
+ </button>
316
+ );
317
+ };
318
+
319
+ /* --- Navbar Mobile Menu Container --- */
320
+ export interface NavbarMobileMenuProps extends JSX.HTMLAttributes<HTMLDivElement> {
321
+ class?: string;
322
+ }
323
+
324
+ export const NavbarMobileMenu: ParentComponent<NavbarMobileMenuProps> = (props) => {
325
+ const [local, rest] = splitProps(props, ["class", "children"]);
326
+ const { isOpen } = useNavbar();
327
+
328
+ return (
329
+ <Show when={isOpen()}>
330
+ <div
331
+ class={cn(
332
+ "md:hidden w-full border-t border-border/60 bg-background/95 backdrop-blur-lg px-4 py-3 space-y-1 shadow-md transition-all",
333
+ local.class
334
+ )}
335
+ {...rest}
336
+ >
337
+ {local.children}
338
+ </div>
339
+ </Show>
340
+ );
341
+ };
342
+
343
+ /* --- Navbar Mobile Item & Link --- */
344
+ export interface NavbarMobileLinkProps extends JSX.AnchorHTMLAttributes<HTMLAnchorElement> {
345
+ class?: string;
346
+ isActive?: boolean;
347
+ }
348
+
349
+ export const NavbarMobileLink: ParentComponent<NavbarMobileLinkProps> = (props) => {
350
+ const [local, rest] = splitProps(props, ["class", "isActive", "children"]);
351
+ const { setIsOpen } = useNavbar();
352
+
353
+ return (
354
+ <a
355
+ onClick={() => setIsOpen(false)}
356
+ class={cn(
357
+ "flex w-full items-center justify-between rounded-md px-3 py-2 text-sm font-medium transition-colors cursor-pointer",
358
+ local.isActive
359
+ ? "bg-primary text-primary-foreground font-semibold shadow-2xs"
360
+ : "text-muted-foreground hover:bg-muted/80 hover:text-foreground",
361
+ local.class
362
+ )}
363
+ {...rest}
364
+ >
365
+ {local.children}
366
+ </a>
367
+ );
368
+ };