@refraction-ui/astro 0.4.2 → 0.4.5

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 (334) hide show
  1. package/dist/accordion/index.ts +1 -0
  2. package/dist/ai/ai-manager.ts +121 -0
  3. package/dist/ai/index.ts +23 -0
  4. package/dist/ai/mock-providers.ts +68 -0
  5. package/dist/ai/sanitizer.ts +174 -0
  6. package/dist/ai/tts-manager.ts +80 -0
  7. package/dist/ai/types.ts +72 -0
  8. package/dist/animated-text/animated-text.styles.ts +28 -0
  9. package/dist/animated-text/animated-text.ts +83 -0
  10. package/dist/animated-text/index.ts +15 -0
  11. package/dist/app-shell/app-shell.ts +252 -0
  12. package/dist/app-shell/auth-shell.ts +84 -0
  13. package/dist/app-shell/index.ts +22 -0
  14. package/dist/app-shell/page-shell.ts +125 -0
  15. package/dist/astro-accordion/Button.astro +1 -1
  16. package/dist/astro-ai/index.ts +1 -1
  17. package/dist/astro-animated-text/AnimatedText.astro +1 -1
  18. package/dist/astro-animated-text/TypewriterText.astro +1 -1
  19. package/dist/astro-app-shell/AppShell.astro +1 -1
  20. package/dist/astro-app-shell/AuthShell.astro +1 -1
  21. package/dist/astro-app-shell/AuthShellCard.astro +1 -1
  22. package/dist/astro-app-shell/PageShell.astro +1 -1
  23. package/dist/astro-app-shell/PageShellSection.astro +1 -1
  24. package/dist/astro-app-shell/index.ts +1 -1
  25. package/dist/astro-auth/index.ts +2 -2
  26. package/dist/astro-avatar/Avatar.astro +1 -1
  27. package/dist/astro-avatar/AvatarFallback.astro +1 -1
  28. package/dist/astro-avatar/AvatarImage.astro +1 -1
  29. package/dist/astro-avatar-group/AvatarGroup.astro +1 -1
  30. package/dist/astro-badge/Badge.astro +1 -1
  31. package/dist/astro-bottom-nav/BottomNav.astro +1 -1
  32. package/dist/astro-breadcrumbs/Breadcrumbs.astro +1 -1
  33. package/dist/astro-button/Button.astro +1 -1
  34. package/dist/astro-calendar/Calendar.astro +1 -1
  35. package/dist/astro-card/Card.astro +1 -1
  36. package/dist/astro-card/CardContent.astro +1 -1
  37. package/dist/astro-card/CardDescription.astro +1 -1
  38. package/dist/astro-card/CardFooter.astro +1 -1
  39. package/dist/astro-card/CardHeader.astro +1 -1
  40. package/dist/astro-card/CardTitle.astro +1 -1
  41. package/dist/astro-card-grid/CardGrid.astro +1 -1
  42. package/dist/astro-carousel/Button.astro +1 -1
  43. package/dist/astro-charts/Bars.astro +1 -1
  44. package/dist/astro-charts/Chart.astro +1 -1
  45. package/dist/astro-charts/Circles.astro +1 -1
  46. package/dist/astro-charts/Histogram.astro +1 -1
  47. package/dist/astro-charts/Line.astro +1 -1
  48. package/dist/astro-charts/PieChart.astro +1 -1
  49. package/dist/astro-charts/ScatterPlot.astro +1 -1
  50. package/dist/astro-charts/index.ts +1 -1
  51. package/dist/astro-checkbox/Checkbox.astro +1 -1
  52. package/dist/astro-code-editor/CodeEditor.astro +1 -1
  53. package/dist/astro-collapsible/Collapsible.astro +1 -1
  54. package/dist/astro-collapsible/CollapsibleContent.astro +1 -1
  55. package/dist/astro-command/Command.astro +1 -1
  56. package/dist/astro-command/CommandGroup.astro +1 -1
  57. package/dist/astro-command/CommandInput.astro +1 -1
  58. package/dist/astro-command/CommandItem.astro +1 -1
  59. package/dist/astro-command-input/CommandInput.astro +1 -1
  60. package/dist/astro-content-protection/ContentProtection.astro +1 -1
  61. package/dist/astro-data-table/DataTable.astro +1 -1
  62. package/dist/astro-date-picker/DatePicker.astro +1 -1
  63. package/dist/astro-device-frame/DeviceFrame.astro +1 -1
  64. package/dist/astro-dialog/DialogContent.astro +1 -1
  65. package/dist/astro-dialog/DialogOverlay.astro +1 -1
  66. package/dist/astro-diff-viewer/DiffViewer.astro +1 -1
  67. package/dist/astro-dropdown-menu/DropdownMenuContent.astro +1 -1
  68. package/dist/astro-dropdown-menu/DropdownMenuItem.astro +1 -1
  69. package/dist/astro-emoji-picker/EmojiPicker.astro +1 -1
  70. package/dist/astro-feedback-dialog/FeedbackDialog.astro +1 -1
  71. package/dist/astro-file-upload/FileUpload.astro +1 -1
  72. package/dist/astro-footer/Footer.astro +1 -1
  73. package/dist/astro-inline-editor/InlineEditor.astro +1 -1
  74. package/dist/astro-input/Input.astro +1 -1
  75. package/dist/astro-input-group/InputGroup.astro +1 -1
  76. package/dist/astro-input-group/InputGroupAddon.astro +1 -1
  77. package/dist/astro-input-group/InputGroupButton.astro +1 -1
  78. package/dist/astro-install-prompt/InstallPrompt.astro +1 -1
  79. package/dist/astro-keyboard-shortcut/ShortcutBadge.astro +1 -1
  80. package/dist/astro-language-selector/LanguageSelector.astro +1 -1
  81. package/dist/astro-link-card/LinkCard.astro +1 -1
  82. package/dist/astro-markdown-renderer/MarkdownRenderer.astro +1 -1
  83. package/dist/astro-mobile-nav/MobileNav.astro +1 -1
  84. package/dist/astro-mobile-nav/MobileNavLink.astro +1 -1
  85. package/dist/astro-mobile-nav/MobileNavTrigger.astro +1 -1
  86. package/dist/astro-navbar/Navbar.astro +1 -1
  87. package/dist/astro-otp-input/OtpInput.astro +1 -1
  88. package/dist/astro-payment/Payment.astro +1 -1
  89. package/dist/astro-popover/PopoverContent.astro +1 -1
  90. package/dist/astro-presence-indicator/PresenceIndicator.astro +1 -1
  91. package/dist/astro-progress-display/BadgeDisplay.astro +1 -1
  92. package/dist/astro-progress-display/ProgressBar.astro +1 -1
  93. package/dist/astro-progress-display/StatsGrid.astro +1 -1
  94. package/dist/astro-radio/RadioGroup.astro +1 -1
  95. package/dist/astro-radio/RadioItem.astro +1 -1
  96. package/dist/astro-reaction-bar/ReactionBar.astro +1 -1
  97. package/dist/astro-resizable-layout/ResizableDivider.astro +1 -1
  98. package/dist/astro-resizable-layout/ResizableLayout.astro +1 -1
  99. package/dist/astro-resizable-layout/ResizablePane.astro +1 -1
  100. package/dist/astro-resizable-layout/index.ts +1 -1
  101. package/dist/astro-rich-editor/index.ts +2 -2
  102. package/dist/astro-search-bar/SearchBar.astro +1 -1
  103. package/dist/astro-search-bar/SearchResults.astro +1 -1
  104. package/dist/astro-select/Select.astro +1 -1
  105. package/dist/astro-select/SelectContent.astro +1 -1
  106. package/dist/astro-select/SelectItem.astro +1 -1
  107. package/dist/astro-select/SelectTrigger.astro +1 -1
  108. package/dist/astro-sidebar/Sidebar.astro +1 -1
  109. package/dist/astro-skeleton/Skeleton.astro +1 -1
  110. package/dist/astro-slide-viewer/SlideViewer.astro +1 -1
  111. package/dist/astro-status-indicator/StatusIndicator.astro +1 -1
  112. package/dist/astro-switch/Switch.astro +1 -1
  113. package/dist/astro-table-of-contents/TableOfContents.astro +1 -1
  114. package/dist/astro-tabs/Tabs.astro +1 -1
  115. package/dist/astro-tabs/TabsList.astro +1 -1
  116. package/dist/astro-tabs/TabsTrigger.astro +1 -1
  117. package/dist/astro-textarea/Textarea.astro +1 -1
  118. package/dist/astro-theme/ThemeScript.astro +1 -1
  119. package/dist/astro-thread-view/ThreadView.astro +1 -1
  120. package/dist/astro-toast/Toast.astro +1 -1
  121. package/dist/astro-tooltip/TooltipContent.astro +1 -1
  122. package/dist/astro-version-selector/VersionSelector.astro +1 -1
  123. package/dist/astro-video-player/VideoPlayer.astro +1 -1
  124. package/dist/auth/adapters/mock.ts +74 -0
  125. package/dist/auth/auth-machine.ts +120 -0
  126. package/dist/auth/index.ts +22 -0
  127. package/dist/auth/rbac.ts +44 -0
  128. package/dist/auth/types.ts +44 -0
  129. package/dist/avatar/avatar.styles.ts +47 -0
  130. package/dist/avatar/avatar.ts +73 -0
  131. package/dist/avatar/index.ts +15 -0
  132. package/dist/avatar-group/avatar-group.styles.ts +63 -0
  133. package/dist/avatar-group/avatar-group.ts +106 -0
  134. package/dist/avatar-group/index.ts +18 -0
  135. package/dist/badge/badge.styles.ts +24 -0
  136. package/dist/badge/badge.ts +48 -0
  137. package/dist/badge/index.ts +10 -0
  138. package/dist/bottom-nav/bottom-nav.styles.ts +18 -0
  139. package/dist/bottom-nav/bottom-nav.ts +33 -0
  140. package/dist/bottom-nav/index.ts +2 -0
  141. package/dist/breadcrumbs/breadcrumbs.styles.ts +20 -0
  142. package/dist/breadcrumbs/breadcrumbs.ts +72 -0
  143. package/dist/breadcrumbs/index.ts +8 -0
  144. package/dist/button/button.styles.ts +38 -0
  145. package/dist/button/button.ts +64 -0
  146. package/dist/button/index.ts +10 -0
  147. package/dist/calendar/calendar.styles.ts +21 -0
  148. package/dist/calendar/calendar.ts +202 -0
  149. package/dist/calendar/index.ts +9 -0
  150. package/dist/callout/callout.ts +1 -0
  151. package/dist/callout/index.ts +1 -0
  152. package/dist/card/card.styles.ts +55 -0
  153. package/dist/card/card.ts +45 -0
  154. package/dist/card/index.ts +20 -0
  155. package/dist/card-grid/card-grid.ts +9 -0
  156. package/dist/card-grid/index.ts +1 -0
  157. package/dist/carousel/index.ts +1 -0
  158. package/dist/charts/axis.ts +50 -0
  159. package/dist/charts/chart.ts +73 -0
  160. package/dist/charts/colorblind.ts +100 -0
  161. package/dist/charts/data.ts +72 -0
  162. package/dist/charts/geometry.ts +54 -0
  163. package/dist/charts/index.ts +61 -0
  164. package/dist/charts/scales.ts +151 -0
  165. package/dist/checkbox/checkbox.styles.ts +33 -0
  166. package/dist/checkbox/checkbox.ts +73 -0
  167. package/dist/checkbox/index.ts +10 -0
  168. package/dist/code-block/code-block.ts +1 -0
  169. package/dist/code-block/index.ts +1 -0
  170. package/dist/code-editor/code-editor.styles.ts +32 -0
  171. package/dist/code-editor/code-editor.ts +140 -0
  172. package/dist/code-editor/index.ts +9 -0
  173. package/dist/collapsible/collapsible.styles.ts +14 -0
  174. package/dist/collapsible/collapsible.ts +93 -0
  175. package/dist/collapsible/index.ts +7 -0
  176. package/dist/command/command.styles.ts +27 -0
  177. package/dist/command/command.ts +179 -0
  178. package/dist/command/index.ts +14 -0
  179. package/dist/command-input/command-input.ts +176 -0
  180. package/dist/command-input/index.ts +1 -0
  181. package/dist/content-protection/content-protection.styles.ts +9 -0
  182. package/dist/content-protection/content-protection.ts +68 -0
  183. package/dist/content-protection/index.ts +8 -0
  184. package/dist/data-table/data-table.styles.ts +55 -0
  185. package/dist/data-table/data-table.ts +183 -0
  186. package/dist/data-table/index.ts +15 -0
  187. package/dist/date-picker/date-picker.styles.ts +31 -0
  188. package/dist/date-picker/date-picker.ts +333 -0
  189. package/dist/date-picker/index.ts +18 -0
  190. package/dist/device-frame/device-frame.styles.ts +21 -0
  191. package/dist/device-frame/device-frame.ts +112 -0
  192. package/dist/device-frame/index.ts +10 -0
  193. package/dist/dialog/dialog.styles.ts +8 -0
  194. package/dist/dialog/dialog.ts +133 -0
  195. package/dist/dialog/index.ts +8 -0
  196. package/dist/diff-viewer/diff-viewer.styles.ts +124 -0
  197. package/dist/diff-viewer/diff-viewer.ts +255 -0
  198. package/dist/diff-viewer/index.ts +20 -0
  199. package/dist/dropdown-menu/dropdown-menu.styles.ts +9 -0
  200. package/dist/dropdown-menu/dropdown-menu.ts +139 -0
  201. package/dist/dropdown-menu/index.ts +9 -0
  202. package/dist/emoji-picker/emoji-data.ts +282 -0
  203. package/dist/emoji-picker/emoji-picker.styles.ts +32 -0
  204. package/dist/emoji-picker/emoji-picker.ts +165 -0
  205. package/dist/emoji-picker/index.ts +25 -0
  206. package/dist/feedback-dialog/feedback-dialog.styles.ts +15 -0
  207. package/dist/feedback-dialog/feedback-dialog.ts +147 -0
  208. package/dist/feedback-dialog/index.ts +11 -0
  209. package/dist/file-upload/file-upload.styles.ts +30 -0
  210. package/dist/file-upload/file-upload.ts +260 -0
  211. package/dist/file-upload/index.ts +19 -0
  212. package/dist/footer/footer.styles.ts +5 -0
  213. package/dist/footer/footer.ts +32 -0
  214. package/dist/footer/index.ts +9 -0
  215. package/dist/index.ts +1 -1
  216. package/dist/inline-editor/index.ts +13 -0
  217. package/dist/inline-editor/inline-editor.styles.ts +42 -0
  218. package/dist/inline-editor/inline-editor.ts +96 -0
  219. package/dist/input/index.ts +9 -0
  220. package/dist/input/input.styles.ts +15 -0
  221. package/dist/input/input.ts +84 -0
  222. package/dist/input-group/index.ts +13 -0
  223. package/dist/input-group/input-group.styles.ts +50 -0
  224. package/dist/input-group/input-group.ts +44 -0
  225. package/dist/install-prompt/index.ts +9 -0
  226. package/dist/install-prompt/install-prompt.styles.ts +5 -0
  227. package/dist/install-prompt/install-prompt.ts +68 -0
  228. package/dist/keyboard-shortcut/index.ts +12 -0
  229. package/dist/keyboard-shortcut/keyboard-shortcut.styles.ts +8 -0
  230. package/dist/keyboard-shortcut/keyboard-shortcut.ts +153 -0
  231. package/dist/language-selector/index.ts +8 -0
  232. package/dist/language-selector/language-selector.styles.ts +28 -0
  233. package/dist/language-selector/language-selector.ts +149 -0
  234. package/dist/link-card/index.ts +1 -0
  235. package/dist/link-card/link-card.ts +9 -0
  236. package/dist/markdown-renderer/index.ts +8 -0
  237. package/dist/markdown-renderer/markdown-renderer.styles.ts +31 -0
  238. package/dist/markdown-renderer/markdown-renderer.ts +251 -0
  239. package/dist/mobile-nav/index.ts +14 -0
  240. package/dist/mobile-nav/mobile-nav.styles.ts +39 -0
  241. package/dist/mobile-nav/mobile-nav.ts +74 -0
  242. package/dist/navbar/index.ts +9 -0
  243. package/dist/navbar/navbar.styles.ts +29 -0
  244. package/dist/navbar/navbar.ts +39 -0
  245. package/dist/otp-input/index.ts +13 -0
  246. package/dist/otp-input/otp-input.styles.ts +51 -0
  247. package/dist/otp-input/otp-input.ts +198 -0
  248. package/dist/pagination/index.ts +1 -0
  249. package/dist/payment/index.ts +1 -0
  250. package/dist/payment/payment.ts +16 -0
  251. package/dist/popover/index.ts +7 -0
  252. package/dist/popover/popover.styles.ts +16 -0
  253. package/dist/popover/popover.ts +89 -0
  254. package/dist/presence-indicator/index.ts +14 -0
  255. package/dist/presence-indicator/presence-indicator.styles.ts +29 -0
  256. package/dist/presence-indicator/presence-indicator.ts +63 -0
  257. package/dist/progress-display/index.ts +15 -0
  258. package/dist/progress-display/progress-display.styles.ts +72 -0
  259. package/dist/progress-display/progress-display.ts +60 -0
  260. package/dist/radio/index.ts +8 -0
  261. package/dist/radio/radio.styles.ts +34 -0
  262. package/dist/radio/radio.ts +70 -0
  263. package/dist/reaction-bar/index.ts +14 -0
  264. package/dist/reaction-bar/reaction-bar.styles.ts +23 -0
  265. package/dist/reaction-bar/reaction-bar.ts +87 -0
  266. package/dist/resizable-layout/index.ts +12 -0
  267. package/dist/resizable-layout/resizable-layout.styles.ts +50 -0
  268. package/dist/resizable-layout/resizable-layout.ts +139 -0
  269. package/dist/rich-editor/editor.ts +342 -0
  270. package/dist/rich-editor/emoji.ts +175 -0
  271. package/dist/rich-editor/history.ts +79 -0
  272. package/dist/rich-editor/index.ts +106 -0
  273. package/dist/rich-editor/markdown-shortcuts.ts +248 -0
  274. package/dist/rich-editor/mentions.ts +162 -0
  275. package/dist/rich-editor/model.ts +206 -0
  276. package/dist/rich-editor/operations.ts +772 -0
  277. package/dist/rich-editor/selection.ts +157 -0
  278. package/dist/rich-editor/serialization.ts +711 -0
  279. package/dist/rich-editor/slash-commands.ts +212 -0
  280. package/dist/search-bar/index.ts +7 -0
  281. package/dist/search-bar/search-bar.styles.ts +29 -0
  282. package/dist/search-bar/search-bar.ts +130 -0
  283. package/dist/select/index.ts +13 -0
  284. package/dist/select/select.styles.ts +52 -0
  285. package/dist/select/select.ts +152 -0
  286. package/dist/sidebar/index.ts +9 -0
  287. package/dist/sidebar/sidebar.styles.ts +27 -0
  288. package/dist/sidebar/sidebar.ts +59 -0
  289. package/dist/skeleton/index.ts +8 -0
  290. package/dist/skeleton/skeleton.styles.ts +16 -0
  291. package/dist/skeleton/skeleton.ts +39 -0
  292. package/dist/skip-to-content/index.ts +1 -0
  293. package/dist/skip-to-content/skip-to-content.ts +1 -0
  294. package/dist/slide-viewer/index.ts +16 -0
  295. package/dist/slide-viewer/slide-viewer.styles.ts +57 -0
  296. package/dist/slide-viewer/slide-viewer.ts +152 -0
  297. package/dist/slider/index.ts +1 -0
  298. package/dist/slider/slider.ts +2 -0
  299. package/dist/status-indicator/index.ts +15 -0
  300. package/dist/status-indicator/status-indicator.styles.ts +41 -0
  301. package/dist/status-indicator/status-indicator.ts +66 -0
  302. package/dist/steps/index.ts +1 -0
  303. package/dist/steps/steps.ts +1 -0
  304. package/dist/switch/index.ts +7 -0
  305. package/dist/switch/switch.styles.ts +55 -0
  306. package/dist/switch/switch.ts +63 -0
  307. package/dist/table-of-contents/index.ts +1 -0
  308. package/dist/table-of-contents/table-of-contents.ts +37 -0
  309. package/dist/tabs/index.ts +8 -0
  310. package/dist/tabs/tabs.styles.ts +9 -0
  311. package/dist/tabs/tabs.ts +133 -0
  312. package/dist/textarea/index.ts +7 -0
  313. package/dist/textarea/textarea.styles.ts +15 -0
  314. package/dist/textarea/textarea.ts +59 -0
  315. package/dist/theme/dom-adapters.ts +60 -0
  316. package/dist/theme/index.ts +18 -0
  317. package/dist/theme/theme-machine.ts +130 -0
  318. package/dist/theme/theme-script.ts +18 -0
  319. package/dist/thread-view/index.ts +26 -0
  320. package/dist/thread-view/thread-view.styles.ts +35 -0
  321. package/dist/thread-view/thread-view.ts +176 -0
  322. package/dist/toast/index.ts +13 -0
  323. package/dist/toast/toast.styles.ts +19 -0
  324. package/dist/toast/toast.ts +203 -0
  325. package/dist/tooltip/index.ts +7 -0
  326. package/dist/tooltip/tooltip.styles.ts +16 -0
  327. package/dist/tooltip/tooltip.ts +109 -0
  328. package/dist/version-selector/index.ts +12 -0
  329. package/dist/version-selector/version-selector.styles.ts +41 -0
  330. package/dist/version-selector/version-selector.ts +136 -0
  331. package/dist/video-player/index.ts +12 -0
  332. package/dist/video-player/video-player.styles.ts +42 -0
  333. package/dist/video-player/video-player.ts +100 -0
  334. package/package.json +1 -1
