diff --git a/packages/registry/package.json b/packages/registry/package.json new file mode 100644 index 0000000..5698f35 --- /dev/null +++ b/packages/registry/package.json @@ -0,0 +1,19 @@ +{ + "name": "pettyui-registry", + "version": "0.1.0", + "private": true, + "description": "PettyUI styled component registry — shadcn model for SolidJS", + "type": "module", + "scripts": { + "test": "vitest run", + "typecheck": "tsc --noEmit" + }, + "peerDependencies": { + "solid-js": "^1.9.0" + }, + "devDependencies": { + "pettyui": "workspace:*", + "solid-js": "^1.9.12", + "vitest": "^4.1.2" + } +} diff --git a/packages/registry/src/components/dialog.tsx b/packages/registry/src/components/dialog.tsx new file mode 100644 index 0000000..222a3cd --- /dev/null +++ b/packages/registry/src/components/dialog.tsx @@ -0,0 +1,40 @@ +import { Dialog as DialogPrimitive } from "pettyui/dialog"; +import { cn } from "../utils"; +import type { JSX } from "solid-js"; +import { splitProps } from "solid-js"; + +const Dialog = DialogPrimitive; +const DialogTrigger = DialogPrimitive.Trigger; +const DialogClose = DialogPrimitive.Close; +const DialogPortal = DialogPrimitive.Portal; +const DialogTitle = DialogPrimitive.Title; +const DialogDescription = DialogPrimitive.Description; + +/** Renders a dimmed backdrop behind the dialog panel. */ +function DialogOverlay(props: JSX.HTMLAttributes): JSX.Element { + const [local, rest] = splitProps(props, ["class"]); + return ( + + ); +} + +/** Pre-composed dialog panel: wraps Content inside Portal with Overlay included. */ +function DialogContent(props: JSX.HTMLAttributes & { children?: JSX.Element }): JSX.Element { + const [local, rest] = splitProps(props, ["class", "children"]); + return ( + + + + {local.children} + + + ); +} + +export { Dialog, DialogTrigger, DialogContent, DialogOverlay, DialogPortal, DialogClose, DialogTitle, DialogDescription }; diff --git a/packages/registry/src/tokens.css b/packages/registry/src/tokens.css new file mode 100644 index 0000000..bd26200 --- /dev/null +++ b/packages/registry/src/tokens.css @@ -0,0 +1,44 @@ +:root { + --background: 0 0% 100%; + --foreground: 0 0% 3.9%; + --card: 0 0% 100%; + --card-foreground: 0 0% 3.9%; + --popover: 0 0% 100%; + --popover-foreground: 0 0% 3.9%; + --primary: 0 0% 9%; + --primary-foreground: 0 0% 98%; + --secondary: 0 0% 96.1%; + --secondary-foreground: 0 0% 9%; + --muted: 0 0% 96.1%; + --muted-foreground: 0 0% 45.1%; + --accent: 0 0% 96.1%; + --accent-foreground: 0 0% 9%; + --destructive: 0 84.2% 60.2%; + --destructive-foreground: 0 0% 98%; + --border: 0 0% 89.8%; + --input: 0 0% 89.8%; + --ring: 0 0% 3.9%; + --radius: 0.5rem; +} + +.dark { + --background: 0 0% 3.9%; + --foreground: 0 0% 98%; + --card: 0 0% 3.9%; + --card-foreground: 0 0% 98%; + --popover: 0 0% 3.9%; + --popover-foreground: 0 0% 98%; + --primary: 0 0% 98%; + --primary-foreground: 0 0% 9%; + --secondary: 0 0% 14.9%; + --secondary-foreground: 0 0% 98%; + --muted: 0 0% 14.9%; + --muted-foreground: 0 0% 63.9%; + --accent: 0 0% 14.9%; + --accent-foreground: 0 0% 98%; + --destructive: 0 62.8% 30.6%; + --destructive-foreground: 0 0% 98%; + --border: 0 0% 14.9%; + --input: 0 0% 14.9%; + --ring: 0 0% 83.1%; +} diff --git a/packages/registry/src/utils.ts b/packages/registry/src/utils.ts new file mode 100644 index 0000000..be7e4e7 --- /dev/null +++ b/packages/registry/src/utils.ts @@ -0,0 +1,7 @@ +/** + * Merges class name strings, filtering out falsy values (undefined, null, false). + * Drop-in replacement for clsx for simple conditional class composition. + */ +export function cn(...inputs: (string | undefined | null | false)[]): string { + return inputs.filter(Boolean).join(" "); +} diff --git a/packages/registry/tests/utils.test.ts b/packages/registry/tests/utils.test.ts new file mode 100644 index 0000000..1c8b6c1 --- /dev/null +++ b/packages/registry/tests/utils.test.ts @@ -0,0 +1,14 @@ +import { describe, expect, it } from "vitest"; +import { cn } from "../src/utils"; + +describe("cn utility", () => { + it("joins class names", () => { + expect(cn("foo", "bar")).toBe("foo bar"); + }); + it("filters falsy values", () => { + expect(cn("foo", undefined, null, false, "bar")).toBe("foo bar"); + }); + it("returns empty string for no classes", () => { + expect(cn()).toBe(""); + }); +}); diff --git a/packages/registry/tsconfig.json b/packages/registry/tsconfig.json new file mode 100644 index 0000000..4d457dc --- /dev/null +++ b/packages/registry/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "src", + "paths": { + "@/*": ["./src/*"] + } + }, + "include": ["src"] +}