@rimelight/ui 0.0.33 → 0.0.34

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 (282) hide show
  1. package/README.md +157 -157
  2. package/package.json +105 -105
  3. package/src/components/astro/RLAAspectRatio.astro +2 -2
  4. package/src/components/astro/RLAButton.astro +141 -139
  5. package/src/components/astro/RLAChart.astro +19 -34
  6. package/src/components/astro/RLAHead.astro +427 -196
  7. package/src/components/astro/RLAHeader.astro +66 -59
  8. package/src/components/astro/RLAImage.astro +61 -19
  9. package/src/components/astro/RLALink.astro +22 -23
  10. package/src/components/astro/RLALinkGroup.astro +66 -4
  11. package/src/components/astro/RLALocaleSelector.astro +136 -113
  12. package/src/components/astro/RLAMain.astro +8 -3
  13. package/src/components/astro/RLAMarquee.astro +9 -2
  14. package/src/components/astro/RLANavigationMenu.astro +245 -56
  15. package/src/components/astro/RLAPagination.astro +2 -4
  16. package/src/components/astro/RLAProgress.astro +8 -2
  17. package/src/components/astro/RLASelect.astro +38 -24
  18. package/src/components/astro/RLASlideover.astro +66 -1
  19. package/src/components/astro/RLASlider.astro +14 -14
  20. package/src/components/astro/RLASplitter.astro +14 -2
  21. package/src/components/astro/RLAStickySurface.astro +9 -2
  22. package/src/components/vue/RLVCheckbox.vue +68 -68
  23. package/src/components/vue/RLVForm.vue +44 -44
  24. package/src/components/vue/RLVFormField.vue +58 -58
  25. package/src/components/vue/RLVInput.vue +93 -93
  26. package/src/components/vue/RLVPost.vue +63 -63
  27. package/src/components/vue/RLVPosts.vue +21 -21
  28. package/src/components/vue/RLVToast.vue +68 -68
  29. package/src/components/vue/RLVToaster.vue +29 -29
  30. package/src/composables/index.ts +3 -3
  31. package/src/composables/useHeaderStore.ts +13 -14
  32. package/src/composables/useScrollToTop.ts +62 -62
  33. package/src/composables/useToast.ts +43 -42
  34. package/src/config/index.ts +1 -0
  35. package/src/config/security.ts +220 -0
  36. package/src/integrations/ui.ts +199 -199
  37. package/src/middleware/security.ts +75 -15
  38. package/src/plugins/index.ts +2 -2
  39. package/src/plugins/starlightDocsApi/index.ts +272 -272
  40. package/src/presets/defaults.ts +297 -297
  41. package/src/presets/index.ts +683 -637
  42. package/src/styles/index.css +160 -160
  43. package/src/themes/3d-hover.theme.ts +13 -13
  44. package/src/themes/accordion.theme.ts +13 -13
  45. package/src/themes/alert.theme.ts +131 -125
  46. package/src/themes/app.theme.ts +13 -13
  47. package/src/themes/audio.theme.ts +13 -13
  48. package/src/themes/avatar.theme.ts +84 -84
  49. package/src/themes/badge.theme.ts +169 -163
  50. package/src/themes/banner.theme.ts +13 -13
  51. package/src/themes/browser-mockup.theme.ts +13 -13
  52. package/src/themes/button.theme.ts +224 -202
  53. package/src/themes/calendar.theme.ts +13 -13
  54. package/src/themes/card.theme.ts +42 -42
  55. package/src/themes/changelog.theme.ts +13 -13
  56. package/src/themes/chart.theme.ts +22 -22
  57. package/src/themes/chat-message.theme.ts +13 -13
  58. package/src/themes/chat-messages.theme.ts +13 -13
  59. package/src/themes/chat-palette.theme.ts +13 -13
  60. package/src/themes/chat-prompt-submit.theme.ts +13 -13
  61. package/src/themes/chat-prompt.theme.ts +13 -13
  62. package/src/themes/chat-reasoning.theme.ts +13 -13
  63. package/src/themes/chat-shimmer.theme.ts +13 -13
  64. package/src/themes/chat-tool.theme.ts +13 -13
  65. package/src/themes/chat.theme.ts +13 -13
  66. package/src/themes/checkbox.theme.ts +50 -50
  67. package/src/themes/chip.theme.ts +74 -74
  68. package/src/themes/color-picker.theme.ts +13 -13
  69. package/src/themes/command-palette.theme.ts +13 -13
  70. package/src/themes/compare.theme.ts +13 -13
  71. package/src/themes/confirm.theme.ts +48 -48
  72. package/src/themes/container.theme.ts +13 -13
  73. package/src/themes/context-menu.theme.ts +13 -13
  74. package/src/themes/dashboard-group.theme.ts +13 -13
  75. package/src/themes/dashboard-navbar.theme.ts +13 -13
  76. package/src/themes/dashboard-panel.theme.ts +13 -13
  77. package/src/themes/dashboard-resize-handle.theme.ts +13 -13
  78. package/src/themes/dashboard-search-button.theme.ts +13 -13
  79. package/src/themes/dashboard-search.theme.ts +13 -13
  80. package/src/themes/dashboard-sidebar-collapse.theme.ts +13 -13
  81. package/src/themes/dashboard-sidebar-toggle.theme.ts +13 -13
  82. package/src/themes/dashboard-sidebar.theme.ts +13 -13
  83. package/src/themes/dashboard-toolbar.theme.ts +13 -13
  84. package/src/themes/dock.theme.ts +13 -13
  85. package/src/themes/drawer.theme.ts +61 -61
  86. package/src/themes/dropdown-menu.theme.ts +29 -29
  87. package/src/themes/editor.theme.ts +13 -13
  88. package/src/themes/empty.theme.ts +13 -13
  89. package/src/themes/error.theme.ts +13 -13
  90. package/src/themes/field-group.theme.ts +24 -24
  91. package/src/themes/fieldset.theme.ts +13 -13
  92. package/src/themes/floating-action.theme.ts +13 -13
  93. package/src/themes/footer.theme.ts +30 -30
  94. package/src/themes/form.theme.ts +13 -13
  95. package/src/themes/gallery.theme.ts +13 -13
  96. package/src/themes/head.theme.ts +13 -13
  97. package/src/themes/header.theme.ts +45 -46
  98. package/src/themes/icon.theme.ts +23 -23
  99. package/src/themes/image.theme.ts +23 -19
  100. package/src/themes/input-date.theme.ts +13 -13
  101. package/src/themes/input-menu.theme.ts +35 -35
  102. package/src/themes/input-number.theme.ts +13 -13
  103. package/src/themes/input-tags.theme.ts +13 -13
  104. package/src/themes/input-time.theme.ts +13 -13
  105. package/src/themes/input.theme.ts +42 -42
  106. package/src/themes/kbd.theme.ts +95 -89
  107. package/src/themes/knob.theme.ts +13 -13
  108. package/src/themes/link-group.theme.ts +32 -32
  109. package/src/themes/link.theme.ts +13 -13
  110. package/src/themes/listbox.theme.ts +13 -13
  111. package/src/themes/locale-selector.theme.ts +49 -49
  112. package/src/themes/logo.theme.ts +13 -13
  113. package/src/themes/main.theme.ts +13 -13
  114. package/src/themes/megamenu.theme.ts +13 -13
  115. package/src/themes/meter.theme.ts +13 -13
  116. package/src/themes/navigation-menu.theme.ts +44 -27
  117. package/src/themes/page-aside.theme.ts +13 -13
  118. package/src/themes/page-body.theme.ts +13 -13
  119. package/src/themes/page-header.theme.ts +13 -13
  120. package/src/themes/page-section.theme.ts +187 -187
  121. package/src/themes/page.theme.ts +13 -13
  122. package/src/themes/password.theme.ts +13 -13
  123. package/src/themes/phone-mockup.theme.ts +13 -13
  124. package/src/themes/placeholder.theme.ts +15 -15
  125. package/src/themes/post.theme.ts +33 -33
  126. package/src/themes/pricing-plan.theme.ts +13 -13
  127. package/src/themes/pricing-table.theme.ts +13 -13
  128. package/src/themes/progress.theme.ts +38 -38
  129. package/src/themes/prose.theme.ts +13 -13
  130. package/src/themes/qr-code.theme.ts +13 -13
  131. package/src/themes/quote.theme.ts +13 -13
  132. package/src/themes/radio-group.theme.ts +13 -13
  133. package/src/themes/rating.theme.ts +13 -13
  134. package/src/themes/scroll-area.theme.ts +26 -26
  135. package/src/themes/scroll-to-top.theme.ts +52 -52
  136. package/src/themes/select.theme.ts +29 -29
  137. package/src/themes/separator.theme.ts +147 -147
  138. package/src/themes/sidebar.theme.ts +38 -38
  139. package/src/themes/skeleton.theme.ts +21 -21
  140. package/src/themes/slideover.theme.ts +4 -4
  141. package/src/themes/slider.theme.ts +36 -36
  142. package/src/themes/speed-dial.theme.ts +13 -13
  143. package/src/themes/spinner.theme.ts +34 -34
  144. package/src/themes/splitter.theme.ts +23 -23
  145. package/src/themes/spoiler.theme.ts +13 -13
  146. package/src/themes/stepper.theme.ts +13 -13
  147. package/src/themes/switch.theme.ts +67 -67
  148. package/src/themes/table-of-contents.theme.ts +48 -48
  149. package/src/themes/tabs.theme.ts +52 -52
  150. package/src/themes/textarea.theme.ts +27 -27
  151. package/src/themes/theme-selector.theme.ts +15 -15
  152. package/src/themes/timeline.theme.ts +13 -13
  153. package/src/themes/toast.theme.ts +31 -31
  154. package/src/themes/tooltip.theme.ts +28 -28
  155. package/src/themes/tour.theme.ts +13 -13
  156. package/src/themes/tree.theme.ts +13 -13
  157. package/src/themes/user.theme.ts +13 -13
  158. package/src/themes/video.theme.ts +17 -17
  159. package/src/themes/watermark.theme.ts +13 -13
  160. package/src/themes/window-mockup.theme.ts +13 -13
  161. package/src/types/components/3d-hover.ts +11 -11
  162. package/src/types/components/alert.ts +2 -2
  163. package/src/types/components/app.ts +11 -11
  164. package/src/types/components/audio.ts +11 -11
  165. package/src/types/components/avatar-group.ts +11 -11
  166. package/src/types/components/avatar.ts +60 -60
  167. package/src/types/components/badge.ts +2 -2
  168. package/src/types/components/banner.ts +11 -11
  169. package/src/types/components/browser-mockup.ts +11 -11
  170. package/src/types/components/button.ts +74 -81
  171. package/src/types/components/calendar.ts +11 -11
  172. package/src/types/components/changelog.ts +11 -11
  173. package/src/types/components/chart.ts +2 -1
  174. package/src/types/components/chat-message.ts +11 -11
  175. package/src/types/components/chat-messages.ts +11 -11
  176. package/src/types/components/chat-palette.ts +11 -11
  177. package/src/types/components/chat-prompt-submit.ts +11 -11
  178. package/src/types/components/chat-prompt.ts +11 -11
  179. package/src/types/components/chat-reasoning.ts +11 -11
  180. package/src/types/components/chat-shimmer.ts +11 -11
  181. package/src/types/components/chat-tool.ts +11 -11
  182. package/src/types/components/chat.ts +11 -11
  183. package/src/types/components/checkbox.ts +2 -2
  184. package/src/types/components/chip.ts +17 -17
  185. package/src/types/components/collapsible.ts +2 -1
  186. package/src/types/components/color-picker.ts +11 -11
  187. package/src/types/components/command-palette.ts +11 -11
  188. package/src/types/components/compare.ts +11 -11
  189. package/src/types/components/container.ts +17 -17
  190. package/src/types/components/context-menu.ts +11 -11
  191. package/src/types/components/dashboard-group.ts +11 -11
  192. package/src/types/components/dashboard-navbar.ts +11 -11
  193. package/src/types/components/dashboard-panel.ts +11 -11
  194. package/src/types/components/dashboard-resize-handle.ts +11 -11
  195. package/src/types/components/dashboard-search-button.ts +11 -11
  196. package/src/types/components/dashboard-search.ts +11 -11
  197. package/src/types/components/dashboard-sidebar-collapse.ts +11 -11
  198. package/src/types/components/dashboard-sidebar-toggle.ts +11 -11
  199. package/src/types/components/dashboard-sidebar.ts +11 -11
  200. package/src/types/components/dashboard-toolbar.ts +11 -11
  201. package/src/types/components/dock.ts +11 -11
  202. package/src/types/components/dropdown-menu.ts +2 -1
  203. package/src/types/components/editor.ts +11 -11
  204. package/src/types/components/empty.ts +11 -11
  205. package/src/types/components/error.ts +11 -11
  206. package/src/types/components/fieldset.ts +11 -11
  207. package/src/types/components/file-upload.ts +2 -1
  208. package/src/types/components/floating-action.ts +11 -11
  209. package/src/types/components/form.ts +19 -19
  210. package/src/types/components/gallery.ts +11 -11
  211. package/src/types/components/icon.ts +19 -19
  212. package/src/types/components/image.ts +32 -28
  213. package/src/types/components/index.ts +134 -135
  214. package/src/types/components/input-date.ts +11 -11
  215. package/src/types/components/input-menu.ts +44 -43
  216. package/src/types/components/input-number.ts +11 -11
  217. package/src/types/components/input-pin.ts +36 -35
  218. package/src/types/components/input-tags.ts +11 -11
  219. package/src/types/components/input-time.ts +11 -11
  220. package/src/types/components/input.ts +2 -2
  221. package/src/types/components/knob.ts +11 -11
  222. package/src/types/components/link-group.ts +45 -23
  223. package/src/types/components/link.ts +4 -0
  224. package/src/types/components/listbox.ts +11 -11
  225. package/src/types/components/locale-selector.ts +33 -33
  226. package/src/types/components/logo.ts +32 -31
  227. package/src/types/components/main.ts +17 -17
  228. package/src/types/components/megamenu.ts +11 -11
  229. package/src/types/components/meter.ts +11 -11
  230. package/src/types/components/modal.ts +39 -39
  231. package/src/types/components/navigation-menu.ts +59 -54
  232. package/src/types/components/page-aside.ts +11 -11
  233. package/src/types/components/page-body.ts +11 -11
  234. package/src/types/components/page-header.ts +11 -11
  235. package/src/types/components/page.ts +11 -11
  236. package/src/types/components/password.ts +11 -11
  237. package/src/types/components/phone-mockup.ts +5 -5
  238. package/src/types/components/pin-input.ts +11 -11
  239. package/src/types/components/popover.ts +23 -23
  240. package/src/types/components/post.ts +35 -35
  241. package/src/types/components/pricing-plan.ts +11 -11
  242. package/src/types/components/pricing-table.ts +11 -11
  243. package/src/types/components/progress.ts +33 -33
  244. package/src/types/components/prose.ts +11 -11
  245. package/src/types/components/qr-code.ts +11 -11
  246. package/src/types/components/radio-group.ts +11 -11
  247. package/src/types/components/rating.ts +11 -11
  248. package/src/types/components/scroll-area.ts +23 -23
  249. package/src/types/components/scroll-to-top.ts +2 -2
  250. package/src/types/components/select.ts +2 -1
  251. package/src/types/components/separator.ts +19 -19
  252. package/src/types/components/sidebar.ts +87 -72
  253. package/src/types/components/slideover.ts +31 -31
  254. package/src/types/components/slider.ts +2 -2
  255. package/src/types/components/speed-dial.ts +11 -11
  256. package/src/types/components/spinner.ts +25 -25
  257. package/src/types/components/splitter.ts +19 -19
  258. package/src/types/components/spoiler.ts +11 -11
  259. package/src/types/components/stepper.ts +11 -11
  260. package/src/types/components/sticky-surface.ts +19 -19
  261. package/src/types/components/switch.ts +41 -41
  262. package/src/types/components/table-of-contents.ts +17 -17
  263. package/src/types/components/tabs.ts +2 -1
  264. package/src/types/components/textarea.ts +2 -1
  265. package/src/types/components/theme-selector.ts +15 -15
  266. package/src/types/components/timeline.ts +11 -11
  267. package/src/types/components/toast.ts +2 -1
  268. package/src/types/components/tooltip.ts +23 -23
  269. package/src/types/components/tour.ts +11 -11
  270. package/src/types/components/tree.ts +11 -11
  271. package/src/types/components/user.ts +11 -11
  272. package/src/types/components/watermark.ts +11 -11
  273. package/src/types/components/window-mockup.ts +11 -11
  274. package/src/types/theme.ts +10 -0
  275. package/src/utils/docs.ts +215 -189
  276. package/src/utils/headerStack.ts +95 -95
  277. package/src/utils/index.ts +5 -5
  278. package/src/components/astro/RLABlogPost.astro +0 -7
  279. package/src/components/astro/RLABlogPosts.astro +0 -9
  280. package/src/components/astro/RLAPosts.astro +0 -23
  281. package/src/themes/posts.theme.ts +0 -13
  282. package/src/types/components/posts.ts +0 -11
