@starwind-ui/core 1.6.2 → 1.7.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 (101) hide show
  1. package/dist/index.js +4 -0
  2. package/dist/index.js.map +1 -1
  3. package/dist/src/components/accordion/Accordion.astro +224 -224
  4. package/dist/src/components/accordion/AccordionContent.astro +13 -13
  5. package/dist/src/components/accordion/AccordionItem.astro +6 -6
  6. package/dist/src/components/accordion/AccordionTrigger.astro +13 -13
  7. package/dist/src/components/accordion/index.ts +4 -4
  8. package/dist/src/components/alert/Alert.astro +15 -15
  9. package/dist/src/components/alert/AlertDescription.astro +1 -1
  10. package/dist/src/components/alert/AlertTitle.astro +2 -2
  11. package/dist/src/components/alert/index.ts +3 -3
  12. package/dist/src/components/avatar/Avatar.astro +16 -16
  13. package/dist/src/components/avatar/AvatarFallback.astro +3 -3
  14. package/dist/src/components/avatar/AvatarImage.astro +12 -12
  15. package/dist/src/components/avatar/index.ts +4 -4
  16. package/dist/src/components/badge/Badge.astro +33 -33
  17. package/dist/src/components/breadcrumb/Breadcrumb.astro +1 -1
  18. package/dist/src/components/breadcrumb/BreadcrumbEllipsis.astro +6 -6
  19. package/dist/src/components/breadcrumb/BreadcrumbItem.astro +1 -1
  20. package/dist/src/components/breadcrumb/BreadcrumbLink.astro +8 -8
  21. package/dist/src/components/breadcrumb/BreadcrumbList.astro +2 -2
  22. package/dist/src/components/breadcrumb/BreadcrumbPage.astro +6 -6
  23. package/dist/src/components/breadcrumb/BreadcrumbSeparator.astro +7 -7
  24. package/dist/src/components/breadcrumb/index.ts +14 -14
  25. package/dist/src/components/button/Button.astro +38 -38
  26. package/dist/src/components/card/Card.astro +1 -1
  27. package/dist/src/components/card/CardContent.astro +1 -1
  28. package/dist/src/components/card/CardDescription.astro +1 -1
  29. package/dist/src/components/card/CardFooter.astro +1 -1
  30. package/dist/src/components/card/CardHeader.astro +1 -1
  31. package/dist/src/components/card/CardTitle.astro +1 -1
  32. package/dist/src/components/card/index.ts +7 -7
  33. package/dist/src/components/checkbox/Checkbox.astro +89 -89
  34. package/dist/src/components/dialog/Dialog.astro +178 -178
  35. package/dist/src/components/dialog/DialogClose.astro +14 -14
  36. package/dist/src/components/dialog/DialogContent.astro +32 -32
  37. package/dist/src/components/dialog/DialogDescription.astro +1 -1
  38. package/dist/src/components/dialog/DialogFooter.astro +1 -1
  39. package/dist/src/components/dialog/DialogHeader.astro +1 -1
  40. package/dist/src/components/dialog/DialogTitle.astro +6 -6
  41. package/dist/src/components/dialog/DialogTrigger.astro +19 -19
  42. package/dist/src/components/dialog/index.ts +16 -16
  43. package/dist/src/components/dropdown/Dropdown.astro +359 -359
  44. package/dist/src/components/dropdown/DropdownContent.astro +63 -63
  45. package/dist/src/components/dropdown/DropdownItem.astro +31 -31
  46. package/dist/src/components/dropdown/DropdownLabel.astro +14 -14
  47. package/dist/src/components/dropdown/DropdownSeparator.astro +5 -5
  48. package/dist/src/components/dropdown/DropdownTrigger.astro +26 -26
  49. package/dist/src/components/dropdown/index.ts +12 -12
  50. package/dist/src/components/dropzone/Dropzone.astro +232 -0
  51. package/dist/src/components/dropzone/DropzoneFilesList.astro +25 -0
  52. package/dist/src/components/dropzone/DropzoneLoadingIndicator.astro +10 -0
  53. package/dist/src/components/dropzone/DropzoneUploadIndicator.astro +10 -0
  54. package/dist/src/components/dropzone/index.ts +13 -0
  55. package/dist/src/components/input/Input.astro +12 -12
  56. package/dist/src/components/label/Label.astro +8 -8
  57. package/dist/src/components/pagination/Pagination.astro +1 -1
  58. package/dist/src/components/pagination/PaginationContent.astro +3 -3
  59. package/dist/src/components/pagination/PaginationEllipsis.astro +2 -2
  60. package/dist/src/components/pagination/PaginationItem.astro +3 -3
  61. package/dist/src/components/pagination/PaginationLink.astro +27 -27
  62. package/dist/src/components/pagination/PaginationNext.astro +7 -6
  63. package/dist/src/components/pagination/PaginationPrevious.astro +7 -6
  64. package/dist/src/components/pagination/index.ts +14 -14
  65. package/dist/src/components/progress/Progress.astro +151 -0
  66. package/dist/src/components/progress/index.ts +5 -0
  67. package/dist/src/components/radio-group/RadioGroup.astro +156 -0
  68. package/dist/src/components/radio-group/RadioGroupItem.astro +125 -0
  69. package/dist/src/components/radio-group/RadioGroupTypes.ts +6 -0
  70. package/dist/src/components/radio-group/index.ts +10 -0
  71. package/dist/src/components/select/Select.astro +475 -475
  72. package/dist/src/components/select/SelectContent.astro +62 -62
  73. package/dist/src/components/select/SelectItem.astro +27 -27
  74. package/dist/src/components/select/SelectLabel.astro +1 -1
  75. package/dist/src/components/select/SelectTrigger.astro +28 -28
  76. package/dist/src/components/select/SelectTypes.ts +5 -5
  77. package/dist/src/components/select/SelectValue.astro +5 -5
  78. package/dist/src/components/select/index.ts +16 -16
  79. package/dist/src/components/skeleton/Skeleton.astro +14 -0
  80. package/dist/src/components/skeleton/index.ts +5 -0
  81. package/dist/src/components/switch/Switch.astro +150 -150
  82. package/dist/src/components/switch/SwitchTypes.ts +4 -4
  83. package/dist/src/components/table/Table.astro +5 -5
  84. package/dist/src/components/table/TableBody.astro +3 -3
  85. package/dist/src/components/table/TableCaption.astro +3 -3
  86. package/dist/src/components/table/TableCell.astro +3 -3
  87. package/dist/src/components/table/TableFoot.astro +3 -3
  88. package/dist/src/components/table/TableHead.astro +3 -3
  89. package/dist/src/components/table/TableHeader.astro +3 -3
  90. package/dist/src/components/table/TableRow.astro +3 -3
  91. package/dist/src/components/table/index.ts +8 -8
  92. package/dist/src/components/tabs/Tabs.astro +250 -250
  93. package/dist/src/components/tabs/TabsContent.astro +10 -10
  94. package/dist/src/components/tabs/TabsList.astro +2 -2
  95. package/dist/src/components/tabs/TabsTrigger.astro +15 -15
  96. package/dist/src/components/tabs/index.ts +4 -4
  97. package/dist/src/components/textarea/Textarea.astro +16 -16
  98. package/dist/src/components/tooltip/Tooltip.astro +217 -217
  99. package/dist/src/components/tooltip/TooltipContent.astro +81 -81
  100. package/dist/src/components/tooltip/index.ts +3 -3
  101. package/package.json +1 -1
