@nikala-ui/core 0.6.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 (62) hide show
  1. package/README.md +42 -0
  2. package/package.json +25 -0
  3. package/registry/accordion.json +18 -0
  4. package/registry/alert.json +18 -0
  5. package/registry/avatar.json +17 -0
  6. package/registry/badge.json +18 -0
  7. package/registry/banner.json +19 -0
  8. package/registry/breadcrumb.json +17 -0
  9. package/registry/button.json +18 -0
  10. package/registry/card.json +17 -0
  11. package/registry/checkbox.json +17 -0
  12. package/registry/command.json +25 -0
  13. package/registry/dialog.json +18 -0
  14. package/registry/dropdown-menu.json +18 -0
  15. package/registry/index.json +297 -0
  16. package/registry/input-group.json +21 -0
  17. package/registry/input.json +17 -0
  18. package/registry/kbd.json +18 -0
  19. package/registry/label.json +18 -0
  20. package/registry/list.json +20 -0
  21. package/registry/radio-group.json +18 -0
  22. package/registry/select.json +18 -0
  23. package/registry/separator.json +17 -0
  24. package/registry/sheet.json +19 -0
  25. package/registry/skeleton.json +17 -0
  26. package/registry/switch.json +17 -0
  27. package/registry/tabs.json +17 -0
  28. package/registry/textarea.json +17 -0
  29. package/registry/theme-manager.json +38 -0
  30. package/src/index.css +11 -0
  31. package/src/lib/cn.ts +9 -0
  32. package/src/registry/components/ui/accordion.tsx +128 -0
  33. package/src/registry/components/ui/alert.tsx +155 -0
  34. package/src/registry/components/ui/avatar.tsx +114 -0
  35. package/src/registry/components/ui/badge.tsx +50 -0
  36. package/src/registry/components/ui/banner.tsx +189 -0
  37. package/src/registry/components/ui/breadcrumb.tsx +136 -0
  38. package/src/registry/components/ui/button.tsx +63 -0
  39. package/src/registry/components/ui/card.tsx +113 -0
  40. package/src/registry/components/ui/checkbox.tsx +85 -0
  41. package/src/registry/components/ui/command.tsx +286 -0
  42. package/src/registry/components/ui/dialog.tsx +195 -0
  43. package/src/registry/components/ui/dropdown-menu.tsx +250 -0
  44. package/src/registry/components/ui/input-group.tsx +80 -0
  45. package/src/registry/components/ui/input.tsx +28 -0
  46. package/src/registry/components/ui/kbd.tsx +73 -0
  47. package/src/registry/components/ui/label.tsx +30 -0
  48. package/src/registry/components/ui/list.tsx +222 -0
  49. package/src/registry/components/ui/radio-group.tsx +95 -0
  50. package/src/registry/components/ui/select.tsx +138 -0
  51. package/src/registry/components/ui/separator.tsx +37 -0
  52. package/src/registry/components/ui/sheet.tsx +216 -0
  53. package/src/registry/components/ui/skeleton.tsx +24 -0
  54. package/src/registry/components/ui/switch.tsx +79 -0
  55. package/src/registry/components/ui/tabs.tsx +212 -0
  56. package/src/registry/components/ui/textarea.tsx +82 -0
  57. package/src/registry/components/ui/theme-toggle.tsx +195 -0
  58. package/src/registry/index.ts +50 -0
  59. package/src/registry/metadata.ts +152 -0
  60. package/src/registry/providers/theme-provider.tsx +208 -0
  61. package/src/registry/providers/theme-script.tsx +58 -0
  62. package/src/registry/providers/theme-transitions.ts +108 -0