@@ -25,10 +25,15 @@ const Tag = as;
25
25
  ---
26
26
 
27
27
  <Tag
28
- class:list={[classes.root]}
28
+ class:list={[classes.root, "rla-main-container"]}
29
29
  data-slot="main"
30
- style="padding-top: var(--rl-total-header-height, 4rem)"
31
30
  {...rest}
32
31
  >
33
32
  <slot />
34
- </Tag>
33
+ </Tag>
34
+
35
+ <style>
36
+ .rla-main-container {
37
+ padding-top: var(--rl-total-header-height, 4rem);
38
+ }
39
+ </style>
@@ -25,12 +25,19 @@ const classes = resolveClasses(marquee, {
25
25
  }, useUi("marquee", uiProp), className)
26
26
 
27
27
  const duration = `${speed}s`
28
+ const id = `marquee-${Math.random().toString(36).substring(2, 9)}`
28
29
  ---
29
30
  <div class={classes.root} data-slot="marquee-root" {...rest}>
30
- <div class={classes.track} data-slot="track" style={{ animationDuration: duration }}>
31
+ <div class:list={[classes.track, id]} data-slot="track">
31
32
  <slot />
32
33
  </div>
33
- <div class={classes.track} data-slot="track" aria-hidden="true" style={{ animationDuration: duration }}>
34
+ <div class:list={[classes.track, id]} data-slot="track" aria-hidden="true">
34
35
  <slot />
