@refraction-ui/astro 0.4.2 → 0.4.4

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,10 @@
1
+ export {
2
+ createDeviceFrame,
3
+ type DeviceType,
4
+ type DeviceOrientation,
5
+ type DeviceFrameProps,
6
+ type DeviceDimensions,
7
+ type DeviceFrameAPI,
8
+ } from './device-frame.js'
9
+
10
+ export { deviceFrameVariants } from './device-frame.styles.js'
@@ -0,0 +1,8 @@
1
+ import { cva } from '../shared/index.ts'
2
+
3
+ export const overlayStyles =
4
+ 'fixed inset-0 z-50 bg-black/80'
5
+
6
+ export const dialogContentVariants = cva({
7
+ base: 'fixed left-1/2 top-1/2 z-50 grid w-full max-w-lg -translate-x-1/2 -translate-y-1/2 gap-4 border bg-background p-6 shadow-lg duration-200 sm:rounded-lg',
8
+ })
@@ -0,0 +1,133 @@
1
+ import type { AccessibilityProps, KeyboardHandlerMap, FocusTrapConfig } from '../shared/index.ts'
2
+ import { createMachine, Keys, generateId } from '../shared/index.ts'
3
+
4
+ export interface DialogProps {
5
+ /** Whether the dialog is open (controlled) */
6
+ open?: boolean
7
+ /** Whether the dialog starts open (uncontrolled) */
8
+ defaultOpen?: boolean
9
+ /** Callback when open state changes */
10
+ onOpenChange?: (open: boolean) => void
11
+ /** Whether the dialog is modal (default: true) */
12
+ modal?: boolean
13
+ }
14
+
15
+ export interface DialogState {
16
+ open: boolean
17
+ }
18
+
19
+ export interface DialogAPI {
20
+ /** Current dialog state */
21
+ state: DialogState
22
+ /** ARIA attributes for the trigger button */
23
+ triggerProps: Partial<AccessibilityProps> & Record<string, unknown>
24
+ /** ARIA attributes for the dialog content */
25
+ contentProps: Partial<AccessibilityProps> & Record<string, unknown>
26
+ /** Data attributes for the overlay */
27
+ overlayProps: Record<string, string>
28
+ /** Open the dialog */
29
+ open(): void
30
+ /** Close the dialog */
31
+ close(): void
32
+ /** Toggle the dialog */
33
+ toggle(): void
34
+ /** Keyboard handlers (Escape to close) */
35
+ keyboardHandlers: KeyboardHandlerMap
36
+ /** Generated IDs for aria linking */
37
+ ids: {
38
+ content: string
39
+ title: string
40
+ description: string
41
+ }
42
+ /**
43
+ * Focus trap configuration for framework wrappers.
44
+ * Pass this to createFocusTrap() with a container element.
45
+ */
46
+ focusTrapConfig: Omit<FocusTrapConfig, 'container'>
47
+ }
48
+
49
+ export function createDialog(props: DialogProps = {}): DialogAPI {
50
+ const { open: controlledOpen, defaultOpen = false, onOpenChange, modal = true } = props
51
+
52
+ const machine = createMachine<'open' | 'closed', 'OPEN' | 'CLOSE'>({
53
+ initial: controlledOpen ?? defaultOpen ? 'open' : 'closed',
54
+ states: {
55
+ closed: { on: { OPEN: 'open' } },
56
+ open: { on: { CLOSE: 'closed' } },
57
+ },
58
+ })
59
+
60
+ const contentId = generateId('rfr-dialog')
61
+ const titleId = generateId('rfr-dialog-title')
62
+ const descriptionId = generateId('rfr-dialog-desc')
63
+
64
+ function isOpen(): boolean {
65
+ if (controlledOpen !== undefined) return controlledOpen
66
+ return machine.matches('open')
67
+ }
68
+
69
+ function openDialog(): void {
70
+ machine.send('OPEN')
71
+ onOpenChange?.(true)
72
+ }
73
+
74
+ function closeDialog(): void {
75
+ machine.send('CLOSE')
76
+ onOpenChange?.(false)
77
+ }
78
+
79
+ function toggleDialog(): void {
80
+ if (isOpen()) {
81
+ closeDialog()
82
+ } else {
83
+ openDialog()
84
+ }
85
+ }
86
+
87
+ const keyboardHandlers: KeyboardHandlerMap = {
88
+ [Keys.Escape]: (e) => {
89
+ e.preventDefault()
90
+ closeDialog()
91
+ },
92
+ }
93
+
94
+ const triggerProps: Partial<AccessibilityProps> & Record<string, unknown> = {
95
+ 'aria-expanded': isOpen(),
96
+ 'aria-controls': contentId,
97
+ 'aria-haspopup': 'dialog',
98
+ }
99
+
100
+ const contentProps: Partial<AccessibilityProps> & Record<string, unknown> = {
101
+ role: 'dialog',
102
+ 'aria-modal': modal,
103
+ 'aria-labelledby': titleId,
104
+ 'aria-describedby': descriptionId,
105
+ id: contentId,
106
+ }
107
+
108
+ const overlayProps: Record<string, string> = {
109
+ 'data-state': isOpen() ? 'open' : 'closed',
110
+ }
111
+
112
+ const focusTrapConfig: Omit<FocusTrapConfig, 'container'> = {
113
+ onEscape: closeDialog,
114
+ returnFocusOnDeactivate: true,
115
+ }
116
+
117
+ return {
118
+ state: { open: isOpen() },
119
+ triggerProps,
120
+ contentProps,
121
+ overlayProps,
122
+ open: openDialog,
123
+ close: closeDialog,
124
+ toggle: toggleDialog,
125
+ keyboardHandlers,
126
+ ids: {
127
+ content: contentId,
128
+ title: titleId,
129
+ description: descriptionId,
130
+ },
131
+ focusTrapConfig,
132
+ }
133
+ }
@@ -0,0 +1,8 @@
1
+ export {
2
+ createDialog,
3
+ type DialogProps,
4
+ type DialogAPI,
5
+ type DialogState,
6
+ } from './dialog.js'
7
+
8
+ export { overlayStyles, dialogContentVariants } from './dialog.styles.js'
@@ -0,0 +1,124 @@
1
+ import { cva } from '../shared/index.ts'
2
+ import type { TokenContract } from '../shared/index.ts'
3
+
4
+ export const diffViewerTokens: TokenContract = {
5
+ name: 'diff-viewer',
6
+ tokens: {
7
+ bg: { variable: '--rfr-diff-bg', fallback: 'hsl(var(--background))' },
8
+ fg: { variable: '--rfr-diff-fg', fallback: 'hsl(var(--foreground))' },
9
+ sidebarBg: { variable: '--rfr-diff-sidebar-bg', fallback: 'hsl(var(--muted))' },
10
+ headerBg: { variable: '--rfr-diff-header-bg', fallback: 'hsl(var(--muted))' },
11
+ border: { variable: '--rfr-diff-border', fallback: 'hsl(var(--border))' },
12
+ addBg: { variable: '--rfr-diff-add-bg', fallback: 'rgba(46, 160, 67, 0.15)' },
13
+ delBg: { variable: '--rfr-diff-del-bg', fallback: 'rgba(248, 81, 73, 0.15)' },
14
+ addFg: { variable: '--rfr-diff-add-fg', fallback: '#3fb950' },
15
+ delFg: { variable: '--rfr-diff-del-fg', fallback: '#f85149' },
16
+ statusbar: { variable: '--rfr-diff-statusbar', fallback: 'hsl(var(--primary))' },
17
+ statusbarFg: { variable: '--rfr-diff-statusbar-fg', fallback: 'hsl(var(--primary-foreground))' },
18
+ },
19
+ }
20
+
21
+ export const diffViewerVariants = cva({
22
+ base: 'flex flex-col overflow-hidden font-sans text-sm',
23
+ variants: {
24
+ theme: {
25
+ light: 'bg-white text-gray-900',
26
+ dark: 'bg-gray-950 text-gray-100',
27
+ },
28
+ fullscreen: {
29
+ 'true': 'h-screen',
30
+ 'false': '',
31
+ },
32
+ },
33
+ defaultVariants: {
34
+ theme: 'dark',
35
+ fullscreen: 'true',
36
+ },
37
+ })
38
+
39
+ export const sidebarVariants = cva({
40
+ base: 'border-r overflow-auto flex-shrink-0',
41
+ variants: {
42
+ theme: {
43
+ light: 'bg-gray-50 border-gray-200',
44
+ dark: 'bg-gray-900 border-gray-800',
45
+ },
46
+ },
47
+ defaultVariants: {
48
+ theme: 'dark',
49
+ },
50
+ })
51
+
52
+ export const sidebarItemVariants = cva({
53
+ base: 'px-2.5 py-1 cursor-pointer text-xs font-mono transition-colors',
54
+ variants: {
55
+ active: {
56
+ 'true': 'border-l-2 border-blue-500',
57
+ 'false': 'border-l-2 border-transparent',
58
+ },
59
+ theme: {
60
+ light: '',
61
+ dark: '',
62
+ },
63
+ },
64
+ compoundVariants: [
65
+ { active: 'true', theme: 'dark', class: 'bg-gray-800 text-gray-100' },
66
+ { active: 'false', theme: 'dark', class: 'text-gray-400 hover:bg-gray-800/50' },
67
+ { active: 'true', theme: 'light', class: 'bg-blue-50 text-gray-900' },
68
+ { active: 'false', theme: 'light', class: 'text-gray-600 hover:bg-gray-100' },
69
+ ],
70
+ defaultVariants: {
71
+ active: 'false',
72
+ theme: 'dark',
73
+ },
74
+ })
75
+
76
+ export const tabBarVariants = cva({
77
+ base: 'flex items-center border-b overflow-auto flex-shrink-0',
78
+ variants: {
79
+ theme: {
80
+ light: 'bg-gray-50 border-gray-200',
81
+ dark: 'bg-gray-900 border-gray-800',
82
+ },
83
+ },
84
+ defaultVariants: {
85
+ theme: 'dark',
86
+ },
87
+ })
88
+
89
+ export const tabVariants = cva({
90
+ base: 'px-3 h-[35px] flex items-center gap-1 cursor-pointer text-xs font-mono border-r shrink-0',
91
+ variants: {
92
+ active: {
93
+ 'true': '',
94
+ 'false': '',
95
+ },
96
+ theme: {
97
+ light: 'border-gray-200',
98
+ dark: 'border-gray-800',
99
+ },
100
+ },
101
+ compoundVariants: [
102
+ { active: 'true', theme: 'dark', class: 'bg-gray-950 text-gray-100 border-b-gray-950 -mb-px' },
103
+ { active: 'false', theme: 'dark', class: 'text-gray-400' },
104
+ { active: 'true', theme: 'light', class: 'bg-white text-gray-900 border-b-white -mb-px' },
105
+ { active: 'false', theme: 'light', class: 'text-gray-500' },
106
+ ],
107
+ defaultVariants: {
108
+ active: 'false',
109
+ theme: 'dark',
110
+ },
111
+ })
112
+
113
+ export const statusBarVariants = cva({
114
+ base: 'h-[22px] flex items-center px-2.5 gap-3 text-[11px] font-mono flex-shrink-0',
115
+ variants: {
116
+ theme: {
117
+ light: 'bg-blue-600 text-white',
118
+ dark: 'bg-blue-700 text-white',
119
+ },
120
+ },
121
+ defaultVariants: {
122
+ theme: 'dark',
123
+ },
124
+ })
@@ -0,0 +1,255 @@
1
+ import type { AccessibilityProps } from '../shared/index.ts'
2
+
3
+ // ---------------------------------------------------------------------------
4
+ // Types
5
+ // ---------------------------------------------------------------------------
6
+
7
+ export type DiffViewerTheme = 'light' | 'dark'
8
+ export type DiffViewMode = 'side-by-side' | 'inline'
9
+
10
+ export type DiffFileStatus = 'added' | 'modified' | 'deleted' | 'renamed'
11
+
12
+ export interface DiffFile {
13
+ /** File path */
14
+ path: string
15
+ /** Change status */
16
+ status: DiffFileStatus
17
+ /** Lines added */
18
+ additions: number
19
+ /** Lines deleted */
20
+ deletions: number
21
+ /** Unified diff content for this file */
22
+ diff?: string
23
+ /** Old path for renamed files */
24
+ oldPath?: string
25
+ }
26
+
27
+ export interface DiffViewerProps {
28
+ /** Files in this diff */
29
+ files?: DiffFile[]
30
+ /** Index of the active file */
31
+ activeFileIndex?: number
32
+ /** View mode */
33
+ viewMode?: DiffViewMode
34
+ /** Theme */
35
+ theme?: DiffViewerTheme
36
+ /** Language for syntax highlighting */
37
+ language?: string
38
+ /** Whether the sidebar is visible */
39
+ sidebarOpen?: boolean
40
+ /** Callback when active file changes */
41
+ onFileSelect?: (index: number) => void
42
+ /** Callback when view mode changes */
43
+ onViewModeChange?: (mode: DiffViewMode) => void
44
+ /** Callback when sidebar toggled */
45
+ onSidebarToggle?: () => void
46
+ }
47
+
48
+ export interface DiffViewerState {
49
+ activeFileIndex: number
50
+ viewMode: DiffViewMode
51
+ theme: DiffViewerTheme
52
+ language: string
53
+ sidebarOpen: boolean
54
+ files: DiffFile[]
55
+ }
56
+
57
+ export interface DiffViewerAPI {
58
+ /** Current viewer state */
59
+ state: DiffViewerState
60
+ /** ARIA attributes for the root element */
61
+ ariaProps: Partial<AccessibilityProps> & Record<string, unknown>
62
+ /** Data attributes for CSS styling hooks */
63
+ dataAttributes: Record<string, string>
64
+ /** Select a file by index */
65
+ selectFile: (index: number) => void
66
+ /** Move to next file */
67
+ nextFile: () => void
68
+ /** Move to previous file */
69
+ prevFile: () => void
70
+ /** Toggle view mode */
71
+ toggleViewMode: () => void
72
+ /** Toggle sidebar */
73
+ toggleSidebar: () => void
74
+ /** Get language label for a file path */
75
+ getLanguageForFile: (path: string) => string
76
+ /** Get human-readable file status icon */
77
+ getFileStatusIcon: (status: DiffFileStatus) => string
78
+ /** Get total additions across all files */
79
+ totalAdditions: () => number
80
+ /** Get total deletions across all files */
81
+ totalDeletions: () => number
82
+ }
83
+
84
+ // ---------------------------------------------------------------------------
85
+ // Language detection
86
+ // ---------------------------------------------------------------------------
87
+
88
+ const extToLanguage: Record<string, string> = {
89
+ ts: 'typescript',
90
+ tsx: 'typescript',
91
+ js: 'javascript',
92
+ jsx: 'javascript',
93
+ py: 'python',
94
+ go: 'go',
95
+ rs: 'rust',
96
+ rb: 'ruby',
97
+ java: 'java',
98
+ swift: 'swift',
99
+ kt: 'kotlin',
100
+ dart: 'dart',
101
+ php: 'php',
102
+ lua: 'lua',
103
+ r: 'r',
104
+ scala: 'scala',
105
+ json: 'json',
106
+ yaml: 'yaml',
107
+ yml: 'yaml',
108
+ md: 'markdown',
109
+ html: 'html',
110
+ css: 'css',
111
+ scss: 'scss',
112
+ sql: 'sql',
113
+ sh: 'shell',
114
+ bash: 'shell',
115
+ zsh: 'shell',
116
+ xml: 'xml',
117
+ toml: 'toml',
118
+ proto: 'protobuf',
119
+ dockerfile: 'dockerfile',
120
+ cpp: 'cpp',
121
+ c: 'c',
122
+ }
123
+
124
+ function getLanguageForFile(filePath: string): string {
125
+ const ext = filePath.split('.').pop()?.toLowerCase() || ''
126
+ const basename = filePath.split('/').pop()?.toLowerCase() || ''
127
+ if (basename === 'dockerfile') return 'dockerfile'
128
+ return extToLanguage[ext] || 'plaintext'
129
+ }
130
+
131
+ // ---------------------------------------------------------------------------
132
+ // Status icons
133
+ // ---------------------------------------------------------------------------
134
+
135
+ const statusIcons: Record<DiffFileStatus, string> = {
136
+ added: '\u{1F7E2}', // green circle
137
+ modified: '\u{1F7E1}', // yellow circle
138
+ deleted: '\u{1F534}', // red circle
139
+ renamed: '\u{1F535}', // blue circle
140
+ }
141
+
142
+ // ---------------------------------------------------------------------------
143
+ // Factory
144
+ // ---------------------------------------------------------------------------
145
+
146
+ /**
147
+ * Create a headless diff viewer API.
148
+ *
149
+ * Manages file selection, view mode, sidebar state, and produces ARIA/data
150
+ * attributes. The actual rendering (Monaco DiffEditor, custom renderer, etc.)
151
+ * is handled by framework-specific wrappers.
152
+ */
153
+ export function createDiffViewer(props: DiffViewerProps = {}): DiffViewerAPI {
154
+ const {
155
+ files = [],
156
+ activeFileIndex = 0,
157
+ viewMode = 'side-by-side',
158
+ theme = 'dark',
159
+ language,
160
+ sidebarOpen = true,
161
+ onFileSelect,
162
+ onViewModeChange,
163
+ onSidebarToggle,
164
+ } = props
165
+
166
+ let currentIndex = Math.min(activeFileIndex, Math.max(0, files.length - 1))
167
+ let currentViewMode = viewMode
168
+ let currentSidebarOpen = sidebarOpen
169
+
170
+ const state: DiffViewerState = {
171
+ activeFileIndex: currentIndex,
172
+ viewMode: currentViewMode,
173
+ theme,
174
+ language: language || (files[currentIndex] ? getLanguageForFile(files[currentIndex].path) : 'plaintext'),
175
+ sidebarOpen: currentSidebarOpen,
176
+ files,
177
+ }
178
+
179
+ const ariaProps: Partial<AccessibilityProps> & Record<string, unknown> = {
180
+ role: 'region',
181
+ 'aria-label': 'Diff viewer',
182
+ }
183
+
184
+ const dataAttributes: Record<string, string> = {
185
+ 'data-view-mode': currentViewMode,
186
+ 'data-theme': theme,
187
+ 'data-file-count': String(files.length),
188
+ }
189
+
190
+ if (!currentSidebarOpen) {
191
+ dataAttributes['data-sidebar-collapsed'] = ''
192
+ }
193
+
194
+ function selectFile(index: number) {
195
+ if (index >= 0 && index < files.length) {
196
+ currentIndex = index
197
+ state.activeFileIndex = index
198
+ state.language = language || getLanguageForFile(files[index].path)
199
+ onFileSelect?.(index)
200
+ }
201
+ }
202
+
203
+ function nextFile() {
204
+ if (currentIndex < files.length - 1) {
205
+ selectFile(currentIndex + 1)
206
+ }
207
+ }
208
+
209
+ function prevFile() {
210
+ if (currentIndex > 0) {
211
+ selectFile(currentIndex - 1)
212
+ }
213
+ }
214
+
215
+ function toggleViewMode() {
216
+ currentViewMode = currentViewMode === 'side-by-side' ? 'inline' : 'side-by-side'
217
+ state.viewMode = currentViewMode
218
+ dataAttributes['data-view-mode'] = currentViewMode
219
+ onViewModeChange?.(currentViewMode)
220
+ }
221
+
222
+ function toggleSidebar() {
223
+ currentSidebarOpen = !currentSidebarOpen
224
+ state.sidebarOpen = currentSidebarOpen
225
+ if (currentSidebarOpen) {
226
+ delete dataAttributes['data-sidebar-collapsed']
227
+ } else {
228
+ dataAttributes['data-sidebar-collapsed'] = ''
229
+ }
230
+ onSidebarToggle?.()
231
+ }
232
+
233
+ function totalAdditions(): number {
234
+ return files.reduce((sum, f) => sum + f.additions, 0)
235
+ }
236
+
237
+ function totalDeletions(): number {
238
+ return files.reduce((sum, f) => sum + f.deletions, 0)
239
+ }
240
+
241
+ return {
242
+ state,
243
+ ariaProps,
244
+ dataAttributes,
245
+ selectFile,
246
+ nextFile,
247
+ prevFile,
248
+ toggleViewMode,
249
+ toggleSidebar,
250
+ getLanguageForFile,
251
+ getFileStatusIcon: (status: DiffFileStatus) => statusIcons[status] || '\u{26AA}',
252
+ totalAdditions,
253
+ totalDeletions,
254
+ }
255
+ }
@@ -0,0 +1,20 @@
1
+ export {
2
+ createDiffViewer,
3
+ type DiffViewerProps,
4
+ type DiffViewerAPI,
5
+ type DiffViewerState,
6
+ type DiffViewerTheme,
7
+ type DiffViewMode,
8
+ type DiffFile,
9
+ type DiffFileStatus,
10
+ } from './diff-viewer.js'
11
+
12
+ export {
13
+ diffViewerTokens,
14
+ diffViewerVariants,
15
+ sidebarVariants,
16
+ sidebarItemVariants,
17
+ tabBarVariants,
18
+ tabVariants,
19
+ statusBarVariants,
20
+ } from './diff-viewer.styles.js'
@@ -0,0 +1,9 @@
1
+ import { cva } from '../shared/index.ts'
2
+
3
+ export const menuContentVariants = cva({
4
+ base: 'z-50 rounded-md border bg-popover shadow-md',
5
+ })
6
+
7
+ export const menuItemVariants = cva({
8
+ base: 'relative flex cursor-default items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
9
+ })