@@ -0,0 +1,13 @@
1
+ import Dropzone from "./Dropzone.astro";
2
+ import DropzoneFilesList from "./DropzoneFilesList.astro";
3
+ import DropzoneLoadingIndicator from "./DropzoneLoadingIndicator.astro";
4
+ import DropzoneUploadIndicator from "./DropzoneUploadIndicator.astro";
5
+
6
+ export { Dropzone, DropzoneFilesList, DropzoneLoadingIndicator, DropzoneUploadIndicator };
7
+
8
+ export default {
9
+ Root: Dropzone,
10
+ FilesList: DropzoneFilesList,
11
+ UploadIndicator: DropzoneUploadIndicator,
12
+ LoadingIndicator: DropzoneLoadingIndicator,
13
+ };
@@ -1,21 +1,21 @@
1
1
  ---
2
2
  import type { HTMLAttributes } from "astro/types";
3
- import { type VariantProps, tv } from "tailwind-variants";
3
+ import { tv, type VariantProps } from "tailwind-variants";
4
4
 
5
5
  type Props = HTMLAttributes<"input"> & VariantProps<typeof input>;
6
6
 
7
7
  const input = tv({
8
- base: [
9
- "border-input bg-background text-foreground w-full rounded-md border",
10
- "focus:outline-outline focus:ring-0 focus:outline-2 focus:outline-offset-2",
11
- "file:text-foreground file:my-auto file:mr-4 file:h-full file:border-0 file:bg-transparent file:text-sm file:font-medium",
12
- "disabled:cursor-not-allowed disabled:opacity-50",
13
- "peer placeholder:text-muted-foreground",
14
- ],
15
- variants: {
16
- size: { sm: "h-9 px-2 text-sm", md: "h-11 px-3 text-base", lg: "h-12 px-4 text-lg" },
17
- },
18
- defaultVariants: { size: "md" },
8
+ base: [
9
+ "border-input bg-background text-foreground w-full rounded-md border",
10
+ "focus:outline-outline focus:ring-0 focus:outline-2 focus:outline-offset-2",
11
+ "file:text-foreground file:my-auto file:mr-4 file:h-full file:border-0 file:bg-transparent file:text-sm file:font-medium",
12
+ "disabled:cursor-not-allowed disabled:opacity-50",
13
+ "peer placeholder:text-muted-foreground",
14
+ ],
15
+ variants: {
16
+ size: { sm: "h-9 px-2 text-sm", md: "h-11 px-3 text-base", lg: "h-12 px-4 text-lg" },
17
+ },
18
+ defaultVariants: { size: "md" },
19
19
  });
