@nikala-ui/core 0.10.1-nightly.4e09f2a → 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 (48) hide show
  1. package/package.json +1 -1
  2. package/registry/bubble.json +18 -0
  3. package/registry/create-chat-scroll.json +13 -0
  4. package/registry/create-pagination.json +13 -0
  5. package/registry/footer.json +18 -0
  6. package/registry/forgot-password-01.json +28 -0
  7. package/registry/hero-01.json +22 -0
  8. package/registry/index.json +288 -0
  9. package/registry/login-01.json +28 -0
  10. package/registry/marker.json +17 -0
  11. package/registry/marquee.json +17 -0
  12. package/registry/message.json +17 -0
  13. package/registry/navbar.json +19 -0
  14. package/registry/navigation-menu.json +22 -0
  15. package/registry/otp-verification-01.json +26 -0
  16. package/registry/pagination.json +22 -0
  17. package/registry/rating.json +19 -0
  18. package/registry/register-01.json +31 -0
  19. package/registry/review-card.json +23 -0
  20. package/registry/scroll-area.json +1 -1
  21. package/registry/sidebar.json +24 -0
  22. package/registry/spinner.json +1 -1
  23. package/registry/stat.json +19 -0
  24. package/registry/timeline.json +18 -0
  25. package/registry/toggle-group.json +21 -0
  26. package/src/registry/blocks/forgot-password-01.tsx +141 -0
  27. package/src/registry/blocks/hero-01.tsx +28 -0
  28. package/src/registry/blocks/login-01.tsx +231 -0
  29. package/src/registry/blocks/otp-verification-01.tsx +170 -0
  30. package/src/registry/blocks/register-01.tsx +318 -0
  31. package/src/registry/components/ui/bubble.tsx +142 -0
  32. package/src/registry/components/ui/footer.tsx +247 -0
  33. package/src/registry/components/ui/marker.tsx +102 -0
  34. package/src/registry/components/ui/marquee.tsx +118 -0
  35. package/src/registry/components/ui/message.tsx +168 -0
  36. package/src/registry/components/ui/navbar.tsx +368 -0
  37. package/src/registry/components/ui/navigation-menu.tsx +358 -0
  38. package/src/registry/components/ui/pagination.tsx +258 -0
  39. package/src/registry/components/ui/rating.tsx +185 -0
  40. package/src/registry/components/ui/review-card.tsx +195 -0
  41. package/src/registry/components/ui/scroll-area.tsx +2 -2
  42. package/src/registry/components/ui/sidebar.tsx +692 -0
  43. package/src/registry/components/ui/spinner.tsx +1 -1
  44. package/src/registry/components/ui/stat.tsx +245 -0
  45. package/src/registry/components/ui/timeline.tsx +350 -0
  46. package/src/registry/components/ui/toggle-group.tsx +203 -0
  47. package/src/registry/index.ts +3 -3
  48. package/src/registry/metadata.ts +120 -0
