@inklu/docs 0.2.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 (56) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/components.json +25 -0
  3. package/dist/index.d.mts +271 -0
  4. package/dist/index.d.ts +271 -0
  5. package/dist/index.js +2455 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/index.mjs +2368 -0
  8. package/dist/index.mjs.map +1 -0
  9. package/dist/shiki.d.mts +10 -0
  10. package/dist/shiki.d.ts +10 -0
  11. package/dist/shiki.js +47 -0
  12. package/dist/shiki.js.map +1 -0
  13. package/dist/shiki.mjs +22 -0
  14. package/dist/shiki.mjs.map +1 -0
  15. package/dist/styles.css +2556 -0
  16. package/package.json +55 -0
  17. package/src/components/content/changelog-content.tsx +119 -0
  18. package/src/components/content/code-block.tsx +111 -0
  19. package/src/components/content/docs-content.tsx +113 -0
  20. package/src/components/layout/docs-layout.tsx +192 -0
  21. package/src/components/layout/site-header.tsx +152 -0
  22. package/src/components/layout/site-layout.tsx +28 -0
  23. package/src/components/layout/site-provider.tsx +23 -0
  24. package/src/components/layout/site-template.tsx +20 -0
  25. package/src/components/layout/theme-provider.tsx +10 -0
  26. package/src/components/layout/theme-switcher.tsx +42 -0
  27. package/src/components/motion-primitives/morph-icon.tsx +97 -0
  28. package/src/components/motion-primitives/progressive-blur.tsx +64 -0
  29. package/src/components/motion-primitives/sliding-number.tsx +131 -0
  30. package/src/components/motion-primitives/text-effect.tsx +290 -0
  31. package/src/components/motion-primitives/text-morph.tsx +77 -0
  32. package/src/components/motion-primitives/text-scramble.tsx +87 -0
  33. package/src/components/shared/command-block.tsx +193 -0
  34. package/src/components/shared/scroll-fade.tsx +22 -0
  35. package/src/components/ui/badge.tsx +50 -0
  36. package/src/components/ui/brand-logo.tsx +68 -0
  37. package/src/components/ui/button-group.tsx +87 -0
  38. package/src/components/ui/button.tsx +104 -0
  39. package/src/components/ui/card.tsx +97 -0
  40. package/src/components/ui/direction.tsx +6 -0
  41. package/src/components/ui/hover-card.tsx +51 -0
  42. package/src/components/ui/item.tsx +201 -0
  43. package/src/components/ui/separator.tsx +25 -0
  44. package/src/components/ui/toast.tsx +322 -0
  45. package/src/components/ui/tooltip.tsx +66 -0
  46. package/src/hooks/use-copy-to-clipboard.ts +54 -0
  47. package/src/index.ts +30 -0
  48. package/src/lib/constants.ts +63 -0
  49. package/src/lib/motions.ts +21 -0
  50. package/src/lib/utils/audio.ts +56 -0
  51. package/src/lib/utils.ts +14 -0
  52. package/src/shiki.ts +25 -0
  53. package/src/styles.css +112 -0
  54. package/src/typeset.css +513 -0
  55. package/tsconfig.json +15 -0
  56. package/tsup.config.ts +11 -0
