Skip to content

Commit

Permalink
feat: updated sheet component
Browse files Browse the repository at this point in the history
  • Loading branch information
stefan-karger committed Apr 3, 2024
1 parent 65062a8 commit f6d30b1
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 143 deletions.
2 changes: 1 addition & 1 deletion apps/docs/public/registry/ui/sheet.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"files": [
{
"name": "sheet.tsx",
"content": "import type { Component, ComponentProps } from \"solid-js\"\nimport { splitProps } from \"solid-js\"\n\nimport { Dialog as SheetPrimitive } from \"@kobalte/core\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"~/lib/utils\"\n\nconst Sheet = SheetPrimitive.Root\n\nconst SheetTrigger = SheetPrimitive.Trigger\n\nconst SheetClose = SheetPrimitive.CloseButton\n\nconst portalVariants = cva(\"fixed inset-0 z-50 flex\", {\n variants: {\n position: {\n top: \"items-start\",\n bottom: \"items-end\",\n left: \"justify-start\",\n right: \"justify-end\"\n }\n },\n defaultVariants: { position: \"right\" }\n})\n\ninterface SheetPortalProps\n extends SheetPrimitive.DialogPortalProps,\n VariantProps<typeof portalVariants> {}\n\nconst SheetPortal: Component<SheetPortalProps> = (props) => {\n const [, rest] = splitProps(props, [\"position\", \"children\"])\n return (\n <SheetPrimitive.Portal {...rest}>\n <div class={portalVariants({ position: props.position })}>{props.children}</div>\n </SheetPrimitive.Portal>\n )\n}\n\nconst SheetOverlay: Component<SheetPrimitive.DialogOverlayProps> = (props) => {\n const [, rest] = splitProps(props, [\"class\"])\n return (\n <SheetPrimitive.Overlay\n class={cn(\n \"fixed inset-0 z-50 bg-background/80 backdrop-blur-sm transition-all duration-100 data-[state=closed]:animate-out data-[state=closed]:fade-out data-[state=open]:fade-in\",\n props.class\n )}\n {...rest}\n />\n )\n}\n\nconst sheetVariants = cva(\n \"fixed z-50 scale-100 gap-4 border bg-background p-6 opacity-100 shadow-lg\",\n {\n variants: {\n position: {\n top: \"w-full duration-300 animate-in slide-in-from-top\",\n bottom: \"w-full duration-300 animate-in slide-in-from-bottom\",\n left: \"h-full duration-300 animate-in slide-in-from-left\",\n right: \"h-full duration-300 animate-in slide-in-from-right\"\n },\n size: {\n content: \"\",\n default: \"\",\n sm: \"\",\n lg: \"\",\n xl: \"\",\n full: \"\"\n }\n },\n compoundVariants: [\n {\n position: [\"top\", \"bottom\"],\n size: \"content\",\n class: \"max-h-screen\"\n },\n {\n position: [\"top\", \"bottom\"],\n size: \"default\",\n class: \"h-1/3\"\n },\n {\n position: [\"top\", \"bottom\"],\n size: \"sm\",\n class: \"h-1/4\"\n },\n {\n position: [\"top\", \"bottom\"],\n size: \"lg\",\n class: \"h-1/2\"\n },\n {\n position: [\"top\", \"bottom\"],\n size: \"xl\",\n class: \"h-5/6\"\n },\n {\n position: [\"top\", \"bottom\"],\n size: \"full\",\n class: \"h-screen\"\n },\n {\n position: [\"right\", \"left\"],\n size: \"content\",\n class: \"max-w-screen\"\n },\n {\n position: [\"right\", \"left\"],\n size: \"default\",\n class: \"w-1/3\"\n },\n {\n position: [\"right\", \"left\"],\n size: \"sm\",\n class: \"w-1/4\"\n },\n {\n position: [\"right\", \"left\"],\n size: \"lg\",\n class: \"w-1/2\"\n },\n {\n position: [\"right\", \"left\"],\n size: \"xl\",\n class: \"w-5/6\"\n },\n {\n position: [\"right\", \"left\"],\n size: \"full\",\n class: \"w-screen\"\n }\n ],\n defaultVariants: {\n position: \"right\",\n size: \"default\"\n }\n }\n)\n\nexport interface DialogContentProps\n extends SheetPrimitive.DialogContentProps,\n VariantProps<typeof sheetVariants> {}\n\nconst SheetContent: Component<DialogContentProps> = (props) => {\n const [, rest] = splitProps(props, [\"position\", \"size\", \"class\", \"children\"])\n return (\n <SheetPortal position={props.position}>\n <SheetOverlay />\n <SheetPrimitive.Content\n class={cn(sheetVariants({ position: props.position, size: props.size }), props.class)}\n {...rest}\n >\n {props.children}\n <SheetPrimitive.CloseButton class=\"absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n class=\"size-4\"\n >\n <path d=\"M18 6l-12 12\" />\n <path d=\"M6 6l12 12\" />\n </svg>\n <span class=\"sr-only\">Close</span>\n </SheetPrimitive.CloseButton>\n </SheetPrimitive.Content>\n </SheetPortal>\n )\n}\n\nconst SheetHeader: Component<ComponentProps<\"div\">> = (props) => {\n const [, rest] = splitProps(props, [\"class\"])\n return (\n <div class={cn(\"flex flex-col space-y-2 text-center sm:text-left\", props.class)} {...rest} />\n )\n}\n\nconst SheetFooter: Component<ComponentProps<\"div\">> = (props) => {\n const [, rest] = splitProps(props, [\"class\"])\n return (\n <div\n class={cn(\"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2\", props.class)}\n {...rest}\n />\n )\n}\n\nconst SheetTitle: Component<SheetPrimitive.DialogTitleProps> = (props) => {\n const [, rest] = splitProps(props, [\"class\"])\n return (\n <SheetPrimitive.Title\n class={cn(\"text-lg font-semibold text-foreground\", props.class)}\n {...rest}\n />\n )\n}\n\nconst SheetDescription: Component<SheetPrimitive.DialogDescriptionProps> = (props) => {\n const [, rest] = splitProps(props, [\"class\"])\n return (\n <SheetPrimitive.Description\n class={cn(\"text-sm text-muted-foreground\", props.class)}\n {...rest}\n />\n )\n}\n\nexport {\n Sheet,\n SheetTrigger,\n SheetClose,\n SheetContent,\n SheetHeader,\n SheetFooter,\n SheetTitle,\n SheetDescription\n}\n"
"content": "import type { Component, ComponentProps } from \"solid-js\"\nimport { splitProps } from \"solid-js\"\n\nimport { Dialog as SheetPrimitive } from \"@kobalte/core\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"~/lib/utils\"\n\nconst Sheet = SheetPrimitive.Root\n\nconst SheetTrigger = SheetPrimitive.Trigger\n\nconst SheetClose = SheetPrimitive.CloseButton\n\nconst portalVariants = cva(\"fixed inset-0 z-50 flex\", {\n variants: {\n position: {\n top: \"items-start\",\n bottom: \"items-end\",\n left: \"justify-start\",\n right: \"justify-end\"\n }\n },\n defaultVariants: { position: \"right\" }\n})\n\ninterface SheetPortalProps\n extends SheetPrimitive.DialogPortalProps,\n VariantProps<typeof portalVariants> {}\n\nconst SheetPortal: Component<SheetPortalProps> = (props) => {\n const [, rest] = splitProps(props, [\"position\", \"children\"])\n return (\n <SheetPrimitive.Portal {...rest}>\n <div class={portalVariants({ position: props.position })}>{props.children}</div>\n </SheetPrimitive.Portal>\n )\n}\n\nconst SheetOverlay: Component<SheetPrimitive.DialogOverlayProps> = (props) => {\n const [, rest] = splitProps(props, [\"class\"])\n return (\n <SheetPrimitive.Overlay\n class={cn(\n \"fixed inset-0 z-50 bg-black/80 data-[expanded=]:animate-in data-[closed=]:animate-out data-[closed=]:fade-out-0 data-[expanded=]:fade-in-0\",\n props.class\n )}\n {...rest}\n />\n )\n}\n\nconst sheetVariants = cva(\n \"fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[closed=]:duration-300 data-[expanded=]:duration-500 data-[expanded=]:animate-in data-[closed=]:animate-out\",\n {\n variants: {\n position: {\n top: \"inset-x-0 top-0 border-b data-[closed=]:slide-out-to-top data-[expanded=]:slide-in-from-top\",\n bottom:\n \"inset-x-0 bottom-0 border-t data-[closed=]:slide-out-to-bottom data-[expanded=]:slide-in-from-bottom\",\n left: \"inset-y-0 left-0 h-full w-3/4 border-r data-[closed=]:slide-out-to-left data-[expanded]:slide-in-from-left sm:max-w-sm\",\n right:\n \"inset-y-0 right-0 h-full w-3/4 border-l data-[closed=]:slide-out-to-right data-[expanded=]:slide-in-from-right sm:max-w-sm\"\n }\n },\n defaultVariants: {\n position: \"right\"\n }\n }\n)\n\nexport interface DialogContentProps\n extends SheetPrimitive.DialogContentProps,\n VariantProps<typeof sheetVariants> {}\n\nconst SheetContent: Component<DialogContentProps> = (props) => {\n const [, rest] = splitProps(props, [\"position\", \"class\", \"children\"])\n return (\n <SheetPortal position={props.position}>\n <SheetOverlay />\n <SheetPrimitive.Content\n class={cn(sheetVariants({ position: props.position }), props.class)}\n {...rest}\n >\n {props.children}\n <SheetPrimitive.CloseButton class=\"absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n class=\"size-4\"\n >\n <path d=\"M18 6l-12 12\" />\n <path d=\"M6 6l12 12\" />\n </svg>\n <span class=\"sr-only\">Close</span>\n </SheetPrimitive.CloseButton>\n </SheetPrimitive.Content>\n </SheetPortal>\n )\n}\n\nconst SheetHeader: Component<ComponentProps<\"div\">> = (props) => {\n const [, rest] = splitProps(props, [\"class\"])\n return (\n <div class={cn(\"flex flex-col space-y-2 text-center sm:text-left\", props.class)} {...rest} />\n )\n}\n\nconst SheetFooter: Component<ComponentProps<\"div\">> = (props) => {\n const [, rest] = splitProps(props, [\"class\"])\n return (\n <div\n class={cn(\"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2\", props.class)}\n {...rest}\n />\n )\n}\n\nconst SheetTitle: Component<SheetPrimitive.DialogTitleProps> = (props) => {\n const [, rest] = splitProps(props, [\"class\"])\n return (\n <SheetPrimitive.Title\n class={cn(\"text-lg font-semibold text-foreground\", props.class)}\n {...rest}\n />\n )\n}\n\nconst SheetDescription: Component<SheetPrimitive.DialogDescriptionProps> = (props) => {\n const [, rest] = splitProps(props, [\"class\"])\n return (\n <SheetPrimitive.Description\n class={cn(\"text-sm text-muted-foreground\", props.class)}\n {...rest}\n />\n )\n}\n\nexport {\n Sheet,\n SheetTrigger,\n SheetClose,\n SheetContent,\n SheetHeader,\n SheetFooter,\n SheetTitle,\n SheetDescription\n}\n"
}
],
"type": "ui"
Expand Down
102 changes: 38 additions & 64 deletions apps/docs/src/registry/example/sheet-demo.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { For, createSignal } from "solid-js"
import { For } from "solid-js"