@@ -0,0 +1,203 @@
1
+ import {
2
+ createContext,
3
+ useContext,
4
+ splitProps,
5
+ type Component,
6
+ type JSX,
7
+ type Accessor,
8
+ } from "solid-js";
9
+ import { cva, type VariantProps } from "class-variance-authority";
10
+ import { createControllableSignal } from "@nikala-ui/hooks";
11
+ import { cn } from "@/lib/cn";
12
+
13
+ export const toggleGroupItemVariants = cva(
14
+ "inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium transition-colors hover:bg-muted hover:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 cursor-pointer",
15
+ {
16
+ variants: {
17
+ variant: {
18
+ default: "bg-transparent",
19
+ outline:
20
+ "border border-border bg-transparent shadow-xs hover:bg-accent hover:text-accent-foreground data-[state=on]:bg-accent data-[state=on]:text-accent-foreground",
21
+ },
22
+ size: {
23
+ default: "h-9 px-3 min-w-9",
24
+ sm: "h-8 px-2 text-xs min-w-8",
25
+ lg: "h-10 px-3 min-w-10",
26
+ },
27
+ },
28
+ defaultVariants: {
29
+ variant: "default",
30
+ size: "default",
31
+ },
32
+ }
33
+ );
34
+
35
+ interface ToggleGroupContextValue {
36
+ type: "single" | "multiple";
37
+ value: Accessor<any>;
38
+ onItemSelect: (itemValue: string) => void;
39
+ variant: Accessor<"default" | "outline">;
40
+ size: Accessor<"default" | "sm" | "lg">;
41
+ disabled: Accessor<boolean>;
42
+ }
43
+
44
+ const ToggleGroupContext = createContext<ToggleGroupContextValue>();
45
+
46
+ export interface ToggleGroupProps<T extends "single" | "multiple" = "single">
47
+ extends Omit<JSX.HTMLAttributes<HTMLDivElement>, "onChange">,
48
+ VariantProps<typeof toggleGroupItemVariants> {
49
+ /** Mode of selection: single choice or multiple choices */
50
+ type?: T;
51
+ /** Controlled value: string for 'single', string[] for 'multiple' */
52
+ value?: T extends "multiple" ? string[] : string;
53
+ /** Uncontrolled default value */
54
+ defaultValue?: T extends "multiple" ? string[] : string;
55
+ /** Callback fired when selection changes */
56
+ onChange?: (value: T extends "multiple" ? string[] : string) => void;
57
+ /** Layout orientation */
58
+ orientation?: "horizontal" | "vertical";
59
+ /** Disables all buttons in the group */
60
+ disabled?: boolean;
61
+ class?: string;
62
+ children?: JSX.Element;
63
+ }
64
+
65
+ /**
66
+ * Root container for grouping connected toggle items with shared single/multiple selection state.
67
+ */
68
+ export const ToggleGroup = <T extends "single" | "multiple" = "single">(
69
+ props: ToggleGroupProps<T>
70
+ ) => {
71
+ const [local, rest] = splitProps(props, [
72
+ "type",
73
+ "value",
74
+ "defaultValue",
75
+ "onChange",
76
+ "orientation",
77
+ "variant",
78
+ "size",
79
+ "disabled",
80
+ "class",
81
+ "children",
82
+ ]);
83
+
84
+ const type = () => local.type ?? ("single" as T);
85
+ const variant = () => local.variant ?? "default";
86
+ const size = () => local.size ?? "default";
87
+ const disabled = () => local.disabled ?? false;
88
+ const orientation = () => local.orientation ?? "horizontal";
89
+
90
+ const [currentValue, setCurrentValue] = createControllableSignal<any>({
91
+ value: () => local.value,
92
+ defaultValue: local.defaultValue ?? (type() === "multiple" ? [] : undefined),
93
+ onChange: (val) => local.onChange?.(val),
94
+ });
95
+
96
+ const onItemSelect = (itemValue: string) => {
97
+ if (disabled()) return;
98
+
99
+ if (type() === "multiple") {
100
+ const currentList = Array.isArray(currentValue()) ? currentValue() : [];
101
+ if (currentList.includes(itemValue)) {
102
+ setCurrentValue(currentList.filter((v: string) => v !== itemValue));
103
+ } else {
104
+ setCurrentValue([...currentList, itemValue]);
105
+ }
106
+ } else {
107
+ const current = currentValue();
108
+ if (current === itemValue) {
109
+ setCurrentValue(undefined);
110
+ } else {
111
+ setCurrentValue(itemValue);
112
+ }
113
+ }
114
+ };
115
+
116
+ const contextValue: ToggleGroupContextValue = {
117
+ type: type(),
118
+ value: currentValue,
119
+ onItemSelect,
120
+ variant,
121
+ size,
122
+ disabled,
123
+ };
124
+
125
+ return (
126
+ <ToggleGroupContext.Provider value={contextValue}>
127
+ <div
128
+ role="group"
129
+ data-orientation={orientation()}
130
+ class={cn(
131
+ "flex items-center justify-center gap-1 rounded-lg",
132
+ orientation() === "vertical" ? "flex-col" : "flex-row",
133
+ local.class
134
+ )}
135
+ {...rest}
136
+ >
137
+ {local.children}
138
+ </div>
139
+ </ToggleGroupContext.Provider>
140
+ );
141
+ };
142
+
143
+ export interface ToggleGroupItemProps
144
+ extends JSX.ButtonHTMLAttributes<HTMLButtonElement>,
145
+ VariantProps<typeof toggleGroupItemVariants> {
146
+ /** Unique value representing this toggle item within the group */
147
+ value: string;
148
+ class?: string;
149
+ children?: JSX.Element;
150
+ }
151
+
152
+ /**
153
+ * Individual toggle button item within a ToggleGroup.
154
+ */
155
+ export const ToggleGroupItem: Component<ToggleGroupItemProps> = (props) => {
156
+ const context = useContext(ToggleGroupContext);
157
+
158
+ if (!context) {
159
+ throw new Error("ToggleGroupItem must be used within a ToggleGroup");
160
+ }
161
+
162
+ const [local, rest] = splitProps(props, [
163
+ "value",
164
+ "variant",
165
+ "size",
166
+ "disabled",
167
+ "class",
168
+ "children",
169
+ ]);
170
+
171
+ const isSelected = () => {
172
+ const groupValue = context.value();
173
+ if (context.type === "multiple") {
174
+ return Array.isArray(groupValue) && groupValue.includes(local.value);
175
+ }
176
+ return groupValue === local.value;
177
+ };
178
+
179
+ const isDisabled = () => local.disabled || context.disabled();
180
+ const itemVariant = () => local.variant || context.variant();
181
+ const itemSize = () => local.size || context.size();
182
+
183
+ return (
184
+ <button
185
+ type="button"
186
+ role={context.type === "single" ? "radio" : "checkbox"}
187
+ aria-checked={isSelected()}
188
+ data-state={isSelected() ? "on" : "off"}
189
+ disabled={isDisabled()}
190
+ onClick={() => context.onItemSelect(local.value)}
191
+ class={cn(
192
+ toggleGroupItemVariants({
193
+ variant: itemVariant(),
194
+ size: itemSize(),
195
+ }),
196
+ local.class
197
+ )}
198
+ {...rest}
199
+ >
200
+ {local.children}
201
+ </button>
202
+ );
203
+ };
@@ -9,7 +9,7 @@ export interface RegistryFile {
9
9
  /** The full raw text content of the file */
10
10
  content: string;
11
11
  /** The category type of the file */
12
- type: "registry:ui" | "registry:util" | "registry:hook";
12
+ type: "registry:ui" | "registry:util" | "registry:hook" | "registry:block";
13
13
  }
