@blibliki/ui 0.9.2
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.
- package/README.md +91 -0
- package/dist/index.d.ts +542 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/eslint/index.js +18 -0
- package/eslint/ui-governance-plugin.js +252 -0
- package/package.json +59 -0
- package/scripts/check-css-palette.mjs +92 -0
- package/src/UIProvider.tsx +38 -0
- package/src/components/badge.tsx +57 -0
- package/src/components/button.tsx +65 -0
- package/src/components/card.tsx +44 -0
- package/src/components/context-menu.tsx +239 -0
- package/src/components/dialog.tsx +127 -0
- package/src/components/divider.tsx +45 -0
- package/src/components/dropdown-menu.tsx +243 -0
- package/src/components/encoder.tsx +323 -0
- package/src/components/fader.tsx +230 -0
- package/src/components/icon-button.tsx +51 -0
- package/src/components/input.tsx +38 -0
- package/src/components/label.tsx +14 -0
- package/src/components/select.tsx +342 -0
- package/src/components/stack.tsx +90 -0
- package/src/components/surface.tsx +88 -0
- package/src/components/switch.tsx +72 -0
- package/src/components/text.tsx +59 -0
- package/src/components/textarea.tsx +43 -0
- package/src/index.ts +120 -0
- package/src/lib/cn.ts +6 -0
- package/src/semantic.ts +72 -0
- package/src/theme.ts +161 -0
- package/styles.css +2041 -0
- package/tokens.css +90 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
|
|
3
|
+
import { join, relative } from "node:path";
|
|
4
|
+
|
|
5
|
+
const ROOT = process.cwd();
|
|
6
|
+
const SRC_DIR = join(ROOT, "src");
|
|
7
|
+
|
|
8
|
+
const CSS_EXTENSION = ".css";
|
|
9
|
+
const IGNORED_FILES = new Set(["tokens.css", "src/tokens.css"]);
|
|
10
|
+
|
|
11
|
+
const RAW_COLOR_PATTERN =
|
|
12
|
+
/#(?:[\da-fA-F]{3,4}|[\da-fA-F]{6}|[\da-fA-F]{8})\b|(?:rgb|rgba|hsl|hsla|oklch)\(/;
|
|
13
|
+
|
|
14
|
+
function collectCssFiles(directory) {
|
|
15
|
+
const entries = readdirSync(directory, { withFileTypes: true });
|
|
16
|
+
const files = [];
|
|
17
|
+
|
|
18
|
+
for (const entry of entries) {
|
|
19
|
+
const fullPath = join(directory, entry.name);
|
|
20
|
+
if (entry.isDirectory()) {
|
|
21
|
+
files.push(...collectCssFiles(fullPath));
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (entry.isFile() && entry.name.endsWith(CSS_EXTENSION)) {
|
|
26
|
+
files.push(fullPath);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return files;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function checkCssFile(absolutePath) {
|
|
34
|
+
const packageRelativePath = relative(ROOT, absolutePath);
|
|
35
|
+
if (IGNORED_FILES.has(packageRelativePath)) {
|
|
36
|
+
return [];
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const source = readFileSync(absolutePath, "utf8");
|
|
40
|
+
const lines = source.split("\n");
|
|
41
|
+
const violations = [];
|
|
42
|
+
|
|
43
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
44
|
+
const line = lines[index];
|
|
45
|
+
if (line.includes("palette-ignore-line")) {
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (!RAW_COLOR_PATTERN.test(line)) {
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
violations.push({
|
|
54
|
+
file: packageRelativePath,
|
|
55
|
+
line: index + 1,
|
|
56
|
+
content: line.trim(),
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return violations;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function main() {
|
|
64
|
+
if (!existsSync(SRC_DIR) || !statSync(SRC_DIR).isDirectory()) {
|
|
65
|
+
console.log("No src directory found, palette check skipped.");
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const cssFiles = collectCssFiles(SRC_DIR);
|
|
70
|
+
const violations = cssFiles.flatMap((file) => checkCssFile(file));
|
|
71
|
+
|
|
72
|
+
if (violations.length === 0) {
|
|
73
|
+
console.log("CSS palette check passed: no raw color literals found.");
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
console.error("CSS palette check failed.");
|
|
78
|
+
console.error("Use variables from tokens.css instead of raw color values.");
|
|
79
|
+
console.error(
|
|
80
|
+
"Add 'palette-ignore-line' on a line only when you intentionally need an exception.",
|
|
81
|
+
);
|
|
82
|
+
console.error("");
|
|
83
|
+
|
|
84
|
+
for (const violation of violations) {
|
|
85
|
+
console.error(`${violation.file}:${violation.line}`);
|
|
86
|
+
console.error(` ${violation.content}`);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
process.exitCode = 1;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
main();
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { cn } from "@/lib/cn";
|
|
3
|
+
import {
|
|
4
|
+
createTheme,
|
|
5
|
+
type UIMode,
|
|
6
|
+
type UITheme,
|
|
7
|
+
themeToCssVariables,
|
|
8
|
+
} from "@/theme";
|
|
9
|
+
|
|
10
|
+
export interface UIProviderProps {
|
|
11
|
+
children: React.ReactNode;
|
|
12
|
+
mode?: UIMode;
|
|
13
|
+
theme?: UITheme;
|
|
14
|
+
className?: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function UIProvider({
|
|
18
|
+
children,
|
|
19
|
+
mode = "light",
|
|
20
|
+
theme,
|
|
21
|
+
className,
|
|
22
|
+
}: UIProviderProps): React.JSX.Element {
|
|
23
|
+
const resolvedTheme = React.useMemo(() => createTheme(theme), [theme]);
|
|
24
|
+
const variables = React.useMemo(
|
|
25
|
+
() => themeToCssVariables(resolvedTheme, mode),
|
|
26
|
+
[resolvedTheme, mode],
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<div
|
|
31
|
+
className={cn(mode === "dark" && "dark", className)}
|
|
32
|
+
data-theme={mode}
|
|
33
|
+
style={variables}
|
|
34
|
+
>
|
|
35
|
+
{children}
|
|
36
|
+
</div>
|
|
37
|
+
);
|
|
38
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { Slot } from "@radix-ui/react-slot";
|
|
2
|
+
import { cva, type VariantProps } from "class-variance-authority";
|
|
3
|
+
import { forwardRef, type HTMLAttributes } from "react";
|
|
4
|
+
import { cn } from "@/lib/cn";
|
|
5
|
+
|
|
6
|
+
const badgeVariants = cva("ui-badge", {
|
|
7
|
+
variants: {
|
|
8
|
+
tone: {
|
|
9
|
+
neutral: "ui-badge--tone-neutral",
|
|
10
|
+
primary: "ui-badge--tone-primary",
|
|
11
|
+
secondary: "ui-badge--tone-secondary",
|
|
12
|
+
success: "ui-badge--tone-success",
|
|
13
|
+
warning: "ui-badge--tone-warning",
|
|
14
|
+
error: "ui-badge--tone-error",
|
|
15
|
+
info: "ui-badge--tone-info",
|
|
16
|
+
},
|
|
17
|
+
variant: {
|
|
18
|
+
soft: "ui-badge--variant-soft",
|
|
19
|
+
solid: "ui-badge--variant-solid",
|
|
20
|
+
outline: "ui-badge--variant-outline",
|
|
21
|
+
},
|
|
22
|
+
size: {
|
|
23
|
+
sm: "ui-badge--size-sm",
|
|
24
|
+
md: "ui-badge--size-md",
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
defaultVariants: {
|
|
28
|
+
tone: "neutral",
|
|
29
|
+
variant: "soft",
|
|
30
|
+
size: "md",
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
type BadgeElement = HTMLSpanElement;
|
|
35
|
+
|
|
36
|
+
export interface BadgeProps
|
|
37
|
+
extends HTMLAttributes<BadgeElement>, VariantProps<typeof badgeVariants> {
|
|
38
|
+
asChild?: boolean;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const Badge = forwardRef<BadgeElement, BadgeProps>(
|
|
42
|
+
({ className, tone, variant, size, asChild = false, ...props }, ref) => {
|
|
43
|
+
const Comp = asChild ? Slot : "span";
|
|
44
|
+
|
|
45
|
+
return (
|
|
46
|
+
<Comp
|
|
47
|
+
ref={ref}
|
|
48
|
+
className={cn(badgeVariants({ tone, variant, size }), className)}
|
|
49
|
+
{...props}
|
|
50
|
+
/>
|
|
51
|
+
);
|
|
52
|
+
},
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
Badge.displayName = "Badge";
|
|
56
|
+
|
|
57
|
+
export { Badge, badgeVariants };
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { Slot } from "@radix-ui/react-slot";
|
|
2
|
+
import { cva, type VariantProps } from "class-variance-authority";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { cn } from "@/lib/cn";
|
|
5
|
+
|
|
6
|
+
const buttonVariants = cva("ui-button", {
|
|
7
|
+
variants: {
|
|
8
|
+
variant: {
|
|
9
|
+
contained: "ui-button--variant-contained",
|
|
10
|
+
outlined: "ui-button--variant-outlined",
|
|
11
|
+
text: "ui-button--variant-text",
|
|
12
|
+
},
|
|
13
|
+
color: {
|
|
14
|
+
primary: "ui-button--color-primary",
|
|
15
|
+
neutral: "ui-button--color-neutral",
|
|
16
|
+
secondary: "ui-button--color-secondary",
|
|
17
|
+
error: "ui-button--color-error",
|
|
18
|
+
warning: "ui-button--color-warning",
|
|
19
|
+
info: "ui-button--color-info",
|
|
20
|
+
success: "ui-button--color-success",
|
|
21
|
+
},
|
|
22
|
+
size: {
|
|
23
|
+
md: "ui-button--size-md",
|
|
24
|
+
sm: "ui-button--size-sm",
|
|
25
|
+
lg: "ui-button--size-lg",
|
|
26
|
+
icon: "ui-button--size-icon",
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
defaultVariants: {
|
|
30
|
+
variant: "contained",
|
|
31
|
+
color: "primary",
|
|
32
|
+
size: "md",
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
type ButtonElement = HTMLButtonElement;
|
|
37
|
+
|
|
38
|
+
export interface ButtonProps
|
|
39
|
+
extends
|
|
40
|
+
Omit<React.ButtonHTMLAttributes<ButtonElement>, "color">,
|
|
41
|
+
VariantProps<typeof buttonVariants> {
|
|
42
|
+
asChild?: boolean;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const Button = React.forwardRef<ButtonElement, ButtonProps>(
|
|
46
|
+
(
|
|
47
|
+
{ className, variant, color, size, asChild = false, type, ...props },
|
|
48
|
+
ref,
|
|
49
|
+
) => {
|
|
50
|
+
const Comp = asChild ? Slot : "button";
|
|
51
|
+
|
|
52
|
+
return (
|
|
53
|
+
<Comp
|
|
54
|
+
ref={ref}
|
|
55
|
+
className={cn(buttonVariants({ variant, color, size }), className)}
|
|
56
|
+
type={asChild ? undefined : (type ?? "button")}
|
|
57
|
+
{...props}
|
|
58
|
+
/>
|
|
59
|
+
);
|
|
60
|
+
},
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
Button.displayName = "Button";
|
|
64
|
+
|
|
65
|
+
export { Button, buttonVariants };
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { type ComponentProps, forwardRef } from "react";
|
|
2
|
+
import { cn } from "@/lib/cn";
|
|
3
|
+
|
|
4
|
+
const Card = forwardRef<HTMLDivElement, ComponentProps<"div">>(
|
|
5
|
+
({ className, ...props }, ref) => {
|
|
6
|
+
return <div ref={ref} className={cn("ui-card", className)} {...props} />;
|
|
7
|
+
},
|
|
8
|
+
);
|
|
9
|
+
|
|
10
|
+
Card.displayName = "Card";
|
|
11
|
+
|
|
12
|
+
function CardHeader({ className, ...props }: ComponentProps<"div">) {
|
|
13
|
+
return <div className={cn("ui-card-header", className)} {...props} />;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function CardTitle({ className, ...props }: ComponentProps<"div">) {
|
|
17
|
+
return <div className={cn("ui-card-title", className)} {...props} />;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function CardDescription({ className, ...props }: ComponentProps<"div">) {
|
|
21
|
+
return <div className={cn("ui-card-description", className)} {...props} />;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function CardAction({ className, ...props }: ComponentProps<"div">) {
|
|
25
|
+
return <div className={cn("ui-card-action", className)} {...props} />;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function CardContent({ className, ...props }: ComponentProps<"div">) {
|
|
29
|
+
return <div className={cn("ui-card-content", className)} {...props} />;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function CardFooter({ className, ...props }: ComponentProps<"div">) {
|
|
33
|
+
return <div className={cn("ui-card-footer", className)} {...props} />;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export {
|
|
37
|
+
Card,
|
|
38
|
+
CardAction,
|
|
39
|
+
CardContent,
|
|
40
|
+
CardDescription,
|
|
41
|
+
CardFooter,
|
|
42
|
+
CardHeader,
|
|
43
|
+
CardTitle,
|
|
44
|
+
};
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import * as ContextMenuPrimitive from "@radix-ui/react-context-menu";
|
|
2
|
+
import type { ComponentProps } from "react";
|
|
3
|
+
import { cn } from "@/lib/cn";
|
|
4
|
+
|
|
5
|
+
function MenuCheckIcon(props: ComponentProps<"svg">) {
|
|
6
|
+
return (
|
|
7
|
+
<svg viewBox="0 0 16 16" fill="none" aria-hidden {...props}>
|
|
8
|
+
<path
|
|
9
|
+
d="M3.5 8.5 6.5 11.5 12.5 4.5"
|
|
10
|
+
stroke="currentColor"
|
|
11
|
+
strokeWidth="1.75"
|
|
12
|
+
strokeLinecap="round"
|
|
13
|
+
strokeLinejoin="round"
|
|
14
|
+
/>
|
|
15
|
+
</svg>
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function MenuDotIcon(props: ComponentProps<"svg">) {
|
|
20
|
+
return (
|
|
21
|
+
<svg viewBox="0 0 16 16" fill="currentColor" aria-hidden {...props}>
|
|
22
|
+
<circle cx="8" cy="8" r="3" />
|
|
23
|
+
</svg>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function MenuChevronRightIcon(props: ComponentProps<"svg">) {
|
|
28
|
+
return (
|
|
29
|
+
<svg viewBox="0 0 16 16" fill="none" aria-hidden {...props}>
|
|
30
|
+
<path
|
|
31
|
+
d="M6 3.5 10.5 8 6 12.5"
|
|
32
|
+
stroke="currentColor"
|
|
33
|
+
strokeWidth="1.5"
|
|
34
|
+
strokeLinecap="round"
|
|
35
|
+
strokeLinejoin="round"
|
|
36
|
+
/>
|
|
37
|
+
</svg>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function ContextMenu(props: ComponentProps<typeof ContextMenuPrimitive.Root>) {
|
|
42
|
+
return <ContextMenuPrimitive.Root {...props} />;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function ContextMenuTrigger(
|
|
46
|
+
props: ComponentProps<typeof ContextMenuPrimitive.Trigger>,
|
|
47
|
+
) {
|
|
48
|
+
return <ContextMenuPrimitive.Trigger {...props} />;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function ContextMenuGroup(
|
|
52
|
+
props: ComponentProps<typeof ContextMenuPrimitive.Group>,
|
|
53
|
+
) {
|
|
54
|
+
return <ContextMenuPrimitive.Group {...props} />;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function ContextMenuPortal(
|
|
58
|
+
props: ComponentProps<typeof ContextMenuPrimitive.Portal>,
|
|
59
|
+
) {
|
|
60
|
+
return <ContextMenuPrimitive.Portal {...props} />;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function ContextMenuSub(
|
|
64
|
+
props: ComponentProps<typeof ContextMenuPrimitive.Sub>,
|
|
65
|
+
) {
|
|
66
|
+
return <ContextMenuPrimitive.Sub {...props} />;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function ContextMenuRadioGroup(
|
|
70
|
+
props: ComponentProps<typeof ContextMenuPrimitive.RadioGroup>,
|
|
71
|
+
) {
|
|
72
|
+
return <ContextMenuPrimitive.RadioGroup {...props} />;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function ContextMenuSubTrigger({
|
|
76
|
+
className,
|
|
77
|
+
inset = false,
|
|
78
|
+
children,
|
|
79
|
+
...props
|
|
80
|
+
}: ComponentProps<typeof ContextMenuPrimitive.SubTrigger> & {
|
|
81
|
+
inset?: boolean;
|
|
82
|
+
}) {
|
|
83
|
+
return (
|
|
84
|
+
<ContextMenuPrimitive.SubTrigger
|
|
85
|
+
data-inset={inset ? "true" : undefined}
|
|
86
|
+
className={cn("ui-dropdown-item ui-dropdown-sub-trigger", className)}
|
|
87
|
+
{...props}
|
|
88
|
+
>
|
|
89
|
+
{children}
|
|
90
|
+
<MenuChevronRightIcon className="ui-dropdown-chevron" />
|
|
91
|
+
</ContextMenuPrimitive.SubTrigger>
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function ContextMenuSubContent({
|
|
96
|
+
className,
|
|
97
|
+
...props
|
|
98
|
+
}: ComponentProps<typeof ContextMenuPrimitive.SubContent>) {
|
|
99
|
+
return (
|
|
100
|
+
<ContextMenuPrimitive.SubContent
|
|
101
|
+
className={cn(
|
|
102
|
+
"ui-dropdown-content ui-dropdown-sub-content ui-context-content ui-context-sub-content",
|
|
103
|
+
className,
|
|
104
|
+
)}
|
|
105
|
+
{...props}
|
|
106
|
+
/>
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function ContextMenuContent({
|
|
111
|
+
className,
|
|
112
|
+
...props
|
|
113
|
+
}: ComponentProps<typeof ContextMenuPrimitive.Content>) {
|
|
114
|
+
return (
|
|
115
|
+
<ContextMenuPrimitive.Portal>
|
|
116
|
+
<ContextMenuPrimitive.Content
|
|
117
|
+
className={cn("ui-dropdown-content ui-context-content", className)}
|
|
118
|
+
{...props}
|
|
119
|
+
/>
|
|
120
|
+
</ContextMenuPrimitive.Portal>
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function ContextMenuItem({
|
|
125
|
+
className,
|
|
126
|
+
inset = false,
|
|
127
|
+
variant = "default",
|
|
128
|
+
...props
|
|
129
|
+
}: ComponentProps<typeof ContextMenuPrimitive.Item> & {
|
|
130
|
+
inset?: boolean;
|
|
131
|
+
variant?: "default" | "destructive";
|
|
132
|
+
}) {
|
|
133
|
+
return (
|
|
134
|
+
<ContextMenuPrimitive.Item
|
|
135
|
+
data-inset={inset ? "true" : undefined}
|
|
136
|
+
data-variant={variant}
|
|
137
|
+
className={cn("ui-dropdown-item", className)}
|
|
138
|
+
{...props}
|
|
139
|
+
/>
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function ContextMenuCheckboxItem({
|
|
144
|
+
className,
|
|
145
|
+
children,
|
|
146
|
+
checked,
|
|
147
|
+
...props
|
|
148
|
+
}: ComponentProps<typeof ContextMenuPrimitive.CheckboxItem>) {
|
|
149
|
+
return (
|
|
150
|
+
<ContextMenuPrimitive.CheckboxItem
|
|
151
|
+
checked={checked}
|
|
152
|
+
className={cn(
|
|
153
|
+
"ui-dropdown-item ui-dropdown-item--with-indicator",
|
|
154
|
+
className,
|
|
155
|
+
)}
|
|
156
|
+
{...props}
|
|
157
|
+
>
|
|
158
|
+
<span className="ui-dropdown-indicator" aria-hidden>
|
|
159
|
+
<ContextMenuPrimitive.ItemIndicator>
|
|
160
|
+
<MenuCheckIcon className="ui-dropdown-indicator-icon" />
|
|
161
|
+
</ContextMenuPrimitive.ItemIndicator>
|
|
162
|
+
</span>
|
|
163
|
+
{children}
|
|
164
|
+
</ContextMenuPrimitive.CheckboxItem>
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function ContextMenuRadioItem({
|
|
169
|
+
className,
|
|
170
|
+
children,
|
|
171
|
+
...props
|
|
172
|
+
}: ComponentProps<typeof ContextMenuPrimitive.RadioItem>) {
|
|
173
|
+
return (
|
|
174
|
+
<ContextMenuPrimitive.RadioItem
|
|
175
|
+
className={cn(
|
|
176
|
+
"ui-dropdown-item ui-dropdown-item--with-indicator",
|
|
177
|
+
className,
|
|
178
|
+
)}
|
|
179
|
+
{...props}
|
|
180
|
+
>
|
|
181
|
+
<span className="ui-dropdown-indicator" aria-hidden>
|
|
182
|
+
<ContextMenuPrimitive.ItemIndicator>
|
|
183
|
+
<MenuDotIcon className="ui-dropdown-indicator-icon" />
|
|
184
|
+
</ContextMenuPrimitive.ItemIndicator>
|
|
185
|
+
</span>
|
|
186
|
+
{children}
|
|
187
|
+
</ContextMenuPrimitive.RadioItem>
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function ContextMenuLabel({
|
|
192
|
+
className,
|
|
193
|
+
inset = false,
|
|
194
|
+
...props
|
|
195
|
+
}: ComponentProps<typeof ContextMenuPrimitive.Label> & {
|
|
196
|
+
inset?: boolean;
|
|
197
|
+
}) {
|
|
198
|
+
return (
|
|
199
|
+
<ContextMenuPrimitive.Label
|
|
200
|
+
data-inset={inset ? "true" : undefined}
|
|
201
|
+
className={cn("ui-dropdown-label", className)}
|
|
202
|
+
{...props}
|
|
203
|
+
/>
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function ContextMenuSeparator({
|
|
208
|
+
className,
|
|
209
|
+
...props
|
|
210
|
+
}: ComponentProps<typeof ContextMenuPrimitive.Separator>) {
|
|
211
|
+
return (
|
|
212
|
+
<ContextMenuPrimitive.Separator
|
|
213
|
+
className={cn("ui-dropdown-separator", className)}
|
|
214
|
+
{...props}
|
|
215
|
+
/>
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function ContextMenuShortcut({ className, ...props }: ComponentProps<"span">) {
|
|
220
|
+
return <span className={cn("ui-dropdown-shortcut", className)} {...props} />;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
export {
|
|
224
|
+
ContextMenu,
|
|
225
|
+
ContextMenuTrigger,
|
|
226
|
+
ContextMenuContent,
|
|
227
|
+
ContextMenuItem,
|
|
228
|
+
ContextMenuCheckboxItem,
|
|
229
|
+
ContextMenuRadioItem,
|
|
230
|
+
ContextMenuLabel,
|
|
231
|
+
ContextMenuSeparator,
|
|
232
|
+
ContextMenuShortcut,
|
|
233
|
+
ContextMenuGroup,
|
|
234
|
+
ContextMenuPortal,
|
|
235
|
+
ContextMenuSub,
|
|
236
|
+
ContextMenuSubContent,
|
|
237
|
+
ContextMenuSubTrigger,
|
|
238
|
+
ContextMenuRadioGroup,
|
|
239
|
+
};
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import * as DialogPrimitive from "@radix-ui/react-dialog";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { cn } from "@/lib/cn";
|
|
4
|
+
|
|
5
|
+
function Dialog(props: React.ComponentProps<typeof DialogPrimitive.Root>) {
|
|
6
|
+
return <DialogPrimitive.Root {...props} />;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function DialogTrigger(
|
|
10
|
+
props: React.ComponentProps<typeof DialogPrimitive.Trigger>,
|
|
11
|
+
) {
|
|
12
|
+
return <DialogPrimitive.Trigger {...props} />;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function DialogPortal(
|
|
16
|
+
props: React.ComponentProps<typeof DialogPrimitive.Portal>,
|
|
17
|
+
) {
|
|
18
|
+
return <DialogPrimitive.Portal {...props} />;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function DialogClose(
|
|
22
|
+
props: React.ComponentProps<typeof DialogPrimitive.Close>,
|
|
23
|
+
) {
|
|
24
|
+
return <DialogPrimitive.Close {...props} />;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function DialogOverlay({
|
|
28
|
+
className,
|
|
29
|
+
...props
|
|
30
|
+
}: React.ComponentProps<typeof DialogPrimitive.Overlay>) {
|
|
31
|
+
return (
|
|
32
|
+
<DialogPrimitive.Overlay
|
|
33
|
+
className={cn("ui-dialog-overlay", className)}
|
|
34
|
+
{...props}
|
|
35
|
+
/>
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function DialogCloseIcon(props: React.ComponentProps<"svg">) {
|
|
40
|
+
return (
|
|
41
|
+
<svg viewBox="0 0 16 16" fill="none" aria-hidden {...props}>
|
|
42
|
+
<path
|
|
43
|
+
d="M3.5 3.5 12.5 12.5M12.5 3.5 3.5 12.5"
|
|
44
|
+
stroke="currentColor"
|
|
45
|
+
strokeWidth="1.5"
|
|
46
|
+
strokeLinecap="round"
|
|
47
|
+
/>
|
|
48
|
+
</svg>
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
interface DialogContentProps extends React.ComponentProps<
|
|
53
|
+
typeof DialogPrimitive.Content
|
|
54
|
+
> {
|
|
55
|
+
hideCloseButton?: boolean;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function DialogContent({
|
|
59
|
+
className,
|
|
60
|
+
children,
|
|
61
|
+
hideCloseButton = false,
|
|
62
|
+
...props
|
|
63
|
+
}: DialogContentProps) {
|
|
64
|
+
return (
|
|
65
|
+
<DialogPortal>
|
|
66
|
+
<DialogOverlay />
|
|
67
|
+
<DialogPrimitive.Content
|
|
68
|
+
className={cn("ui-dialog-content", className)}
|
|
69
|
+
{...props}
|
|
70
|
+
>
|
|
71
|
+
{children}
|
|
72
|
+
{!hideCloseButton && (
|
|
73
|
+
<DialogPrimitive.Close className="ui-dialog-close">
|
|
74
|
+
<DialogCloseIcon className="ui-dialog-close-icon" />
|
|
75
|
+
<span className="ui-visually-hidden">Close</span>
|
|
76
|
+
</DialogPrimitive.Close>
|
|
77
|
+
)}
|
|
78
|
+
</DialogPrimitive.Content>
|
|
79
|
+
</DialogPortal>
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function DialogHeader({ className, ...props }: React.ComponentProps<"div">) {
|
|
84
|
+
return <div className={cn("ui-dialog-header", className)} {...props} />;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function DialogFooter({ className, ...props }: React.ComponentProps<"div">) {
|
|
88
|
+
return <div className={cn("ui-dialog-footer", className)} {...props} />;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function DialogTitle({
|
|
92
|
+
className,
|
|
93
|
+
...props
|
|
94
|
+
}: React.ComponentProps<typeof DialogPrimitive.Title>) {
|
|
95
|
+
return (
|
|
96
|
+
<DialogPrimitive.Title
|
|
97
|
+
className={cn("ui-dialog-title", className)}
|
|
98
|
+
{...props}
|
|
99
|
+
/>
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function DialogDescription({
|
|
104
|
+
className,
|
|
105
|
+
...props
|
|
106
|
+
}: React.ComponentProps<typeof DialogPrimitive.Description>) {
|
|
107
|
+
return (
|
|
108
|
+
<DialogPrimitive.Description
|
|
109
|
+
className={cn("ui-dialog-description", className)}
|
|
110
|
+
{...props}
|
|
111
|
+
/>
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export {
|
|
116
|
+
Dialog,
|
|
117
|
+
DialogPortal,
|
|
118
|
+
DialogOverlay,
|
|
119
|
+
DialogClose,
|
|
120
|
+
DialogTrigger,
|
|
121
|
+
DialogContent,
|
|
122
|
+
DialogHeader,
|
|
123
|
+
DialogFooter,
|
|
124
|
+
DialogTitle,
|
|
125
|
+
DialogDescription,
|
|
126
|
+
type DialogContentProps,
|
|
127
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { cva, type VariantProps } from "class-variance-authority";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { cn } from "@/lib/cn";
|
|
4
|
+
|
|
5
|
+
const dividerVariants = cva("ui-divider", {
|
|
6
|
+
variants: {
|
|
7
|
+
orientation: {
|
|
8
|
+
horizontal: "ui-divider--horizontal",
|
|
9
|
+
vertical: "ui-divider--vertical",
|
|
10
|
+
},
|
|
11
|
+
tone: {
|
|
12
|
+
subtle: "ui-divider--tone-subtle",
|
|
13
|
+
strong: "ui-divider--tone-strong",
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
defaultVariants: {
|
|
17
|
+
orientation: "horizontal",
|
|
18
|
+
tone: "subtle",
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
type DividerElement = HTMLDivElement;
|
|
23
|
+
|
|
24
|
+
export interface DividerProps
|
|
25
|
+
extends
|
|
26
|
+
React.HTMLAttributes<DividerElement>,
|
|
27
|
+
VariantProps<typeof dividerVariants> {}
|
|
28
|
+
|
|
29
|
+
const Divider = React.forwardRef<DividerElement, DividerProps>(
|
|
30
|
+
({ className, orientation, tone, ...props }, ref) => {
|
|
31
|
+
return (
|
|
32
|
+
<div
|
|
33
|
+
ref={ref}
|
|
34
|
+
role="separator"
|
|
35
|
+
aria-orientation={orientation ?? "horizontal"}
|
|
36
|
+
className={cn(dividerVariants({ orientation, tone }), className)}
|
|
37
|
+
{...props}
|
|
38
|
+
/>
|
|
39
|
+
);
|
|
40
|
+
},
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
Divider.displayName = "Divider";
|
|
44
|
+
|
|
45
|
+
export { Divider, dividerVariants };
|