import { As } from "@kobalte/core"

import { Button } from "~/registry/ui/button"
import { Input } from "~/registry/ui/input"
import { Label } from "~/registry/ui/label"
import { RadioGroup, RadioGroupItem } from "~/registry/ui/radio-group"
import {
Sheet,
SheetContent,
Expand All @@ -17,71 +16,46 @@ import {
} from "~/registry/ui/sheet"

const SHEET_POSITIONS = ["top", "right", "bottom", "left"] as const
type SheetPosition = (typeof SHEET_POSITIONS)[number]

const SHEET_SIZES = ["sm", "default", "lg", "xl", "full", "content"] as const
type SheetSize = (typeof SHEET_SIZES)[number]

export default function SheetDemo() {
const [pos, setPos] = createSignal<SheetPosition>("right")
const [size, setSize] = createSignal<SheetSize>("default")

return (
<div class="flex flex-col space-y-8">
<RadioGroup defaultValue={pos()} onChange={(value) => setPos(value as SheetPosition)}>
<div class="grid grid-cols-2 gap-2">
<For each={SHEET_POSITIONS}>
{(pos) => (
<RadioGroupItem value={pos}>
<Label>{pos}</Label>
</RadioGroupItem>
)}
</For>
</div>
</RadioGroup>
<RadioGroup defaultValue={size()} onChange={(value) => setSize(value as SheetSize)}>
<div class="grid grid-cols-2 gap-2">
<For each={SHEET_SIZES}>
{(size) => (
<RadioGroupItem value={size}>
<Label>{size}</Label>
</RadioGroupItem>
)}
</For>
</div>
</RadioGroup>
<Sheet>
<SheetTrigger asChild>
<As component={Button}>
Open {size()} {pos()} sheet
</As>
</SheetTrigger>
<SheetContent size={size()} position={pos()}>
<SheetHeader>
<SheetTitle>Edit profile</SheetTitle>
<SheetDescription>
Make changes to your profile here. Click save when you're done.
</SheetDescription>
</SheetHeader>
<div class="grid gap-4 py-4">
<div class="grid grid-cols-4 items-center gap-4">
<Label for="name" class="text-right">
Name
</Label>
<Input id="name" value="Pedro Duarte" class="col-span-3" />
</div>
<div class="grid grid-cols-4 items-center gap-4">
<Label for="username" class="text-right">
Username
</Label>
<Input id="username" value="@peduarte" class="col-span-3" />
</div>
</div>
<SheetFooter>
<Button type="submit">Save changes</Button>
</SheetFooter>
</SheetContent>
</Sheet>
<div class="grid grid-cols-2 gap-2">
<For each={SHEET_POSITIONS}>
{(position) => (
<Sheet>
<SheetTrigger asChild>
<As component={Button} variant="outline">
{position}
</As>
</SheetTrigger>
<SheetContent position={position}>
<SheetHeader>
<SheetTitle>Edit profile</SheetTitle>
<SheetDescription>
Make changes to your profile here. Click save when you're done.
</SheetDescription>
</SheetHeader>
<div class="grid gap-4 py-4">
<div class="grid grid-cols-4 items-center gap-4">
<Label for="name" class="text-right">
Name
</Label>
<Input id="name" value="Pedro Duarte" class="col-span-3" />
</div>
<div class="grid grid-cols-4 items-center gap-4">
<Label for="username" class="text-right">
Username
</Label>
<Input id="username" value="@peduarte" class="col-span-3" />
</div>
</div>
<SheetFooter>
<Button type="submit">Save changes</Button>
</SheetFooter>
</SheetContent>
</Sheet>
)}
</For>
</div>
)
}
87 changes: 9 additions & 78 deletions apps/docs/src/registry/ui/sheet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ const SheetOverlay: Component<SheetPrimitive.DialogOverlayProps> = (props) => {
return (
<SheetPrimitive.Overlay
class={cn(
"fixed inset-0 z-50 bg-background/80 backdrop-blur-sm transition-all duration-100 data-[closed=]:animate-out data-[closed=]:fade-out data-[expanded=]:fade-in",
"fixed inset-0 z-50 bg-black/80 data-[expanded=]:animate-in data-[closed=]:animate-out data-[closed=]:fade-out-0 data-[expanded=]:fade-in-0",
props.class
)}
{...rest}
Expand All @@ -51,89 +51,20 @@ const SheetOverlay: Component<SheetPrimitive.DialogOverlayProps> = (props) => {
}

const sheetVariants = cva(
"fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[expanded=]:animate-in data-[closed=]:animate-out data-[closed=]:duration-300 data-[expanded=]:duration-500",
"fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[closed=]:duration-300 data-[expanded=]:duration-500 data-[expanded=]:animate-in data-[closed=]:animate-out",
{
variants: {
position: {
top: "inset-x-0 top-0 border-b data-[closed=]:slide-out-to-top data-[expanded=]:slide-in-from-top",
bottom: "inset-x-0 bottom-0 border-t data-[closed=]:slide-out-to-bottom data-[expanded=]:slide-in-from-bottom",
bottom:
"inset-x-0 bottom-0 border-t data-[closed=]:slide-out-to-bottom data-[expanded=]:slide-in-from-bottom",
left: "inset-y-0 left-0 h-full w-3/4 border-r data-[closed=]:slide-out-to-left data-[expanded]:slide-in-from-left sm:max-w-sm",
right: "inset-y-0 right-0 h-full w-3/4 border-l data-[closed=]:slide-out-to-right data-[expanded=]:slide-in-from-right sm:max-w-sm"
},
size: {
content: "",
default: "",
sm: "",
lg: "",
xl: "",
full: ""
right:
"inset-y-0 right-0 h-full w-3/4 border-l data-[closed=]:slide-out-to-right data-[expanded=]:slide-in-from-right sm:max-w-sm"
}
},
compoundVariants: [
{
position: ["top", "bottom"],
size: "content",
class: "max-h-screen"
},
{
position: ["top", "bottom"],
size: "default",
class: "h-1/3"
},
{
position: ["top", "bottom"],
size: "sm",
class: "h-1/4"
},
{
position: ["top", "bottom"],
size: "lg",
class: "h-1/2"
},
{
position: ["top", "bottom"],
size: "xl",
class: "h-5/6"
},
{
position: ["top", "bottom"],
size: "full",
class: "h-screen"
},
{
position: ["right", "left"],
size: "content",
class: "max-w-screen"
},
{
position: ["right", "left"],
size: "default",
class: "w-1/3"
},
{
position: ["right", "left"],
size: "sm",
class: "w-1/4"
},
{
position: ["right", "left"],
size: "lg",
class: "w-1/2"
},
{
position: ["right", "left"],
size: "xl",
class: "w-5/6"
},
{
position: ["right", "left"],
size: "full",
class: "w-screen"
}
],
defaultVariants: {
position: "right",
size: "default"
position: "right"
}
}
)
Expand All @@ -143,12 +74,12 @@ export interface DialogContentProps
VariantProps<typeof sheetVariants> {}

const SheetContent: Component<DialogContentProps> = (props) => {
const [, rest] = splitProps(props, ["position", "size", "class", "children"])
const [, rest] = splitProps(props, ["position", "class", "children"])
return (
<SheetPortal position={props.position}>
<SheetOverlay />
<SheetPrimitive.Content
class={cn(sheetVariants({ position: props.position, size: props.size }), props.class)}
class={cn(sheetVariants({ position: props.position }), props.class)}
{...rest}
>
{props.children}
Expand Down
Loading

0 comments on commit f6d30b1

Please sign in to comment.