20
20
 
21
21
  const { size, class: className, ...rest } = Astro.props;
@@ -1,16 +1,16 @@
1
1
  ---
2
2
  import type { HTMLAttributes } from "astro/types";
3
- import { type VariantProps, tv } from "tailwind-variants";
3
+ import { tv, type VariantProps } from "tailwind-variants";
4
4
 
5
5
  type Props = HTMLAttributes<"label"> & VariantProps<typeof label>;
6
6
 
7
7
  const label = tv({
8
- base: [
9
- "text-foreground leading-none font-medium",
10
- "peer-disabled:cursor-not-allowed peer-disabled:opacity-70 has-[+:disabled]:cursor-not-allowed has-[+:disabled]:opacity-70",
11
- ],
12
- variants: { size: { sm: "text-sm", md: "text-base", lg: "text-lg" } },
13
- defaultVariants: { size: "md" },
8
+ base: [
9
+ "text-foreground leading-none font-medium",
10
+ "peer-disabled:cursor-not-allowed peer-disabled:opacity-70 has-[+:disabled]:cursor-not-allowed has-[+:disabled]:opacity-70",
11
+ ],
12
+ variants: { size: { sm: "text-sm", md: "text-base", lg: "text-lg" } },
13
+ defaultVariants: { size: "md" },
14
14
  });
15
15
 
16
16
  const { size, class: className, ...rest } = Astro.props;
@@ -18,5 +18,5 @@ const { size, class: className, ...rest } = Astro.props;
18
18
 
19
19
  {/* eslint-disable-next-line astro/jsx-a11y/label-has-associated-control */}
20
20
  <label class={label({ size, class: className })} {...rest}>
21
- <slot />
21
+ <slot />
22
22
  </label>