35
36
  </div>
36
37
  </div>
38
+
39
+ <style is:inline set:html={`
40
+ .${id} {
41
+ animation-duration: ${duration} !important;
42
+ }
43
+ `} />
@@ -11,24 +11,36 @@ const {
11
11
  items = [],
12
12
  color = "primary",
13
13
  theme,
14
+ orientation = "horizontal",
14
15
  ui: uiProp,
15
16
  class: className,
16
17
  ...rest
17
18
  } = Astro.props as NavigationMenuProps
18
19
 
19
- const classes = resolveClasses(navigationMenu, { theme }, useUi("navigationMenu", uiProp), className)
20
+ const classes = resolveClasses(navigationMenu, { theme, orientation }, useUi("navigationMenu", uiProp), className)
20
21
  ---
21
22
 
22
- <nav class={classes.root} data-slot="root" data-nav-menu {...rest}>
23
+ <nav class={classes.root} data-slot="root" data-nav-menu data-orientation={orientation} {...rest}>
23
24
  <ul class={classes.list} data-slot="list" role="list">
24
25
  {items.map((item, i) => {
25
26
  const hasChildren = item.children && item.children.length > 0
27
+
28
+ const itemPath = (item.href ?? item.to ?? "#") as string
29
+ const normalizedPath = itemPath.replace(/^\/[a-z]{2}(?:-[a-zA-Z]{2})?(?=\/|$)/, '').replace(/\/+$/, '') || '/'
30
+ const currentPath = Astro.url.pathname.replace(/^\/[a-z]{2}(?:-[a-zA-Z]{2})?(?=\/|$)/, '').replace(/\/+$/, '') || '/'
31
+
32
+ const isActive = item.active ?? (
33
+ normalizedPath !== '' && normalizedPath !== '/'
34
+ ? currentPath.startsWith(normalizedPath)
35
+ : currentPath === '/'
36
+ )
37
+
26
38
  return (
27
- <li class={classes.item} data-slot="item" data-nav-item>
39
+ <li class={classes.item} data-slot="item" data-nav-item data-index={i}>
28
40
  {hasChildren ? (
29
41
  <button
30
42
  type="button"
31
- class={classes.trigger}
43
+ class={classes.link}
32
44
  data-slot="trigger"
33
45
  data-nav-trigger
34
46
  aria-expanded="false"
@@ -43,6 +55,7 @@ const classes = resolveClasses(navigationMenu, { theme }, useUi("navigationMenu"
43
55
  href={item.href ?? item.to ?? "#"}
44
56
  class={classes.link}
45
57
  data-slot="link"
58
+ aria-current={isActive ? "page" : undefined}
46
59
  >
47
60
  {item.icon && <span class={item.icon + " mr-1.5 size-4"} />}
48
61
  {item.label}
@@ -50,25 +63,35 @@ const classes = resolveClasses(navigationMenu, { theme }, useUi("navigationMenu"
50
63
  )}
51
64
 
52
65
  {hasChildren && (
53
- <div class={classes.content + " hidden"} data-slot="content" data-nav-content role="region">
54
- <ul role="list" class="py-1">
55
- {item.children!.map(child => (
56
- <li>
57
- <a
58
- href={child.href ?? child.to ?? "#"}
59
- class="flex items-start gap-3 rounded-sm px-3 py-2 text-sm hover:bg-accent hover:text-accent-foreground transition-colors"
60
- >
61
- {child.icon && <span class={child.icon + " mt-0.5 size-4 shrink-0 text-muted-foreground"} />}
62
- <div>
63
- <div class="font-medium leading-none">{child.label}</div>
64
- {child.description && (
65
- <p class="mt-1 text-xs text-muted-foreground line-clamp-2">{child.description}</p>
66
- )}
67
- </div>
68
- </a>
69
- </li>
70
- ))}
71
- </ul>
66
+ <div
67
+ class={classes.content + " hidden"}
68
+ data-slot="content"
69
+ data-nav-content
70
+ data-item-index={i}
71
+ role="region"
72
+ >
73
+ {item.slot && Astro.slots.has(`${item.slot}-content`) ? (
74
+ <slot name={`${item.slot}-content`} />
75
+ ) : (
76
+ <ul role="list" class="py-1">
77
+ {item.children!.map(child => (
78
+ <li>
79
+ <a
80
+ href={child.href ?? child.to ?? "#"}
81
+ class="flex items-start gap-3 rounded-sm px-3 py-2 text-sm hover:bg-accent hover:text-accent-foreground transition-colors"
82
+ >
83
+ {child.icon && <span class={child.icon + " mt-0.5 size-4 shrink-0 text-muted-foreground"} />}
84
+ <div>
85
+ <div class="font-medium leading-none">{child.label}</div>
86
+ {child.description && (
87
+ <p class="mt-1 text-xs text-muted-foreground line-clamp-2">{child.description}</p>
88
+ )}
89
+ </div>
90
+ </a>
91
+ </li>
92
+ ))}
93
+ </ul>
94
+ )}
72
95
  </div>
73
96
  )}
74
97
  </li>
@@ -78,60 +101,226 @@ const classes = resolveClasses(navigationMenu, { theme }, useUi("navigationMenu"
78
101
 
79
102
  <slot />
80
103
 
81
- <div class={classes.viewport} data-slot="viewport" />
104
+ <div class={classes.viewportWrapper + " hidden"} data-slot="viewport-wrapper" data-nav-viewport-wrapper>
105
+ <div class={classes.viewport} data-slot="viewport" data-nav-viewport />
106
+ </div>
82
107
  </nav>
83
108
 
84
109
  <script>
85
110
  document.querySelectorAll("[data-nav-menu]").forEach(menu => {
111
+ const orientation = menu.getAttribute("data-orientation") || "horizontal";
86
112
  const items = menu.querySelectorAll("[data-nav-item]");
113
+ const viewportWrapper = orientation === "horizontal" ? menu.querySelector("[data-nav-viewport-wrapper]") : null as HTMLElement | null;
114
+ const viewport = orientation === "horizontal" ? menu.querySelector("[data-nav-viewport]") : null;
87
115
 
88
- items.forEach(item => {
89
- const trigger = item.querySelector("[data-nav-trigger]");
90
- const content = item.querySelector("[data-nav-content]");
116
+ // Teleport viewport wrapper to body to escape parent transforms (e.g. translate-x on header)
117
+ if (viewportWrapper && viewportWrapper.parentNode !== document.body) {
118
+ document.body.appendChild(viewportWrapper);
119
+ }
91
120
 
92
- if (!trigger || !content) return;
121
+ let activeItem = null as HTMLElement | null;
122
+ let hoverTimeout = null as any;
123
+
124
+ const updatePosition = () => {
125
+ if (viewportWrapper && activeItem) {
126
+ const header = menu.closest("header") || document.querySelector("header");
127
+ if (header) {
128
+ const headerRect = header.getBoundingClientRect();
129
+ viewportWrapper.style.top = `${headerRect.bottom}px`;
130
+ }
131
+ }
132
+ };
93
133
 
94
- const open = () => {
134
+ window.addEventListener("scroll", updatePosition, { passive: true });
135
+ window.addEventListener("resize", updatePosition, { passive: true });
136
+
137
+ const open = (item: HTMLElement, trigger: HTMLElement, content: HTMLElement) => {
138
+ clearTimeout(hoverTimeout);
139
+
140
+ // If there's another active item, close it first (horizontal viewport mode only)
141
+ if (orientation === "horizontal" && activeItem && activeItem !== item) {
142
+ close(activeItem);
143
+ }
144
+
145
+ if (orientation === "horizontal") {
146
+ activeItem = item;
147
+ updatePosition();
148
+ }
149
+
150
+ if (viewport) {
151
+ viewport.innerHTML = "";
152
+ viewport.appendChild(content);
95
153
  content.classList.remove("hidden");
96
- trigger.setAttribute("aria-expanded", "true");
97
- const icon = trigger.querySelector(".i-lucide-chevron-down");
98
- if (icon) (icon as HTMLElement).style.transform = "rotate(180deg)";
99
- };
154
+ if (viewportWrapper) {
155
+ viewportWrapper.classList.remove("hidden");
156
+ viewportWrapper.setAttribute("data-state", "open");
157
+ }
158
+ } else {
159
+ content.classList.remove("hidden");
160
+ }
161
+
162
+ trigger.setAttribute("aria-expanded", "true");
163
+ trigger.setAttribute("data-state", "open");
164
+ const icon = trigger.querySelector(".i-lucide-chevron-down");
165
+ if (icon) (icon as HTMLElement).style.transform = "rotate(180deg)";
166
+ };
167
+
168
+ const close = (item: HTMLElement) => {
169
+ const trigger = item.querySelector("[data-nav-trigger]") as HTMLElement | null;
170
+ const itemIndex = item.getAttribute("data-index");
171
+
172
+ // Find content - either inside viewport or inside the item
173
+ let content = item.querySelector("[data-nav-content]") as HTMLElement | null;
174
+ if (!content && viewport) {
175
+ content = viewport.querySelector(`[data-nav-content][data-item-index="${itemIndex}"]`) as HTMLElement | null;
176
+ }
100
177
 
101
- const close = () => {
178
+ if (content) {
102
179
  content.classList.add("hidden");
180
+ // Move back to item
181
+ if (viewport && viewport.contains(content)) {
182
+ item.appendChild(content);
183
+ }
184
+ }
185
+
186
+ if (trigger) {
103
187
  trigger.setAttribute("aria-expanded", "false");
188
+ trigger.setAttribute("data-state", "closed");
104
189
  const icon = trigger.querySelector(".i-lucide-chevron-down");
105
190
  if (icon) (icon as HTMLElement).style.transform = "";
106
- };
191
+ }
192
+
193
+ if (orientation === "horizontal" && activeItem === item) {
194
+ activeItem = null;
195
+ }
196
+
197
+ // If no item is active, hide viewport (horizontal viewport mode only)
198
+ if (orientation === "horizontal" && !activeItem && viewportWrapper) {
199
+ viewportWrapper.classList.add("hidden");
200
+ viewportWrapper.setAttribute("data-state", "closed");
201
+ if (viewport) viewport.innerHTML = "";
202
+ }
203
+ };
204
+
205
+ const closeAll = () => {
206
+ items.forEach(item => {
207
+ close(item as HTMLElement);
208
+ });
209
+ };
107
210
 
211
+ items.forEach(itemNode => {
212
+ const item = itemNode as HTMLElement;
213
+ const trigger = item.querySelector("[data-nav-trigger]") as HTMLElement | null;
214
+ const content = item.querySelector("[data-nav-content]") as HTMLElement | null;
215
+
216
+ if (!trigger || !content) return;
217
+
218
+ // Click behavior (works everywhere, including mobile)
108
219
  trigger.addEventListener("click", (e) => {
109
220
  e.stopPropagation();
110
- const isOpen = !content.classList.contains("hidden");
111
- // Close all others
112
- items.forEach(other => {
113
- const otherContent = other.querySelector("[data-nav-content]");
114
- const otherTrigger = other.querySelector("[data-nav-trigger]");
115
- if (otherContent && !otherContent.classList.contains("hidden")) {
116
- otherContent.classList.add("hidden");
117
- otherTrigger?.setAttribute("aria-expanded", "false");
118
- const icon = otherTrigger?.querySelector(".i-lucide-chevron-down");
119
- if (icon) (icon as HTMLElement).style.transform = "";
120
- }
121
- });
122
- if (!isOpen) open();
221
+ const isOpen = trigger.getAttribute("aria-expanded") === "true";
222
+ if (isOpen) {
223
+ close(item);
224
+ } else {
225
+ open(item, trigger, content);
226
+ }
123
227
  });
228
+
229
+ // Hover behavior (horizontal desktop only)
230
+ if (orientation === "horizontal") {
231
+ item.addEventListener("mouseenter", () => {
232
+ clearTimeout(hoverTimeout);
233
+ open(item, trigger, content);
234
+ });
235
+
236
+ item.addEventListener("mouseleave", () => {
237
+ hoverTimeout = setTimeout(() => {
238
+ if (activeItem === item) {
239
+ close(item);
240
+ }
241
+ }, 150);
242
+ });
243
+ }
124
244
  });
125
245
 
126
- document.addEventListener("click", () => {
127
- items.forEach(item => {
128
- const content = item.querySelector("[data-nav-content]");
129
- const trigger = item.querySelector("[data-nav-trigger]");
130
- if (content) content.classList.add("hidden");
131
- if (trigger) trigger.setAttribute("aria-expanded", "false");
132
- const icon = trigger?.querySelector(".i-lucide-chevron-down");
133
- if (icon) (icon as HTMLElement).style.transform = "";
246
+ // Handle viewport wrapper hover so menu stays open when hovering the mega menu itself
247
+ if (viewportWrapper) {
248
+ viewportWrapper.addEventListener("mouseenter", () => {
249
+ clearTimeout(hoverTimeout);
250
+ });
251
+
252
+ viewportWrapper.addEventListener("mouseleave", () => {
253
+ hoverTimeout = setTimeout(() => {
254
+ if (activeItem) {
255
+ close(activeItem);
256
+ }
257
+ }, 150);
134
258
  });
259
+ }
260
+
261
+ // Close on clicking outside
262
+ document.addEventListener("click", (e) => {
263
+ const target = e.target as HTMLElement;
264
+ if (!menu.contains(target) && (!viewportWrapper || !viewportWrapper.contains(target))) {
265
+ closeAll();
266
+ }
135
267
  });
136
268
  });
137
269
  </script>
270
+
271
+ <style is:global>
272
+ /* Reset margins, borders, rounding, and rings on the main viewport container */
273
+ [data-nav-viewport] {
274
+ margin-top: 0 !important;
275
+ border: none !important;
276
+ border-width: 0px !important;
277
+ border-style: none !important;
278
+ border-color: transparent !important;
279
+ border-radius: 0 !important;
280
+ outline: none !important;
281
+ outline-width: 0px !important;
282
+ outline-color: transparent !important;
283
+
284
+ /* Wiping out any UnoCSS/Tailwind rings on the viewport container */
285
+ --un-ring-width: 0px !important;
286
+ --tw-ring-width: 0px !important;
287
+ --un-ring-offset-width: 0px !important;
288
+ --tw-ring-offset-width: 0px !important;
289
+ --un-ring-color: transparent !important;
290
+ --tw-ring-color: transparent !important;
291
+ --un-ring-shadow: none !important;
292
+ --tw-ring-shadow: none !important;
293
+ --un-ring-offset-shadow: none !important;
294
+ --tw-ring-offset-shadow: none !important;
295
+
296
+ /* Premium card shadow */
297
+ box-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.35), 0 8px 10px -6px rgb(0 0 0 / 0.35) !important; /* Premium shadow-xl */
298
+ }
299
+
300
+ /* Reset layout and strip standard dropdown styling (borders/shadows/padding) from teleported content nodes */
301
+ [data-nav-viewport] [data-nav-content] {
302
+ position: static !important;
303
+ width: 100% !important;
304
+ margin: 0 !important;
305
+ transform: none !important;
306
+ border: none !important;
307
+ border-width: 0px !important;
308
+ box-shadow: none !important;
309
+ padding: 0 !important;
310
+ background: transparent !important;
311
+
312
+ /* Wiping out any UnoCSS/Tailwind rings on content */
313
+ --un-ring-width: 0px !important;
314
+ --tw-ring-width: 0px !important;
315
+ --un-ring-offset-width: 0px !important;
316
+ --tw-ring-offset-width: 0px !important;
317
+ --un-ring-color: transparent !important;
318
+ --tw-ring-color: transparent !important;
319
+ --un-ring-shadow: none !important;
320
+ --tw-ring-shadow: none !important;
321
+ --un-ring-offset-shadow: none !important;
322
+ --tw-ring-offset-shadow: none !important;
323
+ --un-shadow: none !important;
324
+ --tw-shadow: none !important;
325
+ }
326
+ </style>
@@ -47,10 +47,9 @@ const pages = getPageNumbers()
47
47
  <li class={classes.item}>
48
48
  <a
49
49
  href={currentPage > 1 ? `${baseUrl}${currentPage - 1}` : undefined}
50
- class={classes.link}
50
+ class:list={[classes.link, currentPage === 1 && "pointer-events-none opacity-50"]}
51
51
  aria-label="Go to previous page"
52
52
  aria-disabled={currentPage === 1}
53
- style={currentPage === 1 ? "pointer-events: none; opacity: 0.5;" : ""}
54
53
  >
55
54
  <span class="i-lucide-chevron-left size-4" aria-hidden="true" />
56
55
  </a>
@@ -86,10 +85,9 @@ const pages = getPageNumbers()
86
85
  <li class={classes.item}>
87
86
  <a
88
87
  href={currentPage < totalPages ? `${baseUrl}${currentPage + 1}` : undefined}
89
- class={classes.link}
88
+ class:list={[classes.link, currentPage === totalPages && "pointer-events-none opacity-50"]}
90
89
  aria-label="Go to next page"
91
90
  aria-disabled={currentPage === totalPages}
92
- style={currentPage === totalPages ? "pointer-events: none; opacity: 0.5;" : ""}
93
91
  >
94
92
  <span class="i-lucide-chevron-right size-4" aria-hidden="true" />
95
93
  </a>
@@ -27,6 +27,7 @@ const classes = resolveClasses(progress, {
27
27
  }, useUi("progress", uiProp), className)
28
28
 
29
29
  const percentage = Math.min(100, Math.max(0, (value / max) * 100))
30
+ const id = `progress-${Math.random().toString(36).substring(2, 9)}`
30
31
  ---
31
32
  <div
32
33
  class={classes.root}
@@ -38,8 +39,13 @@ const percentage = Math.min(100, Math.max(0, (value / max) * 100))
38
39
  {...rest}
39
40
  >
40
41
  <div
41
- class={classes.indicator}
42
+ class:list={[classes.indicator, id]}
42
43
  data-slot="indicator"
43
- style={{ transform: `translateX(-${100 - percentage}%)` }}
44
44
  />
45
45
  </div>
46
+
47
+ <style is:inline set:html={`
48
+ .${id} {
49
+ transform: translateX(-${100 - percentage}%) !important;
50
+ }
51
+ `} />
@@ -72,38 +72,52 @@ const initialLabel = selectedItem ? selectedItem.label : ""
72
72
  </div>
73
73
 
74
74
  <script>
75
- document.querySelectorAll("[data-select-wrapper]").forEach(wrapper => {
76
- const trigger = wrapper.querySelector("[data-select-trigger]") as HTMLButtonElement;
77
- const dropdown = wrapper.querySelector("[data-select-dropdown]") as HTMLDivElement;
78
- const items = wrapper.querySelectorAll("[data-select-item]");
79
- const valueSpan = wrapper.querySelector("[data-select-value]");
80
- const hiddenInput = wrapper.closest("[data-slot=root]")?.querySelector("[data-select-hidden-input]") as HTMLInputElement;
75
+ const initializeSelects = () => {
76
+ document.querySelectorAll("[data-select-wrapper]").forEach(wrapper => {
77
+ if (wrapper.hasAttribute("data-initialized")) return;
78
+ wrapper.setAttribute("data-initialized", "true");
81
79
 
82
- if (!trigger || !dropdown) return;
80
+ const trigger = wrapper.querySelector("[data-select-trigger]") as HTMLButtonElement;
81
+ const dropdown = wrapper.querySelector("[data-select-dropdown]") as HTMLDivElement;
82
+ const items = wrapper.querySelectorAll("[data-select-item]");
83
+ const valueSpan = wrapper.querySelector("[data-select-value]");
84
+ const hiddenInput = wrapper.closest("[data-slot=root]")?.querySelector("[data-select-hidden-input]") as HTMLInputElement;
83
85
 
84
- trigger.addEventListener("click", (e) => {
85
- e.stopPropagation();
86
- dropdown.classList.toggle("hidden");
87
- });
86
+ if (!trigger || !dropdown) return;
88
87
 
89
- items.forEach(item => {
90
- item.addEventListener("click", (e) => {
88
+ trigger.addEventListener("click", (e) => {
91
89
  e.stopPropagation();
92
- const val = (item as HTMLElement).dataset.value || "";
93
- const label = (item as HTMLElement).dataset.label || "";
94
-
95
- if (hiddenInput) hiddenInput.value = val;
96
- if (valueSpan) valueSpan.textContent = label;
97
-
98
- items.forEach(i => i.querySelector("[data-check-icon]")?.classList.add("hidden"));
99
- item.querySelector("[data-check-icon]")?.classList.remove("hidden");
100
-
101
- dropdown.classList.add("hidden");
90
+ dropdown.classList.toggle("hidden");
91
+ });
92
+
93
+ items.forEach(item => {
94
+ item.addEventListener("click", (e) => {
95
+ e.stopPropagation();
96
+ const val = (item as HTMLElement).dataset.value || "";
97
+ const label = (item as HTMLElement).dataset.label || "";
98
+
99
+ if (hiddenInput) {
100
+ hiddenInput.value = val;
101
+ hiddenInput.dispatchEvent(new Event("change", { bubbles: true }));
102
+ }
103
+ if (valueSpan) valueSpan.textContent = label;
104
+
105
+ items.forEach(i => i.querySelector("[data-check-icon]")?.classList.add("hidden"));
106
+ item.querySelector("[data-check-icon]")?.classList.remove("hidden");
107
+
108
+ dropdown.classList.add("hidden");
109
+ });
102
110
  });
103
111
  });
112
+ };
104
113
 
105
- document.addEventListener("click", () => {
114
+ // Close all dropdowns when clicking outside
115
+ document.addEventListener("click", () => {
116
+ document.querySelectorAll("[data-select-dropdown]").forEach(dropdown => {
106
117
  dropdown.classList.add("hidden");
107
118
  });
108
119
  });
120
+
121
+ document.addEventListener("DOMContentLoaded", initializeSelects);
122
+ document.addEventListener("astro:page-load", initializeSelects);
109
123
  </script>
@@ -11,7 +11,7 @@ const slideoverTheme = uiConfig.colors ? createSlideoverTheme() : slideoverTheme
11
11
  const slideover = scv(slideoverTheme)
12
12
 
13
13
  const {
14
- side = "right",
14
+ side = "left",
15
15
  title,
16
16
  description,
17
17
  triggerLabel,
@@ -74,3 +74,68 @@ const dialogId = `rla-slideover-${Math.random().toString(36).substring(2, 9)}`
74
74
  </div>
75
75
  </dialog>
76
76
  </div>
77
+
78
+ <style is:global>
79
+ /* Transition/Animation support for native <dialog> slideovers */
80
+ dialog[data-slot="content"] {
81
+ transition: transform 0.3s ease, opacity 0.3s ease, display 0.3s allow-discrete, overlay 0.3s allow-discrete !important;
82
+ opacity: 0;
83
+ }
84
+
85
+ /* Left side slideover */
86
+ dialog[data-slot="content"].left-0 {
87
+ transform: translateX(-100%);
88
+ }
89
+
90
+ /* Right side slideover */
91
+ dialog[data-slot="content"].right-0 {
92
+ transform: translateX(100%);
93
+ }
94
+
95
+ /* Open states */
96
+ dialog[data-slot="content"][open] {
97
+ opacity: 1 !important;
98
+ transform: translateX(0) !important;
99
+ }
100
+
101
+ /* Starting styles for enter transitions */
102
+ @starting-style {
103
+ dialog[data-slot="content"][open].left-0 {
104
+ opacity: 0 !important;
105
+ transform: translateX(-100%) !important;
106
+ }
107
+ dialog[data-slot="content"][open].right-0 {
108
+ opacity: 0 !important;
109
+ transform: translateX(100%) !important;
110
+ }
111
+ dialog[data-slot="content"][open]::backdrop {
112
+ background-color: rgba(0, 0, 0, 0) !important;
113
+ backdrop-filter: blur(0px) !important;
114
+ }
115
+ }
116
+
117
+ /* Backdrop transition */
118
+ dialog[data-slot="content"]::backdrop {
119
+ transition: background-color 0.3s ease, backdrop-filter 0.3s ease, display 0.3s allow-discrete, overlay 0.3s allow-discrete !important;
120
+ background-color: rgba(0, 0, 0, 0.6) !important;
121
+ backdrop-filter: blur(4px) !important;
122
+ }
123
+ </style>
124
+
125
+ <script is:inline>
126
+ document.addEventListener('click', (e) => {
127
+ if (e.target && e.target.tagName === 'DIALOG' && e.target.getAttribute('data-close-on-click-outside') === 'true') {
128
+ const rect = e.target.getBoundingClientRect();
129
+ const isInModal = (
130
+ rect.top <= e.clientY &&
131
+ e.clientY <= rect.top + rect.height &&
132
+ rect.left <= e.clientX &&
133
+ e.clientX <= rect.left + rect.width
134
+ );
135
+ if (!isInModal) {
136
+ e.target.close();
137
+ }
138
+ }
139
+ });
140
+ </script>
141
+
@@ -29,17 +29,11 @@ const classes = resolveClasses(slider, {
29
29
 
30
30
  const percentage = Math.min(100, Math.max(0, ((value - min) / (max - min)) * 100))
31
31
  ---
32
- <style define:vars={{ sliderPct: `${percentage}%` }}>
33
- [data-slot="range"] { left: 0%; right: calc(100% - var(--slider-pct)); }
34
- [data-slot="thumb"] { left: calc(var(--slider-pct) - 9px); }
35
- </style>
36
-
37
32
  <div class={classes.root} data-slot="slider-root" {...rest}>
38
33
  <div class={classes.track} data-slot="track">
39
- <div
40
- class={classes.range}
41
- data-slot="range"
42
- />
34
+ <svg class="h-full w-full overflow-visible pointer-events-none">
35
+ <rect class:list={[classes.range, "h-full"]} width={`${percentage}%`} fill="currentColor" rx="2" />
36
+ </svg>
43
37
  </div>
44
38
  <input
45
39
  type="range"
@@ -48,11 +42,17 @@ const percentage = Math.min(100, Math.max(0, ((value - min) / (max - min)) * 100
48
42
  step={step}
49
43
  value={value}
50
44
  name={name}
51
- class="absolute inset-0 w-full h-full opacity-0 cursor-pointer"
45
+ class="absolute inset-0 w-full h-full opacity-0 cursor-pointer z-10"
52
46
  data-slot="input"
53
47
  />
54
- <div
55
- class={classes.thumb}
56
- data-slot="thumb"
57
- />
48
+ <svg class="absolute inset-0 h-full w-full overflow-visible pointer-events-none">
49
+ <circle
50
+ cx={`${percentage}%`}
51
+ cy="50%"
52
+ r="8"
53
+ class:list={[classes.thumb, "pointer-events-auto border-none"]}
54
+ data-slot="thumb"
55
+ fill="currentColor"
56
+ />
57
+ </svg>
58
58
  </div>