vaderjs-daisyui 0.0.1

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 (28) hide show
  1. package/Components/Actions/Button/index.tsx +63 -0
  2. package/Components/Actions/Dropdown/index.tsx +104 -0
  3. package/Components/Actions/Fab/index.tsx +76 -0
  4. package/Components/Actions/Modal/index.tsx +147 -0
  5. package/Components/Actions/Swap/index.tsx +52 -0
  6. package/Components/Actions/ThemeController/index.tsx +133 -0
  7. package/Components/Data/Display/Accordion/index.tsx +82 -0
  8. package/Components/Data/Display/Avatar/index.tsx +96 -0
  9. package/Components/Data/Display/Badge/index.tsx +46 -0
  10. package/Components/Data/Display/Card/index.tsx +72 -0
  11. package/Components/Data/Display/Carousel/index.tsx +72 -0
  12. package/Components/Data/Display/ChatBubble/index.tsx +57 -0
  13. package/Components/Data/Display/Collapse/index.tsx +60 -0
  14. package/Components/Data/Display/Countdown/index.tsx +97 -0
  15. package/Components/Data/Display/Diff/index.tsx +60 -0
  16. package/Components/Data/Display/Hover/Card/index.tsx +37 -0
  17. package/Components/Data/Display/Hover/Gallery/index.tsx +57 -0
  18. package/Components/Data/Display/Keyboard/index.tsx +31 -0
  19. package/Components/Data/Display/List/index.tsx +93 -0
  20. package/Components/Data/Display/Stat/index.tsx +114 -0
  21. package/Components/Data/Display/Table/index.tsx +33 -0
  22. package/Components/Data/Display/TextRotate/index.tsx +118 -0
  23. package/Components/Data/Display/Timeline/index.tsx +209 -0
  24. package/Components/Navigation/BreadCrumbs/index.tsx +201 -0
  25. package/Components/Navigation/Doc/index.tsx +394 -0
  26. package/Components/Navigation/Link/index.tsx +87 -0
  27. package/index.ts +130 -0
  28. package/package.json +15 -0