@@ -10,5 +10,5 @@ const { class: className, ...rest } = Astro.props;
10
10
  ---
11
11
 
12
12
  <nav role="navigation" aria-label="pagination" class={pagination({ class: className })} {...rest}>
13
- <slot />
13
+ <slot />
14
14
  </nav>
@@ -3,8 +3,8 @@ import type { HTMLAttributes } from "astro/types";
3
3
  import { tv } from "tailwind-variants";
4
4
 
5
5
  type Props = HTMLAttributes<"ul"> & {
6
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
7
- children: any;
6
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
7
+ children: any;
8
8
  };
9
9
 
10
10
  const paginationContent = tv({ base: "flex flex-row items-center gap-1" });
@@ -13,5 +13,5 @@ const { class: className, ...rest } = Astro.props;
13
13
  ---
14
14
 
15
15
  <ul class={paginationContent({ class: className })} {...rest}>
16
- <slot />
16
+ <slot />
17
17
  </ul>
@@ -11,6 +11,6 @@ const { class: className, ...rest } = Astro.props;
11
11
  ---
12
12
 
13
13
  <span aria-hidden class={paginationEllipsis({ class: className })} {...rest}>
14
- <Dots class="size-4" />
15
- <span class="sr-only">More pages</span>
14
+ <Dots class="size-4" />
15
+ <span class="sr-only">More pages</span>
16
16
  </span>
@@ -3,8 +3,8 @@ import type { HTMLAttributes } from "astro/types";
3
3
  import { tv } from "tailwind-variants";
4
4
 
5
5
  type Props = HTMLAttributes<"li"> & {
6
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
7
- children: any;
6
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
7
+ children: any;
8
8
  };
9
9
 
10
10
  const paginationItem = tv({ base: "" });
@@ -13,5 +13,5 @@ const { class: className, ...rest } = Astro.props;
13
13
  ---
14
14
 
15
15
  <li class={paginationItem({ class: className })} {...rest}>
16
- <slot />
16
+ <slot />
17
17
  </li>
@@ -3,41 +3,41 @@ import type { HTMLAttributes } from "astro/types";
3
3
  import { tv } from "tailwind-variants";
4
4
 
5
5
  interface Props extends HTMLAttributes<"a"> {
6
- isActive?: boolean;
7
- size?: "sm" | "md" | "lg" | "icon";
6
+ isActive?: boolean;
7
+ size?: "sm" | "md" | "lg" | "icon";
8
8
  }
9
9
 
10
10
  const paginationLink = tv({
11
- base: [
12
- "inline-flex items-center justify-center gap-1.5 rounded-md font-medium whitespace-nowrap",
13
- "[&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
14
- "starwind-transition-colors",
15
- "focus-visible:outline-2 focus-visible:outline-offset-2",
16
- "disabled:pointer-events-none disabled:opacity-50",
17
- ],
18
- variants: {
19
- isActive: {
20
- true: "border-border hover:bg-border hover:text-foreground focus-visible:outline-outline border",
21
- false:
22
- "hover:bg-foreground/10 hover:text-foreground focus-visible:outline-outline bg-transparent",
23
- },
24
- size: {
25
- sm: "h-9 px-3 py-2 text-sm",
26
- md: "h-11 px-4 py-2 text-base",
27
- lg: "h-12 px-8 py-2 text-lg",
28
- icon: "h-11 w-11",
29
- },
30
- },
31
- defaultVariants: { isActive: false, size: "icon" },
11
+ base: [
12
+ "inline-flex items-center justify-center gap-1.5 rounded-md font-medium whitespace-nowrap",
13
+ "[&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
14
+ "starwind-transition-colors",
15
+ "focus-visible:outline-2 focus-visible:outline-offset-2",
16
+ "disabled:pointer-events-none disabled:opacity-50",
17
+ ],
18
+ variants: {
19
+ isActive: {
20
+ true: "border-border hover:bg-border hover:text-foreground focus-visible:outline-outline border",
21
+ false:
22
+ "hover:bg-foreground/10 hover:text-foreground focus-visible:outline-outline bg-transparent",
23
+ },
24
+ size: {
25
+ sm: "h-9 px-3 py-2 text-sm",
26
+ md: "h-11 px-4 py-2 text-base",
27
+ lg: "h-12 px-8 py-2 text-lg",
28
+ icon: "h-11 w-11",
29
+ },
30
+ },
31
+ defaultVariants: { isActive: false, size: "icon" },
32
32
  });
