@starwind-ui/core 1.8.0 → 1.10.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.
- package/dist/index.js +50 -23
- package/dist/index.js.map +1 -1
- package/dist/src/components/accordion/Accordion.astro +8 -2
- package/dist/src/components/accordion/AccordionContent.astro +2 -1
- package/dist/src/components/accordion/AccordionItem.astro +8 -2
- package/dist/src/components/accordion/AccordionTrigger.astro +4 -3
- package/dist/src/components/accordion/index.ts +7 -5
- package/dist/src/components/alert/Alert.astro +6 -3
- package/dist/src/components/alert/AlertDescription.astro +4 -4
- package/dist/src/components/alert/AlertTitle.astro +3 -3
- package/dist/src/components/alert/index.ts +6 -4
- package/dist/src/components/alert-dialog/AlertDialog.astro +273 -0
- package/dist/src/components/alert-dialog/AlertDialogAction.astro +44 -0
- package/dist/src/components/alert-dialog/AlertDialogCancel.astro +45 -0
- package/dist/src/components/alert-dialog/AlertDialogContent.astro +50 -0
- package/dist/src/components/alert-dialog/AlertDialogDescription.astro +18 -0
- package/dist/src/components/alert-dialog/AlertDialogFooter.astro +16 -0
- package/dist/src/components/alert-dialog/AlertDialogHeader.astro +14 -0
- package/dist/src/components/alert-dialog/AlertDialogTitle.astro +20 -0
- package/dist/src/components/alert-dialog/AlertDialogTrigger.astro +47 -0
- package/dist/src/components/alert-dialog/index.ts +46 -0
- package/dist/src/components/aspect-ratio/AspectRatio.astro +32 -0
- package/dist/src/components/aspect-ratio/index.ts +7 -0
- package/dist/src/components/avatar/Avatar.astro +2 -2
- package/dist/src/components/avatar/AvatarFallback.astro +2 -2
- package/dist/src/components/avatar/AvatarImage.astro +13 -2
- package/dist/src/components/avatar/index.ts +6 -4
- package/dist/src/components/badge/Badge.astro +15 -12
- package/dist/src/components/badge/index.ts +4 -2
- package/dist/src/components/breadcrumb/Breadcrumb.astro +1 -1
- package/dist/src/components/breadcrumb/BreadcrumbEllipsis.astro +4 -1
- package/dist/src/components/breadcrumb/BreadcrumbItem.astro +2 -2
- package/dist/src/components/breadcrumb/BreadcrumbLink.astro +2 -2
- package/dist/src/components/breadcrumb/BreadcrumbList.astro +2 -2
- package/dist/src/components/breadcrumb/BreadcrumbPage.astro +2 -1
- package/dist/src/components/breadcrumb/BreadcrumbSeparator.astro +2 -1
- package/dist/src/components/breadcrumb/index.ts +16 -6
- package/dist/src/components/button/Button.astro +15 -15
- package/dist/src/components/button/index.ts +4 -2
- package/dist/src/components/card/Card.astro +2 -2
- package/dist/src/components/card/CardContent.astro +2 -2
- package/dist/src/components/card/CardDescription.astro +2 -2
- package/dist/src/components/card/CardFooter.astro +2 -2
- package/dist/src/components/card/CardHeader.astro +2 -2
- package/dist/src/components/card/CardTitle.astro +2 -2
- package/dist/src/components/card/index.ts +16 -7
- package/dist/src/components/carousel/Carousel.astro +55 -0
- package/dist/src/components/carousel/CarouselContent.astro +26 -0
- package/dist/src/components/carousel/CarouselItem.astro +26 -0
- package/dist/src/components/carousel/CarouselNext.astro +33 -0
- package/dist/src/components/carousel/CarouselPrevious.astro +33 -0
- package/dist/src/components/carousel/carousel-script.ts +191 -0
- package/dist/src/components/carousel/index.ts +32 -0
- package/dist/src/components/checkbox/Checkbox.astro +28 -12
- package/dist/src/components/checkbox/index.ts +4 -2
- package/dist/src/components/dialog/Dialog.astro +24 -11
- package/dist/src/components/dialog/DialogClose.astro +7 -2
- package/dist/src/components/dialog/DialogContent.astro +9 -6
- package/dist/src/components/dialog/DialogDescription.astro +2 -2
- package/dist/src/components/dialog/DialogFooter.astro +2 -2
- package/dist/src/components/dialog/DialogHeader.astro +2 -2
- package/dist/src/components/dialog/DialogTitle.astro +2 -2
- package/dist/src/components/dialog/DialogTrigger.astro +7 -1
- package/dist/src/components/dialog/index.ts +20 -5
- package/dist/src/components/dropdown/Dropdown.astro +1 -0
- package/dist/src/components/dropdown/DropdownContent.astro +2 -1
- package/dist/src/components/dropdown/DropdownItem.astro +2 -1
- package/dist/src/components/dropdown/DropdownLabel.astro +2 -2
- package/dist/src/components/dropdown/DropdownSeparator.astro +3 -2
- package/dist/src/components/dropdown/DropdownTrigger.astro +9 -3
- package/dist/src/components/dropdown/index.ts +14 -5
- package/dist/src/components/dropzone/Dropzone.astro +7 -6
- package/dist/src/components/dropzone/DropzoneFilesList.astro +3 -2
- package/dist/src/components/dropzone/DropzoneLoadingIndicator.astro +1 -1
- package/dist/src/components/dropzone/DropzoneUploadIndicator.astro +1 -1
- package/dist/src/components/dropzone/index.ts +14 -3
- package/dist/src/components/input/Input.astro +4 -4
- package/dist/src/components/input/index.ts +4 -2
- package/dist/src/components/item/Item.astro +52 -0
- package/dist/src/components/item/ItemActions.astro +16 -0
- package/dist/src/components/item/ItemContent.astro +16 -0
- package/dist/src/components/item/ItemDescription.astro +19 -0
- package/dist/src/components/item/ItemFooter.astro +16 -0
- package/dist/src/components/item/ItemGroup.astro +16 -0
- package/dist/src/components/item/ItemHeader.astro +16 -0
- package/dist/src/components/item/ItemMedia.astro +40 -0
- package/dist/src/components/item/ItemSeparator.astro +21 -0
- package/dist/src/components/item/ItemTitle.astro +16 -0
- package/dist/src/components/item/index.ts +50 -0
- package/dist/src/components/label/Label.astro +2 -2
- package/dist/src/components/label/index.ts +4 -2
- package/dist/src/components/pagination/Pagination.astro +8 -2
- package/dist/src/components/pagination/PaginationContent.astro +2 -2
- package/dist/src/components/pagination/PaginationEllipsis.astro +7 -2
- package/dist/src/components/pagination/PaginationItem.astro +2 -2
- package/dist/src/components/pagination/PaginationLink.astro +10 -29
- package/dist/src/components/pagination/PaginationNext.astro +2 -1
- package/dist/src/components/pagination/PaginationPrevious.astro +2 -1
- package/dist/src/components/pagination/index.ts +18 -7
- package/dist/src/components/progress/Progress.astro +6 -3
- package/dist/src/components/progress/index.ts +7 -2
- package/dist/src/components/radio-group/RadioGroup.astro +2 -1
- package/dist/src/components/radio-group/RadioGroupItem.astro +17 -15
- package/dist/src/components/radio-group/index.ts +16 -3
- package/dist/src/components/select/Select.astro +1 -0
- package/dist/src/components/select/SelectContent.astro +3 -2
- package/dist/src/components/select/SelectGroup.astro +1 -1
- package/dist/src/components/select/SelectItem.astro +3 -2
- package/dist/src/components/select/SelectLabel.astro +2 -2
- package/dist/src/components/select/SelectSeparator.astro +2 -2
- package/dist/src/components/select/SelectTrigger.astro +4 -3
- package/dist/src/components/select/SelectValue.astro +2 -2
- package/dist/src/components/select/index.ts +18 -6
- package/dist/src/components/separator/Separator.astro +36 -0
- package/dist/src/components/separator/index.ts +7 -0
- package/dist/src/components/sheet/Sheet.astro +13 -0
- package/dist/src/components/sheet/SheetClose.astro +13 -0
- package/dist/src/components/sheet/SheetContent.astro +88 -0
- package/dist/src/components/sheet/SheetDescription.astro +16 -0
- package/dist/src/components/sheet/SheetFooter.astro +16 -0
- package/dist/src/components/sheet/SheetHeader.astro +16 -0
- package/dist/src/components/sheet/SheetTitle.astro +16 -0
- package/dist/src/components/sheet/SheetTrigger.astro +13 -0
- package/dist/src/components/sheet/index.ts +41 -0
- package/dist/src/components/skeleton/Skeleton.astro +3 -3
- package/dist/src/components/skeleton/index.ts +6 -2
- package/dist/src/components/spinner/Spinner.astro +21 -0
- package/dist/src/components/spinner/index.ts +7 -0
- package/dist/src/components/switch/Switch.astro +16 -13
- package/dist/src/components/switch/index.ts +8 -2
- package/dist/src/components/table/Table.astro +3 -3
- package/dist/src/components/table/TableBody.astro +2 -2
- package/dist/src/components/table/TableCaption.astro +2 -2
- package/dist/src/components/table/TableCell.astro +2 -2
- package/dist/src/components/table/TableFoot.astro +2 -2
- package/dist/src/components/table/TableHead.astro +2 -2
- package/dist/src/components/table/TableHeader.astro +2 -2
- package/dist/src/components/table/TableRow.astro +2 -2
- package/dist/src/components/table/index.ts +30 -9
- package/dist/src/components/tabs/Tabs.astro +2 -1
- package/dist/src/components/tabs/TabsContent.astro +4 -1
- package/dist/src/components/tabs/TabsList.astro +9 -3
- package/dist/src/components/tabs/TabsTrigger.astro +6 -3
- package/dist/src/components/tabs/index.ts +12 -5
- package/dist/src/components/textarea/Textarea.astro +4 -4
- package/dist/src/components/textarea/index.ts +6 -2
- package/dist/src/components/tooltip/Tooltip.astro +2 -1
- package/dist/src/components/tooltip/TooltipContent.astro +21 -5
- package/dist/src/components/tooltip/TooltipTrigger.astro +1 -1
- package/dist/src/components/tooltip/index.ts +8 -3
- package/package.json +1 -1
|
@@ -4,11 +4,11 @@ import { tv } from "tailwind-variants";
|
|
|
4
4
|
|
|
5
5
|
type Props = HTMLAttributes<"div">;
|
|
6
6
|
|
|
7
|
-
const card = tv({ base: "bg-card text-card-foreground rounded-2xl border shadow-sm" });
|
|
7
|
+
export const card = tv({ base: "bg-card text-card-foreground rounded-2xl border shadow-sm" });
|
|
8
8
|
|
|
9
9
|
const { class: className, ...rest } = Astro.props;
|
|
10
10
|
---
|
|
11
11
|
|
|
12
|
-
<div class={card({ class: className })} {...rest}>
|
|
12
|
+
<div class={card({ class: className })} data-slot="card" {...rest}>
|
|
13
13
|
<slot />
|
|
14
14
|
</div>
|
|
@@ -4,11 +4,11 @@ import { tv } from "tailwind-variants";
|
|
|
4
4
|
|
|
5
5
|
type Props = HTMLAttributes<"div">;
|
|
6
6
|
|
|
7
|
-
const cardContent = tv({ base: "p-8 pt-0" });
|
|
7
|
+
export const cardContent = tv({ base: "p-8 pt-0" });
|
|
8
8
|
|
|
9
9
|
const { class: className, ...rest } = Astro.props;
|
|
10
10
|
---
|
|
11
11
|
|
|
12
|
-
<div class={cardContent({ class: className })} {...rest}>
|
|
12
|
+
<div class={cardContent({ class: className })} data-slot="card-content" {...rest}>
|
|
13
13
|
<slot />
|
|
14
14
|
</div>
|
|
@@ -4,11 +4,11 @@ import { tv } from "tailwind-variants";
|
|
|
4
4
|
|
|
5
5
|
type Props = HTMLAttributes<"div">;
|
|
6
6
|
|
|
7
|
-
const cardDescription = tv({ base: "text-muted-foreground text-base" });
|
|
7
|
+
export const cardDescription = tv({ base: "text-muted-foreground text-base" });
|
|
8
8
|
|
|
9
9
|
const { class: className, ...rest } = Astro.props;
|
|
10
10
|
---
|
|
11
11
|
|
|
12
|
-
<div class={cardDescription({ class: className })} {...rest}>
|
|
12
|
+
<div class={cardDescription({ class: className })} data-slot="card-description" {...rest}>
|
|
13
13
|
<slot />
|
|
14
14
|
</div>
|
|
@@ -4,11 +4,11 @@ import { tv } from "tailwind-variants";
|
|
|
4
4
|
|
|
5
5
|
type Props = HTMLAttributes<"div">;
|
|
6
6
|
|
|
7
|
-
const cardFooter = tv({ base: "flex items-center p-8 pt-0" });
|
|
7
|
+
export const cardFooter = tv({ base: "flex items-center p-8 pt-0" });
|
|
8
8
|
|
|
9
9
|
const { class: className, ...rest } = Astro.props;
|
|
10
10
|
---
|
|
11
11
|
|
|
12
|
-
<div class={cardFooter({ class: className })} {...rest}>
|
|
12
|
+
<div class={cardFooter({ class: className })} data-slot="card-footer" {...rest}>
|
|
13
13
|
<slot />
|
|
14
14
|
</div>
|
|
@@ -4,11 +4,11 @@ import { tv } from "tailwind-variants";
|
|
|
4
4
|
|
|
5
5
|
type Props = HTMLAttributes<"div">;
|
|
6
6
|
|
|
7
|
-
const cardHeader = tv({ base: "flex flex-col space-y-2 p-8" });
|
|
7
|
+
export const cardHeader = tv({ base: "flex flex-col space-y-2 p-8" });
|
|
8
8
|
|
|
9
9
|
const { class: className, ...rest } = Astro.props;
|
|
10
10
|
---
|
|
11
11
|
|
|
12
|
-
<div class={cardHeader({ class: className })} {...rest}>
|
|
12
|
+
<div class={cardHeader({ class: className })} data-slot="card-header" {...rest}>
|
|
13
13
|
<slot />
|
|
14
14
|
</div>
|
|
@@ -4,11 +4,11 @@ import { tv } from "tailwind-variants";
|
|
|
4
4
|
|
|
5
5
|
type Props = HTMLAttributes<"div">;
|
|
6
6
|
|
|
7
|
-
const cardTitle = tv({ base: "text-
|
|
7
|
+
export const cardTitle = tv({ base: "text-xl leading-none font-semibold tracking-tight" });
|
|
8
8
|
|
|
9
9
|
const { class: className, ...rest } = Astro.props;
|
|
10
10
|
---
|
|
11
11
|
|
|
12
|
-
<div class={cardTitle({ class: className })} {...rest}>
|
|
12
|
+
<div class={cardTitle({ class: className })} data-slot="card-title" {...rest}>
|
|
13
13
|
<slot />
|
|
14
14
|
</div>
|
|
@@ -1,11 +1,20 @@
|
|
|
1
|
-
import Card from "./Card.astro";
|
|
2
|
-
import CardContent from "./CardContent.astro";
|
|
3
|
-
import CardDescription from "./CardDescription.astro";
|
|
4
|
-
import CardFooter from "./CardFooter.astro";
|
|
5
|
-
import CardHeader from "./CardHeader.astro";
|
|
6
|
-
import CardTitle from "./CardTitle.astro";
|
|
1
|
+
import Card, { card } from "./Card.astro";
|
|
2
|
+
import CardContent, { cardContent } from "./CardContent.astro";
|
|
3
|
+
import CardDescription, { cardDescription } from "./CardDescription.astro";
|
|
4
|
+
import CardFooter, { cardFooter } from "./CardFooter.astro";
|
|
5
|
+
import CardHeader, { cardHeader } from "./CardHeader.astro";
|
|
6
|
+
import CardTitle, { cardTitle } from "./CardTitle.astro";
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
const CardVariants = {
|
|
9
|
+
card,
|
|
10
|
+
cardContent,
|
|
11
|
+
cardDescription,
|
|
12
|
+
cardFooter,
|
|
13
|
+
cardHeader,
|
|
14
|
+
cardTitle,
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, CardVariants };
|
|
9
18
|
|
|
10
19
|
export default {
|
|
11
20
|
Root: Card,
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { HTMLAttributes } from "astro/types";
|
|
3
|
+
import { type EmblaOptionsType } from "embla-carousel";
|
|
4
|
+
import { tv } from "tailwind-variants";
|
|
5
|
+
|
|
6
|
+
const carousel = tv({
|
|
7
|
+
base: "starwind-carousel group/carousel relative",
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
export interface Props extends HTMLAttributes<"div"> {
|
|
11
|
+
orientation?: "horizontal" | "vertical";
|
|
12
|
+
opts?: EmblaOptionsType;
|
|
13
|
+
autoInit?: boolean;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const {
|
|
17
|
+
class: className,
|
|
18
|
+
orientation = "horizontal",
|
|
19
|
+
opts = {},
|
|
20
|
+
autoInit = true,
|
|
21
|
+
...rest
|
|
22
|
+
} = Astro.props;
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
<div
|
|
26
|
+
class={carousel({ class: className })}
|
|
27
|
+
role="region"
|
|
28
|
+
aria-roledescription="carousel"
|
|
29
|
+
data-slot="carousel"
|
|
30
|
+
data-axis={orientation === "horizontal" ? "x" : "y"}
|
|
31
|
+
data-opts={JSON.stringify(opts)}
|
|
32
|
+
data-auto-init={autoInit}
|
|
33
|
+
{...rest}
|
|
34
|
+
>
|
|
35
|
+
<slot />
|
|
36
|
+
</div>
|
|
37
|
+
|
|
38
|
+
<script>
|
|
39
|
+
import { initCarousel } from "./index";
|
|
40
|
+
|
|
41
|
+
const setupCarousels = () => {
|
|
42
|
+
const carousels = document.querySelectorAll(".starwind-carousel") as NodeListOf<HTMLElement>;
|
|
43
|
+
carousels.forEach((carousel) => {
|
|
44
|
+
if (carousel.dataset.autoInit === "false") {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
initCarousel(carousel);
|
|
48
|
+
});
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
document.addEventListener("DOMContentLoaded", setupCarousels);
|
|
52
|
+
|
|
53
|
+
// Re-initialize after Astro page transitions
|
|
54
|
+
document.addEventListener("astro:after-swap", setupCarousels);
|
|
55
|
+
</script>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { HTMLAttributes } from "astro/types";
|
|
3
|
+
import { tv } from "tailwind-variants";
|
|
4
|
+
|
|
5
|
+
const carouselContent = tv({
|
|
6
|
+
base: "overflow-hidden",
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
const carouselContainer = tv({
|
|
10
|
+
base: [
|
|
11
|
+
"flex group-data-[axis=y]/carousel:flex-col",
|
|
12
|
+
"group-data-[axis=x]/carousel:-ml-4",
|
|
13
|
+
"group-data-[axis=y]/carousel:-mt-4",
|
|
14
|
+
],
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
type Props = HTMLAttributes<"div">;
|
|
18
|
+
|
|
19
|
+
const { class: className = "", ...rest } = Astro.props;
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
<div class={carouselContent()} data-slot="carousel-content" {...rest}>
|
|
23
|
+
<div class={carouselContainer({ class: className })} data-slot="carousel-container">
|
|
24
|
+
<slot />
|
|
25
|
+
</div>
|
|
26
|
+
</div>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { HTMLAttributes } from "astro/types";
|
|
3
|
+
import { tv } from "tailwind-variants";
|
|
4
|
+
|
|
5
|
+
const carouselItem = tv({
|
|
6
|
+
base: [
|
|
7
|
+
"min-w-0 shrink-0 grow-0 basis-full",
|
|
8
|
+
"group-data-[axis=x]/carousel:pl-4",
|
|
9
|
+
"group-data-[axis=y]/carousel:pt-4",
|
|
10
|
+
],
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
type Props = HTMLAttributes<"div">;
|
|
14
|
+
|
|
15
|
+
const { class: className = "", ...rest } = Astro.props;
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
<div
|
|
19
|
+
role="group"
|
|
20
|
+
aria-roledescription="slide"
|
|
21
|
+
data-slot="carousel-item"
|
|
22
|
+
class={carouselItem({ class: className })}
|
|
23
|
+
{...rest}
|
|
24
|
+
>
|
|
25
|
+
<slot />
|
|
26
|
+
</div>
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
---
|
|
2
|
+
import ArrowRight from "@tabler/icons/outline/arrow-right.svg";
|
|
3
|
+
import type { ComponentProps } from "astro/types";
|
|
4
|
+
import { tv } from "tailwind-variants";
|
|
5
|
+
|
|
6
|
+
import { Button } from "@/components/starwind/button";
|
|
7
|
+
|
|
8
|
+
export const carouselNext = tv({
|
|
9
|
+
base: [
|
|
10
|
+
"starwind-carousel-next absolute size-8 rounded-full",
|
|
11
|
+
// Horizontal positioning
|
|
12
|
+
"group-data-[axis=x]/carousel:top-1/2 group-data-[axis=x]/carousel:-right-12 group-data-[axis=x]/carousel:-translate-y-1/2",
|
|
13
|
+
// Vertical positioning
|
|
14
|
+
"group-data-[axis=y]/carousel:-bottom-12 group-data-[axis=y]/carousel:left-1/2 group-data-[axis=y]/carousel:-translate-x-1/2 group-data-[axis=y]/carousel:rotate-90",
|
|
15
|
+
],
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
type Props = ComponentProps<typeof Button>;
|
|
19
|
+
|
|
20
|
+
const { class: className = "", variant = "outline", size = "icon", ...rest } = Astro.props;
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
<Button
|
|
24
|
+
data-slot="carousel-next"
|
|
25
|
+
variant={variant}
|
|
26
|
+
size={size}
|
|
27
|
+
class={carouselNext({ class: className })}
|
|
28
|
+
aria-label="Next slide"
|
|
29
|
+
{...rest}
|
|
30
|
+
>
|
|
31
|
+
<ArrowRight />
|
|
32
|
+
<span class="sr-only">Next slide</span>
|
|
33
|
+
</Button>
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
---
|
|
2
|
+
import ArrowLeft from "@tabler/icons/outline/arrow-left.svg";
|
|
3
|
+
import type { ComponentProps } from "astro/types";
|
|
4
|
+
import { tv } from "tailwind-variants";
|
|
5
|
+
|
|
6
|
+
import { Button } from "@/components/starwind/button";
|
|
7
|
+
|
|
8
|
+
export const carouselPrevious = tv({
|
|
9
|
+
base: [
|
|
10
|
+
"starwind-carousel-previous absolute size-8 rounded-full",
|
|
11
|
+
// Horizontal positioning
|
|
12
|
+
"group-data-[axis=x]/carousel:top-1/2 group-data-[axis=x]/carousel:-left-12 group-data-[axis=x]/carousel:-translate-y-1/2",
|
|
13
|
+
// Vertical positioning
|
|
14
|
+
"group-data-[axis=y]/carousel:-top-12 group-data-[axis=y]/carousel:left-1/2 group-data-[axis=y]/carousel:-translate-x-1/2 group-data-[axis=y]/carousel:rotate-90",
|
|
15
|
+
],
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
type Props = ComponentProps<typeof Button>;
|
|
19
|
+
|
|
20
|
+
const { class: className = "", variant = "outline", size = "icon", ...rest } = Astro.props;
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
<Button
|
|
24
|
+
data-slot="carousel-previous"
|
|
25
|
+
variant={variant}
|
|
26
|
+
size={size}
|
|
27
|
+
class={carouselPrevious({ class: className })}
|
|
28
|
+
aria-label="Previous slide"
|
|
29
|
+
{...rest}
|
|
30
|
+
>
|
|
31
|
+
<ArrowLeft />
|
|
32
|
+
<span class="sr-only">Previous slide</span>
|
|
33
|
+
</Button>
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import EmblaCarousel, {
|
|
2
|
+
type EmblaCarouselType,
|
|
3
|
+
type EmblaEventType,
|
|
4
|
+
type EmblaOptionsType,
|
|
5
|
+
type EmblaPluginType,
|
|
6
|
+
} from "embla-carousel";
|
|
7
|
+
|
|
8
|
+
export type CarouselApi = EmblaCarouselType;
|
|
9
|
+
|
|
10
|
+
export interface CarouselOptions {
|
|
11
|
+
opts?: EmblaOptionsType;
|
|
12
|
+
plugins?: EmblaPluginType[];
|
|
13
|
+
setApi?: (api: CarouselApi) => void;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface CarouselManager {
|
|
17
|
+
api: CarouselApi;
|
|
18
|
+
scrollPrev: () => void;
|
|
19
|
+
scrollNext: () => void;
|
|
20
|
+
canScrollPrev: () => boolean;
|
|
21
|
+
canScrollNext: () => boolean;
|
|
22
|
+
destroy: () => void;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function initCarousel(
|
|
26
|
+
carouselElement: HTMLElement,
|
|
27
|
+
options: CarouselOptions = {},
|
|
28
|
+
): CarouselManager | null {
|
|
29
|
+
// don't re-initialize if already initialized
|
|
30
|
+
if (carouselElement.dataset.initialized === "true") return null;
|
|
31
|
+
carouselElement.dataset.initialized = "true";
|
|
32
|
+
|
|
33
|
+
if (!carouselElement) {
|
|
34
|
+
console.warn("Carousel element not found");
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Find content element - Embla expects the viewport element, not the container
|
|
39
|
+
const viewportElement = carouselElement.querySelector(
|
|
40
|
+
'[data-slot="carousel-content"]',
|
|
41
|
+
) as HTMLElement;
|
|
42
|
+
if (!viewportElement) {
|
|
43
|
+
console.warn("Carousel content element not found");
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Get configuration from data attributes
|
|
48
|
+
const axisData = carouselElement.dataset.axis;
|
|
49
|
+
const axis: EmblaOptionsType["axis"] = axisData === "y" ? "y" : "x";
|
|
50
|
+
|
|
51
|
+
// Safely parse data options
|
|
52
|
+
let dataOpts = {};
|
|
53
|
+
try {
|
|
54
|
+
const optsString = carouselElement.dataset.opts;
|
|
55
|
+
if (optsString && optsString !== "undefined" && optsString !== "null") {
|
|
56
|
+
dataOpts = JSON.parse(optsString);
|
|
57
|
+
}
|
|
58
|
+
} catch (e) {
|
|
59
|
+
console.warn("Failed to parse carousel opts:", e);
|
|
60
|
+
dataOpts = {};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Ensure dataOpts is a valid object
|
|
64
|
+
if (!dataOpts || typeof dataOpts !== "object") {
|
|
65
|
+
dataOpts = {};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Merge options - ensure we always have a valid object
|
|
69
|
+
const emblaOptions: EmblaOptionsType = {
|
|
70
|
+
axis,
|
|
71
|
+
...dataOpts,
|
|
72
|
+
...(options.opts || {}),
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
// Handle plugins - EmblaCarousel expects undefined when no plugins, not empty array
|
|
76
|
+
const plugins = options.plugins && options.plugins.length > 0 ? options.plugins : undefined;
|
|
77
|
+
|
|
78
|
+
// console.log("ID:", carouselElement.id);
|
|
79
|
+
// console.log("Plugins:", plugins);
|
|
80
|
+
// console.log("Options:", emblaOptions);
|
|
81
|
+
|
|
82
|
+
// Find navigation buttons
|
|
83
|
+
const prevButton = carouselElement.querySelector(
|
|
84
|
+
'[data-slot="carousel-previous"]',
|
|
85
|
+
) as HTMLButtonElement;
|
|
86
|
+
const nextButton = carouselElement.querySelector(
|
|
87
|
+
'[data-slot="carousel-next"]',
|
|
88
|
+
) as HTMLButtonElement;
|
|
89
|
+
|
|
90
|
+
// Initialize Embla
|
|
91
|
+
let emblaApi: EmblaCarouselType;
|
|
92
|
+
if (plugins) {
|
|
93
|
+
emblaApi = EmblaCarousel(viewportElement, emblaOptions, plugins);
|
|
94
|
+
} else {
|
|
95
|
+
emblaApi = EmblaCarousel(viewportElement, emblaOptions);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Update button states
|
|
99
|
+
const updateButtons = () => {
|
|
100
|
+
const canScrollPrev = emblaApi.canScrollPrev();
|
|
101
|
+
const canScrollNext = emblaApi.canScrollNext();
|
|
102
|
+
|
|
103
|
+
if (prevButton) {
|
|
104
|
+
prevButton.disabled = !canScrollPrev;
|
|
105
|
+
prevButton.setAttribute("aria-disabled", (!canScrollPrev).toString());
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (nextButton) {
|
|
109
|
+
nextButton.disabled = !canScrollNext;
|
|
110
|
+
nextButton.setAttribute("aria-disabled", (!canScrollNext).toString());
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
// Event handlers for cleanup
|
|
115
|
+
const prevClickHandler = () => emblaApi.scrollPrev();
|
|
116
|
+
const nextClickHandler = () => emblaApi.scrollNext();
|
|
117
|
+
const keydownHandler = (event: KeyboardEvent) => {
|
|
118
|
+
if (axis === "y") {
|
|
119
|
+
// Vertical axis: ArrowUp = previous, ArrowDown = next
|
|
120
|
+
if (event.key === "ArrowUp") {
|
|
121
|
+
event.preventDefault();
|
|
122
|
+
emblaApi.scrollPrev();
|
|
123
|
+
} else if (event.key === "ArrowDown") {
|
|
124
|
+
event.preventDefault();
|
|
125
|
+
emblaApi.scrollNext();
|
|
126
|
+
}
|
|
127
|
+
} else {
|
|
128
|
+
// Horizontal axis (default): ArrowLeft = previous, ArrowRight = next
|
|
129
|
+
if (event.key === "ArrowLeft") {
|
|
130
|
+
event.preventDefault();
|
|
131
|
+
emblaApi.scrollPrev();
|
|
132
|
+
} else if (event.key === "ArrowRight") {
|
|
133
|
+
event.preventDefault();
|
|
134
|
+
emblaApi.scrollNext();
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
// Setup event listeners
|
|
140
|
+
const setupEventListeners = () => {
|
|
141
|
+
// Navigation button listeners
|
|
142
|
+
prevButton?.addEventListener("click", prevClickHandler);
|
|
143
|
+
nextButton?.addEventListener("click", nextClickHandler);
|
|
144
|
+
|
|
145
|
+
// Keyboard navigation
|
|
146
|
+
carouselElement.addEventListener("keydown", keydownHandler);
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
// Setup user API callback
|
|
150
|
+
const setupUserCallbacks = () => {
|
|
151
|
+
if (options.setApi) {
|
|
152
|
+
options.setApi(emblaApi);
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
// Initialize everything
|
|
157
|
+
updateButtons();
|
|
158
|
+
setupEventListeners();
|
|
159
|
+
setupUserCallbacks();
|
|
160
|
+
|
|
161
|
+
// Setup internal event listeners
|
|
162
|
+
emblaApi.on("select", updateButtons);
|
|
163
|
+
emblaApi.on("init", () => {
|
|
164
|
+
updateButtons();
|
|
165
|
+
});
|
|
166
|
+
emblaApi.on("reInit", () => {
|
|
167
|
+
updateButtons();
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
// Return manager interface
|
|
171
|
+
return {
|
|
172
|
+
api: emblaApi,
|
|
173
|
+
scrollPrev: () => emblaApi.scrollPrev(),
|
|
174
|
+
scrollNext: () => emblaApi.scrollNext(),
|
|
175
|
+
canScrollPrev: () => emblaApi.canScrollPrev(),
|
|
176
|
+
canScrollNext: () => emblaApi.canScrollNext(),
|
|
177
|
+
destroy: () => {
|
|
178
|
+
// Remove event listeners to prevent memory leaks
|
|
179
|
+
if (prevButton) {
|
|
180
|
+
prevButton.removeEventListener("click", prevClickHandler);
|
|
181
|
+
}
|
|
182
|
+
if (nextButton) {
|
|
183
|
+
nextButton.removeEventListener("click", nextClickHandler);
|
|
184
|
+
}
|
|
185
|
+
carouselElement.removeEventListener("keydown", keydownHandler);
|
|
186
|
+
|
|
187
|
+
// Destroy the Embla instance
|
|
188
|
+
emblaApi.destroy();
|
|
189
|
+
},
|
|
190
|
+
};
|
|
191
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import Carousel from "./Carousel.astro";
|
|
2
|
+
import {
|
|
3
|
+
type CarouselApi,
|
|
4
|
+
type CarouselManager,
|
|
5
|
+
type CarouselOptions,
|
|
6
|
+
initCarousel,
|
|
7
|
+
} from "./carousel-script";
|
|
8
|
+
import CarouselContent from "./CarouselContent.astro";
|
|
9
|
+
import CarouselItem from "./CarouselItem.astro";
|
|
10
|
+
import CarouselNext from "./CarouselNext.astro";
|
|
11
|
+
import CarouselPrevious from "./CarouselPrevious.astro";
|
|
12
|
+
|
|
13
|
+
export {
|
|
14
|
+
Carousel,
|
|
15
|
+
type CarouselApi,
|
|
16
|
+
CarouselContent,
|
|
17
|
+
CarouselItem,
|
|
18
|
+
type CarouselManager,
|
|
19
|
+
CarouselNext,
|
|
20
|
+
type CarouselOptions,
|
|
21
|
+
CarouselPrevious,
|
|
22
|
+
initCarousel,
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export default {
|
|
26
|
+
Root: Carousel,
|
|
27
|
+
Content: CarouselContent,
|
|
28
|
+
Item: CarouselItem,
|
|
29
|
+
Next: CarouselNext,
|
|
30
|
+
Previous: CarouselPrevious,
|
|
31
|
+
init: initCarousel,
|
|
32
|
+
};
|
|
@@ -11,12 +11,12 @@ type Props = Omit<HTMLAttributes<"input">, "type"> &
|
|
|
11
11
|
label?: string;
|
|
12
12
|
};
|
|
13
13
|
|
|
14
|
-
const checkbox = tv({
|
|
14
|
+
export const checkbox = tv({
|
|
15
15
|
slots: {
|
|
16
16
|
base: "starwind-checkbox relative flex items-center space-x-2",
|
|
17
17
|
input: [
|
|
18
|
-
"peer border-input bg-background
|
|
19
|
-
"
|
|
18
|
+
"peer border-input bg-background dark:bg-input/30 shrink-0 transform-gpu rounded-sm border",
|
|
19
|
+
"transition-all focus-visible:ring-3",
|
|
20
20
|
"outline-0 focus:ring-0 focus:ring-offset-0",
|
|
21
21
|
"not-disabled:cursor-pointer disabled:cursor-not-allowed disabled:opacity-50",
|
|
22
22
|
],
|
|
@@ -35,28 +35,37 @@ const checkbox = tv({
|
|
|
35
35
|
},
|
|
36
36
|
variant: {
|
|
37
37
|
default: {
|
|
38
|
-
input: "checked:bg-foreground focus-visible:outline-outline",
|
|
38
|
+
input: "checked:bg-foreground focus-visible:ring-outline/50 focus-visible:border-outline",
|
|
39
39
|
icon: "text-background",
|
|
40
40
|
},
|
|
41
41
|
primary: {
|
|
42
|
-
input:
|
|
42
|
+
input:
|
|
43
|
+
"checked:bg-primary checked:border-primary focus-visible:ring-primary/50 focus-visible:border-primary",
|
|
43
44
|
icon: "text-primary-foreground",
|
|
44
45
|
},
|
|
45
46
|
secondary: {
|
|
46
|
-
input:
|
|
47
|
+
input:
|
|
48
|
+
"checked:bg-secondary checked:border-secondary focus-visible:ring-secondary/50 focus-visible:border-secondary",
|
|
47
49
|
icon: "text-secondary-foreground",
|
|
48
50
|
},
|
|
49
|
-
info: {
|
|
51
|
+
info: {
|
|
52
|
+
input:
|
|
53
|
+
"checked:bg-info checked:border-info focus-visible:ring-info/50 focus-visible:border-info",
|
|
54
|
+
icon: "text-info-foreground",
|
|
55
|
+
},
|
|
50
56
|
success: {
|
|
51
|
-
input:
|
|
57
|
+
input:
|
|
58
|
+
"checked:bg-success checked:border-success focus-visible:ring-success/50 focus-visible:border-success",
|
|
52
59
|
icon: "text-success-foreground",
|
|
53
60
|
},
|
|
54
61
|
warning: {
|
|
55
|
-
input:
|
|
62
|
+
input:
|
|
63
|
+
"checked:bg-warning checked:border-warning focus-visible:ring-warning/50 focus-visible:border-warning",
|
|
56
64
|
icon: "text-warning-foreground",
|
|
57
65
|
},
|
|
58
66
|
error: {
|
|
59
|
-
input:
|
|
67
|
+
input:
|
|
68
|
+
"checked:bg-error checked:border-error focus-visible:ring-error/50 focus-visible:border-error",
|
|
60
69
|
icon: "text-error-foreground",
|
|
61
70
|
},
|
|
62
71
|
},
|
|
@@ -70,11 +79,18 @@ const { base, input, icon, label: labelClass } = checkbox({ size, variant });
|
|
|
70
79
|
---
|
|
71
80
|
|
|
72
81
|
<div class={base()}>
|
|
73
|
-
<input
|
|
82
|
+
<input
|
|
83
|
+
type="checkbox"
|
|
84
|
+
id={id}
|
|
85
|
+
class={input({ class: className })}
|
|
86
|
+
data-slot="checkbox-input"
|
|
87
|
+
{checked}
|
|
88
|
+
{...rest}
|
|
89
|
+
/>
|
|
74
90
|
<Check class={icon()} />
|
|
75
91
|
{
|
|
76
92
|
label && (
|
|
77
|
-
<label for={id} class={labelClass()}>
|
|
93
|
+
<label for={id} class={labelClass()} data-slot="checkbox-label">
|
|
78
94
|
{label}
|
|
79
95
|
</label>
|
|
80
96
|
)
|