@@ -0,0 +1,50 @@
1
+ import { mergeProps } from "@base-ui/react/merge-props";
2
+ import { useRender } from "@base-ui/react/use-render";
3
+ import { SmoothCorners } from "@lisse/react";
4
+ import { cva, type VariantProps } from "class-variance-authority";
5
+
6
+ import { cn } from "@/lib/utils";
7
+
8
+ const badgeVariants = cva(
9
+ "inline-flex h-4 items-center justify-center px-1.5 text-[10px] font-mono uppercase tracking-wide transition-all whitespace-nowrap",
10
+ {
11
+ variants: {
12
+ variant: {
13
+ default: "bg-primary text-primary-foreground",
14
+ secondary: "bg-secondary text-muted-foreground hover:text-foreground",
15
+ outline: "border border-border text-foreground",
16
+ },
17
+ },
18
+ defaultVariants: {
19
+ variant: "default",
20
+ },
21
+ },
22
+ );
23
+
24
+ function Badge({
25
+ className,
26
+ variant = "default",
27
+ render,
28
+ ...props
29
+ }: useRender.ComponentProps<"span"> & VariantProps<typeof badgeVariants>) {
30
+ return (
31
+ <SmoothCorners asChild corners={{ radius: 4, smoothing: 1 }}>
32
+ {useRender({
33
+ defaultTagName: "span",
34
+ props: mergeProps<"span">(
35
+ {
36
+ className: cn(badgeVariants({ variant }), className),
37
+ },
38
+ props,
39
+ ),
40
+ render,
41
+ state: {
42
+ slot: "badge",
43
+ variant,
44
+ },
45
+ })}
46
+ </SmoothCorners>
47
+ );
48
+ }
49
+
50
+ export { Badge, badgeVariants };
@@ -0,0 +1,68 @@
1
+ "use client";
2
+
3
+ import { AnimatePresence, type HTMLMotionProps, motion } from "motion/react";
4
+ import { forwardRef, useState } from "react";
5
+
6
+ interface BrandLogoProps extends HTMLMotionProps<"div"> {}
7
+
8
+ export const BrandLogo = forwardRef<HTMLDivElement, BrandLogoProps>(
9
+ ({ className = "", ...props }, ref) => {
10
+ const [isHovered, setIsHovered] = useState(false);
11
+
12
+ // Apple's approach to spring physics
13
+ const springConfig = {
14
+ type: "spring" as const,
15
+ duration: 0.5,
16
+ bounce: 0.2,
17
+ };
18
+
19
+ // Strong ease-out curve for the morphing crossfade
20
+ const easeOut = [0.23, 1, 0.32, 1] as const;
21
+
22
+ return (
23
+ <motion.div
24
+ ref={ref}
25
+ // No background here. The container is completely transparent.
26
+ className={`relative flex items-center justify-center overflow-hidden transition-shadow ${className}`}
27
+ onHoverStart={() => setIsHovered(true)}
28
+ onHoverEnd={() => setIsHovered(false)}
29
+ whileTap={{ scale: 0.97 }}
30
+ // 1. Container width expands/shrinks naturally using layout
31
+ layout
32
+ transition={springConfig}
33
+ style={{
34
+ height: 24, // Keeps vertical rhythm stable
35
+ cursor: "pointer",
36
+ }}
37
+ {...props}
38
+ >
39
+ <AnimatePresence mode="popLayout" initial={false}>
40
+ {isHovered ? (
41
+ <motion.span
42
+ key="text"
43
+ // 2. The blur creates a glowing "morph" between the shapes
44
+ initial={{ opacity: 0, scale: 0.95, filter: "blur(6px)" }}
45
+ animate={{ opacity: 1, scale: 1, filter: "blur(0px)" }}
46
+ exit={{ opacity: 0, scale: 0.95, filter: "blur(6px)" }}
47
+ transition={{ duration: 0.2, ease: easeOut }}
48
+ className="whitespace-nowrap font-sans text-[16px] font-extrabold lowercase leading-none tracking-tight text-slate-900 dark:text-white"
49
+ >
50
+ inklu
51
+ </motion.span>
52
+ ) : (
53
+ <motion.div
54
+ key="icon"
55
+ initial={{ opacity: 0, scale: 0.95, filter: "blur(6px)" }}
56
+ animate={{ opacity: 1, scale: 1, filter: "blur(0px)" }}
57
+ exit={{ opacity: 0, scale: 0.95, filter: "blur(6px)" }}
58
+ transition={{ duration: 0.2, ease: easeOut }}
59
+ className="h-4 w-4 rounded-sm bg-slate-900 dark:bg-white"
60
+ />
61
+ )}
62
+ </AnimatePresence>
63
+ </motion.div>
64
+ );
65
+ },
66
+ );
67
+
68
+ BrandLogo.displayName = "BrandLogo";
@@ -0,0 +1,87 @@
1
+ import { mergeProps } from "@base-ui/react/merge-props";
2
+ import { useRender } from "@base-ui/react/use-render";
3
+ import { cva, type VariantProps } from "class-variance-authority";
4
+ import { Separator } from "@/components/ui/separator";
5
+ import { cn } from "@/lib/utils";
6
+
7
+ const buttonGroupVariants = cva(
8
+ "flex w-fit items-stretch *:focus-visible:relative *:focus-visible:z-10 has-[>[data-slot=button-group]]:gap-2 has-[select[aria-hidden=true]:last-child]:[&>[data-slot=select-trigger]:last-of-type]:rounded-e-md [&>[data-slot=select-trigger]:not([class*='w-'])]:w-fit [&>input]:flex-1",
9
+ {
10
+ variants: {
11
+ orientation: {
12
+ horizontal:
13
+ "*:data-slot:rounded-e-none [&>[data-slot]:not(:has(~[data-slot]))]:rounded-e-md! [&>[data-slot]~[data-slot]]:rounded-s-none [&>[data-slot]~[data-slot]]:border-s-0",
14
+ vertical:
15
+ "flex-col *:data-slot:rounded-b-none [&>[data-slot]:not(:has(~[data-slot]))]:rounded-b-md! [&>[data-slot]~[data-slot]]:rounded-t-none [&>[data-slot]~[data-slot]]:border-t-0",
16
+ },
17
+ },
18
+ defaultVariants: {
19
+ orientation: "horizontal",
20
+ },
21
+ },
22
+ );
23
+
24
+ function ButtonGroup({
25
+ className,
26
+ orientation,
27
+ ...props
28
+ }: React.ComponentProps<"div"> & VariantProps<typeof buttonGroupVariants>) {
29
+ return (
30
+ // biome-ignore lint/a11y/useSemanticElements: Button group pattern
31
+ <div
32
+ role="group"
33
+ data-slot="button-group"
34
+ data-orientation={orientation}
35
+ className={cn(buttonGroupVariants({ orientation }), className)}
36
+ {...props}
37
+ />
38
+ );
39
+ }
40
+
41
+ function ButtonGroupText({
42
+ className,
43
+ render,
44
+ ...props
45
+ }: useRender.ComponentProps<"div">) {
46
+ return useRender({
47
+ defaultTagName: "div",
48
+ props: mergeProps<"div">(
49
+ {
50
+ className: cn(
51
+ "flex items-center gap-2 rounded-md border bg-muted px-2.5 text-xs/relaxed font-medium [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4",
52
+ className,
53
+ ),
54
+ },
55
+ props,
56
+ ),
57
+ render,
58
+ state: {
59
+ slot: "button-group-text",
60
+ },
61
+ });
62
+ }
63
+
64
+ function ButtonGroupSeparator({
65
+ className,
66
+ orientation = "vertical",
67
+ ...props
68
+ }: React.ComponentProps<typeof Separator>) {
69
+ return (
70
+ <Separator
71
+ data-slot="button-group-separator"
72
+ orientation={orientation}
73
+ className={cn(
74
+ "relative self-stretch bg-input data-horizontal:mx-px data-horizontal:w-auto data-vertical:my-px data-vertical:h-auto",
75
+ className,
76
+ )}
77
+ {...props}
78
+ />
79
+ );
80
+ }
81
+
82
+ export {
83
+ ButtonGroup,
84
+ ButtonGroupSeparator,
85
+ ButtonGroupText,
86
+ buttonGroupVariants,
87
+ };
@@ -0,0 +1,104 @@
1
+ import { mergeProps, useRender } from "@base-ui/react";
2
+ import { SmoothCorners } from "@lisse/react";
3
+ import { cva, type VariantProps } from "class-variance-authority";
4
+ import { cn } from "@/lib/utils";
5
+
6
+ export const buttonVariants = cva(
7
+ "group/button inline-flex shrink-0 items-center justify-center border border-transparent font-medium whitespace-nowrap transition duration-[160ms] ease-out outline-none select-none focus-visible:ring-2 focus-visible:ring-white/20 active:scale-[0.97] disabled:pointer-events-none disabled:opacity-50",
8
+ {
9
+ variants: {
10
+ variant: {
11
+ default:
12
+ "bg-primary text-primary-foreground border-transparent hover:bg-primary/90",
13
+ outline:
14
+ "border-border text-foreground hover:bg-accent hover:text-accent-foreground",
15
+ secondary:
16
+ "bg-secondary text-secondary-foreground hover:bg-secondary/80",
17
+ ghost: "text-foreground hover:bg-accent hover:text-accent-foreground",
18
+ destructive:
19
+ "bg-destructive text-destructive-foreground hover:bg-destructive/90",
20
+ link: "text-foreground underline-offset-4 hover:underline",
21
+ },
22
+ size: {
23
+ default: "h-9 px-[calc(--spacing(3)-1px)] sm:h-8",
24
+ icon: "size-9 sm:size-8",
25
+ "icon-lg": "size-10 sm:size-9",
26
+ "icon-sm": "size-8 sm:size-7",
27
+ "icon-xl":
28
+ "size-11 sm:size-10 [&_svg:not([class*='size-'])]:size-5 sm:[&_svg:not([class*='size-'])]:size-4.5",
29
+ "icon-xs":
30
+ "size-7 rounded-md before:rounded-[calc(var(--radius-md)-1px)] sm:size-6 not-in-data-[slot=input-group]:[&_svg:not([class*='size-'])]:size-4 sm:not-in-data-[slot=input-group]:[&_svg:not([class*='size-'])]:size-3.5",
31
+ lg: "h-10 px-[calc(--spacing(3.5)-1px)] sm:h-9",
32
+ sm: "h-8 gap-1.5 px-[calc(--spacing(2.5)-1px)] sm:h-7",
33
+ xl: "h-11 px-[calc(--spacing(4)-1px)] text-lg sm:h-10 sm:text-base [&_svg:not([class*='size-'])]:size-5 sm:[&_svg:not([class*='size-'])]:size-4.5",
34
+ xs: "h-7 gap-1 rounded-md px-[calc(--spacing(2)-1px)] text-sm before:rounded-[calc(var(--radius-md)-1px)] sm:h-6 sm:text-xs [&_svg:not([class*='size-'])]:size-4 sm:[&_svg:not([class*='size-'])]:size-3.5",
35
+ },
36
+ },
37
+ defaultVariants: {
38
+ variant: "default",
39
+ size: "default",
40
+ },
41
+ },
42
+ );
43
+
44
+ export interface ButtonProps extends useRender.ComponentProps<"button"> {
45
+ variant?: VariantProps<typeof buttonVariants>["variant"];
46
+ size?: VariantProps<typeof buttonVariants>["size"];
47
+ loading?: boolean;
48
+ }
49
+ export function Button({
50
+ className,
51
+ variant,
52
+ size = "default",
53
+ render,
54
+ children,
55
+ loading = false,
56
+ disabled: disabledProp,
57
+ ...props
58
+ }: ButtonProps): React.ReactElement {
59
+ const isDisabled: boolean = Boolean(loading || disabledProp);
60
+ const typeValue: React.ButtonHTMLAttributes<HTMLButtonElement>["type"] =
61
+ render ? undefined : "button";
62
+ const defaultProps = {
63
+ children: (
64
+ <>
65
+ {children}
66
+ {loading && (
67
+ <div
68
+ className="pointer-events-none absolute"
69
+ data-slot="button-loading-indicator"
70
+ />
71
+ )}
72
+ </>
73
+ ),
74
+ className: cn(buttonVariants({ className, size, variant })),
75
+ "aria-disabled": loading || undefined,
76
+ "data-loading": loading ? "" : undefined,
77
+ "data-slot": "button",
78
+ disabled: isDisabled,
79
+ type: typeValue,
80
+ };
81
+
82
+ // Determine standard squircle radius depending on size
83
+ let radius = 8;
84
+ if (size === "default") radius = 8;
85
+ else if (size === "sm") radius = 7;
86
+ else if (size === "xs") radius = 5;
87
+ else if (size === "lg") radius = 10;
88
+ else if (size === "xl") radius = 12;
89
+ else if (size === "icon") radius = 8;
90
+ else if (size === "icon-lg") radius = 10;
91
+ else if (size === "icon-sm") radius = 7;
92
+ else if (size === "icon-xl") radius = 12;
93
+ else if (size === "icon-xs") radius = 5;
94
+
95
+ return (
96
+ <SmoothCorners asChild corners={{ radius, smoothing: 1 }}>
97
+ {useRender({
98
+ defaultTagName: "button",
99
+ props: mergeProps<"button">(defaultProps, props),
100
+ render,
101
+ })}
102
+ </SmoothCorners>
103
+ );
104
+ }
@@ -0,0 +1,97 @@
1
+ import { SmoothCorners } from "@lisse/react";
2
+ import type * as React from "react";
3
+
4
+ import { cn } from "@/lib/utils";
5
+
6
+ function Card({
7
+ className,
8
+ size = "default",
9
+ ...props
10
+ }: React.ComponentProps<"div"> & { size?: "default" | "sm" }) {
11
+ return (
12
+ <SmoothCorners asChild corners={{ radius: 24, smoothing: 1 }}>
13
+ <div
14
+ data-slot="card"
15
+ data-size={size}
16
+ className={cn(
17
+ "group/card flex flex-col overflow-hidden bg-card hover:bg-accent transition-colors text-card-foreground",
18
+ className,
19
+ )}
20
+ {...props}
21
+ />
22
+ </SmoothCorners>
23
+ );
24
+ }
25
+
26
+ function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
27
+ return (
28
+ <div
29
+ data-slot="card-header"
30
+ className={cn("flex flex-col gap-1.5 mb-4", className)}
31
+ {...props}
32
+ />
33
+ );
34
+ }
35
+
36
+ function CardTitle({ className, ...props }: React.ComponentProps<"div">) {
37
+ return (
38
+ <div
39
+ data-slot="card-title"
40
+ className={cn("font-medium leading-none tracking-tight", className)}
41
+ {...props}
42
+ />
43
+ );
44
+ }
45
+
46
+ function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
47
+ return (
48
+ <div
49
+ data-slot="card-description"
50
+ className={cn("text-muted-foreground", className)}
51
+ {...props}
52
+ />
53
+ );
54
+ }
55
+
56
+ function CardAction({ className, ...props }: React.ComponentProps<"div">) {
57
+ return (
58
+ <div
59
+ data-slot="card-action"
60
+ className={cn(
61
+ "col-start-2 row-span-2 row-start-1 self-start justify-self-end",
62
+ className,
63
+ )}
64
+ {...props}
65
+ />
66
+ );
67
+ }
68
+
69
+ function CardContent({ className, ...props }: React.ComponentProps<"div">) {
70
+ return (
71
+ <div
72
+ data-slot="card-content"
73
+ className={cn("text-muted-foreground", className)}
74
+ {...props}
75
+ />
76
+ );
77
+ }
78
+
79
+ function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
80
+ return (
81
+ <div
82
+ data-slot="card-footer"
83
+ className={cn("flex items-center pt-4", className)}
84
+ {...props}
85
+ />
86
+ );
87
+ }
88
+
89
+ export {
90
+ Card,
91
+ CardHeader,
92
+ CardFooter,
93
+ CardTitle,
94
+ CardAction,
95
+ CardDescription,
96
+ CardContent,
97
+ };
@@ -0,0 +1,6 @@
1
+ "use client";
2
+
3
+ export {
4
+ DirectionProvider,
5
+ useDirection,
6
+ } from "@base-ui/react/direction-provider";
@@ -0,0 +1,51 @@
1
+ "use client";
2
+
3
+ import { PreviewCard as PreviewCardPrimitive } from "@base-ui/react/preview-card";
4
+
5
+ import { cn } from "@/lib/utils";
6
+
7
+ function HoverCard({ ...props }: PreviewCardPrimitive.Root.Props) {
8
+ return <PreviewCardPrimitive.Root data-slot="hover-card" {...props} />;
9
+ }
10
+
11
+ function HoverCardTrigger({ ...props }: PreviewCardPrimitive.Trigger.Props) {
12
+ return (
13
+ <PreviewCardPrimitive.Trigger data-slot="hover-card-trigger" {...props} />
14
+ );
15
+ }
16
+
17
+ function HoverCardContent({
18
+ className,
19
+ side = "bottom",
20
+ sideOffset = 4,
21
+ align = "center",
22
+ alignOffset = 4,
23
+ ...props
24
+ }: PreviewCardPrimitive.Popup.Props &
25
+ Pick<
26
+ PreviewCardPrimitive.Positioner.Props,
27
+ "align" | "alignOffset" | "side" | "sideOffset"
28
+ >) {
29
+ return (
30
+ <PreviewCardPrimitive.Portal data-slot="hover-card-portal">
31
+ <PreviewCardPrimitive.Positioner
32
+ align={align}
33
+ alignOffset={alignOffset}
34
+ side={side}
35
+ sideOffset={sideOffset}
36
+ className="isolate z-50"
37
+ >
38
+ <PreviewCardPrimitive.Popup
39
+ data-slot="hover-card-content"
40
+ className={cn(
41
+ "z-50 w-64 origin-(--transform-origin) rounded-lg bg-popover p-2.5 text-sm text-popover-foreground shadow-md ring-1 ring-foreground/10 outline-hidden duration-200 ease-out data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
42
+ className,
43
+ )}
44
+ {...props}
45
+ />
46
+ </PreviewCardPrimitive.Positioner>
47
+ </PreviewCardPrimitive.Portal>
48
+ );
49
+ }
50
+
51
+ export { HoverCard, HoverCardTrigger, HoverCardContent };
@@ -0,0 +1,201 @@
1
+ import { mergeProps } from "@base-ui/react/merge-props";
2
+ import { useRender } from "@base-ui/react/use-render";
3
+ import { cva, type VariantProps } from "class-variance-authority";
4
+ import type * as React from "react";
5
+ import { Separator } from "@/components/ui/separator";
6
+ import { cn } from "@/lib/utils";
7
+
8
+ function ItemGroup({ className, ...props }: React.ComponentProps<"div">) {
9
+ return (
10
+ // biome-ignore lint/a11y/useSemanticElements: ARIA list pattern
11
+ <div
12
+ role="list"
13
+ data-slot="item-group"
14
+ className={cn(
15
+ "group/item-group flex w-full flex-col gap-4 has-data-[size=sm]:gap-2.5 has-data-[size=xs]:gap-2",
16
+ className,
17
+ )}
18
+ {...props}
19
+ />
20
+ );
21
+ }
22
+
23
+ function ItemSeparator({
24
+ className,
25
+ ...props
26
+ }: React.ComponentProps<typeof Separator>) {
27
+ return (
28
+ <Separator
29
+ data-slot="item-separator"
30
+ orientation="horizontal"
31
+ className={cn("my-2", className)}
32
+ {...props}
33
+ />
34
+ );
35
+ }
36
+
37
+ const itemVariants = cva(
38
+ "group/item flex w-full flex-wrap items-center rounded-lg border text-sm transition duration-[160ms] ease-out outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 [a]:transition-colors [a]:hover:bg-muted active:scale-[0.97]",
39
+ {
40
+ variants: {
41
+ variant: {
42
+ default: "border-transparent",
43
+ outline: "border-border",
44
+ muted: "border-transparent bg-muted/50",
45
+ },
46
+ size: {
47
+ default: "gap-2.5 px-3 py-2.5",
48
+ sm: "gap-2.5 px-3 py-2.5",
49
+ xs: "gap-2 px-2.5 py-2 in-data-[slot=dropdown-menu-content]:p-0",
50
+ },
51
+ },
52
+ defaultVariants: {
53
+ variant: "default",
54
+ size: "default",
55
+ },
56
+ },
57
+ );
58
+
59
+ function Item({
60
+ className,
61
+ variant = "default",
62
+ size = "default",
63
+ render,
64
+ ...props
65
+ }: useRender.ComponentProps<"div"> & VariantProps<typeof itemVariants>) {
66
+ return useRender({
67
+ defaultTagName: "div",
68
+ props: mergeProps<"div">(
69
+ {
70
+ className: cn(itemVariants({ variant, size, className })),
71
+ },
72
+ props,
73
+ ),
74
+ render,
75
+ state: {
76
+ slot: "item",
77
+ variant,
78
+ size,
79
+ },
80
+ });
81
+ }
82
+
83
+ const itemMediaVariants = cva(
84
+ "flex shrink-0 items-center justify-center gap-2 group-has-data-[slot=item-description]/item:translate-y-0.5 group-has-data-[slot=item-description]/item:self-start [&_svg]:pointer-events-none",
85
+ {
86
+ variants: {
87
+ variant: {
88
+ default: "bg-transparent",
89
+ icon: "[&_svg:not([class*='size-'])]:size-4",
90
+ image:
91
+ "size-10 overflow-hidden rounded-sm group-data-[size=sm]/item:size-8 group-data-[size=xs]/item:size-6 [&_img]:size-full [&_img]:object-cover",
92
+ },
93
+ },
94
+ defaultVariants: {
95
+ variant: "default",
96
+ },
97
+ },
98
+ );
99
+
100
+ function ItemMedia({
101
+ className,
102
+ variant = "default",
103
+ ...props
104
+ }: React.ComponentProps<"div"> & VariantProps<typeof itemMediaVariants>) {
105
+ return (
106
+ <div
107
+ data-slot="item-media"
108
+ data-variant={variant}
109
+ className={cn(itemMediaVariants({ variant, className }))}
110
+ {...props}
111
+ />
112
+ );
113
+ }
114
+
115
+ function ItemContent({ className, ...props }: React.ComponentProps<"div">) {
116
+ return (
117
+ <div
118
+ data-slot="item-content"
119
+ className={cn(
120
+ "flex flex-1 flex-col gap-1 group-data-[size=xs]/item:gap-0 [&+[data-slot=item-content]]:flex-none",
121
+ className,
122
+ )}
123
+ {...props}
124
+ />
125
+ );
126
+ }
127
+
128
+ function ItemTitle({ className, ...props }: React.ComponentProps<"div">) {
129
+ return (
130
+ <div
131
+ data-slot="item-title"
132
+ className={cn(
133
+ "line-clamp-1 flex w-fit items-center gap-2 text-sm leading-snug font-medium underline-offset-4",
134
+ className,
135
+ )}
136
+ {...props}
137
+ />
138
+ );
139
+ }
140
+
141
+ function ItemDescription({ className, ...props }: React.ComponentProps<"p">) {
142
+ return (
143
+ <p
144
+ data-slot="item-description"
145
+ className={cn(
146
+ "line-clamp-2 text-left text-sm leading-normal font-normal text-muted-foreground group-data-[size=xs]/item:text-xs [&>a]:underline [&>a]:underline-offset-4 [&>a:hover]:text-primary",
147
+ className,
148
+ )}
149
+ {...props}
150
+ />
151
+ );
152
+ }
153
+
154
+ function ItemActions({ className, ...props }: React.ComponentProps<"div">) {
155
+ return (
156
+ <div
157
+ data-slot="item-actions"
158
+ className={cn("flex items-center gap-2", className)}
159
+ {...props}
160
+ />
161
+ );
162
+ }
163
+
164
+ function ItemHeader({ className, ...props }: React.ComponentProps<"div">) {
165
+ return (
166
+ <div
167
+ data-slot="item-header"
168
+ className={cn(
169
+ "flex basis-full items-center justify-between gap-2",
170
+ className,
171
+ )}
172
+ {...props}
173
+ />
174
+ );
175
+ }
176
+
177
+ function ItemFooter({ className, ...props }: React.ComponentProps<"div">) {
178
+ return (
179
+ <div
180
+ data-slot="item-footer"
181
+ className={cn(
182
+ "flex basis-full items-center justify-between gap-2",
183
+ className,
184
+ )}
185
+ {...props}
186
+ />
187
+ );
188
+ }
189
+
190
+ export {
191
+ Item,
192
+ ItemMedia,
193
+ ItemContent,
194
+ ItemActions,
195
+ ItemGroup,
196
+ ItemSeparator,
197
+ ItemTitle,
198
+ ItemDescription,
199
+ ItemHeader,
200
+ ItemFooter,
201
+ };
@@ -0,0 +1,25 @@
1
+ "use client";
2
+
3
+ import { Separator as SeparatorPrimitive } from "@base-ui/react/separator";
4
+
5
+ import { cn } from "@/lib/utils";
6
+
7
+ function Separator({
8
+ className,
9
+ orientation = "horizontal",
10
+ ...props
11
+ }: SeparatorPrimitive.Props) {
12
+ return (
13
+ <SeparatorPrimitive
14
+ data-slot="separator"
15
+ orientation={orientation}
16
+ className={cn(
17
+ "shrink-0 bg-border data-horizontal:h-px data-horizontal:w-full data-vertical:w-px data-vertical:self-stretch",
18
+ className,
19
+ )}
20
+ {...props}
21
+ />
22
+ );
23
+ }
24
+
25
+ export { Separator };