33
33
 
34
34
  const { class: className, isActive, size = "icon", ...rest } = Astro.props;
35
35
  ---
36
36
 
37
37
  <a
38
- aria-current={isActive ? "page" : undefined}
39
- class={paginationLink({ isActive, size, class: className })}
40
- {...rest}
38
+ aria-current={isActive ? "page" : undefined}
39
+ class={paginationLink({ isActive, size, class: className })}
40
+ {...rest}
41
41
  >
42
- <slot />
42
+ <slot />
43
43
  </a>
@@ -2,6 +2,7 @@
2
2
  import ChevronRight from "@tabler/icons/outline/chevron-right.svg";
3
3
  import type { HTMLAttributes } from "astro/types";
4
4
  import { tv } from "tailwind-variants";
5
+
5
6
  import PaginationLink from "./PaginationLink.astro";
6
7
 
7
8
  type Props = HTMLAttributes<"a"> & { size?: "sm" | "md" | "lg" | "icon" };
@@ -12,11 +13,11 @@ const { class: className, size = "md", ...rest } = Astro.props;
12
13
  ---
13
14
 
14
15
  <PaginationLink
15
- aria-label="Go to next page"
16
- size={size}
17
- class={paginationNext({ class: className })}
18
- {...rest}
16
+ aria-label="Go to next page"
17
+ size={size}
18
+ class={paginationNext({ class: className })}
19
+ {...rest}
19
20
  >
20
- <slot />
21
- <ChevronRight class="size-4 transition-transform group-hover:translate-x-1" />
21
+ <slot />
22
+ <ChevronRight class="size-4 transition-transform group-hover:translate-x-1" />
22
23
  </PaginationLink>
@@ -2,6 +2,7 @@
2
2
  import ChevronLeft from "@tabler/icons/outline/chevron-left.svg";
3
3
  import type { HTMLAttributes } from "astro/types";
4
4
  import { tv } from "tailwind-variants";
5
+
5
6
  import PaginationLink from "./PaginationLink.astro";
6
7
 
7
8
  type Props = HTMLAttributes<"a"> & { size?: "sm" | "md" | "lg" | "icon" };
@@ -12,11 +13,11 @@ const { class: className, size = "md", ...rest } = Astro.props;
12
13
  ---
13
14
 
14
15
  <PaginationLink
15
- aria-label="Go to previous page"
16
- size={size}
17
- class={paginationPrevious({ class: className })}
18
- {...rest}
16
+ aria-label="Go to previous page"
17
+ size={size}
18
+ class={paginationPrevious({ class: className })}
19
+ {...rest}
19
20
  >
20
- <ChevronLeft class="size-4 transition-transform group-hover:-translate-x-1" />
21
- <slot />
21
+ <ChevronLeft class="size-4 transition-transform group-hover:-translate-x-1" />
22
+ <slot />
22
23
  </PaginationLink>
@@ -7,21 +7,21 @@ import PaginationNext from "./PaginationNext.astro";
7
7
  import PaginationPrevious from "./PaginationPrevious.astro";
8
8
 
9
9
  export {
10
- Pagination,
11
- PaginationContent,
12
- PaginationEllipsis,
13
- PaginationItem,
14
- PaginationLink,
15
- PaginationNext,
16
- PaginationPrevious,
10
+ Pagination,
11
+ PaginationContent,
12
+ PaginationEllipsis,
13
+ PaginationItem,
14
+ PaginationLink,
15
+ PaginationNext,
16
+ PaginationPrevious,
17
17
  };
18
18
 
