@refraction-ui/astro 0.4.0 → 0.4.2

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 (246) hide show
  1. package/dist/astro-accordion/Button.astro +55 -0
  2. package/dist/astro-accordion/index.ts +1 -0
  3. package/dist/astro-ai/AIScript.astro +69 -0
  4. package/dist/astro-ai/TTSScript.astro +60 -0
  5. package/dist/astro-ai/index.ts +16 -0
  6. package/dist/astro-animated-text/AnimatedText.astro +81 -0
  7. package/dist/astro-animated-text/TypewriterText.astro +90 -0
  8. package/dist/astro-animated-text/index.ts +1 -0
  9. package/dist/astro-app-shell/AppShell.astro +195 -0
  10. package/dist/astro-app-shell/AppShellContent.astro +29 -0
  11. package/dist/astro-app-shell/AppShellHeader.astro +54 -0
  12. package/dist/astro-app-shell/AppShellMain.astro +18 -0
  13. package/dist/astro-app-shell/AppShellMobileNav.astro +27 -0
  14. package/dist/astro-app-shell/AppShellOverlay.astro +21 -0
  15. package/dist/astro-app-shell/AppShellSidebar.astro +26 -0
  16. package/dist/astro-app-shell/AuthShell.astro +31 -0
  17. package/dist/astro-app-shell/AuthShellCard.astro +24 -0
  18. package/dist/astro-app-shell/PageShell.astro +36 -0
  19. package/dist/astro-app-shell/PageShellFooter.astro +30 -0
  20. package/dist/astro-app-shell/PageShellNav.astro +33 -0
  21. package/dist/astro-app-shell/PageShellSection.astro +32 -0
  22. package/dist/astro-app-shell/index.ts +21 -0
  23. package/dist/astro-auth/AuthGuard.astro +133 -0
  24. package/dist/astro-auth/index.ts +5 -0
  25. package/dist/astro-avatar/Avatar.astro +22 -0
  26. package/dist/astro-avatar/AvatarFallback.astro +18 -0
  27. package/dist/astro-avatar/AvatarImage.astro +48 -0
  28. package/dist/astro-avatar/index.ts +1 -0
  29. package/dist/astro-avatar-group/AvatarGroup.astro +42 -0
  30. package/dist/astro-avatar-group/index.ts +1 -0
  31. package/dist/astro-badge/Badge.astro +27 -0
  32. package/dist/astro-badge/index.ts +1 -0
  33. package/dist/astro-bottom-nav/BottomNav.astro +40 -0
  34. package/dist/astro-bottom-nav/index.ts +1 -0
  35. package/dist/astro-breadcrumbs/Breadcrumbs.astro +56 -0
  36. package/dist/astro-breadcrumbs/index.ts +1 -0
  37. package/dist/astro-button/Button.astro +55 -0
  38. package/dist/astro-button/index.ts +1 -0
  39. package/dist/astro-calendar/Calendar.astro +259 -0
  40. package/dist/astro-calendar/index.ts +1 -0
  41. package/dist/astro-callout/Callout.astro +3 -0
  42. package/dist/astro-callout/index.ts +1 -0
  43. package/dist/astro-card/Card.astro +20 -0
  44. package/dist/astro-card/CardContent.astro +13 -0
  45. package/dist/astro-card/CardDescription.astro +13 -0
  46. package/dist/astro-card/CardFooter.astro +13 -0
  47. package/dist/astro-card/CardHeader.astro +13 -0
  48. package/dist/astro-card/CardTitle.astro +15 -0
  49. package/dist/astro-card/index.ts +1 -0
  50. package/dist/astro-card-grid/CardGrid.astro +17 -0
  51. package/dist/astro-card-grid/index.ts +1 -0
  52. package/dist/astro-carousel/Button.astro +55 -0
  53. package/dist/astro-carousel/index.ts +1 -0
  54. package/dist/astro-charts/Bars.astro +53 -0
  55. package/dist/astro-charts/Chart.astro +31 -0
  56. package/dist/astro-charts/Circles.astro +48 -0
  57. package/dist/astro-charts/Gradient.astro +34 -0
  58. package/dist/astro-charts/Histogram.astro +107 -0
  59. package/dist/astro-charts/Line.astro +55 -0
  60. package/dist/astro-charts/PieChart.astro +63 -0
  61. package/dist/astro-charts/ScatterPlot.astro +95 -0
  62. package/dist/astro-charts/XAxis.astro +46 -0
  63. package/dist/astro-charts/YAxis.astro +44 -0
  64. package/dist/astro-charts/index.ts +26 -0
  65. package/dist/astro-checkbox/Checkbox.astro +129 -0
  66. package/dist/astro-checkbox/index.ts +1 -0
  67. package/dist/astro-code-block/CodeBlock.astro +3 -0
  68. package/dist/astro-code-block/index.ts +1 -0
  69. package/dist/astro-code-editor/CodeEditor.astro +123 -0
  70. package/dist/astro-code-editor/index.ts +1 -0
  71. package/dist/astro-collapsible/Collapsible.astro +58 -0
  72. package/dist/astro-collapsible/CollapsibleContent.astro +21 -0
  73. package/dist/astro-collapsible/CollapsibleTrigger.astro +17 -0
  74. package/dist/astro-collapsible/index.ts +1 -0
  75. package/dist/astro-command/Command.astro +170 -0
  76. package/dist/astro-command/CommandEmpty.astro +17 -0
  77. package/dist/astro-command/CommandGroup.astro +25 -0
  78. package/dist/astro-command/CommandInput.astro +21 -0
  79. package/dist/astro-command/CommandItem.astro +26 -0
  80. package/dist/astro-command/CommandList.astro +17 -0
  81. package/dist/astro-command/CommandSeparator.astro +14 -0
  82. package/dist/astro-command/index.ts +1 -0
  83. package/dist/astro-command-input/CommandInput.astro +6 -0
  84. package/dist/astro-command-input/index.ts +1 -0
  85. package/dist/astro-content-protection/ContentProtection.astro +104 -0
  86. package/dist/astro-content-protection/index.ts +1 -0
  87. package/dist/astro-data-table/DataTable.astro +263 -0
  88. package/dist/astro-data-table/index.ts +1 -0
  89. package/dist/astro-date-picker/DatePicker.astro +398 -0
  90. package/dist/astro-date-picker/index.ts +1 -0
  91. package/dist/astro-device-frame/DeviceFrame.astro +44 -0
  92. package/dist/astro-device-frame/index.ts +1 -0
  93. package/dist/astro-dialog/Dialog.astro +138 -0
  94. package/dist/astro-dialog/DialogClose.astro +16 -0
  95. package/dist/astro-dialog/DialogContent.astro +24 -0
  96. package/dist/astro-dialog/DialogDescription.astro +15 -0
  97. package/dist/astro-dialog/DialogFooter.astro +14 -0
  98. package/dist/astro-dialog/DialogHeader.astro +14 -0
  99. package/dist/astro-dialog/DialogOverlay.astro +17 -0
  100. package/dist/astro-dialog/DialogTitle.astro +15 -0
  101. package/dist/astro-dialog/DialogTrigger.astro +18 -0
  102. package/dist/astro-dialog/index.ts +1 -0
  103. package/dist/astro-diff-viewer/DiffViewer.astro +371 -0
  104. package/dist/astro-diff-viewer/index.ts +1 -0
  105. package/dist/astro-dropdown-menu/DropdownMenu.astro +138 -0
  106. package/dist/astro-dropdown-menu/DropdownMenuContent.astro +20 -0
  107. package/dist/astro-dropdown-menu/DropdownMenuItem.astro +21 -0
  108. package/dist/astro-dropdown-menu/DropdownMenuLabel.astro +14 -0
  109. package/dist/astro-dropdown-menu/DropdownMenuSeparator.astro +14 -0
  110. package/dist/astro-dropdown-menu/DropdownMenuTrigger.astro +18 -0
  111. package/dist/astro-dropdown-menu/index.ts +1 -0
  112. package/dist/astro-emoji-picker/EmojiPicker.astro +255 -0
  113. package/dist/astro-emoji-picker/index.ts +1 -0
  114. package/dist/astro-feedback-dialog/FeedbackDialog.astro +152 -0
  115. package/dist/astro-feedback-dialog/index.ts +1 -0
  116. package/dist/astro-file-tree/astro-file-tree.astro +4 -0
  117. package/dist/astro-file-tree/index.ts +1 -0
  118. package/dist/astro-file-upload/FileUpload.astro +306 -0
  119. package/dist/astro-file-upload/index.ts +1 -0
  120. package/dist/astro-footer/Footer.astro +61 -0
  121. package/dist/astro-footer/index.ts +1 -0
  122. package/dist/astro-icon-system/astro-icon-system.astro +4 -0
  123. package/dist/astro-icon-system/index.ts +1 -0
  124. package/dist/astro-inline-editor/InlineEditor.astro +169 -0
  125. package/dist/astro-inline-editor/index.ts +1 -0
  126. package/dist/astro-input/Input.astro +49 -0
  127. package/dist/astro-input/index.ts +1 -0
  128. package/dist/astro-input-group/InputGroup.astro +29 -0
  129. package/dist/astro-input-group/InputGroupAddon.astro +14 -0
  130. package/dist/astro-input-group/InputGroupButton.astro +19 -0
  131. package/dist/astro-input-group/InputGroupText.astro +11 -0
  132. package/dist/astro-input-group/index.ts +1 -0
  133. package/dist/astro-install-prompt/InstallPrompt.astro +115 -0
  134. package/dist/astro-install-prompt/index.ts +1 -0
  135. package/dist/astro-keyboard-shortcut/KeyboardShortcut.astro +83 -0
  136. package/dist/astro-keyboard-shortcut/ShortcutBadge.astro +41 -0
  137. package/dist/astro-keyboard-shortcut/index.ts +1 -0
  138. package/dist/astro-language-selector/LanguageSelector.astro +247 -0
  139. package/dist/astro-language-selector/index.ts +1 -0
  140. package/dist/astro-link-card/LinkCard.astro +17 -0
  141. package/dist/astro-link-card/index.ts +1 -0
  142. package/dist/astro-markdown-renderer/MarkdownRenderer.astro +62 -0
  143. package/dist/astro-markdown-renderer/index.ts +1 -0
  144. package/dist/astro-mobile-nav/MobileNav.astro +84 -0
  145. package/dist/astro-mobile-nav/MobileNavContent.astro +29 -0
  146. package/dist/astro-mobile-nav/MobileNavLink.astro +16 -0
  147. package/dist/astro-mobile-nav/MobileNavTrigger.astro +57 -0
  148. package/dist/astro-mobile-nav/index.ts +1 -0
  149. package/dist/astro-navbar/Navbar.astro +49 -0
  150. package/dist/astro-navbar/index.ts +1 -0
  151. package/dist/astro-otp-input/OtpInput.astro +253 -0
  152. package/dist/astro-otp-input/index.ts +1 -0
  153. package/dist/astro-pagination/Pagination.astro +3 -0
  154. package/dist/astro-pagination/index.ts +1 -0
  155. package/dist/astro-payment/Payment.astro +19 -0
  156. package/dist/astro-payment/index.ts +1 -0
  157. package/dist/astro-popover/Popover.astro +87 -0
  158. package/dist/astro-popover/PopoverClose.astro +16 -0
  159. package/dist/astro-popover/PopoverContent.astro +23 -0
  160. package/dist/astro-popover/PopoverTrigger.astro +18 -0
  161. package/dist/astro-popover/index.ts +1 -0
  162. package/dist/astro-presence-indicator/PresenceIndicator.astro +26 -0
  163. package/dist/astro-presence-indicator/index.ts +1 -0
  164. package/dist/astro-progress-display/BadgeDisplay.astro +33 -0
  165. package/dist/astro-progress-display/ProgressBar.astro +27 -0
  166. package/dist/astro-progress-display/StatsGrid.astro +32 -0
  167. package/dist/astro-progress-display/index.ts +1 -0
  168. package/dist/astro-radio/RadioGroup.astro +111 -0
  169. package/dist/astro-radio/RadioItem.astro +36 -0
  170. package/dist/astro-radio/index.ts +1 -0
  171. package/dist/astro-reaction-bar/ReactionBar.astro +117 -0
  172. package/dist/astro-reaction-bar/index.ts +1 -0
  173. package/dist/astro-resizable-layout/ResizableDivider.astro +27 -0
  174. package/dist/astro-resizable-layout/ResizableLayout.astro +162 -0
  175. package/dist/astro-resizable-layout/ResizablePane.astro +28 -0
  176. package/dist/astro-resizable-layout/index.ts +11 -0
  177. package/dist/astro-rich-editor/RichEditor.astro +260 -0
  178. package/dist/astro-rich-editor/index.ts +25 -0
  179. package/dist/astro-search-bar/SearchBar.astro +140 -0
  180. package/dist/astro-search-bar/SearchResultItem.astro +16 -0
  181. package/dist/astro-search-bar/SearchResults.astro +17 -0
  182. package/dist/astro-search-bar/index.ts +1 -0
  183. package/dist/astro-select/Select.astro +165 -0
  184. package/dist/astro-select/SelectContent.astro +19 -0
  185. package/dist/astro-select/SelectItem.astro +42 -0
  186. package/dist/astro-select/SelectTrigger.astro +36 -0
  187. package/dist/astro-select/index.ts +1 -0
  188. package/dist/astro-sidebar/Sidebar.astro +64 -0
  189. package/dist/astro-sidebar/index.ts +1 -0
  190. package/dist/astro-skeleton/Skeleton.astro +39 -0
  191. package/dist/astro-skeleton/SkeletonText.astro +22 -0
  192. package/dist/astro-skeleton/index.ts +1 -0
  193. package/dist/astro-skip-to-content/SkipToContent.astro +3 -0
  194. package/dist/astro-skip-to-content/index.ts +1 -0
  195. package/dist/astro-slide-viewer/SlideViewer.astro +231 -0
  196. package/dist/astro-slide-viewer/index.ts +1 -0
  197. package/dist/astro-slider/index.ts +1 -0
  198. package/dist/astro-status-indicator/StatusIndicator.astro +31 -0
  199. package/dist/astro-status-indicator/index.ts +1 -0
  200. package/dist/astro-steps/Steps.astro +3 -0
  201. package/dist/astro-steps/index.ts +1 -0
  202. package/dist/astro-switch/Switch.astro +89 -0
  203. package/dist/astro-switch/index.ts +1 -0
  204. package/dist/astro-table-of-contents/TableOfContents.astro +53 -0
  205. package/dist/astro-table-of-contents/index.ts +1 -0
  206. package/dist/astro-tabs/Tabs.astro +96 -0
  207. package/dist/astro-tabs/TabsContent.astro +20 -0
  208. package/dist/astro-tabs/TabsList.astro +16 -0
  209. package/dist/astro-tabs/TabsTrigger.astro +24 -0
  210. package/dist/astro-tabs/index.ts +1 -0
  211. package/dist/astro-textarea/Textarea.astro +51 -0
  212. package/dist/astro-textarea/index.ts +1 -0
  213. package/dist/astro-theme/ThemeScript.astro +13 -0
  214. package/dist/astro-theme/ThemeToggle.astro +279 -0
  215. package/dist/astro-theme/index.ts +1 -0
  216. package/dist/astro-thread-view/ThreadView.astro +159 -0
  217. package/dist/astro-thread-view/index.ts +1 -0
  218. package/dist/astro-toast/Toast.astro +49 -0
  219. package/dist/astro-toast/Toaster.astro +142 -0
  220. package/dist/astro-toast/index.ts +1 -0
  221. package/dist/astro-tooltip/Tooltip.astro +95 -0
  222. package/dist/astro-tooltip/TooltipContent.astro +22 -0
  223. package/dist/astro-tooltip/TooltipTrigger.astro +16 -0
  224. package/dist/astro-tooltip/index.ts +1 -0
  225. package/dist/astro-version-selector/VersionSelector.astro +174 -0
  226. package/dist/astro-version-selector/index.ts +1 -0
  227. package/dist/astro-video-player/VideoPlayer.astro +153 -0
  228. package/dist/astro-video-player/index.ts +1 -0
  229. package/dist/index.ts +77 -0
  230. package/dist/shared/a11y.ts +33 -0
  231. package/dist/shared/aria.ts +30 -0
  232. package/dist/shared/cn.ts +35 -0
  233. package/dist/shared/cva.ts +79 -0
  234. package/dist/shared/engine-adapter.ts +10 -0
  235. package/dist/shared/focus-trap.ts +123 -0
  236. package/dist/shared/index.ts +60 -0
  237. package/dist/shared/keyboard.ts +36 -0
  238. package/dist/shared/live-region.ts +90 -0
  239. package/dist/shared/motion.ts +15 -0
  240. package/dist/shared/skip-link.ts +35 -0
  241. package/dist/shared/state-machine.ts +57 -0
  242. package/dist/shared/tokens.ts +16 -0
  243. package/dist/shared/types.ts +45 -0
  244. package/dist/shared/variants.ts +17 -0
  245. package/package.json +20 -19
  246. package/src/index.ts +0 -94