14
14
 
15
15
  /**
@@ -23,7 +23,7 @@ export interface RegistryItem {
23
23
  /** Short summary describing the component */
24
24
  description: string;
25
25
  /** Component category type */
26
- type: "registry:ui" | "registry:util" | "registry:hook";
26
+ type: "registry:ui" | "registry:util" | "registry:hook" | "registry:block";
27
27
  /** Required NPM dependencies to be installed automatically (e.g., ["clsx", "tailwind-merge"]) */
28
28
  dependencies?: string[];
29
29
  /** Internal Nikala UI component dependencies required by this component (e.g., ["button"]) */
@@ -39,7 +39,7 @@ export interface RegistryIndexItem {
39
39
  name: string;
40
40
  title: string;
41
41
  description: string;
42
- type: "registry:ui" | "registry:util" | "registry:hook";
42
+ type: "registry:ui" | "registry:util" | "registry:hook" | "registry:block";
43
43
  dependencies?: string[];
44
44
  registryDependencies?: string[];
45
45
  }
@@ -288,6 +288,81 @@ export const COMPONENT_METADATA: Record<string, ComponentMeta> = {
288
288
  dependencies: ["clsx", "tailwind-merge", "lucide-solid"],
289
289
  registryDependencies: ["create-drop-zone"],
290
290
  },
291
+ "toggle-group": {
292
+ title: "Toggle Group",
293
+ description: "A set of two-state buttons that can be toggled on or off with single or multiple selection modes.",
294
+ dependencies: ["clsx", "tailwind-merge", "class-variance-authority"],
295
+ registryDependencies: ["create-controllable-signal"],
296
+ },
297
+ timeline: {
298
+ title: "Timeline",
299
+ description: "A responsive chronological display for event streams, activity logs, order tracking, and multi-step workflows.",
300
+ dependencies: ["clsx", "tailwind-merge", "class-variance-authority"],
301
+ },
302
+ "navigation-menu": {
303
+ title: "Navigation Menu",
304
+ description: "A responsive and accessible top header navigation menu with mega-menu dropdowns and link previews.",
305
+ dependencies: ["clsx", "tailwind-merge", "class-variance-authority", "lucide-solid"],
306
+ registryDependencies: ["create-click-outside"],
307
+ },
308
+ navbar: {
309
+ title: "Navbar",
310
+ description: "A responsive, accessible, and composable top navigation header suite supporting nested dropdown flyouts, floating card containers, and mobile navigation drawers.",
311
+ dependencies: ["clsx", "tailwind-merge", "class-variance-authority", "lucide-solid"],
312
+ },
313
+ footer: {
314
+ title: "Footer",
315
+ description: "A responsive, accessible, and structured bottom navigation layout suite supporting multi-column link directories, brand sections, and newsletter inputs.",
316
+ dependencies: ["clsx", "tailwind-merge", "class-variance-authority"],
317
+ },
318
+ stat: {
319
+ title: "Stat",
320
+ description: "Display key performance indicators, statistics, financial data, and metrics with trends and icons.",
321
+ dependencies: ["clsx", "tailwind-merge", "class-variance-authority", "lucide-solid"],
322
+ },
323
+ marquee: {
324
+ title: "Marquee",
325
+ description: "A smooth, GPU-accelerated infinite scrolling ticker component for logo clouds, testimonials, and live ribbons.",
326
+ dependencies: ["clsx", "tailwind-merge"],
327
+ },
328
+ "review-card": {
329
+ title: "Review Card",
330
+ description: "A versatile, structured card component for customer testimonials, product ratings, verified buyer badges, and social proof.",
331
+ dependencies: ["clsx", "tailwind-merge", "class-variance-authority", "lucide-solid"],
332
+ registryDependencies: ["avatar", "rating"],
333
+ },
334
+ rating: {
335
+ title: "Rating",
336
+ description: "An accessible star rating component supporting interactive inputs, hover preview states, and read-only score badges.",
337
+ dependencies: ["clsx", "tailwind-merge", "class-variance-authority", "lucide-solid"],
338
+ },
339
+ pagination: {
340
+ title: "Pagination",
341
+ description: "An accessible multi-page navigation bar with previous, next, page numbers, and ellipsis controls.",
342
+ dependencies: ["clsx", "tailwind-merge", "class-variance-authority", "lucide-solid"],
343
+ registryDependencies: ["create-pagination"],
344
+ },
345
+ message: {
346
+ title: "Message",
347
+ description: "A structured chat and conversation message layout with avatars, alignment, headers, footers, and actions.",
348
+ dependencies: ["clsx", "tailwind-merge"],
349
+ },
350
+ bubble: {
351
+ title: "Bubble",
352
+ description: "Chat message bubble container supporting variants, grouped consecutive bubbles, and emoji reactions.",
353
+ dependencies: ["clsx", "tailwind-merge", "class-variance-authority"],
354
+ },
355
+ marker: {
356
+ title: "Marker",
357
+ description: "System chat events, date dividers, and live typing indicator badges.",
358
+ dependencies: ["clsx", "tailwind-merge"],
359
+ },
360
+ sidebar: {
361
+ title: "Sidebar",
362
+ description: "A composable, collapsible, and accessible application sidebar navigation suite with icon mode, mobile drawer, and keyboard shortcuts.",
363
+ dependencies: ["clsx", "tailwind-merge", "class-variance-authority", "lucide-solid"],
364
+ registryDependencies: ["tooltip", "skeleton", "separator"],
365
+ },
291
366
  };
