@refraction-ui/astro 0.3.1 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (246) hide show
  1. package/dist/astro-accordion/Button.astro +55 -0
  2. package/dist/astro-accordion/index.ts +1 -0
  3. package/dist/astro-ai/AIScript.astro +69 -0
  4. package/dist/astro-ai/TTSScript.astro +60 -0
  5. package/dist/astro-ai/index.ts +16 -0
  6. package/dist/astro-animated-text/AnimatedText.astro +81 -0
  7. package/dist/astro-animated-text/TypewriterText.astro +90 -0
  8. package/dist/astro-animated-text/index.ts +1 -0
  9. package/dist/astro-app-shell/AppShell.astro +195 -0
  10. package/dist/astro-app-shell/AppShellContent.astro +29 -0
  11. package/dist/astro-app-shell/AppShellHeader.astro +54 -0
  12. package/dist/astro-app-shell/AppShellMain.astro +18 -0
  13. package/dist/astro-app-shell/AppShellMobileNav.astro +27 -0
  14. package/dist/astro-app-shell/AppShellOverlay.astro +21 -0
  15. package/dist/astro-app-shell/AppShellSidebar.astro +26 -0
  16. package/dist/astro-app-shell/AuthShell.astro +31 -0
  17. package/dist/astro-app-shell/AuthShellCard.astro +24 -0
  18. package/dist/astro-app-shell/PageShell.astro +36 -0
  19. package/dist/astro-app-shell/PageShellFooter.astro +30 -0
  20. package/dist/astro-app-shell/PageShellNav.astro +33 -0
  21. package/dist/astro-app-shell/PageShellSection.astro +32 -0
  22. package/dist/astro-app-shell/index.ts +21 -0
  23. package/dist/astro-auth/AuthGuard.astro +133 -0
  24. package/dist/astro-auth/index.ts +5 -0
  25. package/dist/astro-avatar/Avatar.astro +22 -0
  26. package/dist/astro-avatar/AvatarFallback.astro +18 -0
  27. package/dist/astro-avatar/AvatarImage.astro +48 -0
  28. package/dist/astro-avatar/index.ts +1 -0
  29. package/dist/astro-avatar-group/AvatarGroup.astro +42 -0
  30. package/dist/astro-avatar-group/index.ts +1 -0
  31. package/dist/astro-badge/Badge.astro +27 -0
  32. package/dist/astro-badge/index.ts +1 -0
  33. package/dist/astro-bottom-nav/BottomNav.astro +40 -0
  34. package/dist/astro-bottom-nav/index.ts +1 -0
  35. package/dist/astro-breadcrumbs/Breadcrumbs.astro +56 -0
  36. package/dist/astro-breadcrumbs/index.ts +1 -0
  37. package/dist/astro-button/Button.astro +55 -0
  38. package/dist/astro-button/index.ts +1 -0
  39. package/dist/astro-calendar/Calendar.astro +259 -0
  40. package/dist/astro-calendar/index.ts +1 -0
  41. package/dist/astro-callout/Callout.astro +3 -0
  42. package/dist/astro-callout/index.ts +1 -0
  43. package/dist/astro-card/Card.astro +20 -0
  44. package/dist/astro-card/CardContent.astro +13 -0
  45. package/dist/astro-card/CardDescription.astro +13 -0
  46. package/dist/astro-card/CardFooter.astro +13 -0
  47. package/dist/astro-card/CardHeader.astro +13 -0
  48. package/dist/astro-card/CardTitle.astro +15 -0
  49. package/dist/astro-card/index.ts +1 -0
  50. package/dist/astro-card-grid/CardGrid.astro +17 -0
  51. package/dist/astro-card-grid/index.ts +1 -0
  52. package/dist/astro-carousel/Button.astro +55 -0
  53. package/dist/astro-carousel/index.ts +1 -0
  54. package/dist/astro-charts/Bars.astro +53 -0
  55. package/dist/astro-charts/Chart.astro +31 -0
  56. package/dist/astro-charts/Circles.astro +48 -0
  57. package/dist/astro-charts/Gradient.astro +34 -0
  58. package/dist/astro-charts/Histogram.astro +107 -0
  59. package/dist/astro-charts/Line.astro +55 -0
  60. package/dist/astro-charts/PieChart.astro +63 -0
  61. package/dist/astro-charts/ScatterPlot.astro +95 -0
  62. package/dist/astro-charts/XAxis.astro +46 -0
  63. package/dist/astro-charts/YAxis.astro +44 -0
  64. package/dist/astro-charts/index.ts +26 -0
  65. package/dist/astro-checkbox/Checkbox.astro +129 -0
  66. package/dist/astro-checkbox/index.ts +1 -0
  67. package/dist/astro-code-block/CodeBlock.astro +3 -0
  68. package/dist/astro-code-block/index.ts +1 -0
  69. package/dist/astro-code-editor/CodeEditor.astro +123 -0
  70. package/dist/astro-code-editor/index.ts +1 -0
  71. package/dist/astro-collapsible/Collapsible.astro +58 -0
  72. package/dist/astro-collapsible/CollapsibleContent.astro +21 -0
  73. package/dist/astro-collapsible/CollapsibleTrigger.astro +17 -0
  74. package/dist/astro-collapsible/index.ts +1 -0
  75. package/dist/astro-command/Command.astro +170 -0
  76. package/dist/astro-command/CommandEmpty.astro +17 -0
  77. package/dist/astro-command/CommandGroup.astro +25 -0
  78. package/dist/astro-command/CommandInput.astro +21 -0
  79. package/dist/astro-command/CommandItem.astro +26 -0
  80. package/dist/astro-command/CommandList.astro +17 -0
  81. package/dist/astro-command/CommandSeparator.astro +14 -0
  82. package/dist/astro-command/index.ts +1 -0
  83. package/dist/astro-command-input/CommandInput.astro +6 -0
  84. package/dist/astro-command-input/index.ts +1 -0
  85. package/dist/astro-content-protection/ContentProtection.astro +104 -0
  86. package/dist/astro-content-protection/index.ts +1 -0
  87. package/dist/astro-data-table/DataTable.astro +263 -0
  88. package/dist/astro-data-table/index.ts +1 -0
  89. package/dist/astro-date-picker/DatePicker.astro +398 -0
  90. package/dist/astro-date-picker/index.ts +1 -0
  91. package/dist/astro-device-frame/DeviceFrame.astro +44 -0
  92. package/dist/astro-device-frame/index.ts +1 -0
  93. package/dist/astro-dialog/Dialog.astro +138 -0
  94. package/dist/astro-dialog/DialogClose.astro +16 -0
  95. package/dist/astro-dialog/DialogContent.astro +24 -0
  96. package/dist/astro-dialog/DialogDescription.astro +15 -0
  97. package/dist/astro-dialog/DialogFooter.astro +14 -0
  98. package/dist/astro-dialog/DialogHeader.astro +14 -0
  99. package/dist/astro-dialog/DialogOverlay.astro +17 -0
  100. package/dist/astro-dialog/DialogTitle.astro +15 -0
  101. package/dist/astro-dialog/DialogTrigger.astro +18 -0
  102. package/dist/astro-dialog/index.ts +1 -0
  103. package/dist/astro-diff-viewer/DiffViewer.astro +371 -0
  104. package/dist/astro-diff-viewer/index.ts +1 -0
  105. package/dist/astro-dropdown-menu/DropdownMenu.astro +138 -0
  106. package/dist/astro-dropdown-menu/DropdownMenuContent.astro +20 -0
  107. package/dist/astro-dropdown-menu/DropdownMenuItem.astro +21 -0
  108. package/dist/astro-dropdown-menu/DropdownMenuLabel.astro +14 -0
  109. package/dist/astro-dropdown-menu/DropdownMenuSeparator.astro +14 -0
  110. package/dist/astro-dropdown-menu/DropdownMenuTrigger.astro +18 -0
  111. package/dist/astro-dropdown-menu/index.ts +1 -0
  112. package/dist/astro-emoji-picker/EmojiPicker.astro +255 -0
  113. package/dist/astro-emoji-picker/index.ts +1 -0
  114. package/dist/astro-feedback-dialog/FeedbackDialog.astro +152 -0
  115. package/dist/astro-feedback-dialog/index.ts +1 -0
  116. package/dist/astro-file-tree/astro-file-tree.astro +4 -0
  117. package/dist/astro-file-tree/index.ts +1 -0
  118. package/dist/astro-file-upload/FileUpload.astro +306 -0
  119. package/dist/astro-file-upload/index.ts +1 -0
  120. package/dist/astro-footer/Footer.astro +61 -0
  121. package/dist/astro-footer/index.ts +1 -0
  122. package/dist/astro-icon-system/astro-icon-system.astro +4 -0
  123. package/dist/astro-icon-system/index.ts +1 -0
  124. package/dist/astro-inline-editor/InlineEditor.astro +169 -0
  125. package/dist/astro-inline-editor/index.ts +1 -0
  126. package/dist/astro-input/Input.astro +49 -0
  127. package/dist/astro-input/index.ts +1 -0
  128. package/dist/astro-input-group/InputGroup.astro +29 -0
  129. package/dist/astro-input-group/InputGroupAddon.astro +14 -0
  130. package/dist/astro-input-group/InputGroupButton.astro +19 -0
  131. package/dist/astro-input-group/InputGroupText.astro +11 -0
  132. package/dist/astro-input-group/index.ts +1 -0
  133. package/dist/astro-install-prompt/InstallPrompt.astro +115 -0
  134. package/dist/astro-install-prompt/index.ts +1 -0
  135. package/dist/astro-keyboard-shortcut/KeyboardShortcut.astro +83 -0
  136. package/dist/astro-keyboard-shortcut/ShortcutBadge.astro +41 -0
  137. package/dist/astro-keyboard-shortcut/index.ts +1 -0
  138. package/dist/astro-language-selector/LanguageSelector.astro +247 -0
  139. package/dist/astro-language-selector/index.ts +1 -0
  140. package/dist/astro-link-card/LinkCard.astro +17 -0
  141. package/dist/astro-link-card/index.ts +1 -0
  142. package/dist/astro-markdown-renderer/MarkdownRenderer.astro +62 -0
  143. package/dist/astro-markdown-renderer/index.ts +1 -0
  144. package/dist/astro-mobile-nav/MobileNav.astro +84 -0
  145. package/dist/astro-mobile-nav/MobileNavContent.astro +29 -0
  146. package/dist/astro-mobile-nav/MobileNavLink.astro +16 -0
  147. package/dist/astro-mobile-nav/MobileNavTrigger.astro +57 -0
  148. package/dist/astro-mobile-nav/index.ts +1 -0
  149. package/dist/astro-navbar/Navbar.astro +49 -0
  150. package/dist/astro-navbar/index.ts +1 -0
  151. package/dist/astro-otp-input/OtpInput.astro +253 -0
  152. package/dist/astro-otp-input/index.ts +1 -0
  153. package/dist/astro-pagination/Pagination.astro +3 -0
  154. package/dist/astro-pagination/index.ts +1 -0
  155. package/dist/astro-payment/Payment.astro +19 -0
  156. package/dist/astro-payment/index.ts +1 -0
  157. package/dist/astro-popover/Popover.astro +87 -0
  158. package/dist/astro-popover/PopoverClose.astro +16 -0
  159. package/dist/astro-popover/PopoverContent.astro +23 -0
  160. package/dist/astro-popover/PopoverTrigger.astro +18 -0
  161. package/dist/astro-popover/index.ts +1 -0
  162. package/dist/astro-presence-indicator/PresenceIndicator.astro +26 -0
  163. package/dist/astro-presence-indicator/index.ts +1 -0
  164. package/dist/astro-progress-display/BadgeDisplay.astro +33 -0
  165. package/dist/astro-progress-display/ProgressBar.astro +27 -0
  166. package/dist/astro-progress-display/StatsGrid.astro +32 -0
  167. package/dist/astro-progress-display/index.ts +1 -0
  168. package/dist/astro-radio/RadioGroup.astro +111 -0
  169. package/dist/astro-radio/RadioItem.astro +36 -0
  170. package/dist/astro-radio/index.ts +1 -0
  171. package/dist/astro-reaction-bar/ReactionBar.astro +117 -0
  172. package/dist/astro-reaction-bar/index.ts +1 -0
  173. package/dist/astro-resizable-layout/ResizableDivider.astro +27 -0
  174. package/dist/astro-resizable-layout/ResizableLayout.astro +162 -0
  175. package/dist/astro-resizable-layout/ResizablePane.astro +28 -0
  176. package/dist/astro-resizable-layout/index.ts +11 -0
  177. package/dist/astro-rich-editor/RichEditor.astro +260 -0
  178. package/dist/astro-rich-editor/index.ts +25 -0
  179. package/dist/astro-search-bar/SearchBar.astro +140 -0
  180. package/dist/astro-search-bar/SearchResultItem.astro +16 -0
  181. package/dist/astro-search-bar/SearchResults.astro +17 -0
  182. package/dist/astro-search-bar/index.ts +1 -0
  183. package/dist/astro-select/Select.astro +165 -0
  184. package/dist/astro-select/SelectContent.astro +19 -0
  185. package/dist/astro-select/SelectItem.astro +42 -0
  186. package/dist/astro-select/SelectTrigger.astro +36 -0
  187. package/dist/astro-select/index.ts +1 -0
  188. package/dist/astro-sidebar/Sidebar.astro +64 -0
  189. package/dist/astro-sidebar/index.ts +1 -0
  190. package/dist/astro-skeleton/Skeleton.astro +39 -0
  191. package/dist/astro-skeleton/SkeletonText.astro +22 -0
  192. package/dist/astro-skeleton/index.ts +1 -0
  193. package/dist/astro-skip-to-content/SkipToContent.astro +3 -0
  194. package/dist/astro-skip-to-content/index.ts +1 -0
  195. package/dist/astro-slide-viewer/SlideViewer.astro +231 -0
  196. package/dist/astro-slide-viewer/index.ts +1 -0
  197. package/dist/astro-slider/index.ts +1 -0
  198. package/dist/astro-status-indicator/StatusIndicator.astro +31 -0
  199. package/dist/astro-status-indicator/index.ts +1 -0
  200. package/dist/astro-steps/Steps.astro +3 -0
  201. package/dist/astro-steps/index.ts +1 -0
  202. package/dist/astro-switch/Switch.astro +89 -0
  203. package/dist/astro-switch/index.ts +1 -0
  204. package/dist/astro-table-of-contents/TableOfContents.astro +53 -0
  205. package/dist/astro-table-of-contents/index.ts +1 -0
  206. package/dist/astro-tabs/Tabs.astro +96 -0
  207. package/dist/astro-tabs/TabsContent.astro +20 -0
  208. package/dist/astro-tabs/TabsList.astro +16 -0
  209. package/dist/astro-tabs/TabsTrigger.astro +24 -0
  210. package/dist/astro-tabs/index.ts +1 -0
  211. package/dist/astro-textarea/Textarea.astro +51 -0
  212. package/dist/astro-textarea/index.ts +1 -0
  213. package/dist/astro-theme/ThemeScript.astro +13 -0
  214. package/dist/astro-theme/ThemeToggle.astro +279 -0
  215. package/dist/astro-theme/index.ts +1 -0
  216. package/dist/astro-thread-view/ThreadView.astro +159 -0
  217. package/dist/astro-thread-view/index.ts +1 -0
  218. package/dist/astro-toast/Toast.astro +49 -0
  219. package/dist/astro-toast/Toaster.astro +142 -0
  220. package/dist/astro-toast/index.ts +1 -0
  221. package/dist/astro-tooltip/Tooltip.astro +95 -0
  222. package/dist/astro-tooltip/TooltipContent.astro +22 -0
  223. package/dist/astro-tooltip/TooltipTrigger.astro +16 -0
  224. package/dist/astro-tooltip/index.ts +1 -0
  225. package/dist/astro-version-selector/VersionSelector.astro +174 -0
  226. package/dist/astro-version-selector/index.ts +1 -0
  227. package/dist/astro-video-player/VideoPlayer.astro +153 -0
  228. package/dist/astro-video-player/index.ts +1 -0
  229. package/dist/index.ts +77 -0
  230. package/dist/shared/a11y.ts +33 -0
  231. package/dist/shared/aria.ts +30 -0
  232. package/dist/shared/cn.ts +35 -0
  233. package/dist/shared/cva.ts +79 -0
  234. package/dist/shared/engine-adapter.ts +10 -0
  235. package/dist/shared/focus-trap.ts +123 -0
  236. package/dist/shared/index.ts +60 -0
  237. package/dist/shared/keyboard.ts +36 -0
  238. package/dist/shared/live-region.ts +90 -0
  239. package/dist/shared/motion.ts +15 -0
  240. package/dist/shared/skip-link.ts +35 -0
  241. package/dist/shared/state-machine.ts +57 -0
  242. package/dist/shared/tokens.ts +16 -0
  243. package/dist/shared/types.ts +45 -0
  244. package/dist/shared/variants.ts +17 -0
  245. package/package.json +22 -20
  246. package/src/index.ts +0 -92