@@ -0,0 +1,36 @@
1
+ ---
2
+ import { selectTriggerVariants } from '@refraction-ui/select'
3
+ import { cn } from '../shared/index.ts'
4
+
5
+ interface Props extends astroHTML.JSX.HTMLAttributes {
6
+ size?: 'sm' | 'default' | 'lg'
7
+ placeholder?: string
8
+ }
9
+
10
+ const { size = 'default', placeholder = 'Select an option', class: className, ...props } = Astro.props
11
+ ---
12
+
13
+ <button
14
+ type="button"
15
+ role="combobox"
16
+ aria-expanded="false"
17
+ data-state="closed"
18
+ data-rfr-select-trigger
19
+ class={cn(selectTriggerVariants({ size }), className)}
20
+ {...props}
21
+ >
22
+ <span data-rfr-select-value-text><slot>{placeholder}</slot></span>
23
+ <svg
24
+ class="h-4 w-4 opacity-50 shrink-0"
25
+ xmlns="http://www.w3.org/2000/svg"
26
+ viewBox="0 0 24 24"
27
+ fill="none"
28
+ stroke="currentColor"
29
+ stroke-width="2"
30
+ stroke-linecap="round"
31
+ stroke-linejoin="round"
32
+ aria-hidden="true"
33
+ >
34
+ <path d="m6 9 6 6 6-6" />
35
+ </svg>
36
+ </button>
@@ -0,0 +1 @@
1
+ export {}
@@ -0,0 +1,64 @@
1
+ ---
2
+ import {
3
+ createSidebar,
4
+ sidebarVariants,
5
+ sidebarItemVariants,
6
+ type SidebarSection,
7
+ } from '@refraction-ui/sidebar'
8
+ import { cn } from '../shared/index.ts'
9
+
10
+ interface Props extends astroHTML.JSX.HTMLAttributes {
11
+ sections?: SidebarSection[]
12
+ currentPath?: string
13
+ collapsed?: boolean
14
+ userRoles?: string[]
15
+ }
16
+
17
+ const {
18
+ sections = [],
19
+ currentPath,
20
+ collapsed = false,
21
+ userRoles,
22
+ class: className,
23
+ ...props
24
+ } = Astro.props
25
+
26
+ const api = createSidebar({ sections, currentPath, collapsed, userRoles })
27
+ const classes = cn(
28
+ sidebarVariants({ collapsed: collapsed ? 'true' : 'false' }),
29
+ className,
30
+ )
31
+ ---
32
+
33
+ <aside class={classes} {...api.ariaProps} {...props}>
34
+ <div class="flex flex-col gap-4 p-4">
35
+ {api.visibleSections.map((section, sIdx) => (
36
+ <div>
37
+ {section.title && !collapsed && (
38
+ <h3 class="mb-2 px-3 text-xs font-semibold uppercase tracking-wider text-muted-foreground">
39
+ {section.title}
40
+ </h3>
41
+ )}
42
+ <ul class="space-y-1">
43
+ {section.items.map((item) => {
44
+ const active = api.isActive(item.href)
45
+ return (
46
+ <li>
47
+ <a
48
+ href={item.href}
49
+ class={sidebarItemVariants({
50
+ active: active ? 'true' : 'false',
51
+ })}
52
+ {...api.itemAriaProps(item.href)}
53
+ >
54
+ {item.icon && <span aria-hidden="true">{item.icon}</span>}
55
+ {!collapsed && <span>{item.label}</span>}
56
+ </a>
57
+ </li>
58
+ )
59
+ })}
60
+ </ul>
61
+ </div>
62
+ ))}
63
+ </div>
64
+ </aside>
@@ -0,0 +1 @@
1
+ export {}
@@ -0,0 +1,39 @@
1
+ ---
2
+ import {
3
+ createSkeleton,
4
+ skeletonVariants,
5
+ type SkeletonShape,
6
+ } from '@refraction-ui/skeleton'
7
+ import { cn } from '../shared/index.ts'
8
+
9
+ interface Props extends astroHTML.JSX.HTMLAttributes {
10
+ shape?: SkeletonShape
11
+ width?: string | number
12
+ height?: string | number
13
+ /** Whether to animate the skeleton pulse. Defaults to true */
14
+ animate?: boolean
15
+ }
16
+
17
+ const { shape, width, height, animate, class: className, style, ...props } = Astro.props
18
+ const api = createSkeleton({ shape, animate })
19
+ const classes = cn(skeletonVariants({ shape }), className)
20
+
21
+ const styleObj: Record<string, string | number> = {}
22
+ if (width !== undefined) styleObj.width = width
23
+ if (height !== undefined) styleObj.height = height
24
+
25
+ // Merge any existing inline styles
26
+ const existingStyle = typeof style === 'string' ? style : ''
27
+ const extraStyle = Object.entries(styleObj)
28
+ .map(([k, v]) => `${k}: ${typeof v === 'number' ? `${v}px` : v}`)
29
+ .join('; ')
30
+ const mergedStyle = [existingStyle, extraStyle].filter(Boolean).join('; ') || undefined
31
+ ---
32
+
33
+ <div
34
+ class={classes}
35
+ style={mergedStyle}
36
+ {...api.ariaProps}
37
+ {...api.dataAttributes}
38
+ {...props}
39
+ />
@@ -0,0 +1,22 @@
1
+ ---
2
+ import Skeleton from './Skeleton.astro'
3
+ import { cn } from '../shared/index.ts'
4
+
5
+ interface Props extends astroHTML.JSX.HTMLAttributes {
6
+ /** Number of text lines to render. Defaults to 3 */
7
+ lines?: number
8
+ /** Whether to animate the skeleton pulse. Defaults to true */
9
+ animate?: boolean
10
+ }
11
+
12
+ const { lines = 3, animate, class: className, ...props } = Astro.props
13
+
14
+ /** Width percentages for each line to create a natural-looking text block */
15
+ const lineWidths = ['100%', '92%', '85%', '96%', '78%', '88%', '94%', '82%']
16
+ ---
17
+
18
+ <div class={cn('space-y-2', className)} {...props}>
19
+ {Array.from({ length: lines }, (_, i) => (
20
+ <Skeleton shape="text" width={lineWidths[i % lineWidths.length]} animate={animate} />
21
+ ))}
22
+ </div>
@@ -0,0 +1 @@
1
+ export {}
@@ -0,0 +1,3 @@
1
+ ---
2
+ ---
3
+ <div></div>
@@ -0,0 +1 @@
1
+ export {}
@@ -0,0 +1,231 @@
1
+ ---
2
+ import {
3
+ createSlideViewer,
4
+ slideViewerVariants,
5
+ progressBarVariants,
6
+ slideTypeBadgeVariants,
7
+ type SlideData,
8
+ } from '@refraction-ui/slide-viewer'
9
+ import { cn } from '../shared/index.ts'
10
+
11
+ interface Props extends astroHTML.JSX.HTMLAttributes {
12
+ slides: SlideData[]
13
+ initialSlide?: number
14
+ size?: 'compact' | 'default' | 'full'
15
+ }
16
+
17
+ const {
18
+ slides,
19
+ initialSlide = 0,
20
+ size,
21
+ class: className,
22
+ ...props
23
+ } = Astro.props
24
+
25
+ const api = createSlideViewer({ slides, initialSlide })
26
+ const currentSlide = slides[api.state.currentSlide]
27
+ const slideAriaProps = api.getSlideAriaProps()
28
+ const isBookmarked = api.state.bookmarks.has(api.state.currentSlide)
29
+ const isLastSlide = api.state.currentSlide === api.state.totalSlides - 1
30
+ ---
31
+
32
+ <div
33
+ class={cn(slideViewerVariants({ size }), className)}
34
+ tabindex="0"
35
+ data-rfr-slide-viewer
36
+ data-rfr-slide-current={api.state.currentSlide}
37
+ data-rfr-slide-total={api.state.totalSlides}
38
+ data-rfr-slides={JSON.stringify(slides)}
39
+ {...props}
40
+ >
41
+ <!-- Progress bar -->
42
+ <div class={progressBarVariants({ position: 'top' })}>
43
+ <div
44
+ class="h-full bg-primary transition-all duration-300"
45
+ style={`width: ${api.progress * 100}%`}
46
+ data-rfr-slide-progress
47
+ />
48
+ </div>
49
+
50
+ <!-- Header with type badge and bookmark -->
51
+ <div class="flex items-center justify-between px-4 py-2 border-b">
52
+ <div class="flex items-center gap-2">
53
+ {currentSlide && (
54
+ <span
55
+ class={slideTypeBadgeVariants({ type: currentSlide.type })}
56
+ data-rfr-slide-type-badge
57
+ >
58
+ {currentSlide.type}
59
+ </span>
60
+ )}
61
+ <span class="text-sm text-muted-foreground" data-rfr-slide-counter>
62
+ {api.state.currentSlide + 1} / {api.state.totalSlides}
63
+ </span>
64
+ </div>
65
+ <button
66
+ type="button"
67
+ class={cn(
68
+ 'px-2 py-1 rounded text-xs transition-colors',
69
+ isBookmarked
70
+ ? 'bg-yellow-100 text-yellow-800'
71
+ : 'hover:bg-muted text-muted-foreground',
72
+ )}
73
+ aria-pressed={isBookmarked}
74
+ aria-label="Toggle bookmark"
75
+ data-rfr-slide-bookmark
76
+ >
77
+ {isBookmarked ? 'Bookmarked' : 'Bookmark'}
78
+ </button>
79
+ </div>
80
+
81
+ <!-- Slide content -->
82
+ <div
83
+ class="flex-1 overflow-auto p-6"
84
+ role={slideAriaProps.role}
85
+ aria-roledescription={slideAriaProps['aria-roledescription']}
86
+ aria-label={slideAriaProps['aria-label'] as string}
87
+ aria-live={slideAriaProps['aria-live'] as any}
88
+ data-rfr-slide-content
89
+ >
90
+ {currentSlide && <Fragment set:html={currentSlide.content} />}
91
+ <slot />
92
+ </div>
93
+
94
+ <!-- Navigation buttons -->
95
+ <div class="flex items-center justify-between px-4 py-3 border-t">
96
+ <button
97
+ type="button"
98
+ disabled={api.state.currentSlide === 0}
99
+ class="px-4 py-2 rounded text-sm font-medium disabled:opacity-50 disabled:cursor-not-allowed hover:bg-muted transition-colors"
100
+ aria-label="Previous slide"
101
+ data-rfr-slide-prev
102
+ >
103
+ Previous
104
+ </button>
105
+ <button
106
+ type="button"
107
+ class="px-4 py-2 rounded text-sm font-medium bg-primary text-primary-foreground hover:bg-primary/90 transition-colors"
108
+ aria-label={isLastSlide ? 'Complete' : 'Next slide'}
109
+ data-rfr-slide-next
110
+ >
111
+ {isLastSlide ? 'Complete' : 'Next'}
112
+ </button>
113
+ </div>
114
+ </div>
115
+
116
+ <script>
117
+ document.querySelectorAll<HTMLElement>('[data-rfr-slide-viewer]').forEach((root) => {
118
+ const slides: Array<{ id: string; type: string; content: string }> = JSON.parse(
119
+ root.getAttribute('data-rfr-slides') || '[]',
120
+ )
121
+ const totalSlides = slides.length
122
+ let currentSlide = parseInt(root.getAttribute('data-rfr-slide-current') || '0', 10)
123
+ const bookmarks = new Set<number>()
124
+
125
+ const progressBar = root.querySelector<HTMLElement>('[data-rfr-slide-progress]')
126
+ const counter = root.querySelector<HTMLElement>('[data-rfr-slide-counter]')
127
+ const typeBadge = root.querySelector<HTMLElement>('[data-rfr-slide-type-badge]')
128
+ const contentArea = root.querySelector<HTMLElement>('[data-rfr-slide-content]')
129
+ const bookmarkBtn = root.querySelector<HTMLButtonElement>('[data-rfr-slide-bookmark]')
130
+ const prevBtn = root.querySelector<HTMLButtonElement>('[data-rfr-slide-prev]')
131
+ const nextBtn = root.querySelector<HTMLButtonElement>('[data-rfr-slide-next]')
132
+
133
+ function getProgress() {
134
+ if (totalSlides <= 1) return 1
135
+ return currentSlide / (totalSlides - 1)
136
+ }
137
+
138
+ function updateUI() {
139
+ const slide = slides[currentSlide]
140
+ const progress = getProgress()
141
+ const isLast = currentSlide === totalSlides - 1
142
+ const isFirst = currentSlide === 0
143
+ const isMarked = bookmarks.has(currentSlide)
144
+
145
+ if (progressBar) {
146
+ progressBar.style.width = `${progress * 100}%`
147
+ }
148
+
149
+ if (counter) {
150
+ counter.textContent = `${currentSlide + 1} / ${totalSlides}`
151
+ }
152
+
153
+ if (typeBadge && slide) {
154
+ typeBadge.textContent = slide.type
155
+ }
156
+
157
+ if (contentArea && slide) {
158
+ contentArea.setAttribute(
159
+ 'aria-label',
160
+ `Slide ${currentSlide + 1} of ${totalSlides}: ${slide.type} slide`,
161
+ )
162
+ // Only update innerHTML for data-driven content (preserve slot content)
163
+ const slotContent = contentArea.querySelector('[data-astro-slot]')
164
+ if (!slotContent) {
165
+ contentArea.innerHTML = slide.content
166
+ }
167
+ }
168
+
169
+ if (bookmarkBtn) {
170
+ bookmarkBtn.textContent = isMarked ? 'Bookmarked' : 'Bookmark'
171
+ bookmarkBtn.setAttribute('aria-pressed', String(isMarked))
172
+ if (isMarked) {
173
+ bookmarkBtn.className = 'px-2 py-1 rounded text-xs transition-colors bg-yellow-100 text-yellow-800'
174
+ } else {
175
+ bookmarkBtn.className = 'px-2 py-1 rounded text-xs transition-colors hover:bg-muted text-muted-foreground'
176
+ }
177
+ }
178
+
179
+ if (prevBtn) {
180
+ prevBtn.disabled = isFirst
181
+ }
182
+
183
+ if (nextBtn) {
184
+ nextBtn.textContent = isLast ? 'Complete' : 'Next'
185
+ nextBtn.setAttribute('aria-label', isLast ? 'Complete' : 'Next slide')
186
+ }
187
+
188
+ root.setAttribute('data-rfr-slide-current', String(currentSlide))
189
+ root.dispatchEvent(new CustomEvent('slidechange', { detail: { index: currentSlide } }))
190
+ }
191
+
192
+ function goNext() {
193
+ if (currentSlide < totalSlides - 1) {
194
+ currentSlide++
195
+ updateUI()
196
+ } else {
197
+ root.dispatchEvent(new CustomEvent('complete'))
198
+ }
199
+ }
200
+
201
+ function goPrev() {
202
+ if (currentSlide > 0) {
203
+ currentSlide--
204
+ updateUI()
205
+ }
206
+ }
207
+
208
+ function toggleBookmark() {
209
+ if (bookmarks.has(currentSlide)) {
210
+ bookmarks.delete(currentSlide)
211
+ } else {
212
+ bookmarks.add(currentSlide)
213
+ }
214
+ updateUI()
215
+ }
216
+
217
+ if (prevBtn) prevBtn.addEventListener('click', goPrev)
218
+ if (nextBtn) nextBtn.addEventListener('click', goNext)
219
+ if (bookmarkBtn) bookmarkBtn.addEventListener('click', toggleBookmark)
220
+
221
+ root.addEventListener('keydown', (e) => {
222
+ if (e.key === 'ArrowRight') {
223
+ e.preventDefault()
224
+ goNext()
225
+ } else if (e.key === 'ArrowLeft') {
226
+ e.preventDefault()
227
+ goPrev()
228
+ }
229
+ })
230
+ })
231
+ </script>
@@ -0,0 +1 @@
1
+ export {}
@@ -0,0 +1 @@
1
+ export {}
@@ -0,0 +1,31 @@
1
+ ---
2
+ import {
3
+ createStatusIndicator,
4
+ statusContainerStyles,
5
+ statusDotVariants,
6
+ statusPulseVariants,
7
+ statusLabelStyles,
8
+ type StatusType,
9
+ } from '@refraction-ui/status-indicator'
10
+ import { cn } from '../shared/index.ts'
11
+
12
+ interface Props {
13
+ type: StatusType
14
+ label?: string
15
+ pulse?: boolean
16
+ showLabel?: boolean
17
+ class?: string
18
+ }
19
+
20
+ const { type, label, pulse, showLabel = true, class: className } = Astro.props
21
+ const api = createStatusIndicator({ type, label, pulse })
22
+
23
+ const dotClassName = api.pulse
24
+ ? statusPulseVariants({ type })
25
+ : statusDotVariants({ type })
26
+ ---
27
+
28
+ <span {...api.ariaProps} class={cn(statusContainerStyles, className)}>
29
+ <span class={dotClassName} />
30
+ {showLabel && <span class={statusLabelStyles}>{api.label}</span>}
31
+ </span>
@@ -0,0 +1 @@
1
+ export {}
@@ -0,0 +1,3 @@
1
+ ---
2
+ ---
3
+ <div></div>
@@ -0,0 +1 @@
1
+ export { default as Steps } from './Steps.astro';
@@ -0,0 +1,89 @@
1
+ ---
2
+ import {
3
+ createSwitch,
4
+ switchVariants,
5
+ switchThumbVariants,
6
+ } from '@refraction-ui/switch'
7
+ import { cn } from '../shared/index.ts'
8
+
9
+ interface Props extends astroHTML.JSX.HTMLAttributes {
10
+ checked?: boolean
11
+ disabled?: boolean
12
+ size?: 'sm' | 'default' | 'lg'
13
+ name?: string
14
+ }
15
+
16
+ const { checked = false, disabled = false, size = 'default', name, class: className, ...props } = Astro.props
17
+ const api = createSwitch({ checked, disabled })
18
+ ---
19
+
20
+ <button
21
+ type="button"
22
+ role="switch"
23
+ aria-checked={String(checked)}
24
+ data-state={checked ? 'checked' : 'unchecked'}
25
+ data-disabled={disabled ? '' : undefined}
26
+ class={cn(switchVariants({ checked: checked ? 'true' : 'false', size }), className)}
27
+ disabled={disabled}
28
+ data-rfr-switch
29
+ data-rfr-switch-size={size}
30
+ {...props}
31
+ >
32
+ <span class={cn(switchThumbVariants({ checked: checked ? 'true' : 'false', size }))} data-rfr-switch-thumb />
33
+ {name && <input type="hidden" name={name} value={String(checked)} data-rfr-switch-input />}
34
+ </button>
35
+
36
+ <script>
37
+ const THUMB_TRANSLATE: Record<string, string> = {
38
+ sm: 'translate-x-3',
39
+ default: 'translate-x-4',
40
+ lg: 'translate-x-5',
41
+ }
42
+
43
+ document.querySelectorAll<HTMLButtonElement>('[data-rfr-switch]').forEach((el) => {
44
+ el.addEventListener('click', () => {
45
+ if (el.disabled) return
46
+ const checked = el.getAttribute('aria-checked') === 'true'
47
+ const newChecked = !checked
48
+ const size = el.getAttribute('data-rfr-switch-size') || 'default'
49
+
50
+ el.setAttribute('aria-checked', String(newChecked))
51
+ el.setAttribute('data-state', newChecked ? 'checked' : 'unchecked')
52
+
53
+ // Update track classes
54
+ if (newChecked) {
55
+ el.classList.add('bg-primary')
56
+ el.classList.remove('bg-input')
57
+ } else {
58
+ el.classList.remove('bg-primary')
59
+ el.classList.add('bg-input')
60
+ }
61
+
62
+ // Update thumb position
63
+ const thumb = el.querySelector('[data-rfr-switch-thumb]') as HTMLElement
64
+ if (thumb) {
65
+ const translateClass = THUMB_TRANSLATE[size] || THUMB_TRANSLATE.default
66
+ if (newChecked) {
67
+ thumb.classList.remove('translate-x-0')
68
+ thumb.classList.add(translateClass)
69
+ } else {
70
+ thumb.classList.remove(translateClass)
71
+ thumb.classList.add('translate-x-0')
72
+ }
73
+ }
74
+
75
+ // Update hidden input
76
+ const input = el.querySelector('[data-rfr-switch-input]') as HTMLInputElement | null
77
+ if (input) input.value = String(newChecked)
78
+
79
+ el.dispatchEvent(new CustomEvent('change', { detail: { checked: newChecked } }))
80
+ })
81
+
82
+ el.addEventListener('keydown', (e) => {
83
+ if (e.key === ' ') {
84
+ e.preventDefault()
85
+ el.click()
86
+ }
87
+ })
88
+ })
89
+ </script>
@@ -0,0 +1 @@
1
+ export {}
@@ -0,0 +1,53 @@
1
+ ---
2
+ import { cn } from '../shared/index.ts';
3
+
4
+ export interface Props extends astroHTML.JSX.HTMLAttributes {
5
+ selectors?: string;
6
+ }
7
+
8
+ const { selectors = 'h2, h3, h4', class: className, ...props } = Astro.props;
9
+ ---
10
+
11
+ <nav class={cn("space-y-1 refraction-toc", className)} data-selectors={selectors} {...props as any}>
12
+ <ul class="m-0 list-none p-0 toc-list">
13
+ </ul>
14
+ </nav>
15
+
16
+ <script>
17
+ import { parseHeadings, observeHeadings } from '@refraction-ui/table-of-contents';
18
+
19
+ document.querySelectorAll('.refraction-toc').forEach((el) => {
20
+ const selectors = el.getAttribute('data-selectors') || 'h2, h3, h4';
21
+ const container = document.body;
22
+ const headings = parseHeadings(container, selectors);
23
+ const list = el.querySelector('.toc-list');
24
+
25
+ if (!list || headings.length === 0) return;
26
+
27
+ headings.forEach(heading => {
28
+ const li = document.createElement('li');
29
+ li.className = `py-1 ${heading.level === 3 ? 'pl-4' : heading.level === 4 ? 'pl-8' : ''}`;
30
+
31
+ const a = document.createElement('a');
32
+ a.href = `#${heading.id}`;
33
+ a.className = 'block text-sm transition-colors hover:text-foreground text-muted-foreground toc-link';
34
+ a.textContent = heading.text;
35
+ a.dataset.id = heading.id;
36
+
37
+ li.appendChild(a);
38
+ list.appendChild(li);
39
+ });
40
+
41
+ observeHeadings(headings.map(h => h.id), (activeId) => {
42
+ el.querySelectorAll('.toc-link').forEach(link => {
43
+ if ((link as HTMLAnchorElement).dataset.id === activeId) {
44
+ link.classList.remove('text-muted-foreground');
45
+ link.classList.add('font-medium', 'text-foreground');
46
+ } else {
47
+ link.classList.remove('font-medium', 'text-foreground');
48
+ link.classList.add('text-muted-foreground');
49
+ }
50
+ });
51
+ });
52
+ });
53
+ </script>
@@ -0,0 +1 @@
1
+ export { default as TableOfContents } from './TableOfContents.astro'