@@ -0,0 +1,202 @@
1
+ import type { AccessibilityProps } from '../shared/index.ts'
2
+ import { generateId } from '../shared/index.ts'
3
+
4
+ export interface CalendarProps {
5
+ /** Selected date (controlled) */
6
+ value?: Date
7
+ /** Default selected date (uncontrolled) */
8
+ defaultValue?: Date
9
+ /** Callback when a date is selected */
10
+ onSelect?: (date: Date) => void
11
+ /** Displayed month (controlled) */
12
+ month?: Date
13
+ /** Callback when the displayed month changes */
14
+ onMonthChange?: (month: Date) => void
15
+ /** Minimum selectable date */
16
+ minDate?: Date
17
+ /** Maximum selectable date */
18
+ maxDate?: Date
19
+ /** Specific dates to disable */
20
+ disabledDates?: Date[]
21
+ }
22
+
23
+ export interface CalendarDay {
24
+ /** The date this cell represents */
25
+ date: Date
26
+ /** Whether the date is today */
27
+ isToday: boolean
28
+ /** Whether the date is currently selected */
29
+ isSelected: boolean
30
+ /** Whether the date belongs to the currently displayed month */
31
+ isCurrentMonth: boolean
32
+ /** Whether the date is disabled */
33
+ isDisabled: boolean
34
+ }
35
+
36
+ export interface CalendarState {
37
+ /** The currently displayed month */
38
+ currentMonth: Date
39
+ /** The currently selected date, if any */
40
+ selectedDate: Date | undefined
41
+ }
42
+
43
+ export interface CalendarAPI {
44
+ /** Current calendar state */
45
+ state: CalendarState
46
+ /** Array of day objects for the current month grid (always 42: 6 weeks x 7 days) */
47
+ days: CalendarDay[]
48
+ /** Navigate to the previous month */
49
+ prevMonth(): void
50
+ /** Navigate to the next month */
51
+ nextMonth(): void
52
+ /** Select a date */
53
+ select(date: Date): void
54
+ /** ARIA attributes for the calendar grid */
55
+ ariaProps: Partial<AccessibilityProps> & Record<string, unknown>
56
+ /** Get ARIA attributes for a specific day cell */
57
+ getDayAriaProps(day: CalendarDay): Partial<AccessibilityProps> & Record<string, unknown>
58
+ /** Generated IDs */
59
+ ids: {
60
+ grid: string
61
+ label: string
62
+ }
63
+ }
64
+
65
+ /** Check if two dates represent the same calendar day */
66
+ function isSameDay(a: Date, b: Date): boolean {
67
+ return (
68
+ a.getFullYear() === b.getFullYear() &&
69
+ a.getMonth() === b.getMonth() &&
70
+ a.getDate() === b.getDate()
71
+ )
72
+ }
73
+
74
+ /** Get the first day of a month */
75
+ function startOfMonth(date: Date): Date {
76
+ return new Date(date.getFullYear(), date.getMonth(), 1)
77
+ }
78
+
79
+ /** Get day names */
80
+ const DAY_NAMES = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']
81
+
82
+ export function createCalendar(props: CalendarProps = {}): CalendarAPI {
83
+ const {
84
+ value: controlledValue,
85
+ defaultValue,
86
+ onSelect,
87
+ month: controlledMonth,
88
+ onMonthChange,
89
+ minDate,
90
+ maxDate,
91
+ disabledDates = [],
92
+ } = props
93
+
94
+ const today = new Date()
95
+
96
+ // Determine selected date
97
+ const selectedDate = controlledValue ?? defaultValue
98
+
99
+ // Determine current displayed month
100
+ const currentMonth = controlledMonth
101
+ ? startOfMonth(controlledMonth)
102
+ : selectedDate
103
+ ? startOfMonth(selectedDate)
104
+ : startOfMonth(today)
105
+
106
+ const gridId = generateId('rfr-calendar')
107
+ const labelId = generateId('rfr-calendar-label')
108
+
109
+ function isDateDisabled(date: Date): boolean {
110
+ if (minDate && date < startOfDay(minDate)) return true
111
+ if (maxDate && date > endOfDay(maxDate)) return true
112
+ return disabledDates.some((d) => isSameDay(d, date))
113
+ }
114
+
115
+ function startOfDay(date: Date): Date {
116
+ return new Date(date.getFullYear(), date.getMonth(), date.getDate())
117
+ }
118
+
119
+ function endOfDay(date: Date): Date {
120
+ return new Date(date.getFullYear(), date.getMonth(), date.getDate(), 23, 59, 59, 999)
121
+ }
122
+
123
+ /** Build the 42-cell grid for the current month view */
124
+ function buildDays(): CalendarDay[] {
125
+ const year = currentMonth.getFullYear()
126
+ const month = currentMonth.getMonth()
127
+
128
+ // First day of the month
129
+ const first = new Date(year, month, 1)
130
+ // Day of week the month starts on (0 = Sunday)
131
+ const startDow = first.getDay()
132
+
133
+ // Start from the Sunday before (or on) the first
134
+ const gridStart = new Date(year, month, 1 - startDow)
135
+
136
+ const days: CalendarDay[] = []
137
+ for (let i = 0; i < 42; i++) {
138
+ const date = new Date(
139
+ gridStart.getFullYear(),
140
+ gridStart.getMonth(),
141
+ gridStart.getDate() + i,
142
+ )
143
+ days.push({
144
+ date,
145
+ isToday: isSameDay(date, today),
146
+ isSelected: selectedDate ? isSameDay(date, selectedDate) : false,
147
+ isCurrentMonth: date.getMonth() === month,
148
+ isDisabled: isDateDisabled(date),
149
+ })
150
+ }
151
+ return days
152
+ }
153
+
154
+ function prevMonth(): void {
155
+ const prev = new Date(currentMonth.getFullYear(), currentMonth.getMonth() - 1, 1)
156
+ onMonthChange?.(prev)
157
+ }
158
+
159
+ function nextMonth(): void {
160
+ const next = new Date(currentMonth.getFullYear(), currentMonth.getMonth() + 1, 1)
161
+ onMonthChange?.(next)
162
+ }
163
+
164
+ function select(date: Date): void {
165
+ if (!isDateDisabled(date)) {
166
+ onSelect?.(date)
167
+ }
168
+ }
169
+
170
+ const ariaProps: Partial<AccessibilityProps> & Record<string, unknown> = {
171
+ role: 'grid',
172
+ 'aria-labelledby': labelId,
173
+ id: gridId,
174
+ }
175
+
176
+ function getDayAriaProps(day: CalendarDay): Partial<AccessibilityProps> & Record<string, unknown> {
177
+ return {
178
+ role: 'gridcell',
179
+ 'aria-selected': day.isSelected,
180
+ 'aria-disabled': day.isDisabled,
181
+ 'aria-current': day.isToday ? ('date' as const) : undefined,
182
+ 'aria-label': `${DAY_NAMES[day.date.getDay()]}, ${day.date.toLocaleDateString('en-US', { month: 'long', day: 'numeric', year: 'numeric' })}`,
183
+ }
184
+ }
185
+
186
+ return {
187
+ state: {
188
+ currentMonth,
189
+ selectedDate,
190
+ },
191
+ days: buildDays(),
192
+ prevMonth,
193
+ nextMonth,
194
+ select,
195
+ ariaProps,
196
+ getDayAriaProps,
197
+ ids: {
198
+ grid: gridId,
199
+ label: labelId,
200
+ },
201
+ }
202
+ }
@@ -0,0 +1,9 @@
1
+ export {
2
+ createCalendar,
3
+ type CalendarProps,
4
+ type CalendarDay,
5
+ type CalendarState,
6
+ type CalendarAPI,
7
+ } from './calendar.js'
8
+
9
+ export { calendarVariants, dayVariants } from './calendar.styles.js'
@@ -0,0 +1 @@
1
+ export const callout = {};
@@ -0,0 +1 @@
1
+ export * from './callout';
@@ -0,0 +1,55 @@
1
+ import { cva } from '../shared/index.ts'
2
+ import type { TokenContract } from '../shared/index.ts'
3
+
4
+ export const cardTokens: TokenContract = {
5
+ name: 'card',
6
+ tokens: {
7
+ bg: { variable: '--rfr-card-bg', fallback: 'hsl(var(--card))' },
8
+ fg: { variable: '--rfr-card-fg', fallback: 'hsl(var(--card-foreground))' },
9
+ border: { variable: '--rfr-card-border', fallback: 'hsl(var(--border))' },
10
+ },
11
+ }
12
+
13
+ export const cardVariants = cva({
14
+ base: 'rounded-lg border bg-card text-card-foreground shadow',
15
+ variants: {
16
+ padding: {
17
+ none: '',
18
+ default: 'p-6',
19
+ compact: 'p-4',
20
+ },
21
+ },
22
+ defaultVariants: {
23
+ padding: 'none',
24
+ },
25
+ })
26
+
27
+ export const cardHeaderVariants = cva({
28
+ base: 'flex flex-col space-y-1.5 p-6',
29
+ })
30
+
31
+ export const cardTitleVariants = cva({
32
+ base: 'font-semibold leading-none tracking-tight',
33
+ variants: {
34
+ size: {
35
+ sm: 'text-lg',
36
+ default: 'text-2xl',
37
+ lg: 'text-3xl',
38
+ },
39
+ },
40
+ defaultVariants: {
41
+ size: 'default',
42
+ },
43
+ })
44
+
45
+ export const cardDescriptionVariants = cva({
46
+ base: 'text-sm text-muted-foreground',
47
+ })
48
+
49
+ export const cardContentVariants = cva({
50
+ base: 'p-6 pt-0',
51
+ })
52
+
53
+ export const cardFooterVariants = cva({
54
+ base: 'flex items-center p-6 pt-0',
55
+ })
@@ -0,0 +1,45 @@
1
+ import type { AccessibilityProps } from '../shared/index.ts'
2
+
3
+ export interface CardProps {
4
+ /** Optional accessible role override */
5
+ role?: string
6
+ }
7
+
8
+ export interface CardAPI {
9
+ /** ARIA attributes to spread on the element */
10
+ ariaProps: Partial<AccessibilityProps>
11
+ /** Data attributes for CSS styling hooks */
12
+ dataAttributes: Record<string, string>
13
+ }
14
+
15
+ export function createCard(props: CardProps = {}): CardAPI {
16
+ const ariaProps: Partial<AccessibilityProps> = {}
17
+ if (props.role) {
18
+ ariaProps.role = props.role
19
+ }
20
+
21
+ return {
22
+ ariaProps,
23
+ dataAttributes: { 'data-slot': 'card' },
24
+ }
25
+ }
26
+
27
+ export function createCardHeader(): { dataAttributes: Record<string, string> } {
28
+ return { dataAttributes: { 'data-slot': 'card-header' } }
29
+ }
30
+
31
+ export function createCardTitle(): { dataAttributes: Record<string, string> } {
32
+ return { dataAttributes: { 'data-slot': 'card-title' } }
33
+ }
34
+
35
+ export function createCardDescription(): { dataAttributes: Record<string, string> } {
36
+ return { dataAttributes: { 'data-slot': 'card-description' } }
37
+ }
38
+
39
+ export function createCardContent(): { dataAttributes: Record<string, string> } {
40
+ return { dataAttributes: { 'data-slot': 'card-content' } }
41
+ }
42
+
43
+ export function createCardFooter(): { dataAttributes: Record<string, string> } {
44
+ return { dataAttributes: { 'data-slot': 'card-footer' } }
45
+ }
@@ -0,0 +1,20 @@
1
+ export {
2
+ createCard,
3
+ createCardHeader,
4
+ createCardTitle,
5
+ createCardDescription,
6
+ createCardContent,
7
+ createCardFooter,
8
+ type CardProps,
9
+ type CardAPI,
10
+ } from './card.js'
11
+
12
+ export {
13
+ cardVariants,
14
+ cardHeaderVariants,
15
+ cardTitleVariants,
16
+ cardDescriptionVariants,
17
+ cardContentVariants,
18
+ cardFooterVariants,
19
+ cardTokens,
20
+ } from './card.styles.js'
@@ -0,0 +1,9 @@
1
+ export interface CardGridProps {
2
+ columns?: number
3
+ }
4
+
5
+ export function createCardGrid(_props: CardGridProps = {}) {
6
+ return {
7
+ dataAttributes: { 'data-slot': 'card-grid' }
8
+ }
9
+ }
@@ -0,0 +1 @@
1
+ export * from './card-grid.js'
@@ -0,0 +1 @@
1
+ export {}
@@ -0,0 +1,50 @@
1
+ import type { LinearScale, BandScale, TimeScale } from './scales.js'
2
+
3
+ type AnyScale = LinearScale | BandScale | TimeScale
4
+
5
+ export function generateTicks(
6
+ scale: AnyScale,
7
+ count?: number,
8
+ ): (number | string | Date)[] {
9
+ if (scale.type === 'band') {
10
+ return scale.domain
11
+ }
12
+ if (scale.type === 'time') {
13
+ return scale.ticks(count)
14
+ }
15
+ // linear
16
+ return scale.ticks(count)
17
+ }
18
+
19
+ export function formatTick(
20
+ value: number | string | Date,
21
+ type: 'number' | 'date' | 'string',
22
+ ): string {
23
+ if (type === 'string') {
24
+ return String(value)
25
+ }
26
+
27
+ if (type === 'date') {
28
+ if (value instanceof Date) {
29
+ return value.toISOString().split('T')[0]
30
+ }
31
+ return String(value)
32
+ }
33
+
34
+ // type === 'number'
35
+ const num = value as number
36
+ if (!Number.isFinite(num)) return String(num)
37
+
38
+ // Check if integer
39
+ if (Number.isInteger(num)) {
40
+ // Format with locale separators for large numbers
41
+ return num.toLocaleString('en-US', { maximumFractionDigits: 0 })
42
+ }
43
+
44
+ // Decimal: show up to 2 decimal places, strip trailing zeros
45
+ const formatted = num.toLocaleString('en-US', {
46
+ minimumFractionDigits: 0,
47
+ maximumFractionDigits: 2,
48
+ })
49
+ return formatted
50
+ }
@@ -0,0 +1,73 @@
1
+ export interface Margin {
2
+ top: number
3
+ right: number
4
+ bottom: number
5
+ left: number
6
+ }
7
+
8
+ export interface Dimensions {
9
+ width: number
10
+ height: number
11
+ margin: Margin
12
+ boundedWidth: number
13
+ boundedHeight: number
14
+ }
15
+
16
+ export interface ChartConfig {
17
+ width?: number
18
+ height?: number
19
+ margin?: Partial<Margin>
20
+ data?: unknown[]
21
+ }
22
+
23
+ export interface ChartAPI {
24
+ dimensions: Dimensions
25
+ scales: Record<string, unknown>
26
+ updateDimensions: (partial: Partial<ChartConfig>) => void
27
+ }
28
+
29
+ const DEFAULT_MARGIN: Margin = {
30
+ top: 40,
31
+ right: 30,
32
+ bottom: 40,
33
+ left: 75,
34
+ }
35
+
36
+ const DEFAULT_WIDTH = 600
37
+ const DEFAULT_HEIGHT = 400
38
+
39
+ export function combineDimensions(partial: Partial<ChartConfig>): Dimensions {
40
+ const width = partial.width ?? DEFAULT_WIDTH
41
+ const height = partial.height ?? DEFAULT_HEIGHT
42
+ const margin: Margin = {
43
+ ...DEFAULT_MARGIN,
44
+ ...(partial.margin ?? {}),
45
+ }
46
+ const boundedWidth = Math.max(0, width - margin.left - margin.right)
47
+ const boundedHeight = Math.max(0, height - margin.top - margin.bottom)
48
+
49
+ return { width, height, margin, boundedWidth, boundedHeight }
50
+ }
51
+
52
+ export function createChart(config: ChartConfig): ChartAPI {
53
+ let dimensions = combineDimensions(config)
54
+ const scales: Record<string, unknown> = {}
55
+
56
+ return {
57
+ get dimensions() {
58
+ return dimensions
59
+ },
60
+ scales,
61
+ updateDimensions(partial: Partial<ChartConfig>) {
62
+ const merged: Partial<ChartConfig> = {
63
+ width: partial.width ?? dimensions.width,
64
+ height: partial.height ?? dimensions.height,
65
+ margin: {
66
+ ...dimensions.margin,
67
+ ...(partial.margin ?? {}),
68
+ },
69
+ }
70
+ dimensions = combineDimensions(merged)
71
+ },
72
+ }
73
+ }
@@ -0,0 +1,100 @@
1
+ /**
2
+ * Colorblind-safe color palettes for charts.
3
+ * Based on Wong (2011) "Points of view: Color blindness" — Nature Methods.
4
+ * These 8 colors are distinguishable by people with all types of color vision deficiency.
5
+ */
6
+ export const COLORBLIND_SAFE_PALETTE = [
7
+ '#0072B2', // blue
8
+ '#E69F00', // orange
9
+ '#009E73', // green (blue-tinted, safe for protanopia/deuteranopia)
10
+ '#F0E442', // yellow
11
+ '#56B4E9', // sky blue
12
+ '#D55E00', // vermillion (not red — distinguishable from green)
13
+ '#CC79A7', // pink
14
+ '#000000', // black
15
+ ] as const
16
+
17
+ /** Convert hex to HSL string for CSS variables */
18
+ export function hexToHSL(hex: string): string {
19
+ // Remove # prefix
20
+ const h = hex.replace(/^#/, '')
21
+
22
+ const r = parseInt(h.substring(0, 2), 16) / 255
23
+ const g = parseInt(h.substring(2, 4), 16) / 255
24
+ const b = parseInt(h.substring(4, 6), 16) / 255
25
+
26
+ const max = Math.max(r, g, b)
27
+ const min = Math.min(r, g, b)
28
+ const l = (max + min) / 2
29
+
30
+ if (max === min) {
31
+ // Achromatic
32
+ return `0 0% ${Math.round(l * 100)}%`
33
+ }
34
+
35
+ const d = max - min
36
+ const s = l > 0.5 ? d / (2 - max - min) : d / (max + min)
37
+
38
+ let hue: number
39
+ if (max === r) {
40
+ hue = ((g - b) / d + (g < b ? 6 : 0)) / 6
41
+ } else if (max === g) {
42
+ hue = ((b - r) / d + 2) / 6
43
+ } else {
44
+ hue = ((r - g) / d + 4) / 6
45
+ }
46
+
47
+ return `${Math.round(hue * 360)} ${Math.round(s * 100)}% ${Math.round(l * 100)}%`
48
+ }
49
+
50
+ /** Get a colorblind-safe color by index (wraps around) */
51
+ export function getChartColor(index: number): string {
52
+ return COLORBLIND_SAFE_PALETTE[index % COLORBLIND_SAFE_PALETTE.length]
53
+ }
54
+
55
+ /**
56
+ * Pattern fills for charts — when color alone isn't enough.
57
+ * Returns SVG pattern definitions that can be used as fill.
58
+ */
59
+ export type PatternType = 'solid' | 'diagonal' | 'dots' | 'crosshatch' | 'horizontal' | 'vertical' | 'zigzag' | 'checker'
60
+
61
+ export function getPatternDef(type: PatternType, color: string, id: string): string {
62
+ const size = 8
63
+
64
+ switch (type) {
65
+ case 'solid':
66
+ return `<pattern id="${id}" width="${size}" height="${size}" patternUnits="userSpaceOnUse"><rect width="${size}" height="${size}" fill="${color}"/></pattern>`
67
+
68
+ case 'diagonal':
69
+ return `<pattern id="${id}" width="${size}" height="${size}" patternUnits="userSpaceOnUse"><rect width="${size}" height="${size}" fill="${color}" opacity="0.3"/><line x1="0" y1="${size}" x2="${size}" y2="0" stroke="${color}" stroke-width="1.5"/></pattern>`
70
+
71
+ case 'dots':
72
+ return `<pattern id="${id}" width="${size}" height="${size}" patternUnits="userSpaceOnUse"><rect width="${size}" height="${size}" fill="${color}" opacity="0.3"/><circle cx="${size / 2}" cy="${size / 2}" r="1.5" fill="${color}"/></pattern>`
73
+
74
+ case 'crosshatch':
75
+ return `<pattern id="${id}" width="${size}" height="${size}" patternUnits="userSpaceOnUse"><rect width="${size}" height="${size}" fill="${color}" opacity="0.3"/><line x1="0" y1="0" x2="${size}" y2="${size}" stroke="${color}" stroke-width="1"/><line x1="${size}" y1="0" x2="0" y2="${size}" stroke="${color}" stroke-width="1"/></pattern>`
76
+
77
+ case 'horizontal':
78
+ return `<pattern id="${id}" width="${size}" height="${size}" patternUnits="userSpaceOnUse"><rect width="${size}" height="${size}" fill="${color}" opacity="0.3"/><line x1="0" y1="${size / 2}" x2="${size}" y2="${size / 2}" stroke="${color}" stroke-width="1.5"/></pattern>`
79
+
80
+ case 'vertical':
81
+ return `<pattern id="${id}" width="${size}" height="${size}" patternUnits="userSpaceOnUse"><rect width="${size}" height="${size}" fill="${color}" opacity="0.3"/><line x1="${size / 2}" y1="0" x2="${size / 2}" y2="${size}" stroke="${color}" stroke-width="1.5"/></pattern>`
82
+
83
+ case 'zigzag':
84
+ return `<pattern id="${id}" width="${size}" height="${size}" patternUnits="userSpaceOnUse"><rect width="${size}" height="${size}" fill="${color}" opacity="0.3"/><polyline points="0,${size} ${size / 2},0 ${size},${size}" fill="none" stroke="${color}" stroke-width="1.5"/></pattern>`
85
+
86
+ case 'checker':
87
+ return `<pattern id="${id}" width="${size}" height="${size}" patternUnits="userSpaceOnUse"><rect width="${size}" height="${size}" fill="${color}" opacity="0.3"/><rect width="${size / 2}" height="${size / 2}" fill="${color}"/><rect x="${size / 2}" y="${size / 2}" width="${size / 2}" height="${size / 2}" fill="${color}"/></pattern>`
88
+ }
89
+ }
90
+
91
+ export const PATTERNS: PatternType[] = [
92
+ 'solid',
93
+ 'diagonal',
94
+ 'dots',
95
+ 'crosshatch',
96
+ 'horizontal',
97
+ 'vertical',
98
+ 'zigzag',
99
+ 'checker',
100
+ ]
@@ -0,0 +1,72 @@
1
+ export interface HistogramBin {
2
+ x0: number
3
+ x1: number
4
+ count: number
5
+ }
6
+
7
+ export function computeExtent(data: number[]): [number, number] {
8
+ let min = data[0]
9
+ let max = data[0]
10
+ for (let i = 1; i < data.length; i++) {
11
+ if (data[i] < min) min = data[i]
12
+ if (data[i] > max) max = data[i]
13
+ }
14
+ return [min, max]
15
+ }
16
+
17
+ export function computeMean(data: number[]): number {
18
+ let sum = 0
19
+ for (let i = 0; i < data.length; i++) {
20
+ sum += data[i]
21
+ }
22
+ return sum / data.length
23
+ }
24
+
25
+ export function computeHistogramBins(
26
+ data: number[],
27
+ binCount?: number,
28
+ ): HistogramBin[] {
29
+ const count = binCount ?? Math.ceil(Math.sqrt(data.length))
30
+ const [min, max] = computeExtent(data)
31
+ const span = max - min
32
+
33
+ // Handle case where all values are the same
34
+ if (span === 0) {
35
+ const bins: HistogramBin[] = []
36
+ for (let i = 0; i < count; i++) {
37
+ bins.push({ x0: min, x1: max, count: 0 })
38
+ }
39
+ // Put all items in the first bin
40
+ bins[0].count = data.length
41
+ return bins
42
+ }
43
+
44
+ const binWidth = span / count
45
+ const bins: HistogramBin[] = []
46
+ for (let i = 0; i < count; i++) {
47
+ bins.push({
48
+ x0: min + i * binWidth,
49
+ x1: min + (i + 1) * binWidth,
50
+ count: 0,
51
+ })
52
+ }
53
+
54
+ for (const value of data) {
55
+ let idx = Math.floor((value - min) / binWidth)
56
+ // Values at the max boundary go into the last bin
57
+ if (idx >= count) idx = count - 1
58
+ bins[idx].count++
59
+ }
60
+
61
+ return bins
62
+ }
63
+
64
+ export function normalizeData<T>(
65
+ data: T[],
66
+ accessor: string | ((d: T) => unknown),
67
+ ): unknown[] {
68
+ if (typeof accessor === 'string') {
69
+ return data.map((d) => (d as Record<string, unknown>)[accessor])
70
+ }
71
+ return data.map(accessor)
72
+ }