@@ -0,0 +1,55 @@
1
+ ---
2
+ import {
3
+ createButton,
4
+ buttonVariants,
5
+ getButtonType,
6
+ type ButtonVariant,
7
+ type ButtonSize,
8
+ } from '@refraction-ui/button'
9
+ import { cn } from '../shared/index.ts'
10
+
11
+ interface Props extends astroHTML.JSX.HTMLAttributes {
12
+ variant?: ButtonVariant
13
+ size?: ButtonSize
14
+ loading?: boolean
15
+ disabled?: boolean
16
+ }
17
+
18
+ const { variant, size, loading, disabled, class: className, ...props } = Astro.props
19
+ const api = createButton({ variant, size, disabled, loading, type: props.type as string })
20
+ const classes = cn(buttonVariants({ variant, size }), className)
21
+ ---
22
+
23
+ <button
24
+ type={getButtonType({ type: props.type as string }) as any}
25
+ class={classes}
26
+ disabled={disabled || loading}
27
+ {...api.ariaProps}
28
+ {...api.dataAttributes}
29
+ {...props}
30
+ >
31
+ {loading && (
32
+ <svg
33
+ class="animate-spin h-4 w-4"
34
+ xmlns="http://www.w3.org/2000/svg"
35
+ fill="none"
36
+ viewBox="0 0 24 24"
37
+ aria-hidden="true"
38
+ >
39
+ <circle
40
+ class="opacity-25"
41
+ cx="12"
42
+ cy="12"
43
+ r="10"
44
+ stroke="currentColor"
45
+ stroke-width="4"
46
+ />
47
+ <path
48
+ class="opacity-75"
49
+ fill="currentColor"
50
+ d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
51
+ />
52
+ </svg>
53
+ )}
54
+ <slot />
55
+ </button>
@@ -0,0 +1 @@
1
+ export {}
@@ -0,0 +1,69 @@
1
+ ---
2
+ /**
3
+ * AIScript — injects a <script> that initializes the AI client on the page.
4
+ * Exposes `window.__rfr_ai` for other scripts to call generateText / generateJSON.
5
+ *
6
+ * Props mirror AIConfig from @refraction-ui/ai.
7
+ */
8
+
9
+ interface Props extends astroHTML.JSX.HTMLAttributes {
10
+ /** Default provider name */
11
+ default?: string
12
+ /** Fallback chain of provider names */
13
+ fallback?: string[]
14
+ }
15
+
16
+ const { default: defaultProvider, fallback, ...props } = Astro.props
17
+
18
+ const configJSON = JSON.stringify({
19
+ default: defaultProvider,
20
+ fallback,
21
+ })
22
+ ---
23
+
24
+ <script
25
+ data-rfr-ai-config={configJSON}
26
+ {...props}
27
+ is:inline
28
+ >
29
+ ;(function () {
30
+ // Only initialize once
31
+ if (window.__rfr_ai) return
32
+
33
+ // We cannot import ES modules from an inline script, so we stash the config
34
+ // and let the consumer call the init function from their own module script.
35
+ // This inline script sets up the namespace and a deferred init helper.
36
+ var configEl = document.querySelector('[data-rfr-ai-config]')
37
+ var config = {}
38
+ if (configEl) {
39
+ try { config = JSON.parse(configEl.getAttribute('data-rfr-ai-config') || '{}') } catch (_) { /* */ }
40
+ }
41
+
42
+ // Placeholder that will be replaced once createAI is called
43
+ window.__rfr_ai = {
44
+ _config: config,
45
+ _api: null,
46
+ _ready: false,
47
+ init: function (createAI, providers) {
48
+ var api = createAI(config)
49
+ if (providers) {
50
+ Object.keys(providers).forEach(function (name) {
51
+ api.addProvider(name, providers[name])
52
+ })
53
+ }
54
+ window.__rfr_ai._api = api
55
+ window.__rfr_ai._ready = true
56
+ window.__rfr_ai.generateText = api.generateText.bind(api)
57
+ window.__rfr_ai.generateJSON = api.generateJSON.bind(api)
58
+ window.__rfr_ai.addProvider = api.addProvider.bind(api)
59
+ window.__rfr_ai.removeProvider = api.removeProvider.bind(api)
60
+ window.__rfr_ai.providers = api.providers
61
+ },
62
+ generateText: function () { throw new Error('AI not initialized. Call window.__rfr_ai.init(createAI, providers) first.') },
63
+ generateJSON: function () { throw new Error('AI not initialized. Call window.__rfr_ai.init(createAI, providers) first.') },
64
+ addProvider: function () { throw new Error('AI not initialized.') },
65
+ removeProvider: function () { throw new Error('AI not initialized.') },
66
+ providers: [],
67
+ }
68
+ })()
69
+ </script>
@@ -0,0 +1,60 @@
1
+ ---
2
+ /**
3
+ * TTSScript — injects a <script> that initializes TTS on the page.
4
+ * Exposes `window.__rfr_tts` for other scripts to call speak / stop.
5
+ *
6
+ * Props mirror TTSConfig from @refraction-ui/ai.
7
+ */
8
+
9
+ interface Props extends astroHTML.JSX.HTMLAttributes {
10
+ /** Default TTS provider name */
11
+ default?: string
12
+ }
13
+
14
+ const { default: defaultProvider, ...props } = Astro.props
15
+
16
+ const configJSON = JSON.stringify({
17
+ default: defaultProvider,
18
+ })
19
+ ---
20
+
21
+ <script
22
+ data-rfr-tts-config={configJSON}
23
+ {...props}
24
+ is:inline
25
+ >
26
+ ;(function () {
27
+ if (window.__rfr_tts) return
28
+
29
+ var configEl = document.querySelector('[data-rfr-tts-config]')
30
+ var config = {}
31
+ if (configEl) {
32
+ try { config = JSON.parse(configEl.getAttribute('data-rfr-tts-config') || '{}') } catch (_) { /* */ }
33
+ }
34
+
35
+ window.__rfr_tts = {
36
+ _config: config,
37
+ _api: null,
38
+ _ready: false,
39
+ init: function (createTTS, providers) {
40
+ var api = createTTS(config)
41
+ if (providers) {
42
+ Object.keys(providers).forEach(function (name) {
43
+ api.addProvider(name, providers[name])
44
+ })
45
+ }
46
+ window.__rfr_tts._api = api
47
+ window.__rfr_tts._ready = true
48
+ window.__rfr_tts.speak = api.speak.bind(api)
49
+ window.__rfr_tts.stop = api.stop.bind(api)
50
+ window.__rfr_tts.addProvider = api.addProvider.bind(api)
51
+ window.__rfr_tts.providers = api.providers
52
+ },
53
+ speak: function () { throw new Error('TTS not initialized. Call window.__rfr_tts.init(createTTS, providers) first.') },
54
+ stop: function () { throw new Error('TTS not initialized.') },
55
+ addProvider: function () { throw new Error('TTS not initialized.') },
56
+ providers: [],
57
+ isSpeaking: false,
58
+ }
59
+ })()
60
+ </script>
@@ -0,0 +1,16 @@
1
+ export { default as AIScript } from './AIScript.astro'
2
+ export { default as TTSScript } from './TTSScript.astro'
3
+
4
+ // Re-export core types and factories for convenience
5
+ export {
6
+ createAI,
7
+ createTTS,
8
+ type AIConfig,
9
+ type TTSConfig,
10
+ type AIAPI,
11
+ type TTSAPI,
12
+ type AIProvider,
13
+ type TTSProvider,
14
+ type GenerateOptions,
15
+ type TTSOptions,
16
+ } from '@refraction-ui/ai'
@@ -0,0 +1,81 @@
1
+ ---
2
+ import { animatedTextVariants } from '@refraction-ui/animated-text'
3
+ import { cn } from '../shared/index.ts'
4
+
5
+ interface Props extends astroHTML.JSX.HTMLAttributes {
6
+ /** Array of words to cycle through */
7
+ words: string[]
8
+ /** Interval between word changes in ms. Default: 2500 */
9
+ interval?: number
10
+ /** Duration of the transition in ms. Default: 1000 */
11
+ transitionDuration?: number
12
+ }
13
+
14
+ const {
15
+ words,
16
+ interval = 2500,
17
+ transitionDuration = 1000,
18
+ class: className,
19
+ ...props
20
+ } = Astro.props
21
+
22
+ const classes = cn(animatedTextVariants({ state: 'idle' }), className)
23
+ ---
24
+
25
+ <span
26
+ data-rfr-animated-text
27
+ data-rfr-animated-words={JSON.stringify(words)}
28
+ data-rfr-animated-interval={interval}
29
+ data-rfr-animated-transition-duration={transitionDuration}
30
+ class={classes}
31
+ aria-live="polite"
32
+ aria-atomic="true"
33
+ {...props}
34
+ >
35
+ {words.length > 0 ? words[0] : ''}
36
+ </span>
37
+
38
+ <script>
39
+ function initAnimatedTexts() {
40
+ document.querySelectorAll<HTMLElement>('[data-rfr-animated-text]').forEach((el) => {
41
+ if (el.hasAttribute('data-rfr-animated-text-init')) return
42
+ el.setAttribute('data-rfr-animated-text-init', '')
43
+
44
+ const words: string[] = JSON.parse(el.getAttribute('data-rfr-animated-words') || '[]')
45
+ const interval = Number(el.getAttribute('data-rfr-animated-interval') || 2500)
46
+ const transitionDuration = Number(el.getAttribute('data-rfr-animated-transition-duration') || 1000)
47
+
48
+ if (words.length <= 1) return
49
+
50
+ const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches
51
+ let currentIndex = 0
52
+
53
+ const tick = setInterval(() => {
54
+ if (prefersReducedMotion) {
55
+ currentIndex = (currentIndex + 1) % words.length
56
+ el.textContent = words[currentIndex]
57
+ } else {
58
+ // Exit transition
59
+ el.style.opacity = '0'
60
+ setTimeout(() => {
61
+ currentIndex = (currentIndex + 1) % words.length
62
+ el.textContent = words[currentIndex]
63
+ // Enter transition
64
+ el.style.opacity = '1'
65
+ }, transitionDuration / 2)
66
+ }
67
+ }, interval)
68
+
69
+ // Set transition style if motion is allowed
70
+ if (!prefersReducedMotion) {
71
+ el.style.transition = `opacity ${transitionDuration / 2}ms ease`
72
+ }
73
+
74
+ // Cleanup on removal (Astro page transitions)
75
+ el.addEventListener('astro:before-swap', () => clearInterval(tick), { once: true })
76
+ })
77
+ }
78
+
79
+ initAnimatedTexts()
80
+ document.addEventListener('astro:after-swap', initAnimatedTexts)
81
+ </script>
@@ -0,0 +1,90 @@
1
+ ---
2
+ import { typewriterVariants } from '@refraction-ui/animated-text'
3
+ import { cn } from '../shared/index.ts'
4
+
5
+ interface Props extends astroHTML.JSX.HTMLAttributes {
6
+ /** The text to type out */
7
+ text: string
8
+ /** Typing speed in ms per character. Default: 50 */
9
+ speed?: number
10
+ /** Delay before starting in ms. Default: 0 */
11
+ startDelay?: number
12
+ }
13
+
14
+ const {
15
+ text,
16
+ speed = 50,
17
+ startDelay = 0,
18
+ class: className,
19
+ ...props
20
+ } = Astro.props
21
+
22
+ const classes = cn(typewriterVariants({ cursor: 'blinking' }), className)
23
+ ---
24
+
25
+ <span
26
+ data-rfr-typewriter
27
+ data-rfr-typewriter-text={text}
28
+ data-rfr-typewriter-speed={speed}
29
+ data-rfr-typewriter-start-delay={startDelay}
30
+ class={classes}
31
+ aria-label={text}
32
+ {...props}
33
+ ></span>
34
+
35
+ <script>
36
+ function initTypewriters() {
37
+ document.querySelectorAll<HTMLElement>('[data-rfr-typewriter]').forEach((el) => {
38
+ if (el.hasAttribute('data-rfr-typewriter-init')) return
39
+ el.setAttribute('data-rfr-typewriter-init', '')
40
+
41
+ const text = el.getAttribute('data-rfr-typewriter-text') || ''
42
+ const speed = Number(el.getAttribute('data-rfr-typewriter-speed') || 50)
43
+ const startDelay = Number(el.getAttribute('data-rfr-typewriter-start-delay') || 0)
44
+
45
+ const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches
46
+
47
+ if (prefersReducedMotion) {
48
+ el.textContent = text
49
+ // Remove cursor classes when complete
50
+ el.className = el.className
51
+ .replace(/after:inline-block/g, '')
52
+ .replace(/after:w-\[2px\]/g, '')
53
+ .replace(/after:h-\[1em\]/g, '')
54
+ .replace(/after:bg-current/g, '')
55
+ .replace(/after:ml-\[1px\]/g, '')
56
+ .replace(/after:animate-blink/g, '')
57
+ .replace(/after:align-text-bottom/g, '')
58
+ return
59
+ }
60
+
61
+ let currentIndex = 0
62
+
63
+ const startTimeout = setTimeout(() => {
64
+ function tick() {
65
+ if (currentIndex < text.length) {
66
+ currentIndex += 1
67
+ el.textContent = text.slice(0, currentIndex)
68
+ setTimeout(tick, speed)
69
+ } else {
70
+ // Typing complete — remove cursor
71
+ el.className = el.className
72
+ .replace(/after:inline-block/g, '')
73
+ .replace(/after:w-\[2px\]/g, '')
74
+ .replace(/after:h-\[1em\]/g, '')
75
+ .replace(/after:bg-current/g, '')
76
+ .replace(/after:ml-\[1px\]/g, '')
77
+ .replace(/after:animate-blink/g, '')
78
+ .replace(/after:align-text-bottom/g, '')
79
+ }
80
+ }
81
+ tick()
82
+ }, startDelay)
83
+
84
+ el.addEventListener('astro:before-swap', () => clearTimeout(startTimeout), { once: true })
85
+ })
86
+ }
87
+
88
+ initTypewriters()
89
+ document.addEventListener('astro:after-swap', initTypewriters)
90
+ </script>
@@ -0,0 +1 @@
1
+ export {}
@@ -0,0 +1,195 @@
1
+ ---
2
+ /**
3
+ * AppShell — root layout container for app-style layouts with sidebar, header, and main content.
4
+ * Includes a client-side script for responsive breakpoint detection and sidebar toggling.
5
+ */
6
+ import { createAppShell, type AppShellConfig } from '@refraction-ui/app-shell'
7
+ import { cn } from '../shared/index.ts'
8
+
9
+ interface Props extends astroHTML.JSX.HTMLAttributes {
10
+ /** Sidebar width when expanded (default '16rem') */
11
+ sidebarWidth?: string
12
+ /** Sidebar width when collapsed (default '4rem') */
13
+ sidebarCollapsedWidth?: string
14
+ /** Header height (default '3.5rem') */
15
+ headerHeight?: string
16
+ /** Breakpoint below which layout is mobile (default 768) */
17
+ mobileBreakpoint?: number
18
+ /** Breakpoint below which layout is tablet (default 1024) */
19
+ tabletBreakpoint?: number
20
+ /** Sidebar position (default 'left') */
21
+ sidebarPosition?: 'left' | 'right'
22
+ /** Whether sidebar can collapse on desktop (default true) */
23
+ sidebarCollapsible?: boolean
24
+ /** Whether sidebar starts collapsed (default false) */
25
+ sidebarDefaultCollapsed?: boolean
26
+ /** Mobile nav position (default 'bottom') */
27
+ mobileNavPosition?: 'bottom' | 'none'
28
+ }
29
+
30
+ const {
31
+ sidebarWidth,
32
+ sidebarCollapsedWidth,
33
+ headerHeight,
34
+ mobileBreakpoint,
35
+ tabletBreakpoint,
36
+ sidebarPosition,
37
+ sidebarCollapsible,
38
+ sidebarDefaultCollapsed,
39
+ mobileNavPosition,
40
+ class: className,
41
+ ...props
42
+ } = Astro.props
43
+
44
+ const config: AppShellConfig = {
45
+ sidebarWidth,
46
+ sidebarCollapsedWidth,
47
+ headerHeight,
48
+ mobileBreakpoint,
49
+ tabletBreakpoint,
50
+ sidebarPosition,
51
+ sidebarCollapsible,
52
+ sidebarDefaultCollapsed,
53
+ mobileNavPosition,
54
+ }
55
+
56
+ const api = createAppShell(config)
57
+ const cssVars = api.getCSSVariables()
58
+ const styleStr = Object.entries(cssVars).map(([k, v]) => `${k}:${v}`).join(';')
59
+
60
+ const configJSON = JSON.stringify(api.config)
61
+ ---
62
+
63
+ <div
64
+ class={cn('flex h-screen w-full overflow-hidden', className)}
65
+ style={styleStr}
66
+ data-rfr-shell
67
+ data-rfr-shell-config={configJSON}
68
+ {...props}
69
+ >
70
+ <slot />
71
+ </div>
72
+
73
+ <script is:inline>
74
+ ;(function () {
75
+ var shell = document.querySelector('[data-rfr-shell]')
76
+ if (!shell) return
77
+
78
+ var config = {}
79
+ try { config = JSON.parse(shell.getAttribute('data-rfr-shell-config') || '{}') } catch (_) { /* */ }
80
+
81
+ var mobileBp = config.mobileBreakpoint || 768
82
+ var tabletBp = config.tabletBreakpoint || 1024
83
+ var sidebarCollapsible = config.sidebarCollapsible !== false
84
+ var sidebarWidth = config.sidebarWidth || '16rem'
85
+ var sidebarCollapsedWidth = config.sidebarCollapsedWidth || '4rem'
86
+ var sidebarPosition = config.sidebarPosition || 'left'
87
+
88
+ var state = {
89
+ breakpoint: 'desktop',
90
+ sidebarOpen: false,
91
+ sidebarCollapsed: config.sidebarDefaultCollapsed || false,
92
+ }
93
+
94
+ function isMobile() { return state.breakpoint === 'mobile' }
95
+
96
+ function updateBreakpoint() {
97
+ var w = window.innerWidth
98
+ var bp = w < mobileBp ? 'mobile' : w < tabletBp ? 'tablet' : 'desktop'
99
+ if (bp !== state.breakpoint) {
100
+ state.breakpoint = bp
101
+ if (bp !== 'mobile') state.sidebarOpen = false
102
+ applyState()
103
+ }
104
+ }
105
+
106
+ function toggleSidebar() {
107
+ if (isMobile()) {
108
+ state.sidebarOpen = !state.sidebarOpen
109
+ } else if (sidebarCollapsible) {
110
+ state.sidebarCollapsed = !state.sidebarCollapsed
111
+ }
112
+ applyState()
113
+ }
114
+
115
+ function closeSidebar() {
116
+ state.sidebarOpen = false
117
+ applyState()
118
+ }
119
+
120
+ function applyState() {
121
+ var sidebar = shell.querySelector('[data-rfr-shell-sidebar]')
122
+ var overlay = shell.querySelector('[data-rfr-shell-overlay]')
123
+ var mobileNav = shell.querySelector('[data-rfr-shell-mobile-nav]')
124
+ var hamburgers = shell.querySelectorAll('[data-rfr-shell-toggle]')
125
+
126
+ // Update CSS variable for sidebar width
127
+ var currentWidth = state.sidebarCollapsed ? sidebarCollapsedWidth : sidebarWidth
128
+ shell.style.setProperty('--shell-sidebar-width', currentWidth)
129
+
130
+ if (sidebar) {
131
+ if (isMobile()) {
132
+ sidebar.style.position = 'fixed'
133
+ sidebar.style.top = '0'
134
+ sidebar.style.zIndex = '40'
135
+ sidebar.style.width = sidebarWidth
136
+ sidebar.style[sidebarPosition === 'right' ? 'right' : 'left'] = '0'
137
+ sidebar.style.transform = state.sidebarOpen
138
+ ? 'translateX(0)'
139
+ : sidebarPosition === 'right' ? 'translateX(100%)' : 'translateX(-100%)'
140
+ sidebar.removeAttribute('data-collapsed')
141
+ } else {
142
+ sidebar.style.position = 'relative'
143
+ sidebar.style.transform = ''
144
+ sidebar.style.width = currentWidth
145
+ if (state.sidebarCollapsed) {
146
+ sidebar.setAttribute('data-collapsed', '')
147
+ } else {
148
+ sidebar.removeAttribute('data-collapsed')
149
+ }
150
+ }
151
+ if (state.sidebarOpen) {
152
+ sidebar.setAttribute('data-open', '')
153
+ } else {
154
+ sidebar.removeAttribute('data-open')
155
+ }
156
+ }
157
+
158
+ if (overlay) {
159
+ if (isMobile() && state.sidebarOpen) {
160
+ overlay.style.display = ''
161
+ } else {
162
+ overlay.style.display = 'none'
163
+ }
164
+ }
165
+
166
+ if (mobileNav) {
167
+ mobileNav.style.display = isMobile() ? '' : 'none'
168
+ }
169
+
170
+ hamburgers.forEach(function (btn) {
171
+ btn.setAttribute('aria-expanded', String(state.sidebarOpen))
172
+ })
173
+ }
174
+
175
+ // Bind toggle buttons
176
+ shell.addEventListener('click', function (e) {
177
+ var toggle = e.target.closest('[data-rfr-shell-toggle]')
178
+ if (toggle) {
179
+ toggleSidebar()
180
+ return
181
+ }
182
+ var overlayClick = e.target.closest('[data-rfr-shell-overlay]')
183
+ if (overlayClick) {
184
+ closeSidebar()
185
+ }
186
+ })
187
+
188
+ // Expose API for external scripts
189
+ window.__rfr_shell = { toggleSidebar: toggleSidebar, closeSidebar: closeSidebar, state: state }
190
+
191
+ // Responsive listener
192
+ window.addEventListener('resize', updateBreakpoint)
193
+ updateBreakpoint()
194
+ })()
195
+ </script>
@@ -0,0 +1,29 @@
1
+ ---
2
+ /**
3
+ * AppShellContent — scrollable content area within AppShellMain.
4
+ */
5
+ import { cn } from '../shared/index.ts'
6
+
7
+ interface Props extends astroHTML.JSX.HTMLAttributes {
8
+ /** Tailwind max-width class suffix, e.g. '6xl' -> max-w-6xl */
9
+ maxWidth?: string
10
+ }
11
+
12
+ const { maxWidth, class: className, ...props } = Astro.props
13
+
14
+ const mwClass = maxWidth ? `max-w-${maxWidth} mx-auto w-full` : ''
15
+ ---
16
+
17
+ <main
18
+ role="main"
19
+ class={cn(
20
+ 'flex-1 overflow-y-auto',
21
+ mwClass,
22
+ 'px-4 sm:px-6 lg:px-8 py-6',
23
+ className,
24
+ )}
25
+ data-rfr-shell-content
26
+ {...props}
27
+ >
28
+ <slot />
29
+ </main>
@@ -0,0 +1,54 @@
1
+ ---
2
+ /**
3
+ * AppShellHeader — header area within the AppShell.
4
+ * On mobile, automatically renders a hamburger toggle button.
5
+ */
6
+ import { cn } from '../shared/index.ts'
7
+
8
+ interface Props extends astroHTML.JSX.HTMLAttributes {
9
+ /** Hide the hamburger menu button */
10
+ hideToggle?: boolean
11
+ }
12
+
13
+ const { hideToggle, class: className, ...props } = Astro.props
14
+ ---
15
+
16
+ <header
17
+ role="banner"
18
+ class={cn(
19
+ 'sticky top-0 z-30 flex items-center shrink-0',
20
+ 'h-[var(--shell-header-height)]',
21
+ 'border-b bg-background px-4',
22
+ className,
23
+ )}
24
+ data-rfr-shell-header
25
+ {...props}
26
+ >
27
+ {!hideToggle && (
28
+ <button
29
+ type="button"
30
+ aria-label="Toggle sidebar"
31
+ aria-expanded="false"
32
+ class="inline-flex items-center justify-center p-2 mr-2 md:hidden"
33
+ data-rfr-shell-toggle
34
+ >
35
+ <svg
36
+ xmlns="http://www.w3.org/2000/svg"
37
+ width="24"
38
+ height="24"
39
+ viewBox="0 0 24 24"
40
+ fill="none"
41
+ stroke="currentColor"
42
+ stroke-width="2"
43
+ stroke-linecap="round"
44
+ stroke-linejoin="round"
45
+ aria-hidden="true"
46
+ >
47
+ <line x1="3" y1="6" x2="21" y2="6" />
48
+ <line x1="3" y1="12" x2="21" y2="12" />
49
+ <line x1="3" y1="18" x2="21" y2="18" />
50
+ </svg>
51
+ </button>
52
+ )}
53
+ <slot />
54
+ </header>
@@ -0,0 +1,18 @@
1
+ ---
2
+ /**
3
+ * AppShellMain — main content area wrapper (flex column).
4
+ */
5
+ import { cn } from '../shared/index.ts'
6
+
7
+ interface Props extends astroHTML.JSX.HTMLAttributes {}
8
+
9
+ const { class: className, ...props } = Astro.props
10
+ ---
11
+
12
+ <div
13
+ class={cn('flex flex-1 flex-col min-w-0 h-full', className)}
14
+ data-rfr-shell-main
15
+ {...props}
16
+ >
17
+ <slot />
18
+ </div>