@starwind-ui/core 1.13.0 → 1.15.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 (47) hide show
  1. package/dist/index.js +28 -5
  2. package/dist/index.js.map +1 -1
  3. package/dist/src/components/badge/Badge.astro +8 -2
  4. package/dist/src/components/button/Button.astro +8 -7
  5. package/dist/src/components/collapsible/Collapsible.astro +161 -0
  6. package/dist/src/components/collapsible/CollapsibleContent.astro +22 -0
  7. package/dist/src/components/collapsible/CollapsibleTrigger.astro +44 -0
  8. package/dist/src/components/collapsible/index.ts +13 -0
  9. package/dist/src/components/dialog/Dialog.astro +35 -1
  10. package/dist/src/components/input-otp/InputOtp.astro +319 -0
  11. package/dist/src/components/input-otp/InputOtpGroup.astro +16 -0
  12. package/dist/src/components/input-otp/InputOtpSeparator.astro +25 -0
  13. package/dist/src/components/input-otp/InputOtpSlot.astro +48 -0
  14. package/dist/src/components/input-otp/InputOtpTypes.ts +6 -0
  15. package/dist/src/components/input-otp/index.ts +33 -0
  16. package/dist/src/components/prose/Prose.astro +617 -0
  17. package/dist/src/components/prose/index.ts +9 -0
  18. package/dist/src/components/select/Select.astro +3 -0
  19. package/dist/src/components/sidebar/Sidebar.astro +213 -0
  20. package/dist/src/components/sidebar/SidebarContent.astro +24 -0
  21. package/dist/src/components/sidebar/SidebarFooter.astro +21 -0
  22. package/dist/src/components/sidebar/SidebarGroup.astro +21 -0
  23. package/dist/src/components/sidebar/SidebarGroupContent.astro +21 -0
  24. package/dist/src/components/sidebar/SidebarGroupLabel.astro +52 -0
  25. package/dist/src/components/sidebar/SidebarHeader.astro +21 -0
  26. package/dist/src/components/sidebar/SidebarInput.astro +22 -0
  27. package/dist/src/components/sidebar/SidebarInset.astro +21 -0
  28. package/dist/src/components/sidebar/SidebarMenu.astro +21 -0
  29. package/dist/src/components/sidebar/SidebarMenuAction.astro +59 -0
  30. package/dist/src/components/sidebar/SidebarMenuBadge.astro +30 -0
  31. package/dist/src/components/sidebar/SidebarMenuButton.astro +129 -0
  32. package/dist/src/components/sidebar/SidebarMenuItem.astro +21 -0
  33. package/dist/src/components/sidebar/SidebarMenuSkeleton.astro +40 -0
  34. package/dist/src/components/sidebar/SidebarMenuSub.astro +24 -0
  35. package/dist/src/components/sidebar/SidebarMenuSubButton.astro +49 -0
  36. package/dist/src/components/sidebar/SidebarMenuSubItem.astro +16 -0
  37. package/dist/src/components/sidebar/SidebarProvider.astro +213 -0
  38. package/dist/src/components/sidebar/SidebarRail.astro +71 -0
  39. package/dist/src/components/sidebar/SidebarSeparator.astro +22 -0
  40. package/dist/src/components/sidebar/SidebarTrigger.astro +66 -0
  41. package/dist/src/components/sidebar/index.ts +103 -0
  42. package/dist/src/components/theme-toggle/ThemeToggle.astro +208 -0
  43. package/dist/src/components/theme-toggle/index.ts +7 -0
  44. package/dist/src/components/toggle/Toggle.astro +1 -1
  45. package/dist/src/components/tooltip/Tooltip.astro +80 -37
  46. package/dist/src/components/tooltip/TooltipContent.astro +9 -34
  47. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -16,7 +16,7 @@ var registry_default = {
16
16
  },
17
17
  { name: "aspect-ratio", type: "component", version: "1.0.0", dependencies: [] },
18
18
  { name: "avatar", type: "component", version: "1.2.1", dependencies: [] },
19
- { name: "badge", type: "component", version: "1.3.0", dependencies: [] },
19
+ { name: "badge", type: "component", version: "1.4.0", dependencies: [] },
20
20
  { name: "breadcrumb", type: "component", version: "1.1.1", dependencies: [] },