19
19
  export default {
20
- Root: Pagination,
21
- Content: PaginationContent,
22
- Ellipsis: PaginationEllipsis,
23
- Item: PaginationItem,
24
- Link: PaginationLink,
25
- Next: PaginationNext,
26
- Previous: PaginationPrevious,
20
+ Root: Pagination,
21
+ Content: PaginationContent,
22
+ Ellipsis: PaginationEllipsis,
23
+ Item: PaginationItem,
24
+ Link: PaginationLink,
25
+ Next: PaginationNext,
26
+ Previous: PaginationPrevious,
27
27
  };
@@ -0,0 +1,151 @@
1
+ ---
2
+ import type { HTMLAttributes } from "astro/types";
3
+ import { tv } from "tailwind-variants";
4
+
5
+ type Props = HTMLAttributes<"div"> & {
6
+ /**
7
+ * Current value of the progress bar (omit for indeterminate state)
8
+ */
9
+ value?: number;
10
+ /**
11
+ * Maximum value for the progress bar (default: 100)
12
+ */
13
+ max?: number;
14
+ /**
15
+ * Color variant for the progress indicator (default: default)
16
+ */
17
+ variant?: "default" | "primary" | "secondary" | "info" | "success" | "warning" | "error";
18
+ };
19
+
20
+ const { class: className, value, max = 100, variant = "default", ...rest } = Astro.props;
21
+
22
+ const isIndeterminate = value == null;
23
+ const valuePercent = isIndeterminate ? undefined : Math.round((value / max) * 100);
24
+ const valueText = isIndeterminate ? undefined : `${valuePercent}%`;
25
+
26
+ const progress = tv({
27
+ base: ["starwind-progress-bar", "bg-accent h-2 w-full overflow-hidden rounded-full"],
28
+ variants: {
29
+ variant: {
30
+ indeterminate: "relative",
31
+ },
32
+ },
33
+ });
34
+
35
+ const indicator = tv({
36
+ base: ["starwind-progress-indicator", "h-full w-full flex-1 transition-transform"],
37
+ variants: {
38
+ variant: {
39
+ indeterminate: "absolute inset-y-0 start-0 w-3/4",
40
+ },
41
+ color: {
42
+ primary: "bg-primary",
43
+ secondary: "bg-secondary",
44
+ default: "bg-foreground",
45
+ info: "bg-info",
46
+ success: "bg-success",
47
+ warning: "bg-warning",
48
+ error: "bg-error",
49
+ },
50
+ },
51
+ defaultVariants: {
52
+ color: "primary",
53
+ },
54
+ });
55
+
56
+ const progressClasses = progress({
57
+ variant: isIndeterminate ? "indeterminate" : undefined,
58
+ class: className,
59
+ });
60
+
61
+ const indicatorClasses = indicator({
62
+ variant: isIndeterminate ? "indeterminate" : undefined,
63
+ color: variant,
64
+ });
65
+
66
+ const indicatorStyle = isIndeterminate
67
+ ? ""
68
+ : `transform: translateX(-${100 - (valuePercent ?? 0)}%);`;
69
+ ---
70
+
71
+ <div
72
+ role="progressbar"
73
+ aria-valuemin={0}
74
+ aria-valuemax={max}
75
+ aria-valuenow={isIndeterminate ? undefined : value}
76
+ aria-valuetext={valueText}
77
+ class:list={[progressClasses]}
78
+ data-value={value}
79
+ data-max={max}
80
+ data-indeterminate={isIndeterminate}
81
+ {...rest}
82
+ >
83
+ <div class:list={[indicatorClasses]} style={indicatorStyle}></div>
84
+ </div>
85
+
86
+ <script>
87
+ class ProgressHandler {
88
+ private progressElement: HTMLElement;
89
+ private observer!: MutationObserver;
90
+
91
+ constructor(progressElement: HTMLElement) {
92
+ this.progressElement = progressElement;
93
+ this.setupMutationObserver();
94
+ this.updateProgress(); // Initial update
95
+ }
96
+
97
+ private setupMutationObserver(): void {
98
+ // Create a MutationObserver to watch for data-value attribute changes
99
+ this.observer = new MutationObserver((mutations) => {
100
+ mutations.forEach((mutation) => {
101
+ if (mutation.attributeName === "data-value" || mutation.attributeName === "data-max") {
102
+ this.updateProgress();
103
+ }
104
+ });
105
+ });
106
+
107
+ // Start observing
108
+ this.observer.observe(this.progressElement, { attributes: true });
109
+ }
110
+
111
+ private updateProgress(): void {
112
+ const value = Number(this.progressElement.getAttribute("data-value"));
113
+ const max = Number(this.progressElement.getAttribute("data-max") || 100);
114
+ const isIndeterminate = this.progressElement.hasAttribute("data-indeterminate")
115
+ ? this.progressElement.getAttribute("data-indeterminate") === "true"
116
+ : value == null;
117
+
118
+ // Update ARIA attributes
119
+ if (!isIndeterminate) {
120
+ const valuePercent = Math.round((value / max) * 100);
121
+ this.progressElement.setAttribute("aria-valuenow", String(value));
122
+ this.progressElement.setAttribute("aria-valuetext", `${valuePercent}%`);
123
+
124
+ // Update indicator position
125
+ const indicator = this.progressElement.querySelector("div");
126
+ if (indicator) {
127
+ indicator.style.transform = `translateX(-${100 - valuePercent}%)`;
128
+ }
129
+ }
130
+ }
131
+
132
+ // Clean up method to disconnect observer
133
+ public destroy(): void {
134
+ this.observer.disconnect();
135
+ }
136
+ }
137
+
138
+ // Store instances in a WeakMap to avoid memory leaks
139
+ const progressInstances = new WeakMap<HTMLElement, ProgressHandler>();
140
+
141
+ const setupProgressBars = () => {
142
+ document.querySelectorAll<HTMLElement>(".starwind-progress-bar").forEach((progressElement) => {
143
+ if (!progressInstances.has(progressElement)) {
144
+ progressInstances.set(progressElement, new ProgressHandler(progressElement));
145
+ }
146
+ });
147
+ };
148
+
149
+ setupProgressBars();
150
+ document.addEventListener("astro:after-swap", setupProgressBars);
151
+ </script>
@@ -0,0 +1,5 @@
1
+ import Progress from "./Progress.astro";
2
+
3
+ export { Progress };
4
+
5
+ export default Progress;
@@ -0,0 +1,156 @@
1
+ ---
2
+ import type { HTMLAttributes } from "astro/types";
3
+ import { tv } from "tailwind-variants";
4
+
5
+ type Props = HTMLAttributes<"fieldset"> & {
6
+ /**
7
+ * Value for the radio group
8
+ */
9
+ value?: string;
10
+ /**
11
+ * Default value for the radio group
12
+ */
13
+ defaultValue?: string;
14
+ /**
15
+ * Legend for the radio group
16
+ */
17
+ legend?: string;
18
+ /**
19
+ * Whether the radio group is disabled
20
+ */
21
+ disabled?: boolean;
22
+ /**
23
+ * Orientation of the radio group
24
+ */
25
+ orientation?: "horizontal" | "vertical";
26
+ };
27
+
28
+ const radioGroup = tv({
29
+ base: "starwind-radio-group disabled:cursor-not-allowed disabled:opacity-70",
30
+ variants: {
31
+ orientation: {
32
+ vertical: "grid gap-3",
33
+ horizontal: "flex flex-row items-center gap-3",
34
+ },
35
+ },
36
+ defaultVariants: {
37
+ orientation: "vertical",
38
+ },
39
+ });
40
+
41
+ const {
42
+ class: className,
43
+ value,
44
+ defaultValue,
45
+ legend,
46
+ disabled = false,
47
+ orientation = "vertical",
48
+ ...rest
49
+ } = Astro.props;
50
+ ---
51
+
52
+ <fieldset
53
+ class:list={[radioGroup({ orientation, class: className })]}
54
+ data-value={value || defaultValue}
55
+ disabled={disabled}
56
+ {...rest}
57
+ >
58
+ {legend && <legend class="sr-only">{legend}</legend>}
59
+ <slot />
60
+ </fieldset>
61
+
62
+ <script>
63
+ import type { RadioGroupChangeEvent } from "./RadioGroupTypes";
64
+
65
+ class RadioGroupHandler {
66
+ private radioGroup: HTMLFieldSetElement;
67
+ private radioInputs: NodeListOf<HTMLInputElement> | undefined;
68
+ private radioGroupId: string | undefined;
69
+
70
+ constructor(radioGroup: HTMLFieldSetElement, idx: number) {
71
+ this.radioGroup = radioGroup;
72
+ this.radioGroupId = radioGroup.id || `starwind-radio-group-${idx}`;
73
+ this.radioInputs = radioGroup.querySelectorAll<HTMLInputElement>('input[type="radio"]');
74
+ this.init();
75
+ }
76
+
77
+ private init() {
78
+ // Initialize checked state based on data-value
79
+ this.syncWithDataValue();
80
+
81
+ // Setup event listeners
82
+ this.setupEvents();
83
+ }
84
+
85
+ private syncWithDataValue() {
86
+ const initialValue = this.radioGroup.dataset.value;
87
+ if (!initialValue || !this.radioInputs) return;
88
+
89
+ // Find the radio input with the matching value and check it
90
+ this.radioInputs.forEach((input) => {
91
+ if (input.value === initialValue) {
92
+ input.checked = true;
93
+ } else {
94
+ input.checked = false;
95
+ }
96
+ });
97
+ }
98
+
99
+ private setupEvents() {
100
+ // Listen for changes to update the fieldset's data-value attribute
101
+ this.radioGroup.addEventListener("change", this.handleChange.bind(this));
102
+ }
103
+
104
+ private handleChange(e: Event) {
105
+ const target = e.target as HTMLInputElement;
106
+ console.log("target", target);
107
+ if (target.type !== "radio") return;
108
+
109
+ // Update the data-value attribute
110
+ this.radioGroup.dataset.value = target.value;
111
+
112
+ // Ensure all other radio buttons in the group are unchecked
113
+ if (this.radioInputs) {
114
+ this.radioInputs.forEach((radio) => {
115
+ if (radio !== target) {
116
+ radio.checked = false;
117
+ }
118
+ });
119
+ }
120
+
121
+ // Explicitly mark the clicked radio as checked
122
+ target.checked = true;
123
+
124
+ // Dispatch custom event for external listeners
125
+ this.dispatchChangeEvent(target.value);
126
+ }
127
+
128
+ private dispatchChangeEvent(value: string) {
129
+ const event = new CustomEvent<RadioGroupChangeEvent["detail"]>("starwind:value-change", {
130
+ bubbles: true,
131
+ detail: {
132
+ value: value,
133
+ radioGroupId: this.radioGroupId,
134
+ },
135
+ });
136
+ this.radioGroup.dispatchEvent(event);
137
+ }
138
+ }
139
+
140
+ // Store instances in a WeakMap to avoid memory leaks
141
+ const radioGroupInstances = new WeakMap<HTMLElement, RadioGroupHandler>();
142
+
143
+ const setupRadioGroups = () => {
144
+ document
145
+ .querySelectorAll<HTMLFieldSetElement>(".starwind-radio-group")
146
+ .forEach((radioGroup, idx) => {
147
+ if (!radioGroupInstances.has(radioGroup)) {
148
+ radioGroupInstances.set(radioGroup, new RadioGroupHandler(radioGroup, idx));
149
+ }
150
+ });
151
+ };
152
+
153
+ // Initialize on page load and after Astro view transitions
154
+ setupRadioGroups();
155
+ document.addEventListener("astro:after-swap", setupRadioGroups);
156
+ </script>