@@ -0,0 +1,212 @@
1
+ import {
2
+ createContext,
3
+ useContext,
4
+ createSignal,
5
+ splitProps,
6
+ Show,
7
+ type Component,
8
+ type JSX,
9
+ type Accessor,
10
+ } from "solid-js";
11
+ import { cn } from "@/lib/cn";
12
+
13
+ interface TabsContextValue {
14
+ value: Accessor<string | undefined>;
15
+ setValue: (value: string) => void;
16
+ orientation: Accessor<"horizontal" | "vertical">;
17
+ }
18
+
19
+ const TabsContext = createContext<TabsContextValue>();
20
+
21
+ export interface TabsProps
22
+ extends Omit<JSX.HTMLAttributes<HTMLDivElement>, "onChange"> {
23
+ /** Controlled active tab value */
24
+ value?: string;
25
+ /** Uncontrolled default active tab value */
26
+ defaultValue?: string;
27
+ /** Callback fired when active tab changes */
28
+ onChange?: (value: string) => void;
29
+ /** Layout orientation of tab triggers and content */
30
+ orientation?: "horizontal" | "vertical";
31
+ class?: string;
32
+ }
33
+
34
+ /**
35
+ * Root Tabs container component managing active tab context state and orientation.
36
+ */
37
+ export const Tabs: Component<TabsProps> = (props) => {
38
+ const [local, rest] = splitProps(props, [
39
+ "value",
40
+ "defaultValue",
41
+ "onChange",
42
+ "orientation",
43
+ "class",
44
+ "children",
45
+ ]);
46
+
47
+ const [internalValue, setInternalValue] = createSignal(local.defaultValue);
48
+
49
+ const currentValue = () =>
50
+ local.value !== undefined ? local.value : internalValue();
51
+
52
+ const orientation = () => local.orientation || "horizontal";
53
+
54
+ const handleSelect = (val: string) => {
55
+ if (local.value === undefined) {
56
+ setInternalValue(val);
57
+ }
58
+ if (typeof local.onChange === "function") {
59
+ local.onChange(val);
60
+ }
61
+ };
62
+
63
+ const contextValue: TabsContextValue = {
64
+ value: currentValue,
65
+ setValue: handleSelect,
66
+ orientation,
67
+ };
68
+
69
+ return (
70
+ <TabsContext.Provider value={contextValue}>
71
+ <div
72
+ data-orientation={orientation()}
73
+ class={cn(
74
+ "w-full",
75
+ orientation() === "vertical" ? "flex flex-row gap-4" : "flex flex-col gap-2",
76
+ local.class
77
+ )}
78
+ {...rest}
79
+ >
80
+ {local.children}
81
+ </div>
82
+ </TabsContext.Provider>
83
+ );
84
+ };
85
+
86
+ export interface TabsListProps extends JSX.HTMLAttributes<HTMLDivElement> {
87
+ class?: string;
88
+ }
89
+
90
+ /**
91
+ * Container wrapper for Tab triggers.
92
+ */
93
+ export const TabsList: Component<TabsListProps> = (props) => {
94
+ const [local, rest] = splitProps(props, ["class", "children"]);
95
+ const context = useContext(TabsContext);
96
+
97
+ const isVertical = () => context?.orientation() === "vertical";
98
+
99
+ return (
100
+ <div
101
+ role="tablist"
102
+ aria-orientation={context?.orientation() || "horizontal"}
103
+ class={cn(
104
+ "inline-flex rounded-lg bg-muted p-1 text-muted-foreground",
105
+ isVertical()
106
+ ? "flex-col h-auto w-auto items-stretch justify-start"
107
+ : "h-9 items-center justify-center",
108
+ local.class
109
+ )}
110
+ {...rest}
111
+ >
112
+ {local.children}
113
+ </div>
114
+ );
115
+ };
116
+
117
+ export interface TabsTriggerProps
118
+ extends Omit<JSX.ButtonHTMLAttributes<HTMLButtonElement>, "onChange"> {
119
+ /** Unique value identifier for this tab */
120
+ value: string;
121
+ class?: string;
122
+ }
123
+
124
+ /**
125
+ * Tab button trigger to activate a specific tab panel.
126
+ */
127
+ export const TabsTrigger: Component<TabsTriggerProps> = (props) => {
128
+ const [local, rest] = splitProps(props, [
129
+ "value",
130
+ "disabled",
131
+ "class",
132
+ "children",
133
+ "onClick",
134
+ ]);
135
+ const context = useContext(TabsContext);
136
+
137
+ if (!context) {
138
+ throw new Error("TabsTrigger must be used within a Tabs component");
139
+ }
140
+
141
+ const isSelected = () => context.value() === local.value;
142
+ const isVertical = () => context.orientation() === "vertical";
143
+
144
+ const handleClick = (
145
+ e: MouseEvent & { currentTarget: HTMLButtonElement; target: Element }
146
+ ) => {
147
+ if (local.disabled) return;
148
+ context.setValue(local.value);
149
+ if (typeof local.onClick === "function") {
150
+ local.onClick(e);
151
+ }
152
+ };
153
+
154
+ return (
155
+ <button
156
+ type="button"
157
+ role="tab"
158
+ aria-selected={isSelected()}
159
+ data-state={isSelected() ? "active" : "inactive"}
160
+ data-orientation={context.orientation()}
161
+ disabled={local.disabled}
162
+ onClick={handleClick}
163
+ class={cn(
164
+ "inline-flex items-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm cursor-pointer",
165
+ isVertical() ? "justify-start py-1.5" : "justify-center",
166
+ local.class
167
+ )}
168
+ {...rest}
169
+ >
170
+ {local.children}
171
+ </button>
172
+ );
173
+ };
174
+
175
+ export interface TabsContentProps extends JSX.HTMLAttributes<HTMLDivElement> {
176
+ /** Value matching the corresponding tab trigger */
177
+ value: string;
178
+ class?: string;
179
+ }
180
+
181
+ /**
182
+ * Content panel revealed when the associated tab is active.
183
+ */
184
+ export const TabsContent: Component<TabsContentProps> = (props) => {
185
+ const [local, rest] = splitProps(props, ["value", "class", "children"]);
186
+ const context = useContext(TabsContext);
187
+
188
+ if (!context) {
189
+ throw new Error("TabsContent must be used within a Tabs component");
190
+ }
191
+
192
+ const isSelected = () => context.value() === local.value;
193
+ const isVertical = () => context.orientation() === "vertical";
194
+
195
+ return (
196
+ <Show when={isSelected()}>
197
+ <div
198
+ role="tabpanel"
199
+ data-state={isSelected() ? "active" : "inactive"}
200
+ data-orientation={context.orientation()}
201
+ class={cn(
202
+ "ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
203
+ isVertical() ? "flex-1 mt-0" : "mt-2",
204
+ local.class
205
+ )}
206
+ {...rest}
207
+ >
208
+ {local.children}
209
+ </div>
210
+ </Show>
211
+ );
212
+ };
@@ -0,0 +1,82 @@
1
+ // src/components/ui/textarea.tsx
2
+ import {
3
+ createSignal,
4
+ splitProps,
5
+ Show,
6
+ type Component,
7
+ type JSX,
8
+ } from "solid-js";
9
+ import { cn } from "@/lib/cn";
10
+
11
+ export interface TextareaProps
12
+ extends JSX.TextareaHTMLAttributes<HTMLTextAreaElement> {
13
+ /** Uncontrolled initial default value */
14
+ defaultValue?: string | number;
15
+ /** Maximum allowed character limit */
16
+ maxLength?: number;
17
+ /** Whether to show live character count badge */
18
+ showCount?: boolean;
19
+ class?: string;
20
+ }
21
+
22
+ /**
23
+ * Nikala UI Textarea component with optional live character counter and limit indicators.
24
+ */
25
+ export const Textarea: Component<TextareaProps> = (props) => {
26
+ const [local, rest] = splitProps(props, [
27
+ "maxLength",
28
+ "showCount",
29
+ "value",
30
+ "defaultValue",
31
+ "onInput",
32
+ "class",
33
+ ]);
34
+
35
+ /* Internal reactive signal for character count tracking */
36
+ const [currentValue, setCurrentValue] = createSignal<string>(
37
+ String(local.value || local.defaultValue || "")
38
+ );
39
+
40
+ const handleInput: JSX.EventHandlerUnion<HTMLTextAreaElement, InputEvent> = (
41
+ e
42
+ ) => {
43
+ setCurrentValue(e.currentTarget.value);
44
+ if (typeof local.onInput === "function") {
45
+ (local.onInput as (e: InputEvent) => void)(e);
46
+ }
47
+ };
48
+
49
+ const count = () => currentValue().length;
50
+ const isAtLimit = () =>
51
+ local.maxLength !== undefined && count() >= local.maxLength;
52
+
53
+ return (
54
+ <div class="relative flex flex-col w-full">
55
+ <textarea
56
+ value={local.value !== undefined ? String(local.value) : currentValue()}
57
+ maxLength={local.maxLength}
58
+ onInput={handleInput}
59
+ class={cn(
60
+ "flex min-h-[80px] w-full rounded-md border border-input bg-transparent px-3 py-2 text-base shadow-2xs transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
61
+ local.class
62
+ )}
63
+ {...rest}
64
+ />
65
+
66
+ {/* Dynamic Character Counter */}
67
+ <Show when={local.showCount ?? Boolean(local.maxLength)}>
68
+ <div
69
+ class={cn(
70
+ "mt-1 text-right text-[11px] font-mono transition-colors select-none",
71
+ isAtLimit() ? "text-rose-500 font-bold" : "text-muted-foreground"
72
+ )}
73
+ >
74
+ <span>{count()}</span>
75
+ <Show when={local.maxLength}>
76
+ <span> / {local.maxLength}</span>
77
+ </Show>
78
+ </div>
79
+ </Show>
80
+ </div>
81
+ );
82
+ };
@@ -0,0 +1,195 @@
1
+ import { splitProps, type Component, For, Show } from "solid-js";
2
+ import { Sun, Moon, Monitor } from "lucide-solid";
3
+ import {
4
+ useTheme,
5
+ type AccentColor,
6
+ type Radius,
7
+ type Theme,
8
+ } from "../../providers/theme-provider";
9
+ import {
10
+ runThemeTransition,
11
+ type ThemeEffect,
12
+ } from "../../providers/theme-transitions";
13
+ import { Button } from "./button";
14
+ import {
15
+ DropdownMenu,
16
+ DropdownMenuTrigger,
17
+ DropdownMenuContent,
18
+ DropdownMenuItem,
19
+ DropdownMenuLabel,
20
+ DropdownMenuSeparator,
21
+ } from "./dropdown-menu";
22
+ import { cn } from "@/lib/cn";
23
+
24
+ export interface ThemeToggleProps {
25
+ /** Display mode: "mini" for compact dropdown, "max" for full customizer panel (default: "mini") */
26
+ mode?: "mini" | "max";
27
+ /** Transition animation effect when changing themes ("none", "circular", "fade") */
28
+ effect?: ThemeEffect;
29
+ class?: string;
30
+ }
31
+
32
+ const ACCENT_OPTIONS: { name: AccentColor; label: string; color: string }[] = [
33
+ { name: "wine", label: "Wine", color: "bg-[#722f37]" },
34
+ { name: "violet", label: "Violet", color: "bg-[#7c3aed]" },
35
+ { name: "sky", label: "Sky", color: "bg-[#0284c7]" },
36
+ { name: "emerald", label: "Emerald", color: "bg-[#059669]" },
37
+ { name: "rose", label: "Rose", color: "bg-[#e11d48]" },
38
+ { name: "amber", label: "Amber", color: "bg-[#d97706]" },
39
+ { name: "zinc", label: "Zinc", color: "bg-[#18181b]" },
40
+ ];
41
+
42
+ const RADIUS_OPTIONS: { value: Radius; label: string }[] = [
43
+ { value: "0", label: "0" },
44
+ { value: "0.3", label: "0.3" },
45
+ { value: "0.5", label: "0.5" },
46
+ { value: "0.75", label: "0.75" },
47
+ { value: "1.0", label: "1.0" },
48
+ ];
49
+
50
+ /**
51
+ * Interactive UI theme switcher supporting mini/max modes and View Transition animations.
52
+ */
53
+ export const ThemeToggle: Component<ThemeToggleProps> = (props) => {
54
+ const [local] = splitProps(props, ["mode", "effect", "class"]);
55
+ const { theme, setTheme, accent, setAccent, radius, setRadius } = useTheme();
56
+
57
+ const mode = () => local.mode || "mini";
58
+ const effect = () => local.effect || "none";
59
+
60
+ /* Reactive accessor determining whether dark mode is active */
61
+ const isDarkMode = () => {
62
+ const currentTheme = theme();
63
+ if (currentTheme === "dark") return true;
64
+ if (currentTheme === "light") return false;
65
+ return (
66
+ typeof window !== "undefined" &&
67
+ window.matchMedia("(prefers-color-scheme: dark)").matches
68
+ );
69
+ };
70
+
71
+ const changeThemeWithEffect = (newTheme: Theme, e: MouseEvent) => {
72
+ runThemeTransition(effect(), e, () => {
73
+ setTheme(newTheme);
74
+ });
75
+ };
76
+
77
+ return (
78
+ <DropdownMenu placement="bottom-end">
79
+ <DropdownMenuTrigger
80
+ as={Button}
81
+ variant="outline"
82
+ size="icon"
83
+ class={cn("relative h-9 w-9 cursor-pointer", local.class)}
84
+ >
85
+ {/* Reactive Sun / Moon Icon Toggle */}
86
+ <Show
87
+ when={isDarkMode()}
88
+ fallback={<Sun class="h-4 w-4 text-foreground transition-transform" />}
89
+ >
90
+ <Moon class="h-4 w-4 text-foreground transition-transform" />
91
+ </Show>
92
+
93
+ <span class="sr-only">Toggle theme</span>
94
+ </DropdownMenuTrigger>
95
+
96
+ <Show
97
+ when={mode() === "max"}
98
+ fallback={
99
+ /* Mini Mode: Compact Dropdown */
100
+ <DropdownMenuContent>
101
+ <DropdownMenuItem onClick={(e: MouseEvent) => changeThemeWithEffect("light", e)}>
102
+ <Sun class="mr-2 h-4 w-4 text-muted-foreground" />
103
+ Light
104
+ </DropdownMenuItem>
105
+
106
+ <DropdownMenuItem onClick={(e: MouseEvent) => changeThemeWithEffect("dark", e)}>
107
+ <Moon class="mr-2 h-4 w-4 text-muted-foreground" />
108
+ Dark
109
+ </DropdownMenuItem>
110
+
111
+ <DropdownMenuItem onClick={(e: MouseEvent) => changeThemeWithEffect("system", e)}>
112
+ <Monitor class="mr-2 h-4 w-4 text-muted-foreground" />
113
+ System
114
+ </DropdownMenuItem>
115
+ </DropdownMenuContent>
116
+ }
117
+ >
118
+ {/* Max Mode: Full Theme Customizer Panel */}
119
+ <DropdownMenuContent class="w-64 p-3">
120
+ <DropdownMenuLabel class="px-0 pt-0 text-xs font-semibold uppercase tracking-wider text-muted-foreground">
121
+ Theme Mode
122
+ </DropdownMenuLabel>
123
+ <div class="grid grid-cols-3 gap-1 my-1.5">
124
+ <Button
125
+ variant={theme() === "light" ? "default" : "outline"}
126
+ size="sm"
127
+ onClick={(e: MouseEvent) => changeThemeWithEffect("light", e)}
128
+ class="h-8 text-xs cursor-pointer"
129
+ >
130
+ Light
131
+ </Button>
132
+ <Button
133
+ variant={theme() === "dark" ? "default" : "outline"}
134
+ size="sm"
135
+ onClick={(e: MouseEvent) => changeThemeWithEffect("dark", e)}
136
+ class="h-8 text-xs cursor-pointer"
137
+ >
138
+ Dark
139
+ </Button>
140
+ <Button
141
+ variant={theme() === "system" ? "default" : "outline"}
142
+ size="sm"
143
+ onClick={(e: MouseEvent) => changeThemeWithEffect("system", e)}
144
+ class="h-8 text-xs cursor-pointer"
145
+ >
146
+ System
147
+ </Button>
148
+ </div>
149
+
150
+ <DropdownMenuSeparator class="my-2" />
151
+
152
+ <DropdownMenuLabel class="px-0 text-xs font-semibold uppercase tracking-wider text-muted-foreground">
153
+ Brand Accent Color
154
+ </DropdownMenuLabel>
155
+ <div class="flex flex-wrap gap-1.5 my-1.5">
156
+ <For each={ACCENT_OPTIONS}>
157
+ {(opt) => (
158
+ <button
159
+ type="button"
160
+ title={opt.label}
161
+ onClick={() => setAccent(opt.name)}
162
+ class={cn(
163
+ "h-6 w-6 rounded-md transition-all cursor-pointer border border-border flex items-center justify-center",
164
+ opt.color,
165
+ accent() === opt.name ? "ring-2 ring-primary ring-offset-2 ring-offset-background scale-110" : "hover:scale-105"
166
+ )}
167
+ />
168
+ )}
169
+ </For>
170
+ </div>
171
+
172
+ <DropdownMenuSeparator class="my-2" />
173
+
174
+ <DropdownMenuLabel class="px-0 text-xs font-semibold uppercase tracking-wider text-muted-foreground">
175
+ Border Radius
176
+ </DropdownMenuLabel>
177
+ <div class="grid grid-cols-5 gap-1 my-1.5">
178
+ <For each={RADIUS_OPTIONS}>
179
+ {(r) => (
180
+ <Button
181
+ variant={radius() === r.value ? "default" : "outline"}
182
+ size="sm"
183
+ onClick={() => setRadius(r.value)}
184
+ class="h-7 text-xs px-1 cursor-pointer"
185
+ >
186
+ {r.label}
187
+ </Button>
188
+ )}
189
+ </For>
190
+ </div>
191
+ </DropdownMenuContent>
192
+ </Show>
193
+ </DropdownMenu>
194
+ );
195
+ };
@@ -0,0 +1,50 @@
1
+ // src/registry/index.ts
2
+
3
+ /**
4
+ * Represents a single file within a component registry item.
5
+ */
6
+ export interface RegistryFile {
7
+ /** The target relative path where the file will be placed in the user's project (e.g., "ui/button.tsx") */
8
+ path: string;
9
+ /** The full raw text content of the file */
10
+ content: string;
11
+ /** The category type of the file */
12
+ type: "registry:ui" | "registry:util" | "registry:hook";
13
+ }
14
+
15
+ /**
16
+ * Represents the complete manifest structure for a single Nikala UI component.
17
+ */
18
+ export interface RegistryItem {
19
+ /** The unique identifier name of the component (e.g., "button") */
20
+ name: string;
21
+ /** Display title for CLI prompts and documentation */
22
+ title: string;
23
+ /** Short summary describing the component */
24
+ description: string;
25
+ /** Component category type */
26
+ type: "registry:ui";
27
+ /** Required NPM dependencies to be installed automatically (e.g., ["clsx", "tailwind-merge"]) */
28
+ dependencies?: string[];
29
+ /** Internal Nikala UI component dependencies required by this component (e.g., ["button"]) */
30
+ registryDependencies?: string[];
31
+ /** Array of code files comprising this component */
32
+ files: RegistryFile[];
33
+ }
34
+
35
+ /**
36
+ * Lightweight metadata structure used for the central registry index list.
37
+ */
38
+ export interface RegistryIndexItem {
39
+ name: string;
40
+ title: string;
41
+ description: string;
42
+ type: "registry:ui";
43
+ dependencies?: string[];
44
+ registryDependencies?: string[];
45
+ }
46
+
47
+ /**
48
+ * Type alias for the central registry index manifest.
49
+ */
50
+ export type RegistryIndex = RegistryIndexItem[];
@@ -0,0 +1,152 @@
1
+ export interface ComponentMeta {
2
+ title: string;
3
+ description: string;
4
+ dependencies?: string[];
5
+ registryDependencies?: string[];
6
+ }
7
+
8
+ /**
9
+ * Static metadata configuration for all registered Nikala UI components.
10
+ * Extend this record when adding new TSX components.
11
+ */
12
+ export const COMPONENT_METADATA: Record<string, ComponentMeta> = {
13
+ button: {
14
+ title: "Button",
15
+ description: "An interactive button component with variant and size options.",
16
+ dependencies: ["clsx", "tailwind-merge", "class-variance-authority"],
17
+ },
18
+ input: {
19
+ title: "Input",
20
+ description: "A standard text input field with styling variants.",
21
+ dependencies: ["clsx", "tailwind-merge"],
22
+ },
23
+ card: {
24
+ title: "Card",
25
+ description: "A versatile container component with header, content, and footer sections.",
26
+ dependencies: ["clsx", "tailwind-merge"],
27
+ },
28
+ badge: {
29
+ title: "Badge",
30
+ description: "A small badge component for status indicators and tags.",
31
+ dependencies: ["clsx", "tailwind-merge", "class-variance-authority"],
32
+ },
33
+ avatar: {
34
+ title: "Avatar",
35
+ description: "An image element with fallback representation for representing users.",
36
+ dependencies: ["clsx", "tailwind-merge"],
37
+ },
38
+ separator: {
39
+ title: "Separator",
40
+ description: "Visually or semantically separates content horizontally or vertically.",
41
+ dependencies: ["clsx", "tailwind-merge"],
42
+ },
43
+ textarea: {
44
+ title: "Textarea",
45
+ description: "A multi-line text input field with responsive focus styles.",
46
+ dependencies: ["clsx", "tailwind-merge"],
47
+ },
48
+ label: {
49
+ title: "Label",
50
+ description: "Accessible caption label for form controls and inputs.",
51
+ dependencies: ["clsx", "tailwind-merge", "class-variance-authority"],
52
+ },
53
+ skeleton: {
54
+ title: "Skeleton",
55
+ description: "Renders an animated pulse loading placeholder for content loading states.",
56
+ dependencies: ["clsx", "tailwind-merge"],
57
+ },
58
+ switch: {
59
+ title: "Switch",
60
+ description: "A control that allows the user to toggle between checked and unchecked states.",
61
+ dependencies: ["clsx", "tailwind-merge"],
62
+ },
63
+ checkbox: {
64
+ title: "Checkbox",
65
+ description: "A control that allows the user to toggle between checked and unchecked options.",
66
+ dependencies: ["clsx", "tailwind-merge"],
67
+ },
68
+ "radio-group": {
69
+ title: "Radio Group",
70
+ description: "A set of checkable buttons built on Kobalte primitives where only one button can be checked at a time.",
71
+ dependencies: ["clsx", "tailwind-merge", "@kobalte/core"],
72
+ },
73
+ select: {
74
+ title: "Select",
75
+ description: "Displays a list of options for the user to pick from, built on Kobalte primitives.",
76
+ dependencies: ["clsx", "tailwind-merge", "@kobalte/core"],
77
+ },
78
+ tabs: {
79
+ title: "Tabs",
80
+ description: "A set of layered sections of content displayed one at a time.",
81
+ dependencies: ["clsx", "tailwind-merge"],
82
+ },
83
+ accordion: {
84
+ title: "Accordion",
85
+ description: "A vertically stacked set of interactive headings built on Kobalte primitives.",
86
+ dependencies: ["clsx", "tailwind-merge", "@kobalte/core"],
87
+ },
88
+ breadcrumb: {
89
+ title: "Breadcrumb",
90
+ description: "Displays the path to the current resource using a hierarchy of links.",
91
+ dependencies: ["clsx", "tailwind-merge"],
92
+ },
93
+ alert: {
94
+ title: "Alert",
95
+ description: "Displays a callout banner for user feedback with variants, dismiss button, and timer.",
96
+ dependencies: ["clsx", "tailwind-merge", "class-variance-authority"],
97
+ },
98
+ dialog: {
99
+ title: "Dialog",
100
+ description: "A modal window overlaying the main content, built on Kobalte primitives with blur and outside-click options.",
101
+ dependencies: ["clsx", "tailwind-merge", "@kobalte/core"],
102
+ },
103
+ sheet: {
104
+ title: "Sheet / Drawer",
105
+ description: "Extends the dialog component to display content that slides in from screen edges.",
106
+ dependencies: ["clsx", "tailwind-merge", "class-variance-authority", "@kobalte/core"],
107
+ },
108
+ "dropdown-menu": {
109
+ title: "Dropdown Menu",
110
+ description: "Displays a menu to the user—such as a set of actions or functions—triggered by a button or avatar.",
111
+ dependencies: ["clsx", "tailwind-merge", "@kobalte/core"],
112
+ },
113
+ "theme-manager": {
114
+ title: "Theme Manager",
115
+ description: "Zero-dependency ThemeProvider and ThemeToggle component for switching light, dark, and system themes.",
116
+ dependencies: ["clsx", "tailwind-merge", "@kobalte/core", "lucide-solid"],
117
+ registryDependencies: ["button", "dropdown-menu"],
118
+ },
119
+ banner: {
120
+ title: "Banner",
121
+ description: "An announcement banner with sticky positioning, dismissal persistence, auto-hide timer, Lucide icons, and variant styles.",
122
+ dependencies: ["clsx", "tailwind-merge", "class-variance-authority", "lucide-solid"],
123
+ },
124
+ list: {
125
+ title: "List / List Item",
126
+ description: "Compound list components supporting icons, avatars, titles, subtitles, hotkey badges, chevron indicators, and interactive links.",
127
+ dependencies: ["clsx", "tailwind-merge", "class-variance-authority", "lucide-solid", "@kobalte/core"],
128
+ },
129
+ kbd: {
130
+ title: "Kbd (Keyboard Key)",
131
+ description: "Keyboard key and shortcut group indicators for displaying hotkeys.",
132
+ dependencies: ["clsx", "tailwind-merge", "class-variance-authority"],
133
+ },
134
+ "input-group": {
135
+ title: "Input Group",
136
+ description: "Compound input wrapper for combining text inputs with prefix and suffix addons.",
137
+ dependencies: ["clsx", "tailwind-merge", "class-variance-authority"],
138
+ registryDependencies: ["kbd"],
139
+ },
140
+ command: {
141
+ title: "Command / Command Palette",
142
+ description: "Fast, accessible command palette and search modal built on Kobalte Dialog primitives with auto-filtering.",
143
+ dependencies: [
144
+ "clsx",
145
+ "tailwind-merge",
146
+ "class-variance-authority",
147
+ "lucide-solid",
148
+ "@kobalte/core",
149
+ ],
150
+ registryDependencies: ["kbd", "input-group", "list"],
151
+ },
152
+ };