21
21
  {
22
22
  name: "button-group",
@@ -24,7 +24,7 @@ var registry_default = {
24
24
  version: "1.0.0",
25
25
  dependencies: ["@starwind-ui/core/separator@^1.0.0"]
26
26
  },
27
- { name: "button", type: "component", version: "2.2.0", dependencies: [] },
27
+ { name: "button", type: "component", version: "2.3.0", dependencies: [] },
28
28
  { name: "card", type: "component", version: "1.3.0", dependencies: [] },
29
29
  {
30
30
  name: "carousel",
@@ -33,11 +33,13 @@ var registry_default = {
33
33
  dependencies: ["@starwind-ui/core/button@^2.1.0", "embla-carousel@^8.6.0"]
34
34
  },
35
35
  { name: "checkbox", type: "component", version: "1.4.1", dependencies: [] },
36
- { name: "dialog", type: "component", version: "1.4.2", dependencies: [] },
36
+ { name: "collapsible", type: "component", version: "1.0.0", dependencies: [] },
37
+ { name: "dialog", type: "component", version: "1.4.3", dependencies: [] },
37
38
  { name: "dropdown", type: "component", version: "1.2.3", dependencies: [] },
38
39
  { name: "dropzone", type: "component", version: "1.2.2", dependencies: [] },
39
40
  { name: "image", type: "component", version: "1.0.0", dependencies: [] },
40
41
  { name: "input", type: "component", version: "1.3.1", dependencies: [] },
42
+ { name: "input-otp", type: "component", version: "1.0.0", dependencies: [] },
41
43
  {
42
44
  name: "item",
43
45
  type: "component",
@@ -48,8 +50,9 @@ var registry_default = {
48
50
  { name: "label", type: "component", version: "1.2.0", dependencies: [] },
49
51
  { name: "pagination", type: "component", version: "3.0.2", dependencies: [] },
50
52
  { name: "progress", type: "component", version: "1.1.1", dependencies: [] },
53
+ { name: "prose", type: "component", version: "1.0.0", dependencies: [] },
51
54
  { name: "radio-group", type: "component", version: "1.2.4", dependencies: [] },
52
- { name: "select", type: "component", version: "1.8.1", dependencies: [] },
55
+ { name: "select", type: "component", version: "1.8.2", dependencies: [] },
53
56
  { name: "separator", type: "component", version: "1.0.0", dependencies: [] },
54
57
  {
55
58
  name: "sheet",
@@ -57,6 +60,20 @@ var registry_default = {
57
60
  version: "1.1.1",
58
61
  dependencies: ["@starwind-ui/core/dialog@^1.3.0"]
59
62
  },
63
+ {
64
+ name: "sidebar",
65
+ type: "component",
66
+ version: "1.0.0",
67
+ dependencies: [
68
+ "@starwind-ui/core/button@^2.3.0",
69
+ "@starwind-ui/core/dialog@^1.4.3",
70
+ "@starwind-ui/core/input@^1.3.1",
71
+ "@starwind-ui/core/separator@^1.0.0",
72
+ "@starwind-ui/core/sheet@^1.1.1",
73
+ "@starwind-ui/core/skeleton@^1.2.0",
74
+ "@starwind-ui/core/tooltip@^1.4.0"
75
+ ]
76
+ },
60
77
  { name: "skeleton", type: "component", version: "1.2.0", dependencies: [] },
61
78
  { name: "slider", type: "component", version: "1.0.0", dependencies: [] },
62
79
  { name: "spinner", type: "component", version: "1.0.0", dependencies: [] },
@@ -64,9 +81,15 @@ var registry_default = {
64
81
  { name: "table", type: "component", version: "1.1.0", dependencies: [] },
65
82
  { name: "tabs", type: "component", version: "1.4.1", dependencies: [] },
66
83
  { name: "textarea", type: "component", version: "1.3.1", dependencies: [] },
84
+ {
85
+ name: "theme-toggle",
86
+ type: "component",
87
+ version: "1.0.0",
88
+ dependencies: ["@starwind-ui/core/toggle@^1.0.1"]
89
+ },
67
90
  { name: "toast", type: "component", version: "1.0.0", dependencies: [] },
68
91
  { name: "toggle", type: "component", version: "1.0.1", dependencies: [] },
69
- { name: "tooltip", type: "component", version: "1.3.1", dependencies: [] },
92
+ { name: "tooltip", type: "component", version: "1.4.0", dependencies: [] },
70
93
  { name: "video", type: "component", version: "1.0.0", dependencies: [] }
71
94
  ]
72
95
  };
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/registry.json"],"sourcesContent":["import { join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nimport componentRegistry from \"./registry.json\" with { type: \"json\" };\n\n/**\n * Component metadata interface describing a Starwind UI component\n */\nexport interface ComponentMeta {\n name: string;\n version: string;\n type: \"component\";\n dependencies: string[];\n}\n\n/**\n * Registry interface containing all available components\n */\nexport interface Registry {\n components: ComponentMeta[];\n}\n\nconst __dirname = fileURLToPath(new URL(\".\", import.meta.url));\n\n/**\n * Get the absolute path to a component file\n * @param {string} componentName - The name of the component\n * @param {string} fileName - The name of the file within the component\n * @returns {string} The absolute path to the component file\n */\nexport const getComponentPath = (componentName: string, fileName: string): string => {\n // In production (when installed as a dependency), the components will be in dist/src/components\n // In development, they will be in src/components\n const componentsDir = __dirname.includes(\"dist\") ? \"src/components\" : \"src/components\";\n return join(__dirname, componentsDir, componentName, fileName);\n};\n\n/**\n * Map of all components and their metadata from registry\n */\nexport const registry = componentRegistry.components as ComponentMeta[];\n","{\n \"$schema\": \"https://starwind.dev/registry-schema.json\",\n \"components\": [\n { \"name\": \"accordion\", \"type\": \"component\", \"version\": \"1.3.3\", \"dependencies\": [] },\n { \"name\": \"alert\", \"type\": \"component\", \"version\": \"1.3.0\", \"dependencies\": [] },\n {\n \"name\": \"alert-dialog\",\n \"type\": \"component\",\n \"version\": \"1.0.3\",\n \"dependencies\": [\"@starwind-ui/core/button@^2.1.0\"]\n },\n { \"name\": \"aspect-ratio\", \"type\": \"component\", \"version\": \"1.0.0\", \"dependencies\": [] },\n { \"name\": \"avatar\", \"type\": \"component\", \"version\": \"1.2.1\", \"dependencies\": [] },\n { \"name\": \"badge\", \"type\": \"component\", \"version\": \"1.3.0\", \"dependencies\": [] },\n { \"name\": \"breadcrumb\", \"type\": \"component\", \"version\": \"1.1.1\", \"dependencies\": [] },\n {\n \"name\": \"button-group\",\n \"type\": \"component\",\n \"version\": \"1.0.0\",\n \"dependencies\": [\"@starwind-ui/core/separator@^1.0.0\"]\n },\n { \"name\": \"button\", \"type\": \"component\", \"version\": \"2.2.0\", \"dependencies\": [] },\n { \"name\": \"card\", \"type\": \"component\", \"version\": \"1.3.0\", \"dependencies\": [] },\n {\n \"name\": \"carousel\",\n \"type\": \"component\",\n \"version\": \"1.0.1\",\n \"dependencies\": [\"@starwind-ui/core/button@^2.1.0\", \"embla-carousel@^8.6.0\"]\n },\n { \"name\": \"checkbox\", \"type\": \"component\", \"version\": \"1.4.1\", \"dependencies\": [] },\n { \"name\": \"dialog\", \"type\": \"component\", \"version\": \"1.4.2\", \"dependencies\": [] },\n { \"name\": \"dropdown\", \"type\": \"component\", \"version\": \"1.2.3\", \"dependencies\": [] },\n { \"name\": \"dropzone\", \"type\": \"component\", \"version\": \"1.2.2\", \"dependencies\": [] },\n { \"name\": \"image\", \"type\": \"component\", \"version\": \"1.0.0\", \"dependencies\": [] },\n { \"name\": \"input\", \"type\": \"component\", \"version\": \"1.3.1\", \"dependencies\": [] },\n {\n \"name\": \"item\",\n \"type\": \"component\",\n \"version\": \"1.0.0\",\n \"dependencies\": [\"@starwind-ui/core/separator@^1.0.0\"]\n },\n { \"name\": \"kbd\", \"type\": \"component\", \"version\": \"1.0.0\", \"dependencies\": [] },\n { \"name\": \"label\", \"type\": \"component\", \"version\": \"1.2.0\", \"dependencies\": [] },\n { \"name\": \"pagination\", \"type\": \"component\", \"version\": \"3.0.2\", \"dependencies\": [] },\n { \"name\": \"progress\", \"type\": \"component\", \"version\": \"1.1.1\", \"dependencies\": [] },\n { \"name\": \"radio-group\", \"type\": \"component\", \"version\": \"1.2.4\", \"dependencies\": [] },\n { \"name\": \"select\", \"type\": \"component\", \"version\": \"1.8.1\", \"dependencies\": [] },\n { \"name\": \"separator\", \"type\": \"component\", \"version\": \"1.0.0\", \"dependencies\": [] },\n {\n \"name\": \"sheet\",\n \"type\": \"component\",\n \"version\": \"1.1.1\",\n \"dependencies\": [\"@starwind-ui/core/dialog@^1.3.0\"]\n },\n { \"name\": \"skeleton\", \"type\": \"component\", \"version\": \"1.2.0\", \"dependencies\": [] },\n { \"name\": \"slider\", \"type\": \"component\", \"version\": \"1.0.0\", \"dependencies\": [] },\n { \"name\": \"spinner\", \"type\": \"component\", \"version\": \"1.0.0\", \"dependencies\": [] },\n { \"name\": \"switch\", \"type\": \"component\", \"version\": \"1.3.1\", \"dependencies\": [] },\n { \"name\": \"table\", \"type\": \"component\", \"version\": \"1.1.0\", \"dependencies\": [] },\n { \"name\": \"tabs\", \"type\": \"component\", \"version\": \"1.4.1\", \"dependencies\": [] },\n { \"name\": \"textarea\", \"type\": \"component\", \"version\": \"1.3.1\", \"dependencies\": [] },\n { \"name\": \"toast\", \"type\": \"component\", \"version\": \"1.0.0\", \"dependencies\": [] },\n { \"name\": \"toggle\", \"type\": \"component\", \"version\": \"1.0.1\", \"dependencies\": [] },\n { \"name\": \"tooltip\", \"type\": \"component\", \"version\": \"1.3.1\", \"dependencies\": [] },\n { \"name\": \"video\", \"type\": \"component\", \"version\": \"1.0.0\", \"dependencies\": [] }\n ]\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/registry.json"],"sourcesContent":["import { join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nimport componentRegistry from \"./registry.json\" with { type: \"json\" };\n\n/**\n * Component metadata interface describing a Starwind UI component\n */\nexport interface ComponentMeta {\n name: string;\n version: string;\n type: \"component\";\n dependencies: string[];\n}\n\n/**\n * Registry interface containing all available components\n */\nexport interface Registry {\n components: ComponentMeta[];\n}\n\nconst __dirname = fileURLToPath(new URL(\".\", import.meta.url));\n\n/**\n * Get the absolute path to a component file\n * @param {string} componentName - The name of the component\n * @param {string} fileName - The name of the file within the component\n * @returns {string} The absolute path to the component file\n */\nexport const getComponentPath = (componentName: string, fileName: string): string => {\n // In production (when installed as a dependency), the components will be in dist/src/components\n // In development, they will be in src/components\n const componentsDir = __dirname.includes(\"dist\") ? \"src/components\" : \"src/components\";\n return join(__dirname, componentsDir, componentName, fileName);\n};\n\n/**\n * Map of all components and their metadata from registry\n */\nexport const registry = componentRegistry.components as ComponentMeta[];\n","{\n \"$schema\": \"https://starwind.dev/registry-schema.json\",\n \"components\": [\n { \"name\": \"accordion\", \"type\": \"component\", \"version\": \"1.3.3\", \"dependencies\": [] },\n { \"name\": \"alert\", \"type\": \"component\", \"version\": \"1.3.0\", \"dependencies\": [] },\n {\n \"name\": \"alert-dialog\",\n \"type\": \"component\",\n \"version\": \"1.0.3\",\n \"dependencies\": [\"@starwind-ui/core/button@^2.1.0\"]\n },\n { \"name\": \"aspect-ratio\", \"type\": \"component\", \"version\": \"1.0.0\", \"dependencies\": [] },\n { \"name\": \"avatar\", \"type\": \"component\", \"version\": \"1.2.1\", \"dependencies\": [] },\n { \"name\": \"badge\", \"type\": \"component\", \"version\": \"1.4.0\", \"dependencies\": [] },\n { \"name\": \"breadcrumb\", \"type\": \"component\", \"version\": \"1.1.1\", \"dependencies\": [] },\n {\n \"name\": \"button-group\",\n \"type\": \"component\",\n \"version\": \"1.0.0\",\n \"dependencies\": [\"@starwind-ui/core/separator@^1.0.0\"]\n },\n { \"name\": \"button\", \"type\": \"component\", \"version\": \"2.3.0\", \"dependencies\": [] },\n { \"name\": \"card\", \"type\": \"component\", \"version\": \"1.3.0\", \"dependencies\": [] },\n {\n \"name\": \"carousel\",\n \"type\": \"component\",\n \"version\": \"1.0.1\",\n \"dependencies\": [\"@starwind-ui/core/button@^2.1.0\", \"embla-carousel@^8.6.0\"]\n },\n { \"name\": \"checkbox\", \"type\": \"component\", \"version\": \"1.4.1\", \"dependencies\": [] },\n { \"name\": \"collapsible\", \"type\": \"component\", \"version\": \"1.0.0\", \"dependencies\": [] },\n { \"name\": \"dialog\", \"type\": \"component\", \"version\": \"1.4.3\", \"dependencies\": [] },\n { \"name\": \"dropdown\", \"type\": \"component\", \"version\": \"1.2.3\", \"dependencies\": [] },\n { \"name\": \"dropzone\", \"type\": \"component\", \"version\": \"1.2.2\", \"dependencies\": [] },\n { \"name\": \"image\", \"type\": \"component\", \"version\": \"1.0.0\", \"dependencies\": [] },\n { \"name\": \"input\", \"type\": \"component\", \"version\": \"1.3.1\", \"dependencies\": [] },\n { \"name\": \"input-otp\", \"type\": \"component\", \"version\": \"1.0.0\", \"dependencies\": [] },\n {\n \"name\": \"item\",\n \"type\": \"component\",\n \"version\": \"1.0.0\",\n \"dependencies\": [\"@starwind-ui/core/separator@^1.0.0\"]\n },\n { \"name\": \"kbd\", \"type\": \"component\", \"version\": \"1.0.0\", \"dependencies\": [] },\n { \"name\": \"label\", \"type\": \"component\", \"version\": \"1.2.0\", \"dependencies\": [] },\n { \"name\": \"pagination\", \"type\": \"component\", \"version\": \"3.0.2\", \"dependencies\": [] },\n { \"name\": \"progress\", \"type\": \"component\", \"version\": \"1.1.1\", \"dependencies\": [] },\n { \"name\": \"prose\", \"type\": \"component\", \"version\": \"1.0.0\", \"dependencies\": [] },\n { \"name\": \"radio-group\", \"type\": \"component\", \"version\": \"1.2.4\", \"dependencies\": [] },\n { \"name\": \"select\", \"type\": \"component\", \"version\": \"1.8.2\", \"dependencies\": [] },\n { \"name\": \"separator\", \"type\": \"component\", \"version\": \"1.0.0\", \"dependencies\": [] },\n {\n \"name\": \"sheet\",\n \"type\": \"component\",\n \"version\": \"1.1.1\",\n \"dependencies\": [\"@starwind-ui/core/dialog@^1.3.0\"]\n },\n {\n \"name\": \"sidebar\",\n \"type\": \"component\",\n \"version\": \"1.0.0\",\n \"dependencies\": [\n \"@starwind-ui/core/button@^2.3.0\",\n \"@starwind-ui/core/dialog@^1.4.3\",\n \"@starwind-ui/core/input@^1.3.1\",\n \"@starwind-ui/core/separator@^1.0.0\",\n \"@starwind-ui/core/sheet@^1.1.1\",\n \"@starwind-ui/core/skeleton@^1.2.0\",\n \"@starwind-ui/core/tooltip@^1.4.0\"\n ]\n },\n { \"name\": \"skeleton\", \"type\": \"component\", \"version\": \"1.2.0\", \"dependencies\": [] },\n { \"name\": \"slider\", \"type\": \"component\", \"version\": \"1.0.0\", \"dependencies\": [] },\n { \"name\": \"spinner\", \"type\": \"component\", \"version\": \"1.0.0\", \"dependencies\": [] },\n { \"name\": \"switch\", \"type\": \"component\", \"version\": \"1.3.1\", \"dependencies\": [] },\n { \"name\": \"table\", \"type\": \"component\", \"version\": \"1.1.0\", \"dependencies\": [] },\n { \"name\": \"tabs\", \"type\": \"component\", \"version\": \"1.4.1\", \"dependencies\": [] },\n { \"name\": \"textarea\", \"type\": \"component\", \"version\": \"1.3.1\", \"dependencies\": [] },\n {\n \"name\": \"theme-toggle\",\n \"type\": \"component\",\n \"version\": \"1.0.0\",\n \"dependencies\": [\"@starwind-ui/core/toggle@^1.0.1\"]\n },\n { \"name\": \"toast\", \"type\": \"component\", \"version\": \"1.0.0\", \"dependencies\": [] },\n { \"name\": \"toggle\", \"type\": \"component\", \"version\": \"1.0.1\", \"dependencies\": [] },\n { \"name\": \"tooltip\", \"type\": \"component\", \"version\": \"1.4.0\", \"dependencies\": [] },\n { \"name\": \"video\", \"type\": \"component\", \"version\": \"1.0.0\", \"dependencies\": [] }\n ]\n}\n"],"mappings":"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","names":[]}
@@ -7,8 +7,10 @@ interface Props
7
7
 
8
8
  export const badge = tv({
9
9
  base: [
10
- "starwind-badge inline-flex items-center rounded-full font-semibold",
10
+ "starwind-badge inline-flex items-center gap-1.5 rounded-full font-medium whitespace-nowrap",
11
+ "[&_svg]:pointer-events-none [&_svg]:shrink-0",
11
12
  "transition-all outline-none focus-visible:ring-3",
13
+ "aria-invalid:border-error aria-invalid:focus-visible:ring-error/40",
12
14
  ],
13
15
  variants: {
14
16
  variant: {
@@ -22,7 +24,11 @@ export const badge = tv({
22
24
  warning: "bg-warning text-warning-foreground focus-visible:ring-warning/50",
23
25
  error: "bg-error text-error-foreground focus-visible:ring-error/50",
24
26
  },
25
- size: { sm: "px-2.5 py-0.5 text-xs", md: "px-3 py-0.5 text-sm", lg: "px-4 py-1 text-base" },
27
+ size: {
28
+ sm: "px-2.5 py-0.5 text-xs [&_svg:not([class*='size-'])]:size-3",
29
+ md: "px-3 py-0.5 text-sm [&_svg:not([class*='size-'])]:size-4",
30
+ lg: "px-4 py-1 text-base [&_svg:not([class*='size-'])]:size-4.5",
31
+ },
26
32
  isLink: { true: "cursor-pointer", false: "" },
27
33
  },
28
34
  compoundVariants: [
@@ -13,9 +13,10 @@ const { variant, size, class: className, ...rest } = Astro.props;
13
13
  export const button = tv({
14
14
  base: [
15
15
  "inline-flex items-center justify-center gap-1.5 rounded-md font-medium whitespace-nowrap",
16
- "[&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
16
+ "[&_svg]:pointer-events-none [&_svg]:shrink-0",
17
17
  "transition-all outline-none focus-visible:ring-3",
18
18
  "disabled:pointer-events-none disabled:opacity-50",
19
+ "aria-invalid:border-error aria-invalid:focus-visible:ring-error/40",
19
20
  ],
20
21
  variants: {
21
22
  variant: {
@@ -35,12 +36,12 @@ export const button = tv({
35
36
  error: "bg-error text-error-foreground hover:bg-error/90 focus-visible:ring-error/50",
36
37
  },
37
38
  size: {
38
- sm: "h-9 px-3 py-2 text-sm",
39
- md: "h-11 px-4 py-2 text-base",
40
- lg: "h-12 px-8 py-2 text-lg",
41
- icon: "size-11",
42
- "icon-sm": "size-9",
43
- "icon-lg": "size-12",
39
+ sm: "h-9 px-4 text-sm has-[>svg]:px-3 [&_svg:not([class*='size-'])]:size-3.5",
40
+ md: "h-11 px-5 text-base has-[>svg]:px-4 [&_svg:not([class*='size-'])]:size-4.5",
41
+ lg: "h-12 px-8 text-lg has-[>svg]:px-6 [&_svg:not([class*='size-'])]:size-5",
42
+ "icon-sm": "size-9 [&_svg:not([class*='size-'])]:size-3.5",
43
+ icon: "size-11 [&_svg:not([class*='size-'])]:size-4.5",
44
+ "icon-lg": "size-12 [&_svg:not([class*='size-'])]:size-5",
44
45
  },
45
46
  },
46
47
  defaultVariants: { variant: "default", size: "md" },
@@ -0,0 +1,161 @@
1
+ ---
2
+ import type { HTMLAttributes } from "astro/types";
3
+ import { tv } from "tailwind-variants";
4
+
5
+ type Props = HTMLAttributes<"div"> & {
6
+ /**
7
+ * Whether the collapsible panel is initially open
8
+ */
9
+ defaultOpen?: boolean;
10
+ /**
11
+ * Whether the component should ignore user interaction
12
+ */
13
+ disabled?: boolean;
14
+ };
15
+
16
+ export const collapsible = tv({ base: "starwind-collapsible" });
17
+
18
+ const { defaultOpen = false, disabled = false, class: className, ...rest } = Astro.props;
19
+
20
+ // Keys owned by the runtime that should not be spread from rest
21
+ const runtimeOwnedKeys = ["id", "data-state", "data-disabled", "class"] as const;
22
+ const sanitizedRest = Object.fromEntries(
23
+ Object.entries(rest).filter(
24
+ ([key]) => !runtimeOwnedKeys.includes(key as (typeof runtimeOwnedKeys)[number]),
25
+ ),
26
+ );
27
+
28
+ // Compute final values, preferring consumer-provided values
29
+ const finalDataState =
30
+ (rest as Record<string, unknown>)["data-state"] ?? (defaultOpen ? "open" : "closed");
31
+ const finalDataDisabled =
32
+ (rest as Record<string, unknown>)["data-disabled"] ?? (disabled ? "" : undefined);
33
+ const finalId = (rest as Record<string, unknown>)["id"] as string | undefined;
34
+ ---
35
+
36
+ <div
37
+ {...sanitizedRest}
38
+ id={finalId}
39
+ class={collapsible({ class: className })}
40
+ data-state={finalDataState}
41
+ data-disabled={finalDataDisabled}
42
+ data-slot="collapsible"
43
+ >
44
+ <slot />
45
+ </div>
46
+
47
+ <script>
48
+ type CollapsibleState = "open" | "closed";
49
+
50
+ /**
51
+ * Handles the functionality of a collapsible component.
52
+ * Manages open/close state and accessibility attributes.
53
+ */
54
+ class CollapsibleHandler {
55
+ private root: HTMLElement;
56
+ private trigger: HTMLElement | null;
57
+ private content: HTMLElement | null;
58
+ private collapsibleId: string;
59
+
60
+ constructor(root: HTMLElement, idx: number) {
61
+ this.root = root;
62
+ this.collapsibleId = `starwind-collapsible-${idx}`;
63
+
64
+ this.trigger = root.querySelector<HTMLElement>(".starwind-collapsible-trigger");
65
+ this.content = root.querySelector<HTMLElement>(".starwind-collapsible-content");
66
+
67
+ if (this.trigger && this.content) {
68
+ this.setupAccessibility();
69
+ this.setupEventListeners();
70
+ this.setInitialState();
71
+ }
72
+ }
73
+
74
+ private setupAccessibility(): void {
75
+ if (!this.trigger || !this.content) return;
76
+
77
+ const triggerId = `${this.collapsibleId}-trigger`;
78
+ const contentId = `${this.collapsibleId}-content`;
79
+
80
+ // Use "set if missing" semantics for IDs
81
+ if (!this.trigger.id) this.trigger.id = triggerId;
82
+ if (!this.content.id) this.content.id = contentId;
83
+
84
+ // Use actual IDs (consumer-provided or generated) for ARIA
85
+ this.trigger.setAttribute("aria-controls", this.content.id);
86
+ this.content.setAttribute("aria-labelledby", this.trigger.id);
87
+ this.content.setAttribute("role", "region");
88
+
89
+ this.updateAriaExpanded();
90
+ }
91
+
92
+ private setInitialState(): void {
93
+ const isOpen = this.root.dataset.state === "open";
94
+ this.setState(isOpen);
95
+ }
96
+
97
+ private setupEventListeners(): void {
98
+ if (!this.trigger) return;
99
+
100
+ this.trigger.addEventListener("click", () => {
101
+ if (this.root.dataset.disabled !== undefined) return;
102
+ this.toggle();
103
+ });
104
+ }
105
+
106
+ private toggle(): void {
107
+ const isOpen = this.root.dataset.state === "open";
108
+ this.setState(!isOpen);
109
+ }
110
+
111
+ private setState(isOpen: boolean): void {
112
+ const state: CollapsibleState = isOpen ? "open" : "closed";
113
+
114
+ this.root.dataset.state = state;
115
+
116
+ if (this.trigger) {
117
+ this.trigger.dataset.state = state;
118
+ if (isOpen) {
119
+ this.trigger.dataset.panelOpen = "";
120
+ } else {
121
+ delete this.trigger.dataset.panelOpen;
122
+ }
123
+ }
124
+
125
+ if (this.content) {
126
+ this.content.dataset.state = state;
127
+ if (isOpen) {
128
+ this.content.hidden = false;
129
+ } else {
130
+ this.content.hidden = true;
131
+ }
132
+ }
133
+
134
+ this.updateAriaExpanded();
135
+ }
136
+
137
+ private updateAriaExpanded(): void {
138
+ if (!this.trigger) return;
139
+ const isOpen = this.root.dataset.state === "open";
140
+ this.trigger.setAttribute("aria-expanded", isOpen.toString());
141
+ }
142
+ }
143
+
144
+ const collapsibleInstances = new WeakMap<HTMLElement, CollapsibleHandler>();
145
+ let collapsibleCounter = 0;
146
+
147
+ const setupCollapsibles = () => {
148
+ document.querySelectorAll<HTMLElement>(".starwind-collapsible").forEach((collapsible) => {
149
+ if (!collapsibleInstances.has(collapsible)) {
150
+ collapsibleInstances.set(
151
+ collapsible,
152
+ new CollapsibleHandler(collapsible, collapsibleCounter++),
153
+ );
154
+ }
155
+ });
156
+ };
157
+
158
+ setupCollapsibles();
159
+ document.addEventListener("astro:after-swap", setupCollapsibles);
160
+ document.addEventListener("starwind:init", setupCollapsibles);
161
+ </script>
@@ -0,0 +1,22 @@
1
+ ---
2
+ import type { HTMLAttributes } from "astro/types";
3
+ import { tv } from "tailwind-variants";
4
+
5
+ type Props = HTMLAttributes<"div">;
6
+
7
+ export const collapsibleContent = tv({
8
+ base: "starwind-collapsible-content",
9
+ });
10
+
11
+ const { class: className, ...rest } = Astro.props;
12
+ ---
13
+
14
+ <div
15
+ class={collapsibleContent({ class: className })}
16
+ data-state="closed"
17
+ data-slot="collapsible-content"
18
+ hidden
19
+ {...rest}
20
+ >
21
+ <slot />
22
+ </div>
@@ -0,0 +1,44 @@
1
+ ---
2
+ import type { HTMLAttributes } from "astro/types";
3
+ import { tv } from "tailwind-variants";
4
+
5
+ type Props = HTMLAttributes<"button"> & {
6
+ /**
7
+ * When true, renders as a wrapper div instead of a button,
8
+ * allowing a custom trigger element as a child
9
+ */
10
+ asChild?: boolean;
11
+ };
12
+
13
+ export const collapsibleTrigger = tv({
14
+ base: "starwind-collapsible-trigger",
15
+ });
16
+
17
+ const { class: className, asChild = false, ...rest } = Astro.props;
18
+
19
+ let hasChildren = false;
20
+ if (Astro.slots.has("default")) {
21
+ hasChildren = true;
22
+ }
23
+ ---
24
+
25
+ {
26
+ asChild && hasChildren ? (
27
+ <div
28
+ class={collapsibleTrigger({ class: className })}
29
+ data-slot="collapsible-trigger"
30
+ data-as-child
31
+ >
32
+ <slot />
33
+ </div>
34
+ ) : (
35
+ <button
36
+ type="button"
37
+ class={collapsibleTrigger({ class: className })}
38
+ data-slot="collapsible-trigger"
39
+ {...rest}
40
+ >
41
+ <slot />
42
+ </button>
43
+ )
44
+ }
@@ -0,0 +1,13 @@
1
+ import Collapsible, { collapsible } from "./Collapsible.astro";
2
+ import CollapsibleContent, { collapsibleContent } from "./CollapsibleContent.astro";
3
+ import CollapsibleTrigger, { collapsibleTrigger } from "./CollapsibleTrigger.astro";
4
+
5
+ const CollapsibleVariants = { collapsible, collapsibleContent, collapsibleTrigger };
6
+
7
+ export { Collapsible, CollapsibleContent, CollapsibleTrigger, CollapsibleVariants };
8
+
9
+ export default {
10
+ Root: Collapsible,
11
+ Content: CollapsibleContent,
12
+ Trigger: CollapsibleTrigger,
13
+ };
@@ -30,6 +30,8 @@ const { class: className, ...rest } = Astro.props;
30
30
  private parentDialog: DialogHandler | null = null;
31
31
  private nestedOpenCount: number = 0;
32
32
  private isNested: boolean = false;
33
+ private _closeTimeout: number | null = null;
34
+ private _isClosing: boolean = false;
33
35
 
34
36
  constructor(dialogWrapper: HTMLElement, dialogNumber: number) {
35
37
  this.dialogWrapper = dialogWrapper;
@@ -149,6 +151,18 @@ const { class: className, ...rest } = Astro.props;
149
151
 
150
152
  private setupEvents(): void {
151
153
  if (!this.dialog) return;
154
+
155
+ // Add programmatic open/close via custom events on the wrapper
156
+ this.dialogWrapper.addEventListener("dialog:open", () => this.open());
157
+ this.dialogWrapper.addEventListener("dialog:close", () => this.close());
158
+ this.dialogWrapper.addEventListener("dialog:toggle", () => {
159
+ if (this.dialog?.open) {
160
+ this.close();
161
+ } else {
162
+ this.open();
163
+ }
164
+ });
165
+
152
166
  // Add click listeners to all triggers
153
167
  this.triggers.forEach((trigger) => {
154
168
  trigger.addEventListener("click", () => {
@@ -224,6 +238,15 @@ const { class: className, ...rest } = Astro.props;
224
238
 
225
239
  private open(): void {
226
240
  if (!this.dialog || !this.backdrop) return;
241
+ // Return early if already open
242
+ if (this.dialog.open && !this._isClosing) return;
243
+
244
+ // Cancel any pending close
245
+ if (this._closeTimeout !== null) {
246
+ clearTimeout(this._closeTimeout);
247
+ this._closeTimeout = null;
248
+ }
249
+ this._isClosing = false;
227
250
 
228
251
  // Reset nested count when opening (in case it wasn't properly reset)
229
252
  this.nestedOpenCount = 0;
@@ -246,7 +269,16 @@ const { class: className, ...rest } = Astro.props;
246
269
 
247
270
  private close(): void {
248
271
  if (!this.dialog || !this.backdrop) return;
272
+ // Return early if already closed or closing
273
+ if (!this.dialog.open || this._isClosing) return;
274
+
275
+ // Clear any existing close timeout
276
+ if (this._closeTimeout !== null) {
277
+ clearTimeout(this._closeTimeout);
278
+ this._closeTimeout = null;
279
+ }
249
280
 
281
+ this._isClosing = true;
250
282
  this.dialog.dataset.state = "closed";
251
283
 
252
284
  // Notify parent dialog that nested dialog is closing
@@ -257,11 +289,13 @@ const { class: className, ...rest } = Astro.props;
257
289
  }
258
290
 
259
291
  // Wait for animation to finish before hiding backdrop
260
- setTimeout(() => {
292
+ this._closeTimeout = window.setTimeout(() => {
261
293
  if (!this.isNested) {
262
294
  this.backdrop?.classList.add("hidden");
263
295
  }
264
296
  this.dialog?.close();
297
+ this._isClosing = false;
298
+ this._closeTimeout = null;
265
299
  const stillOpen = document.querySelectorAll("dialog[open]").length;
266
300
  if (stillOpen === 0) {
267
301
  document.body.classList.remove("overflow-hidden");