292
367
 
293
368
  /**
@@ -458,4 +533,49 @@ export const HOOK_METADATA: Record<string, ComponentMeta> = {
458
533
  title: "createDropZone",
459
534
  description: "SolidJS reactive primitive for file drag & drop operations, validation, and file chooser dialogs",
460
535
  },
536
+ "create-pagination": {
537
+ title: "createPagination",
538
+ description: "SolidJS reactive primitive for computing pagination state, dynamic page ranges with ellipses, and navigation controls",
539
+ },
540
+ "create-chat-scroll": {
541
+ title: "createChatScroll",
542
+ description: "SolidJS reactive primitive for automated chat container scrolling with manual scroll-up detection",
543
+ },
544
+ };
545
+
546
+ /**
547
+ * Static metadata configuration for ready-to-use application and marketing blocks.
548
+ */
549
+ export const BLOCK_METADATA: Record<string, ComponentMeta> = {
550
+ "hero-01": {
551
+ title: "Hero 01 — Simple Centered with Actions",
552
+ description: "A clean centered hero section with badge pill, high-contrast headline, and dual CTA buttons.",
553
+ dependencies: ["clsx", "tailwind-merge", "lucide-solid"],
554
+ registryDependencies: ["button", "badge"],
555
+ },
556
+ "login-01": {
557
+ title: "Login 01 — Split Screen with Social Auth & Testimonial",
558
+ description: "A modern split-screen authentication page block with OAuth providers, email sign-in form, and brand testimonial visual.",
559
+ dependencies: ["clsx", "tailwind-merge", "lucide-solid"],
560
+ registryDependencies: ["button", "input", "label", "checkbox", "separator", "form", "field", "form-message"],
561
+ },
562
+ "register-01": {
563
+ title: "Register 01 — Sign-Up Card with Password Strength",
564
+ description: "A comprehensive sign-up card featuring social logins, live password strength meter with validation checklist, and terms agreement.",
565
+ dependencies: ["clsx", "tailwind-merge", "lucide-solid"],
566
+ registryDependencies: ["card", "input", "label", "button", "checkbox", "progress", "badge", "separator", "form", "field", "form-message"],
567
+ },
568
+ "otp-verification-01": {
569
+ title: "OTP Verification 01 — Two-Factor Security Code",
570
+ description: "A clean 2-Factor Authentication block with a 6-digit PIN input, countdown resend timer, and security notifications.",
571
+ dependencies: ["clsx", "tailwind-merge", "lucide-solid"],
572
+ registryDependencies: ["card", "pin-input", "button", "alert", "badge", "form"],
573
+ },
574
+ "forgot-password-01": {
575
+ title: "Forgot Password 01 — Account Recovery Flow",
576
+ description: "A sleek password recovery block with email instructions submission and success confirmation states.",
577
+ dependencies: ["clsx", "tailwind-merge", "lucide-solid"],
578
+ registryDependencies: ["card", "input", "label", "button", "alert", "form", "field", "form-message"],
579
+ },
461
580
  };
581
+