@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,183 @@
1
+ import type { AccessibilityProps } from '../shared/index.ts'
2
+
3
+ export interface ColumnDef<T = Record<string, unknown>> {
4
+ /** Unique column identifier */
5
+ id: string
6
+ /** Column header text */
7
+ header: string
8
+ /** Accessor function to get cell value from row */
9
+ accessor: (row: T) => unknown
10
+ /** Whether this column is sortable */
11
+ sortable?: boolean
12
+ /** Whether this column is filterable */
13
+ filterable?: boolean
14
+ }
15
+
16
+ export type SortDirection = 'asc' | 'desc'
17
+
18
+ export interface DataTableProps<T = Record<string, unknown>> {
19
+ /** Column definitions */
20
+ columns: ColumnDef<T>[]
21
+ /** Data rows */
22
+ data: T[]
23
+ /** Current sort column */
24
+ sortBy?: string
25
+ /** Current sort direction */
26
+ sortDir?: SortDirection
27
+ /** Callback when sort changes */
28
+ onSort?: (columnId: string, direction: SortDirection) => void
29
+ /** Active filters: columnId -> filter value */
30
+ filters?: Record<string, string>
31
+ }
32
+
33
+ export interface DataTableState<T = Record<string, unknown>> {
34
+ sortedData: T[]
35
+ sortBy: string | null
36
+ sortDir: SortDirection
37
+ filters: Record<string, string>
38
+ }
39
+
40
+ export interface DataTableAPI<T = Record<string, unknown>> {
41
+ /** Current table state */
42
+ state: DataTableState<T>
43
+ /** Toggle sort for a column */
44
+ sort(columnId: string): void
45
+ /** Set a filter value for a column */
46
+ setFilter(columnId: string, value: string): void
47
+ /** Get ARIA and role props for a header cell */
48
+ getHeaderProps(col: ColumnDef<T>): Partial<AccessibilityProps> & Record<string, unknown>
49
+ /** Get props for a data cell */
50
+ getCellProps(col: ColumnDef<T>, row: T): Record<string, unknown>
51
+ /** Get props for a data row */
52
+ getRowProps(row: T, index: number): Record<string, unknown>
53
+ }
54
+
55
+ export function createDataTable<T = Record<string, unknown>>(
56
+ props: DataTableProps<T>,
57
+ ): DataTableAPI<T> {
58
+ const {
59
+ columns,
60
+ data,
61
+ sortBy: initialSortBy,
62
+ sortDir: initialSortDir = 'asc',
63
+ onSort,
64
+ filters: initialFilters,
65
+ } = props
66
+
67
+ let sortBy: string | null = initialSortBy ?? null
68
+ let sortDir: SortDirection = initialSortDir
69
+ let filters: Record<string, string> = { ...(initialFilters ?? {}) }
70
+
71
+ function getFilteredData(): T[] {
72
+ let result = [...data]
73
+
74
+ for (const [columnId, filterValue] of Object.entries(filters)) {
75
+ if (!filterValue) continue
76
+ const col = columns.find((c) => c.id === columnId)
77
+ if (!col) continue
78
+ const lowerFilter = filterValue.toLowerCase()
79
+ result = result.filter((row) => {
80
+ const cellValue = col.accessor(row)
81
+ return String(cellValue ?? '').toLowerCase().includes(lowerFilter)
82
+ })
83
+ }
84
+
85
+ return result
86
+ }
87
+
88
+ function getSortedData(): T[] {
89
+ const filtered = getFilteredData()
90
+
91
+ if (!sortBy) return filtered
92
+
93
+ const col = columns.find((c) => c.id === sortBy)
94
+ if (!col) return filtered
95
+
96
+ return [...filtered].sort((a, b) => {
97
+ const aVal = col.accessor(a)
98
+ const bVal = col.accessor(b)
99
+ const aStr = String(aVal ?? '')
100
+ const bStr = String(bVal ?? '')
101
+
102
+ const cmp = aStr.localeCompare(bStr, undefined, { numeric: true })
103
+ return sortDir === 'asc' ? cmp : -cmp
104
+ })
105
+ }
106
+
107
+ function sort(columnId: string): void {
108
+ const col = columns.find((c) => c.id === columnId)
109
+ if (!col?.sortable) return
110
+
111
+ if (sortBy === columnId) {
112
+ sortDir = sortDir === 'asc' ? 'desc' : 'asc'
113
+ } else {
114
+ sortBy = columnId
115
+ sortDir = 'asc'
116
+ }
117
+
118
+ onSort?.(sortBy, sortDir)
119
+ }
120
+
121
+ function setFilter(columnId: string, value: string): void {
122
+ filters = { ...filters, [columnId]: value }
123
+ }
124
+
125
+ function getHeaderProps(
126
+ col: ColumnDef<T>,
127
+ ): Partial<AccessibilityProps> & Record<string, unknown> {
128
+ const props: Partial<AccessibilityProps> & Record<string, unknown> = {
129
+ role: 'columnheader',
130
+ }
131
+
132
+ if (col.sortable) {
133
+ if (sortBy === col.id) {
134
+ props['aria-sort'] = sortDir === 'asc' ? 'ascending' : 'descending'
135
+ } else {
136
+ props['aria-sort'] = 'none'
137
+ }
138
+ }
139
+
140
+ return props
141
+ }
142
+
143
+ function getCellProps(
144
+ col: ColumnDef<T>,
145
+ _row: T,
146
+ ): Record<string, unknown> {
147
+ return {
148
+ role: 'cell',
149
+ 'data-column': col.id,
150
+ }
151
+ }
152
+
153
+ function getRowProps(_row: T, index: number): Record<string, unknown> {
154
+ return {
155
+ role: 'row',
156
+ 'data-row-index': index,
157
+ }
158
+ }
159
+
160
+ return {
161
+ get state(): DataTableState<T> {
162
+ return {
163
+ get sortedData() {
164
+ return getSortedData()
165
+ },
166
+ get sortBy() {
167
+ return sortBy
168
+ },
169
+ get sortDir() {
170
+ return sortDir
171
+ },
172
+ get filters() {
173
+ return { ...filters }
174
+ },
175
+ }
176
+ },
177
+ sort,
178
+ setFilter,
179
+ getHeaderProps,
180
+ getCellProps,
181
+ getRowProps,
182
+ }
183
+ }
@@ -0,0 +1,15 @@
1
+ export {
2
+ createDataTable,
3
+ type ColumnDef,
4
+ type SortDirection,
5
+ type DataTableProps,
6
+ type DataTableState,
7
+ type DataTableAPI,
8
+ } from './data-table.js'
9
+
10
+ export {
11
+ tableVariants,
12
+ headerVariants,
13
+ cellVariants,
14
+ rowVariants,
15
+ } from './data-table.styles.js'
@@ -0,0 +1,31 @@
1
+ import { cva } from '../shared/index.ts'
2
+
3
+ export const datePickerTriggerStyles =
4
+ 'inline-flex items-center gap-2 rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring cursor-pointer'
5
+
6
+ export const datePickerDropdownStyles =
7
+ 'absolute z-50 mt-1 rounded-md border bg-popover p-4 text-popover-foreground shadow-md'
8
+
9
+ export const datePickerGridStyles = 'w-full border-collapse'
10
+
11
+ export const datePickerDayVariants = cva({
12
+ base: 'inline-flex h-8 w-8 items-center justify-center rounded-md text-sm cursor-pointer hover:bg-accent hover:text-accent-foreground',
13
+ variants: {
14
+ state: {
15
+ default: '',
16
+ selected: 'bg-primary text-primary-foreground hover:bg-primary/90',
17
+ today: 'border border-accent-foreground',
18
+ disabled: 'text-muted-foreground opacity-50 pointer-events-none',
19
+ outside: 'text-muted-foreground opacity-30',
20
+ },
21
+ },
22
+ defaultVariants: {
23
+ state: 'default',
24
+ },
25
+ })
26
+
27
+ export const datePickerTimeStyles =
28
+ 'flex items-center gap-2 mt-3 pt-3 border-t'
29
+
30
+ export const datePickerTimeInputStyles =
31
+ 'w-14 rounded-md border border-input bg-background px-2 py-1 text-sm text-center'
@@ -0,0 +1,333 @@
1
+ import type { AccessibilityProps, KeyboardHandlerMap } from '../shared/index.ts'
2
+ import { generateId, Keys } from '../shared/index.ts'
3
+
4
+ export type DatePickerView = 'calendar' | 'time'
5
+
6
+ export interface DatePickerProps {
7
+ /** Selected date (controlled) */
8
+ value?: Date
9
+ /** Callback when value changes */
10
+ onChange?: (date: Date) => void
11
+ /** Minimum selectable date */
12
+ minDate?: Date
13
+ /** Maximum selectable date */
14
+ maxDate?: Date
15
+ /** Show time selection */
16
+ showTime?: boolean
17
+ /** Display format string */
18
+ format?: string
19
+ /** Placeholder text */
20
+ placeholder?: string
21
+ /** Whether the picker is open (controlled) */
22
+ open?: boolean
23
+ /** Default open state */
24
+ defaultOpen?: boolean
25
+ /** Callback when open changes */
26
+ onOpenChange?: (open: boolean) => void
27
+ }
28
+
29
+ export interface DatePickerState {
30
+ open: boolean
31
+ selectedDate: Date | undefined
32
+ view: DatePickerView
33
+ hours: number
34
+ minutes: number
35
+ currentMonth: Date
36
+ }
37
+
38
+ export interface CalendarDay {
39
+ date: Date
40
+ isToday: boolean
41
+ isSelected: boolean
42
+ isCurrentMonth: boolean
43
+ isDisabled: boolean
44
+ }
45
+
46
+ export interface DatePickerAPI {
47
+ /** Current state */
48
+ state: DatePickerState
49
+ /** Calendar days grid (42 cells) */
50
+ days: CalendarDay[]
51
+ /** Open the picker */
52
+ openPicker(): void
53
+ /** Close the picker */
54
+ closePicker(): void
55
+ /** Toggle the picker */
56
+ togglePicker(): void
57
+ /** Select a date from calendar */
58
+ selectDate(date: Date): void
59
+ /** Set hours */
60
+ setHours(hours: number): void
61
+ /** Set minutes */
62
+ setMinutes(minutes: number): void
63
+ /** Navigate to previous month */
64
+ prevMonth(): void
65
+ /** Navigate to next month */
66
+ nextMonth(): void
67
+ /** Switch between calendar and time views */
68
+ setView(view: DatePickerView): void
69
+ /** Format the selected date for display */
70
+ formatDisplay(): string
71
+ /** ARIA attributes for the trigger input */
72
+ triggerProps: Partial<AccessibilityProps> & Record<string, unknown>
73
+ /** ARIA attributes for the dropdown */
74
+ dropdownProps: Partial<AccessibilityProps> & Record<string, unknown>
75
+ /** ARIA props for the calendar grid */
76
+ gridProps: Partial<AccessibilityProps> & Record<string, unknown>
77
+ /** Get ARIA props for a day cell */
78
+ getDayAriaProps(day: CalendarDay): Partial<AccessibilityProps> & Record<string, unknown>
79
+ /** Keyboard handlers */
80
+ keyboardHandlers: KeyboardHandlerMap
81
+ /** Generated IDs */
82
+ ids: {
83
+ trigger: string
84
+ dropdown: string
85
+ grid: string
86
+ label: string
87
+ }
88
+ }
89
+
90
+ function isSameDay(a: Date, b: Date): boolean {
91
+ return (
92
+ a.getFullYear() === b.getFullYear() &&
93
+ a.getMonth() === b.getMonth() &&
94
+ a.getDate() === b.getDate()
95
+ )
96
+ }
97
+
98
+ function startOfMonth(date: Date): Date {
99
+ return new Date(date.getFullYear(), date.getMonth(), 1)
100
+ }
101
+
102
+ function startOfDay(date: Date): Date {
103
+ return new Date(date.getFullYear(), date.getMonth(), date.getDate())
104
+ }
105
+
106
+ function endOfDay(date: Date): Date {
107
+ return new Date(date.getFullYear(), date.getMonth(), date.getDate(), 23, 59, 59, 999)
108
+ }
109
+
110
+ const DAY_NAMES = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']
111
+
112
+ function padZero(n: number): string {
113
+ return n < 10 ? `0${n}` : `${n}`
114
+ }
115
+
116
+ export function formatDate(date: Date | undefined, format: string, showTime: boolean): string {
117
+ if (!date) return ''
118
+ const year = date.getFullYear()
119
+ const month = padZero(date.getMonth() + 1)
120
+ const day = padZero(date.getDate())
121
+ const hours = padZero(date.getHours())
122
+ const minutes = padZero(date.getMinutes())
123
+
124
+ let result = format
125
+ .replace('YYYY', String(year))
126
+ .replace('MM', month)
127
+ .replace('DD', day)
128
+
129
+ if (showTime) {
130
+ result = result.replace('HH', hours).replace('mm', minutes)
131
+ }
132
+
133
+ return result
134
+ }
135
+
136
+ export function createDatePicker(props: DatePickerProps = {}): DatePickerAPI {
137
+ const {
138
+ value,
139
+ onChange,
140
+ minDate,
141
+ maxDate,
142
+ showTime = false,
143
+ format = showTime ? 'YYYY-MM-DD HH:mm' : 'YYYY-MM-DD',
144
+ placeholder = 'Select date...',
145
+ open: controlledOpen,
146
+ defaultOpen = false,
147
+ onOpenChange,
148
+ } = props
149
+
150
+ const today = new Date()
151
+ let internalOpen = controlledOpen ?? defaultOpen
152
+ let currentMonth = value ? startOfMonth(value) : startOfMonth(today)
153
+ let view: DatePickerView = 'calendar'
154
+ const hours = value ? value.getHours() : 0
155
+ const minutes = value ? value.getMinutes() : 0
156
+
157
+ const triggerId = generateId('rfr-datepicker-trigger')
158
+ const dropdownId = generateId('rfr-datepicker-dropdown')
159
+ const gridId = generateId('rfr-datepicker-grid')
160
+ const labelId = generateId('rfr-datepicker-label')
161
+
162
+ function isOpen(): boolean {
163
+ if (controlledOpen !== undefined) return controlledOpen
164
+ return internalOpen
165
+ }
166
+
167
+ function isDateDisabled(date: Date): boolean {
168
+ if (minDate && date < startOfDay(minDate)) return true
169
+ if (maxDate && date > endOfDay(maxDate)) return true
170
+ return false
171
+ }
172
+
173
+ function buildDays(): CalendarDay[] {
174
+ const year = currentMonth.getFullYear()
175
+ const month = currentMonth.getMonth()
176
+ const first = new Date(year, month, 1)
177
+ const startDow = first.getDay()
178
+ const gridStart = new Date(year, month, 1 - startDow)
179
+
180
+ const days: CalendarDay[] = []
181
+ for (let i = 0; i < 42; i++) {
182
+ const date = new Date(
183
+ gridStart.getFullYear(),
184
+ gridStart.getMonth(),
185
+ gridStart.getDate() + i,
186
+ )
187
+ days.push({
188
+ date,
189
+ isToday: isSameDay(date, today),
190
+ isSelected: value ? isSameDay(date, value) : false,
191
+ isCurrentMonth: date.getMonth() === month,
192
+ isDisabled: isDateDisabled(date),
193
+ })
194
+ }
195
+ return days
196
+ }
197
+
198
+ function openPicker(): void {
199
+ internalOpen = true
200
+ onOpenChange?.(true)
201
+ }
202
+
203
+ function closePicker(): void {
204
+ internalOpen = false
205
+ onOpenChange?.(false)
206
+ }
207
+
208
+ function togglePicker(): void {
209
+ if (isOpen()) {
210
+ closePicker()
211
+ } else {
212
+ openPicker()
213
+ }
214
+ }
215
+
216
+ function selectDate(date: Date): void {
217
+ if (isDateDisabled(date)) return
218
+ const newDate = new Date(date)
219
+ if (value) {
220
+ newDate.setHours(value.getHours())
221
+ newDate.setMinutes(value.getMinutes())
222
+ }
223
+ onChange?.(newDate)
224
+ if (!showTime) {
225
+ closePicker()
226
+ }
227
+ }
228
+
229
+ function setHours(h: number): void {
230
+ if (h < 0 || h > 23) return
231
+ const newDate = value ? new Date(value) : new Date()
232
+ newDate.setHours(h)
233
+ onChange?.(newDate)
234
+ }
235
+
236
+ function setMinutes(m: number): void {
237
+ if (m < 0 || m > 59) return
238
+ const newDate = value ? new Date(value) : new Date()
239
+ newDate.setMinutes(m)
240
+ onChange?.(newDate)
241
+ }
242
+
243
+ function prevMonth(): void {
244
+ currentMonth = new Date(currentMonth.getFullYear(), currentMonth.getMonth() - 1, 1)
245
+ }
246
+
247
+ function nextMonth(): void {
248
+ currentMonth = new Date(currentMonth.getFullYear(), currentMonth.getMonth() + 1, 1)
249
+ }
250
+
251
+ function setView(v: DatePickerView): void {
252
+ view = v
253
+ }
254
+
255
+ function formatDisplay(): string {
256
+ return value ? formatDate(value, format, showTime) : placeholder
257
+ }
258
+
259
+ const keyboardHandlers: KeyboardHandlerMap = {
260
+ [Keys.Escape]: (e) => {
261
+ e.preventDefault()
262
+ closePicker()
263
+ },
264
+ }
265
+
266
+ const triggerProps: Partial<AccessibilityProps> & Record<string, unknown> = {
267
+ 'aria-expanded': isOpen(),
268
+ 'aria-controls': dropdownId,
269
+ 'aria-haspopup': 'dialog',
270
+ id: triggerId,
271
+ role: 'combobox',
272
+ }
273
+
274
+ const dropdownProps: Partial<AccessibilityProps> & Record<string, unknown> = {
275
+ role: 'dialog',
276
+ 'aria-modal': true,
277
+ 'aria-labelledby': labelId,
278
+ id: dropdownId,
279
+ }
280
+
281
+ const gridProps: Partial<AccessibilityProps> & Record<string, unknown> = {
282
+ role: 'grid',
283
+ 'aria-labelledby': labelId,
284
+ id: gridId,
285
+ }
286
+
287
+ function getDayAriaProps(day: CalendarDay): Partial<AccessibilityProps> & Record<string, unknown> {
288
+ return {
289
+ role: 'gridcell',
290
+ 'aria-selected': day.isSelected,
291
+ 'aria-disabled': day.isDisabled,
292
+ 'aria-current': day.isToday ? ('date' as const) : undefined,
293
+ 'aria-label': `${DAY_NAMES[day.date.getDay()]}, ${day.date.toLocaleDateString('en-US', {
294
+ month: 'long',
295
+ day: 'numeric',
296
+ year: 'numeric',
297
+ })}`,
298
+ }
299
+ }
300
+
301
+ return {
302
+ state: {
303
+ open: isOpen(),
304
+ selectedDate: value,
305
+ view,
306
+ hours,
307
+ minutes,
308
+ currentMonth,
309
+ },
310
+ days: buildDays(),
311
+ openPicker,
312
+ closePicker,
313
+ togglePicker,
314
+ selectDate,
315
+ setHours,
316
+ setMinutes,
317
+ prevMonth,
318
+ nextMonth,
319
+ setView,
320
+ formatDisplay,
321
+ triggerProps,
322
+ dropdownProps,
323
+ gridProps,
324
+ getDayAriaProps,
325
+ keyboardHandlers,
326
+ ids: {
327
+ trigger: triggerId,
328
+ dropdown: dropdownId,
329
+ grid: gridId,
330
+ label: labelId,
331
+ },
332
+ }
333
+ }
@@ -0,0 +1,18 @@
1
+ export {
2
+ createDatePicker,
3
+ formatDate,
4
+ type DatePickerProps,
5
+ type DatePickerState,
6
+ type DatePickerView,
7
+ type DatePickerAPI,
8
+ type CalendarDay,
9
+ } from './date-picker.js'
10
+
11
+ export {
12
+ datePickerTriggerStyles,
13
+ datePickerDropdownStyles,
14
+ datePickerGridStyles,
15
+ datePickerDayVariants,
16
+ datePickerTimeStyles,
17
+ datePickerTimeInputStyles,
18
+ } from './date-picker.styles.js'
@@ -0,0 +1,21 @@
1
+ import { cva } from '../shared/index.ts'
2
+
3
+ export const deviceFrameVariants = cva({
4
+ base: 'relative overflow-hidden bg-black border-4 border-gray-800 shadow-xl',
5
+ variants: {
6
+ device: {
7
+ iphone: 'rounded-[44px] border-[6px]',
8
+ ipad: 'rounded-[18px] border-[6px]',
9
+ 'android-phone': 'rounded-[24px] border-4',
10
+ 'android-tablet': 'rounded-[16px] border-4',
11
+ },
12
+ orientation: {
13
+ portrait: '',
14
+ landscape: '',
15
+ },
16
+ },
17
+ defaultVariants: {
18
+ device: 'iphone',
19
+ orientation: 'portrait',
20
+ },
21
+ })
@@ -0,0 +1,112 @@
1
+ import type { AccessibilityProps } from '../shared/index.ts'
2
+
3
+ export type DeviceType = 'iphone' | 'ipad' | 'android-phone' | 'android-tablet'
4
+ export type DeviceOrientation = 'portrait' | 'landscape'
5
+
6
+ export interface DeviceFrameProps {
7
+ /** The type of device to display */
8
+ device: DeviceType
9
+ /** The orientation of the device */
10
+ orientation?: DeviceOrientation
11
+ }
12
+
13
+ export interface DeviceDimensions {
14
+ /** Width in pixels */
15
+ width: number
16
+ /** Height in pixels */
17
+ height: number
18
+ /** Border radius in pixels */
19
+ radius: number
20
+ /** Whether the device has a notch */
21
+ notch: boolean
22
+ /** Whether the device has a home indicator bar */
23
+ homeIndicator: boolean
24
+ }
25
+
26
+ export interface DeviceFrameAPI {
27
+ /** Computed dimensions for the device */
28
+ dimensions: DeviceDimensions
29
+ /** ARIA attributes for the device frame */
30
+ ariaProps: Partial<AccessibilityProps> & Record<string, unknown>
31
+ /** Data attributes for styling hooks */
32
+ dataAttributes: Record<string, string>
33
+ }
34
+
35
+ interface DeviceSpec {
36
+ width: number
37
+ height: number
38
+ radius: number
39
+ notch: boolean
40
+ homeIndicator: boolean
41
+ }
42
+
43
+ const DEVICE_SPECS: Record<DeviceType, DeviceSpec> = {
44
+ iphone: {
45
+ width: 375,
46
+ height: 812,
47
+ radius: 44,
48
+ notch: true,
49
+ homeIndicator: true,
50
+ },
51
+ ipad: {
52
+ width: 810,
53
+ height: 1080,
54
+ radius: 18,
55
+ notch: false,
56
+ homeIndicator: true,
57
+ },
58
+ 'android-phone': {
59
+ width: 360,
60
+ height: 800,
61
+ radius: 24,
62
+ notch: false,
63
+ homeIndicator: false,
64
+ },
65
+ 'android-tablet': {
66
+ width: 800,
67
+ height: 1280,
68
+ radius: 16,
69
+ notch: false,
70
+ homeIndicator: false,
71
+ },
72
+ }
73
+
74
+ const DEVICE_LABELS: Record<DeviceType, string> = {
75
+ iphone: 'iPhone',
76
+ ipad: 'iPad',
77
+ 'android-phone': 'Android Phone',
78
+ 'android-tablet': 'Android Tablet',
79
+ }
80
+
81
+ export function createDeviceFrame(props: DeviceFrameProps): DeviceFrameAPI {
82
+ const { device, orientation = 'portrait' } = props
83
+ const spec = DEVICE_SPECS[device]
84
+
85
+ const isLandscape = orientation === 'landscape'
86
+
87
+ const dimensions: DeviceDimensions = {
88
+ width: isLandscape ? spec.height : spec.width,
89
+ height: isLandscape ? spec.width : spec.height,
90
+ radius: spec.radius,
91
+ notch: spec.notch,
92
+ homeIndicator: spec.homeIndicator,
93
+ }
94
+
95
+ const ariaProps: Partial<AccessibilityProps> & Record<string, unknown> = {
96
+ role: 'img',
97
+ 'aria-label': `${DEVICE_LABELS[device]} device frame in ${orientation} orientation`,
98
+ }
99
+
100
+ const dataAttributes: Record<string, string> = {
101
+ 'data-device': device,
102
+ 'data-orientation': orientation,
103
+ ...(spec.notch ? { 'data-notch': 'true' } : {}),
104
+ ...(spec.homeIndicator ? { 'data-home-indicator': 'true' } : {}),
105
+ }
106
+
107
+ return {
108
+ dimensions,
109
+ ariaProps,
110
+ dataAttributes,
111
+ }
112
+ }