@@ -0,0 +1,201 @@
1
+ import { component, createElement, VNode } from "vaderjs";
2
+
3
+ export type BreadcrumbItem = {
4
+ label: string | VNode;
5
+ href?: string;
6
+ icon?: VNode | string;
7
+ active?: boolean;
8
+ onClick?: (e: MouseEvent) => void;
9
+ className?: string;
10
+ };
11
+
12
+ export type BreadcrumbsProps = {
13
+ items: BreadcrumbItem[];
14
+ maxWidth?: string; // e.g., "max-w-xs", "max-w-md"
15
+ size?: "xs" | "sm" | "md" | "lg" | "xl";
16
+ separator?: "slash" | "chevron" | "arrow" | "bullet" | "custom";
17
+ customSeparator?: VNode | string;
18
+ className?: string;
19
+ scrollable?: boolean;
20
+ };
21
+
22
+ export const Breadcrumbs = component((props: BreadcrumbsProps) => {
23
+ const {
24
+ items,
25
+ maxWidth,
26
+ size = "sm",
27
+ separator = "slash",
28
+ className = "",
29
+ scrollable = false,
30
+ } = props;
31
+
32
+ const sizeClass = `text-${size}`;
33
+ const maxWidthClass = maxWidth || "";
34
+ const scrollableClass = scrollable ? "overflow-x-auto" : "";
35
+
36
+ const breadcrumbsClasses = [
37
+ "breadcrumbs flex items-center flex-wrap",
38
+ sizeClass,
39
+ maxWidthClass,
40
+ scrollableClass,
41
+ className,
42
+ ].filter(Boolean).join(" ");
43
+
44
+ // Map separator symbols
45
+ const separatorSymbols: Record<string, string> = {
46
+ slash: "/",
47
+ chevron: "›",
48
+ arrow: "→",
49
+ bullet: "•",
50
+ };
51
+ const sepSymbol = separatorSymbols[separator] || "/";
52
+
53
+ const listItems: VNode[] = items.map((item, index) => {
54
+ const { label, href, icon, active = false, onClick, className: itemClassName = "" } = item;
55
+
56
+ const itemClasses = [
57
+ "inline-flex items-center gap-2",
58
+ !active ? "hover:underline cursor-pointer" : "",
59
+ active ? "font-semibold" : "",
60
+ itemClassName,
61
+ // add pseudo separator to all except last
62
+ index < items.length - 1 ? "breadcrumb-separator" : "",
63
+ ].filter(Boolean).join(" ");
64
+
65
+ const content = createElement(
66
+ "span",
67
+ { className: "inline-flex items-center gap-2" },
68
+ [
69
+ icon ? createElement("span", { className: "w-4 h-4" }, icon) : null,
70
+ typeof label === "string" ? label : label,
71
+ ].filter(Boolean)
72
+ );
73
+
74
+ if (onClick) {
75
+ return createElement(
76
+ "li",
77
+ {
78
+ key: index,
79
+ className: itemClasses,
80
+ },
81
+ createElement(
82
+ "span",
83
+ {
84
+ role: "button",
85
+ tabIndex: 0,
86
+ onClick,
87
+ onKeyDown: (e: KeyboardEvent) => {
88
+ if (e.key === "Enter" || e.key === " ") {
89
+ e.preventDefault();
90
+ onClick(e as unknown as MouseEvent);
91
+ }
92
+ },
93
+ },
94
+ content
95
+ )
96
+ );
97
+ } else if (href && !active) {
98
+ return createElement(
99
+ "li",
100
+ { key: index, className: itemClasses },
101
+ createElement(
102
+ "a",
103
+ { href },
104
+ content
105
+ )
106
+ );
107
+ } else {
108
+ return createElement(
109
+ "li",
110
+ { key: index, className: itemClasses },
111
+ content
112
+ );
113
+ }
114
+ });
115
+
116
+ return createElement(
117
+ "div",
118
+ { className: breadcrumbsClasses },
119
+ createElement("ul", { className: "flex items-center flex-wrap" }, listItems)
120
+ );
121
+ });
122
+
123
+
124
+
125
+ // Helper for common icons
126
+ export const BreadcrumbIcons = {
127
+ Home: () => createElement(
128
+ "svg",
129
+ {
130
+ xmlns: "http://www.w3.org/2000/svg",
131
+ fill: "none",
132
+ viewBox: "0 0 24 24",
133
+ className: "w-4 h-4 stroke-current",
134
+ },
135
+ createElement("path", {
136
+ strokeLinecap: "round",
137
+ strokeLinejoin: "round",
138
+ strokeWidth: 2,
139
+ d: "M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z",
140
+ })
141
+ ),
142
+
143
+ Documents: () => createElement(
144
+ "svg",
145
+ {
146
+ xmlns: "http://www.w3.org/2000/svg",
147
+ fill: "none",
148
+ viewBox: "0 0 24 24",
149
+ className: "w-4 h-4 stroke-current",
150
+ },
151
+ createElement("path", {
152
+ strokeLinecap: "round",
153
+ strokeLinejoin: "round",
154
+ strokeWidth: 2,
155
+ d: "M9 13h6m-3-3v6m5 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z",
156
+ })
157
+ ),
158
+
159
+ Folder: () => createElement(
160
+ "svg",
161
+ {
162
+ xmlns: "http://www.w3.org/2000/svg",
163
+ fill: "none",
164
+ viewBox: "0 0 24 24",
165
+ className: "w-4 h-4 stroke-current",
166
+ },
167
+ createElement("path", {
168
+ strokeLinecap: "round",
169
+ strokeLinejoin: "round",
170
+ strokeWidth: 2,
171
+ d: "M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z",
172
+ })
173
+ ),
174
+
175
+ Settings: () => createElement(
176
+ "svg",
177
+ {
178
+ xmlns: "http://www.w3.org/2000/svg",
179
+ fill: "none",
180
+ viewBox: "0 0 24 24",
181
+ className: "w-4 h-4 stroke-current",
182
+ },
183
+ createElement("path", {
184
+ strokeLinecap: "round",
185
+ strokeLinejoin: "round",
186
+ strokeWidth: 2,
187
+ d: "M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z",
188
+ }),
189
+ createElement("path", {
190
+ strokeLinecap: "round",
191
+ strokeLinejoin: "round",
192
+ strokeWidth: 2,
193
+ d: "M15 12a3 3 0 11-6 0 3 3 0 016 0z",
194
+ })
195
+ ),
196
+ };
197
+
198
+ // Pre-built examples
199
+
200
+
201
+ export default Breadcrumbs;
@@ -0,0 +1,394 @@
1
+ import { component, createElement, VNode } from "vaderjs";
2
+
3
+ export type DockItem = {
4
+ label?: string;
5
+ icon: VNode | string;
6
+ active?: boolean;
7
+ onClick?: (e: MouseEvent) => void;
8
+ href?: string;
9
+ className?: string;
10
+ badge?: string | number;
11
+ disabled?: boolean;
12
+ tooltip?: string;
13
+ };
14
+
15
+ export type DockProps = {
16
+ items: DockItem[];
17
+ size?: "xs" | "sm" | "md" | "lg" | "xl";
18
+ position?: "bottom" | "top" | "left" | "right";
19
+ fixed?: boolean;
20
+ rounded?: boolean;
21
+ border?: boolean;
22
+ shadow?: boolean;
23
+ className?: string;
24
+ color?: "neutral" | "primary" | "secondary" | "accent" | "info" | "success" | "warning" | "error" | "base" | "ghost";
25
+ maxWidth?: string; // e.g., "max-w-sm", "max-w-md"
26
+ showLabels?: boolean; // Show labels for all items (not just on hover)
27
+ compact?: boolean; // Hide labels (icons only)
28
+ };
29
+
30
+ export const Dock = component((props: DockProps) => {
31
+ const {
32
+ items,
33
+ size = "md",
34
+ position = "bottom",
35
+ fixed = false,
36
+ rounded = true,
37
+ border = true,
38
+ shadow = true,
39
+ className = "",
40
+ color = "base",
41
+ maxWidth,
42
+ showLabels = true,
43
+ compact = false,
44
+ } = props;
45
+
46
+ // Build dock classes
47
+ const dockClasses = [
48
+ "dock",
49
+ `dock-${size}`,
50
+ fixed ? "fixed" : "relative",
51
+ position === "bottom" ? "bottom-0 left-0 right-0" : "",
52
+ position === "top" ? "top-0 left-0 right-0" : "",
53
+ position === "left" ? "left-0 top-0 bottom-0 flex-col" : "",
54
+ position === "right" ? "right-0 top-0 bottom-0 flex-col" : "",
55
+ rounded ? "rounded-box" : "",
56
+ border ? "border border-base-300" : "",
57
+ shadow ? "shadow-lg" : "",
58
+ color === "base" ? "bg-base-100" : `bg-${color} text-${color}-content`,
59
+ maxWidth,
60
+ className,
61
+ ].filter(Boolean).join(" ");
62
+
63
+ // Build position classes for container
64
+ const containerClasses = [
65
+ position === "bottom" ? "items-end justify-center" : "",
66
+ position === "top" ? "items-start justify-center" : "",
67
+ position === "left" ? "justify-start items-center" : "",
68
+ position === "right" ? "justify-end items-center" : "",
69
+ "flex",
70
+ ].filter(Boolean).join(" ");
71
+
72
+ const renderItem = (item: DockItem, index: number) => {
73
+ const {
74
+ label,
75
+ icon,
76
+ active = false,
77
+ onClick,
78
+ href,
79
+ className: itemClassName = "",
80
+ badge,
81
+ disabled = false,
82
+ tooltip,
83
+ } = item;
84
+
85
+ const itemClasses = [
86
+ "flex flex-col items-center justify-center",
87
+ active ? "dock-active" : "",
88
+ disabled ? "opacity-50 cursor-not-allowed" : "hover:bg-base-200 hover:bg-opacity-50",
89
+ itemClassName,
90
+ ].filter(Boolean).join(" ");
91
+
92
+ const content = createElement(
93
+ "div",
94
+ { className: "flex flex-col items-center justify-center p-2" },
95
+ [
96
+ // Icon container
97
+ createElement(
98
+ "div",
99
+ {
100
+ className: "relative",
101
+ style: { width: "2em", height: "2em" }
102
+ },
103
+ [
104
+ // Icon
105
+ createElement(
106
+ "div",
107
+ { className: "flex items-center justify-center w-full h-full" },
108
+ typeof icon === "string"
109
+ ? createElement("span", {}, icon)
110
+ : icon
111
+ ),
112
+ // Badge
113
+ badge ? createElement(
114
+ "span",
115
+ {
116
+ className: "absolute -top-1 -right-1 badge badge-xs badge-primary",
117
+ style: { minWidth: "1.25rem", minHeight: "1.25rem" }
118
+ },
119
+ badge
120
+ ) : null,
121
+ ].filter(Boolean)
122
+ ),
123
+ // Label (only show if showLabels is true and label exists)
124
+ showLabels && label && !compact ? createElement(
125
+ "span",
126
+ { className: "dock-label text-xs mt-1" },
127
+ label
128
+ ) : null,
129
+ // Tooltip (for compact mode)
130
+ !showLabels && compact && tooltip ? createElement(
131
+ "div",
132
+ {
133
+ className: "absolute opacity-0 group-hover:opacity-100 transition-opacity bg-base-100 text-base-content px-2 py-1 rounded text-xs whitespace-nowrap",
134
+ style: {
135
+ top: position === "bottom" ? "-2.5rem" : "auto",
136
+ bottom: position === "top" ? "-2.5rem" : "auto",
137
+ left: position === "right" ? "-2.5rem" : "auto",
138
+ right: position === "left" ? "-2.5rem" : "auto",
139
+ }
140
+ },
141
+ tooltip
142
+ ) : null,
143
+ ].filter(Boolean)
144
+ );
145
+
146
+ const commonProps = {
147
+ className: itemClasses,
148
+ disabled,
149
+ "aria-label": label || tooltip,
150
+ title: tooltip,
151
+ };
152
+
153
+ if (href && !disabled) {
154
+ return createElement(
155
+ "a",
156
+ {
157
+ key: index,
158
+ href,
159
+ ...commonProps,
160
+ },
161
+ content
162
+ );
163
+ }
164
+
165
+ return createElement(
166
+ "button",
167
+ {
168
+ key: index,
169
+ type: "button",
170
+ onClick: disabled ? undefined : onClick,
171
+ ...commonProps,
172
+ },
173
+ content
174
+ );
175
+ };
176
+
177
+ return createElement(
178
+ "div",
179
+ { className: containerClasses },
180
+ createElement(
181
+ "div",
182
+ { className: dockClasses },
183
+ items.map(renderItem)
184
+ )
185
+ );
186
+ });
187
+
188
+ // Pre-built icon components
189
+ export const DockIcons = {
190
+ Home: () => createElement(
191
+ "svg",
192
+ {
193
+ xmlns: "http://www.w3.org/2000/svg",
194
+ viewBox: "0 0 24 24",
195
+ className: "size-[1.2em]",
196
+ },
197
+ createElement("g", {
198
+ fill: "currentColor",
199
+ strokeLinejoin: "miter",
200
+ strokeLinecap: "butt"
201
+ }, [
202
+ createElement("polyline", {
203
+ points: "1 11 12 2 23 11",
204
+ fill: "none",
205
+ stroke: "currentColor",
206
+ strokeMiterlimit: "10",
207
+ strokeWidth: "2",
208
+ }),
209
+ createElement("path", {
210
+ d: "m5,13v7c0,1.105.895,2,2,2h10c1.105,0,2-.895,2-2v-7",
211
+ fill: "none",
212
+ stroke: "currentColor",
213
+ strokeLinecap: "square",
214
+ strokeMiterlimit: "10",
215
+ strokeWidth: "2",
216
+ }),
217
+ createElement("line", {
218
+ x1: "12",
219
+ y1: "22",
220
+ x2: "12",
221
+ y2: "18",
222
+ fill: "none",
223
+ stroke: "currentColor",
224
+ strokeLinecap: "square",
225
+ strokeMiterlimit: "10",
226
+ strokeWidth: "2",
227
+ }),
228
+ ])
229
+ ),
230
+
231
+ Inbox: () => createElement(
232
+ "svg",
233
+ {
234
+ xmlns: "http://www.w3.org/2000/svg",
235
+ viewBox: "0 0 24 24",
236
+ className: "size-[1.2em]",
237
+ },
238
+ createElement("g", {
239
+ fill: "currentColor",
240
+ strokeLinejoin: "miter",
241
+ strokeLinecap: "butt"
242
+ }, [
243
+ createElement("polyline", {
244
+ points: "3 14 9 14 9 17 15 17 15 14 21 14",
245
+ fill: "none",
246
+ stroke: "currentColor",
247
+ strokeMiterlimit: "10",
248
+ strokeWidth: "2",
249
+ }),
250
+ createElement("rect", {
251
+ x: "3",
252
+ y: "3",
253
+ width: "18",
254
+ height: "18",
255
+ rx: "2",
256
+ ry: "2",
257
+ fill: "none",
258
+ stroke: "currentColor",
259
+ strokeLinecap: "square",
260
+ strokeMiterlimit: "10",
261
+ strokeWidth: "2",
262
+ }),
263
+ ])
264
+ ),
265
+
266
+ Settings: () => createElement(
267
+ "svg",
268
+ {
269
+ xmlns: "http://www.w3.org/2000/svg",
270
+ viewBox: "0 0 24 24",
271
+ className: "size-[1.2em]",
272
+ },
273
+ createElement("g", {
274
+ fill: "currentColor",
275
+ strokeLinejoin: "miter",
276
+ strokeLinecap: "butt"
277
+ }, [
278
+ createElement("circle", {
279
+ cx: "12",
280
+ cy: "12",
281
+ r: "3",
282
+ fill: "none",
283
+ stroke: "currentColor",
284
+ strokeLinecap: "square",
285
+ strokeMiterlimit: "10",
286
+ strokeWidth: "2",
287
+ }),
288
+ createElement("path", {
289
+ d: "m22,13.25v-2.5l-2.318-.966c-.167-.581-.395-1.135-.682-1.654l.954-2.318-1.768-1.768-2.318.954c-.518-.287-1.073-.515-1.654-.682l-.966-2.318h-2.5l-.966,2.318c-.581.167-1.135.395-1.654.682l-2.318-.954-1.768,1.768.954,2.318c-.287.518-.515,1.073-.682,1.654l-2.318.966v2.5l2.318.966c.167.581.395,1.135.682,1.654l-.954,2.318,1.768,1.768,2.318-.954c.518.287,1.073.515,1.654.682l.966,2.318h2.5l.966-2.318c.581-.167,1.135-.395,1.654-.682l2.318.954,1.768-1.768-.954-2.318c.287-.518.515-1.073.682-1.654l2.318-.966Z",
290
+ fill: "none",
291
+ stroke: "currentColor",
292
+ strokeLinecap: "square",
293
+ strokeMiterlimit: "10",
294
+ strokeWidth: "2",
295
+ }),
296
+ ])
297
+ ),
298
+
299
+ Search: () => createElement(
300
+ "svg",
301
+ {
302
+ xmlns: "http://www.w3.org/2000/svg",
303
+ viewBox: "0 0 24 24",
304
+ className: "size-[1.2em]",
305
+ },
306
+ createElement("circle", {
307
+ cx: "11",
308
+ cy: "11",
309
+ r: "8",
310
+ fill: "none",
311
+ stroke: "currentColor",
312
+ strokeWidth: "2",
313
+ }),
314
+ createElement("line", {
315
+ x1: "21",
316
+ y1: "21",
317
+ x2: "16.65",
318
+ y2: "16.65",
319
+ stroke: "currentColor",
320
+ strokeWidth: "2",
321
+ })
322
+ ),
323
+
324
+ Profile: () => createElement(
325
+ "svg",
326
+ {
327
+ xmlns: "http://www.w3.org/2000/svg",
328
+ viewBox: "0 0 24 24",
329
+ className: "size-[1.2em]",
330
+ },
331
+ createElement("circle", {
332
+ cx: "12",
333
+ cy: "8",
334
+ r: "4",
335
+ fill: "none",
336
+ stroke: "currentColor",
337
+ strokeWidth: "2",
338
+ }),
339
+ createElement("path", {
340
+ d: "M5.3 19c.9-1.8 2.7-3 4.7-3h4c2 0 3.8 1.2 4.7 3",
341
+ fill: "none",
342
+ stroke: "currentColor",
343
+ strokeWidth: "2",
344
+ })
345
+ ),
346
+ };
347
+
348
+ // Pre-built examples
349
+ export const DockExamples = {
350
+ Basic: () => createElement(Dock, {
351
+ items: [
352
+ { label: "Home", icon: DockIcons.Home(), onClick: () => console.log("Home clicked") },
353
+ { label: "Inbox", icon: DockIcons.Inbox(), active: true, badge: "3" },
354
+ { label: "Settings", icon: DockIcons.Settings() },
355
+ ],
356
+ maxWidth: "max-w-sm",
357
+ }),
358
+
359
+ Compact: () => createElement(Dock, {
360
+ items: [
361
+ { icon: DockIcons.Home(), tooltip: "Home" },
362
+ { icon: DockIcons.Inbox(), active: true, tooltip: "Inbox (3)", badge: "3" },
363
+ { icon: DockIcons.Settings(), tooltip: "Settings" },
364
+ { icon: DockIcons.Search(), tooltip: "Search" },
365
+ { icon: DockIcons.Profile(), tooltip: "Profile" },
366
+ ],
367
+ size: "sm",
368
+ compact: true,
369
+ maxWidth: "max-w-sm",
370
+ }),
371
+
372
+ Colored: () => createElement(Dock, {
373
+ items: [
374
+ { label: "Home", icon: DockIcons.Home() },
375
+ { label: "Inbox", icon: DockIcons.Inbox(), active: true, badge: "5" },
376
+ { label: "Settings", icon: DockIcons.Settings() },
377
+ ],
378
+ color: "primary",
379
+ maxWidth: "max-w-sm",
380
+ }),
381
+
382
+ AllSizes: (size: "xs" | "sm" | "md" | "lg" | "xl") => createElement(Dock, {
383
+ items: [
384
+ { label: "Home", icon: DockIcons.Home() },
385
+ { label: "Inbox", icon: DockIcons.Inbox(), active: true },
386
+ { label: "Settings", icon: DockIcons.Settings() },
387
+ ],
388
+ size,
389
+ maxWidth: "max-w-sm",
390
+ showLabels: size !== "xs" && size !== "sm",
391
+ }),
392
+ };
393
+
394
+ export default Dock;
@@ -0,0 +1,87 @@
1
+ import { component, createElement, VNode } from "vaderjs";
2
+
3
+ export type LinkProps = {
4
+ href?: string;
5
+ children: VNode | VNode[] | string;
6
+ color?: "neutral" | "primary" | "secondary" | "accent" | "info" | "success" | "warning" | "error";
7
+ hover?: boolean; // Only show underline on hover
8
+ underline?: boolean; // Force underline (default is true for link class)
9
+ className?: string;
10
+ onClick?: (e: MouseEvent) => void;
11
+ target?: "_blank" | "_self" | "_parent" | "_top";
12
+ rel?: string;
13
+ disabled?: boolean;
14
+ external?: boolean; // Add external link icon
15
+ icon?: VNode | string; // Add icon before text
16
+ iconAfter?: VNode | string; // Add icon after text
17
+ noUnderline?: boolean; // Remove underline completely
18
+ active?: boolean; // Active state
19
+ block?: boolean; // Display as block
20
+ size?: "xs" | "sm" | "md" | "lg" | "xl"; // Text size
21
+ };
22
+
23
+ export const Link = component((props: LinkProps) => {
24
+ const {
25
+ href,
26
+ children,
27
+ color,
28
+ hover = false,
29
+ className = "",
30
+ onClick,
31
+ external = false,
32
+ ...rest
33
+ } = props;
34
+
35
+ // Build link classes
36
+ const linkClasses = [
37
+ "link",
38
+ color ? `link-${color}` : "",
39
+ hover ? "link-hover" : "",
40
+ className,
41
+ ].filter(Boolean).join(" ");
42
+
43
+ // Handle external links
44
+ const linkRel = external ? "noopener noreferrer" : undefined;
45
+ const linkTarget = external ? "_blank" : undefined;
46
+
47
+ const commonProps = {
48
+ className: linkClasses,
49
+ onClick,
50
+ target: linkTarget,
51
+ rel: linkRel,
52
+ ...rest,
53
+ };
54
+
55
+ if (href) {
56
+ return createElement("a", { href, ...commonProps }, children);
57
+ }
58
+
59
+ // If no href but has onClick, render as button
60
+ if (onClick) {
61
+ return createElement("button", { type: "button", ...commonProps }, children);
62
+ }
63
+
64
+ // Otherwise render as span
65
+ return createElement("span", commonProps, children);
66
+ });
67
+
68
+
69
+ // Pre-configured link types
70
+ export const LinkPresets = {
71
+ Primary: (props: Omit<LinkProps, "color">) => createElement(Link, { color: "primary", ...props }),
72
+ Secondary: (props: Omit<LinkProps, "color">) => createElement(Link, { color: "secondary", ...props }),
73
+ Accent: (props: Omit<LinkProps, "color">) => createElement(Link, { color: "accent", ...props }),
74
+ Success: (props: Omit<LinkProps, "color">) => createElement(Link, { color: "success", ...props }),
75
+ Error: (props: Omit<LinkProps, "color">) => createElement(Link, { color: "error", ...props }),
76
+ External: (props: Omit<LinkProps, "external">) => createElement(Link, { external: true, ...props }),
77
+ ButtonLike: (props: LinkProps) => createElement(
78
+ Link,
79
+ {
80
+ className: "btn btn-ghost btn-sm",
81
+ noUnderline: true,
82
+ ...props,
83
+ }
84
+ ),
85
+ };
86
+
87
+ export default Link;