@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,32 @@
1
+ ---
2
+ import {
3
+ createProgressDisplay,
4
+ statsGridVariants,
5
+ statCardVariants,
6
+ type StatCardData,
7
+ type BadgeData,
8
+ } from '@refraction-ui/progress-display'
9
+ import { cn } from '../shared/index.ts'
10
+
11
+ interface Props extends astroHTML.JSX.HTMLAttributes {
12
+ stats: StatCardData[]
13
+ badges?: BadgeData[]
14
+ }
15
+
16
+ const { stats, badges = [], class: className, ...props } = Astro.props
17
+ const api = createProgressDisplay({ stats, badges })
18
+ ---
19
+
20
+ <div class={cn(statsGridVariants(), className)} {...api.ariaProps} {...props}>
21
+ {api.stats.map((stat) => (
22
+ <div
23
+ class={statCardVariants({
24
+ color: (stat.color as 'default' | 'primary' | 'success' | 'warning' | 'destructive') ?? 'default',
25
+ })}
26
+ >
27
+ {stat.icon && <span class="text-2xl">{stat.icon}</span>}
28
+ <div class="text-2xl font-bold">{stat.value}</div>
29
+ <div class="text-sm text-muted-foreground">{stat.label}</div>
30
+ </div>
31
+ ))}
32
+ </div>
@@ -0,0 +1 @@
1
+ export {}
@@ -0,0 +1,111 @@
1
+ ---
2
+ import { radioGroupVariants } from '@refraction-ui/radio'
3
+ import { cn } from '../shared/index.ts'
4
+
5
+ interface Props extends astroHTML.JSX.HTMLAttributes {
6
+ value?: string
7
+ name?: string
8
+ disabled?: boolean
9
+ orientation?: 'horizontal' | 'vertical'
10
+ }
11
+
12
+ const { value, name, disabled = false, orientation = 'vertical', class: className, ...props } = Astro.props
13
+ ---
14
+
15
+ <div
16
+ role="radiogroup"
17
+ aria-orientation={orientation}
18
+ aria-disabled={disabled || undefined}
19
+ class={cn(radioGroupVariants({ orientation }), className)}
20
+ data-rfr-radio-group
21
+ data-rfr-radio-value={value || ''}
22
+ data-rfr-radio-name={name || ''}
23
+ data-rfr-radio-disabled={disabled ? '' : undefined}
24
+ {...props}
25
+ >
26
+ <slot />
27
+ {name && <input type="hidden" name={name} value={value || ''} data-rfr-radio-input />}
28
+ </div>
29
+
30
+ <script>
31
+ document.querySelectorAll<HTMLElement>('[data-rfr-radio-group]').forEach((group) => {
32
+ const items = () => group.querySelectorAll<HTMLButtonElement>('[data-rfr-radio-item]')
33
+
34
+ function selectItem(item: HTMLButtonElement) {
35
+ const groupDisabled = group.hasAttribute('data-rfr-radio-disabled')
36
+ if (groupDisabled || item.disabled) return
37
+
38
+ const value = item.getAttribute('data-rfr-radio-item-value') || ''
39
+
40
+ // Update all items in this group
41
+ items().forEach((btn) => {
42
+ const btnValue = btn.getAttribute('data-rfr-radio-item-value') || ''
43
+ const isSelected = btnValue === value
44
+ btn.setAttribute('aria-checked', String(isSelected))
45
+ btn.setAttribute('tabindex', isSelected ? '0' : '-1')
46
+
47
+ const label = btn.closest('[data-rfr-radio-item-label]') as HTMLElement | null
48
+ if (label) {
49
+ label.setAttribute('data-state', isSelected ? 'checked' : 'unchecked')
50
+ }
51
+
52
+ // Update circle styling
53
+ const circle = btn as HTMLElement
54
+ if (isSelected) {
55
+ circle.classList.add('border-primary', 'bg-primary')
56
+ circle.classList.remove('border-input')
57
+ // Ensure inner dot exists
58
+ if (!circle.querySelector('[data-rfr-radio-dot]')) {
59
+ const dot = document.createElement('span')
60
+ dot.className = 'block h-2 w-2 rounded-full bg-primary-foreground mx-auto'
61
+ dot.setAttribute('data-rfr-radio-dot', '')
62
+ circle.appendChild(dot)
63
+ }
64
+ } else {
65
+ circle.classList.remove('border-primary', 'bg-primary')
66
+ circle.classList.add('border-input')
67
+ const dot = circle.querySelector('[data-rfr-radio-dot]')
68
+ if (dot) dot.remove()
69
+ }
70
+ })
71
+
72
+ // Update group data attribute
73
+ group.setAttribute('data-rfr-radio-value', value)
74
+
75
+ // Update hidden input
76
+ const input = group.querySelector('[data-rfr-radio-input]') as HTMLInputElement | null
77
+ if (input) input.value = value
78
+
79
+ group.dispatchEvent(new CustomEvent('change', { detail: { value } }))
80
+ }
81
+
82
+ group.addEventListener('click', (e) => {
83
+ const item = (e.target as HTMLElement).closest<HTMLButtonElement>('[data-rfr-radio-item]')
84
+ if (item) selectItem(item)
85
+ })
86
+
87
+ group.addEventListener('keydown', (e) => {
88
+ const target = e.target as HTMLElement
89
+ if (!target.hasAttribute('data-rfr-radio-item')) return
90
+
91
+ const allItems = Array.from(items()).filter((i) => !i.disabled)
92
+ const currentIndex = allItems.indexOf(target as HTMLButtonElement)
93
+ if (currentIndex === -1) return
94
+
95
+ let nextIndex = -1
96
+ if (e.key === 'ArrowDown' || e.key === 'ArrowRight') {
97
+ e.preventDefault()
98
+ nextIndex = (currentIndex + 1) % allItems.length
99
+ } else if (e.key === 'ArrowUp' || e.key === 'ArrowLeft') {
100
+ e.preventDefault()
101
+ nextIndex = (currentIndex - 1 + allItems.length) % allItems.length
102
+ }
103
+
104
+ if (nextIndex >= 0) {
105
+ const nextItem = allItems[nextIndex]
106
+ nextItem.focus()
107
+ selectItem(nextItem)
108
+ }
109
+ })
110
+ })
111
+ </script>
@@ -0,0 +1,36 @@
1
+ ---
2
+ import { radioItemVariants, radioCircleVariants } from '@refraction-ui/radio'
3
+ import { cn } from '../shared/index.ts'
4
+
5
+ interface Props extends astroHTML.JSX.HTMLAttributes {
6
+ value: string
7
+ disabled?: boolean
8
+ checked?: boolean
9
+ }
10
+
11
+ const { value, disabled = false, checked = false, class: className, ...props } = Astro.props
12
+ ---
13
+
14
+ <label
15
+ class={cn(radioItemVariants({ disabled: disabled ? 'true' : 'false' }), className)}
16
+ data-state={checked ? 'checked' : 'unchecked'}
17
+ data-rfr-radio-item-label
18
+ {...props}
19
+ >
20
+ <button
21
+ type="button"
22
+ role="radio"
23
+ aria-checked={checked}
24
+ aria-disabled={disabled || undefined}
25
+ tabindex={checked ? 0 : -1}
26
+ disabled={disabled || undefined}
27
+ class={cn(radioCircleVariants({ checked: checked ? 'true' : 'false' }))}
28
+ data-rfr-radio-item
29
+ data-rfr-radio-item-value={value}
30
+ >
31
+ {checked && (
32
+ <span class="block h-2 w-2 rounded-full bg-primary-foreground mx-auto" data-rfr-radio-dot />
33
+ )}
34
+ </button>
35
+ <span class="text-sm"><slot /></span>
36
+ </label>
@@ -0,0 +1 @@
1
+ export {}
@@ -0,0 +1,117 @@
1
+ ---
2
+ import {
3
+ createReactionBar,
4
+ reactionBarStyles,
5
+ reactionPillVariants,
6
+ reactionAddButtonStyles,
7
+ reactionEmojiStyles,
8
+ reactionCountStyles,
9
+ type Reaction,
10
+ } from '@refraction-ui/reaction-bar'
11
+ import { cn } from '../shared/index.ts'
12
+
13
+ interface Props extends astroHTML.JSX.HTMLAttributes {
14
+ /** Array of reactions to display */
15
+ reactions: Reaction[]
16
+ /** Whether to show the add reaction button. Default: true */
17
+ showAddButton?: boolean
18
+ }
19
+
20
+ const {
21
+ reactions,
22
+ showAddButton = true,
23
+ class: className,
24
+ ...props
25
+ } = Astro.props
26
+
27
+ const api = createReactionBar({ reactions })
28
+ ---
29
+
30
+ <div
31
+ data-rfr-reaction-bar
32
+ data-rfr-rb-reactions={JSON.stringify(reactions)}
33
+ class={cn(reactionBarStyles, className)}
34
+ role="group"
35
+ aria-label="Reactions"
36
+ {...props}
37
+ >
38
+ {api.reactions.map((reaction) => (
39
+ <button
40
+ type="button"
41
+ data-rfr-rb-emoji={reaction.emoji}
42
+ class={reactionPillVariants({ state: reaction.userReacted ? 'active' : 'inactive' })}
43
+ role="button"
44
+ aria-pressed={reaction.userReacted ? 'true' : 'false'}
45
+ aria-label={`${reaction.emoji} ${reaction.count} reaction${reaction.count === 1 ? '' : 's'}${reaction.userReacted ? ', you reacted' : ''}`}
46
+ >
47
+ <span class={reactionEmojiStyles}>{reaction.emoji}</span>
48
+ <span class={reactionCountStyles} data-rfr-rb-count>{reaction.count}</span>
49
+ </button>
50
+ ))}
51
+ {showAddButton && (
52
+ <button
53
+ type="button"
54
+ data-rfr-rb-add
55
+ class={reactionAddButtonStyles}
56
+ role="button"
57
+ aria-label="Add reaction"
58
+ >
59
+ +
60
+ </button>
61
+ )}
62
+ </div>
63
+
64
+ <script>
65
+ function initReactionBars() {
66
+ document.querySelectorAll<HTMLElement>('[data-rfr-reaction-bar]').forEach((el) => {
67
+ if (el.hasAttribute('data-rfr-rb-init')) return
68
+ el.setAttribute('data-rfr-rb-init', '')
69
+
70
+ // Handle emoji button clicks (toggle reaction)
71
+ el.querySelectorAll<HTMLElement>('[data-rfr-rb-emoji]').forEach((btn) => {
72
+ btn.addEventListener('click', () => {
73
+ const emoji = btn.getAttribute('data-rfr-rb-emoji')
74
+ if (!emoji) return
75
+
76
+ const isPressed = btn.getAttribute('aria-pressed') === 'true'
77
+ const countEl = btn.querySelector<HTMLElement>('[data-rfr-rb-count]')
78
+ const currentCount = countEl ? Number(countEl.textContent || 0) : 0
79
+
80
+ // Toggle state
81
+ const newPressed = !isPressed
82
+ const newCount = newPressed ? currentCount + 1 : Math.max(0, currentCount - 1)
83
+
84
+ btn.setAttribute('aria-pressed', String(newPressed))
85
+ if (countEl) countEl.textContent = String(newCount)
86
+
87
+ // Update styling
88
+ const activeClass = 'border-primary bg-primary/10 text-primary'
89
+ const inactiveClass = 'border-border bg-background text-foreground'
90
+ const baseClass = 'inline-flex items-center gap-1 rounded-full border px-2 py-0.5 text-xs cursor-pointer transition-colors hover:bg-accent'
91
+
92
+ btn.className = `${baseClass} ${newPressed ? activeClass : inactiveClass}`
93
+
94
+ // Update aria-label
95
+ btn.setAttribute('aria-label', `${emoji} ${newCount} reaction${newCount === 1 ? '' : 's'}${newPressed ? ', you reacted' : ''}`)
96
+
97
+ el.dispatchEvent(new CustomEvent('rfr-reaction-toggle', {
98
+ detail: { emoji, userReacted: newPressed, count: newCount },
99
+ bubbles: true,
100
+ }))
101
+ })
102
+ })
103
+
104
+ // Handle add button click
105
+ const addBtn = el.querySelector<HTMLElement>('[data-rfr-rb-add]')
106
+ addBtn?.addEventListener('click', () => {
107
+ el.dispatchEvent(new CustomEvent('rfr-reaction-add', {
108
+ detail: { emoji: '\u{1F44D}' },
109
+ bubbles: true,
110
+ }))
111
+ })
112
+ })
113
+ }
114
+
115
+ initReactionBars()
116
+ document.addEventListener('astro:after-swap', initReactionBars)
117
+ </script>
@@ -0,0 +1 @@
1
+ export {}
@@ -0,0 +1,27 @@
1
+ ---
2
+ /**
3
+ * ResizableDivider — draggable handle between two panes.
4
+ * Pointer events are handled by the parent ResizableLayout script.
5
+ */
6
+ import { resizableDividerVariants } from '@refraction-ui/resizable-layout'
7
+ import { cn } from '../shared/index.ts'
8
+ import type { Orientation } from '../shared/index.ts'
9
+
10
+ interface Props extends astroHTML.JSX.HTMLAttributes {
11
+ /** Index of the divider (between pane[index] and pane[index+1]) */
12
+ index: number
13
+ /** Orientation inherited from parent (default 'horizontal') */
14
+ orientation?: Orientation
15
+ }
16
+
17
+ const { index, orientation = 'horizontal', class: className, ...props } = Astro.props
18
+ ---
19
+
20
+ <div
21
+ role="separator"
22
+ aria-orientation={orientation}
23
+ tabindex="0"
24
+ class={cn(resizableDividerVariants({ orientation }), className)}
25
+ data-rfr-divider-index={index}
26
+ {...props}
27
+ />
@@ -0,0 +1,162 @@
1
+ ---
2
+ /**
3
+ * ResizableLayout — flex container with resizable panes separated by draggable dividers.
4
+ * Includes a client-side script for pointer-based drag resize.
5
+ */
6
+ import {
7
+ resizableLayoutVariants,
8
+ } from '@refraction-ui/resizable-layout'
9
+ import { cn } from '../shared/index.ts'
10
+ import type { Orientation } from '../shared/index.ts'
11
+
12
+ interface Props extends astroHTML.JSX.HTMLAttributes {
13
+ /** Layout direction (default 'horizontal') */
14
+ orientation?: Orientation
15
+ /** Initial pane sizes as percentages (must sum to 100) */
16
+ defaultSizes?: number[]
17
+ /** Minimum size for each pane (percentage) */
18
+ minSizes?: number[]
19
+ /** Maximum size for each pane (percentage) */
20
+ maxSizes?: number[]
21
+ /** localStorage key for persisting sizes */
22
+ persistKey?: string
23
+ }
24
+
25
+ const {
26
+ orientation = 'horizontal',
27
+ defaultSizes = [50, 50],
28
+ minSizes = [],
29
+ maxSizes = [],
30
+ persistKey,
31
+ class: className,
32
+ style,
33
+ ...props
34
+ } = Astro.props
35
+
36
+ // Build initial CSS variables for pane sizes
37
+ const cssVars = defaultSizes.map((s, i) => `--rfr-pane-${i}-size:${s}%`).join(';')
38
+ const fullStyle = [cssVars, typeof style === 'string' ? style : ''].filter(Boolean).join(';')
39
+
40
+ const configJSON = JSON.stringify({ orientation, defaultSizes, minSizes, maxSizes, persistKey })
41
+ ---
42
+
43
+ <div
44
+ class={cn(resizableLayoutVariants({ orientation }), className)}
45
+ style={fullStyle}
46
+ data-rfr-resizable-layout
47
+ data-rfr-resizable-config={configJSON}
48
+ data-orientation={orientation}
49
+ {...props}
50
+ >
51
+ <slot />
52
+ </div>
53
+
54
+ <script is:inline>
55
+ ;(function () {
56
+ document.querySelectorAll('[data-rfr-resizable-layout]').forEach(function (layout) {
57
+ var config = {}
58
+ try { config = JSON.parse(layout.getAttribute('data-rfr-resizable-config') || '{}') } catch (_) { /* */ }
59
+
60
+ var orientation = config.orientation || 'horizontal'
61
+ var sizes = null
62
+ var persistKey = config.persistKey
63
+ var minSizes = config.minSizes || []
64
+ var maxSizes = config.maxSizes || []
65
+
66
+ // Try loading from localStorage
67
+ if (persistKey) {
68
+ try {
69
+ var stored = localStorage.getItem(persistKey)
70
+ if (stored) {
71
+ var parsed = JSON.parse(stored)
72
+ if (Array.isArray(parsed) && parsed.length === (config.defaultSizes || []).length) {
73
+ sizes = parsed
74
+ }
75
+ }
76
+ } catch (_) { /* */ }
77
+ }
78
+ if (!sizes) {
79
+ sizes = (config.defaultSizes || [50, 50]).slice()
80
+ }
81
+
82
+ // Apply initial sizes
83
+ function applySizes() {
84
+ for (var i = 0; i < sizes.length; i++) {
85
+ layout.style.setProperty('--rfr-pane-' + i + '-size', sizes[i] + '%')
86
+ }
87
+ // Update pane flex-basis
88
+ var panes = layout.querySelectorAll('[data-rfr-pane-index]')
89
+ panes.forEach(function (pane) {
90
+ var idx = parseInt(pane.getAttribute('data-rfr-pane-index'), 10)
91
+ if (!isNaN(idx) && sizes[idx] !== undefined) {
92
+ pane.style.flexBasis = sizes[idx] + '%'
93
+ }
94
+ })
95
+ }
96
+
97
+ applySizes()
98
+
99
+ function clamp(val, min, max) {
100
+ return Math.min(Math.max(val, min), max)
101
+ }
102
+
103
+ function getMin(i) { return minSizes[i] || 0 }
104
+ function getMax(i) { return maxSizes[i] || 100 }
105
+
106
+ // Handle divider drag
107
+ var resizingIndex = null
108
+ var startPos = 0
109
+ var containerSize = 0
110
+ var sizesBeforeResize = []
111
+
112
+ layout.addEventListener('pointerdown', function (e) {
113
+ var divider = e.target.closest('[data-rfr-divider-index]')
114
+ if (!divider) return
115
+
116
+ e.preventDefault()
117
+ divider.setPointerCapture(e.pointerId)
118
+
119
+ resizingIndex = parseInt(divider.getAttribute('data-rfr-divider-index'), 10)
120
+ sizesBeforeResize = sizes.slice()
121
+
122
+ var rect = layout.getBoundingClientRect()
123
+ containerSize = orientation === 'horizontal' ? rect.width : rect.height
124
+ startPos = orientation === 'horizontal' ? e.clientX : e.clientY
125
+ })
126
+
127
+ layout.addEventListener('pointermove', function (e) {
128
+ if (resizingIndex === null) return
129
+
130
+ var currentPos = orientation === 'horizontal' ? e.clientX : e.clientY
131
+ var pxDelta = currentPos - startPos
132
+ var pctDelta = (pxDelta / containerSize) * 100
133
+
134
+ var i = resizingIndex
135
+ var j = i + 1
136
+ if (j >= sizes.length) return
137
+
138
+ var total = sizesBeforeResize[i] + sizesBeforeResize[j]
139
+ var newI = clamp(sizesBeforeResize[i] + pctDelta, getMin(i), getMax(i))
140
+ var newJ = clamp(total - newI, getMin(j), getMax(j))
141
+ newI = total - newJ
142
+
143
+ sizes[i] = newI
144
+ sizes[j] = newJ
145
+ applySizes()
146
+ })
147
+
148
+ layout.addEventListener('pointerup', function (e) {
149
+ var divider = e.target.closest('[data-rfr-divider-index]')
150
+ if (divider && resizingIndex !== null) {
151
+ divider.releasePointerCapture(e.pointerId)
152
+ }
153
+ resizingIndex = null
154
+ sizesBeforeResize = []
155
+
156
+ if (persistKey) {
157
+ try { localStorage.setItem(persistKey, JSON.stringify(sizes)) } catch (_) { /* */ }
158
+ }
159
+ })
160
+ })
161
+ })()
162
+ </script>
@@ -0,0 +1,28 @@
1
+ ---
2
+ /**
3
+ * ResizablePane — a single pane whose size is driven by CSS custom properties.
4
+ */
5
+ import { resizablePaneVariants } from '@refraction-ui/resizable-layout'
6
+ import { cn } from '../shared/index.ts'
7
+ import type { Orientation } from '../shared/index.ts'
8
+
9
+ interface Props extends astroHTML.JSX.HTMLAttributes {
10
+ /** Zero-based index of this pane */
11
+ index: number
12
+ /** Orientation inherited from parent (default 'horizontal') */
13
+ orientation?: Orientation
14
+ }
15
+
16
+ const { index, orientation = 'horizontal', class: className, style, ...props } = Astro.props
17
+
18
+ const paneStyle = `flex-basis:var(--rfr-pane-${index}-size, 50%);flex-grow:0;flex-shrink:0;${typeof style === 'string' ? style : ''}`
19
+ ---
20
+
21
+ <div
22
+ class={cn(resizablePaneVariants({ orientation }), className)}
23
+ style={paneStyle}
24
+ data-rfr-pane-index={index}
25
+ {...props}
26
+ >
27
+ <slot />
28
+ </div>
@@ -0,0 +1,11 @@
1
+ export { default as ResizableLayout } from './ResizableLayout.astro'
2
+ export { default as ResizablePane } from './ResizablePane.astro'
3
+ export { default as ResizableDivider } from './ResizableDivider.astro'
4
+
5
+ // Re-export core types and utilities
6
+ export {
7
+ createResizableLayout,
8
+ resizableLayoutVariants,
9
+ resizableDividerVariants,
10
+ resizablePaneVariants,
11
+ } from '@refraction-ui/resizable-layout'