@rimelight/ui 0.0.46 → 0.0.48

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 (222) hide show
  1. package/dist/icons-DPnFQCts.d.mts +72 -0
  2. package/dist/icons.d.mts +1 -1
  3. package/dist/index.d.mts +5 -6
  4. package/dist/preset.d.mts +1 -1
  5. package/dist/preset.mjs +73 -1
  6. package/dist/resolver.d.mts +4 -5
  7. package/dist/resolver.mjs +2 -4
  8. package/dist/shortcuts.d.mts +10 -11
  9. package/dist/stores.d.mts +3 -4
  10. package/dist/{types-DqAgCNcm.d.mts → types-DWmKMcYC.d.mts} +1 -1
  11. package/dist/types.d.mts +1 -1
  12. package/package.json +8 -6
  13. package/src/components/3d-hover/RLS3dHover.tsx +21 -0
  14. package/src/components/accordion/RLSAccordion.tsx +112 -0
  15. package/src/components/app/RLSApp.tsx +21 -0
  16. package/src/components/aspect-ratio/RLSAspectRatio.tsx +30 -0
  17. package/src/components/audio/RLSAudio.tsx +27 -0
  18. package/src/components/avatar/RLSAvatar.tsx +142 -0
  19. package/src/components/avatar/avatar.ts +22 -21
  20. package/src/components/avatar-group/RLSAvatarGroup.tsx +163 -0
  21. package/src/components/badge/RLSBadge.tsx +1 -1
  22. package/src/components/badge/RLVBadge.vue +5 -3
  23. package/src/components/banner/RLABanner.astro +1 -1
  24. package/src/components/banner/RLSBanner.tsx +151 -0
  25. package/src/components/breadcrumb/RLSBreadcrumb.tsx +194 -0
  26. package/src/components/browser-mockup/RLSBrowserMockup.tsx +21 -0
  27. package/src/components/button/RLSButton.tsx +53 -38
  28. package/src/components/button/RLVButton.vue +44 -32
  29. package/src/components/calendar/RLSCalendar.tsx +26 -0
  30. package/src/components/callout/RLSCallout.tsx +151 -0
  31. package/src/components/card/RLSCard.tsx +4 -0
  32. package/src/components/card/RLVCard.vue +4 -0
  33. package/src/components/card/card.ts +10 -0
  34. package/src/components/carousel/RLACarousel.astro +14 -1
  35. package/src/components/carousel/RLSCarousel.tsx +260 -0
  36. package/src/components/chart/RLSChart.tsx +299 -0
  37. package/src/components/chat/RLSChat.tsx +27 -0
  38. package/src/components/chat-message/RLSChatMessage.tsx +27 -0
  39. package/src/components/chat-messages/RLSChatMessages.tsx +27 -0
  40. package/src/components/chat-palette/RLSChatPalette.tsx +27 -0
  41. package/src/components/chat-prompt/RLSChatPrompt.tsx +27 -0
  42. package/src/components/chat-prompt-submit/RLSChatPromptSubmit.tsx +27 -0
  43. package/src/components/chat-reasoning/RLSChatReasoning.tsx +27 -0
  44. package/src/components/chat-shimmer/RLSChatShimmer.tsx +27 -0
  45. package/src/components/chat-tool/RLSChatTool.tsx +27 -0
  46. package/src/components/checkbox/RLACheckbox.astro +1 -0
  47. package/src/components/checkbox/RLSCheckbox.tsx +1 -1
  48. package/src/components/checkbox/checkbox.theme.ts +2 -2
  49. package/src/components/chip/RLSChip.tsx +65 -0
  50. package/src/components/collapsible/RLSCollapsible.tsx +89 -0
  51. package/src/components/color-area/RLSColorArea.tsx +554 -0
  52. package/src/components/color-field/RLSColorField.tsx +236 -0
  53. package/src/components/color-picker/RLSColorPicker.tsx +26 -0
  54. package/src/components/color-slider/RLSColorSlider.tsx +373 -0
  55. package/src/components/command-palette/RLSCommandPalette.tsx +26 -0
  56. package/src/components/compare/RLSCompare.tsx +26 -0
  57. package/src/components/confirm/RLSConfirm.tsx +173 -0
  58. package/src/components/container/RLSContainer.tsx +24 -0
  59. package/src/components/context-menu/RLSContextMenu.tsx +26 -0
  60. package/src/components/copy-markdown/RLSCopyMarkdown.tsx +57 -0
  61. package/src/components/dashboard-group/RLSDashboardGroup.tsx +29 -0
  62. package/src/components/dashboard-navbar/RLSDashboardNavbar.tsx +116 -0
  63. package/src/components/dashboard-panel/RLSDashboardPanel.tsx +84 -0
  64. package/src/components/dashboard-resize-handle/RLSDashboardResizeHandle.tsx +35 -0
  65. package/src/components/dashboard-search/RLADashboardSearch.astro +1 -1
  66. package/src/components/dashboard-search/RLSDashboardSearch.tsx +125 -0
  67. package/src/components/dashboard-search-button/RLSDashboardSearchButton.tsx +82 -0
  68. package/src/components/dashboard-sidebar/RLADashboardSidebar.astro +4 -4
  69. package/src/components/dashboard-sidebar/RLSDashboardSidebar.tsx +184 -0
  70. package/src/components/dashboard-sidebar-collapse/RLSDashboardSidebarCollapse.tsx +46 -0
  71. package/src/components/dashboard-sidebar-toggle/RLSDashboardSidebarToggle.tsx +35 -0
  72. package/src/components/dashboard-toolbar/RLSDashboardToolbar.tsx +49 -0
  73. package/src/components/date/RLSDate.tsx +34 -0
  74. package/src/components/dock/RLSDock.tsx +26 -0
  75. package/src/components/drawer/RLSDrawer.tsx +177 -0
  76. package/src/components/dropdown-menu/RLADropdownMenu.astro +250 -241
  77. package/src/components/dropdown-menu/RLSDropdownMenu.tsx +183 -86
  78. package/src/components/editor/RLSEditor.tsx +26 -0
  79. package/src/components/empty/RLSEmpty.tsx +132 -0
  80. package/src/components/error/RLSError.tsx +26 -0
  81. package/src/components/field-group/RLSFieldGroup.tsx +46 -0
  82. package/src/components/fieldset/RLSFieldset.tsx +26 -0
  83. package/src/components/file-upload/RLAFileUpload.astro +1 -1
  84. package/src/components/file-upload/RLSFileUpload.tsx +163 -0
  85. package/src/components/floating-action/RLSFloatingAction.tsx +26 -0
  86. package/src/components/footer/RLSFooter.tsx +56 -0
  87. package/src/components/form/RLSForm.tsx +34 -0
  88. package/src/components/gallery/RLSGallery.tsx +21 -0
  89. package/src/components/gamepad/RLSGamepad.tsx +269 -0
  90. package/src/components/grid/RLSGrid.tsx +29 -0
  91. package/src/components/head/RLAHead.astro +9 -0
  92. package/src/components/head/RLSHead.tsx +42 -0
  93. package/src/components/head/UIHead.astro +3 -0
  94. package/src/components/header/HeaderLayer.astro +1 -1
  95. package/src/components/header/RLSHeader.tsx +87 -0
  96. package/src/components/hover-card/RLSHoverCard.tsx +72 -0
  97. package/src/components/icon/RLSIcon.tsx +3 -1
  98. package/src/components/image/RLAImage.astro +447 -138
  99. package/src/components/image/RLSImage.tsx +545 -0
  100. package/src/components/image/image.theme.ts +19 -3
  101. package/src/components/image/image.ts +31 -1
  102. package/src/components/input/RLAInput.astro +62 -51
  103. package/src/components/input/RLSInput.tsx +1 -1
  104. package/src/components/input-date/RLSInputDate.tsx +92 -0
  105. package/src/components/input-menu/RLAInputMenu.astro +3 -3
  106. package/src/components/input-menu/RLSInputMenu.tsx +199 -0
  107. package/src/components/input-number/RLSInputNumber.tsx +184 -0
  108. package/src/components/input-pin/RLSInputPin.tsx +185 -0
  109. package/src/components/input-rating/RLAInputRating.astro +8 -8
  110. package/src/components/input-rating/RLSInputRating.tsx +198 -0
  111. package/src/components/input-rating/input-rating.ts +4 -0
  112. package/src/components/input-tags/RLSInputTags.tsx +94 -0
  113. package/src/components/input-time/RLSInputTime.tsx +92 -0
  114. package/src/components/kbd/RLSKbd.tsx +37 -0
  115. package/src/components/keyboard/RLSKeyboard.tsx +476 -0
  116. package/src/components/knob/RLSKnob.tsx +27 -0
  117. package/src/components/label/RLSLabel.tsx +27 -0
  118. package/src/components/layout-grid/RLALayoutGrid.astro +29 -29
  119. package/src/components/layout-grid/RLSLayoutGrid.tsx +402 -0
  120. package/src/components/layout-grid/layout-grid.ts +25 -1
  121. package/src/components/link/RLALink.astro +5 -5
  122. package/src/components/link/RLSLink.tsx +6 -5
  123. package/src/components/link/link.ts +21 -12
  124. package/src/components/link-group/RLSLinkGroup.tsx +76 -0
  125. package/src/components/listbox/RLSListbox.tsx +27 -0
  126. package/src/components/locale-selector/RLALocaleSelector.astro +110 -102
  127. package/src/components/locale-selector/RLSLocaleSelector.tsx +178 -0
  128. package/src/components/locale-selector/locale-selector.ts +2 -7
  129. package/src/components/logo/RLALogo.astro +153 -102
  130. package/src/components/logo/RLSLogo.tsx +129 -0
  131. package/src/components/main/RLSMain.tsx +40 -0
  132. package/src/components/marquee/RLSMarquee.tsx +80 -0
  133. package/src/components/meter/RLSMeter.tsx +27 -0
  134. package/src/components/modal/RLAModal.astro +1 -1
  135. package/src/components/modal/RLSModal.tsx +109 -72
  136. package/src/components/navigation-menu/RLANavigationMenu.astro +6 -6
  137. package/src/components/navigation-menu/RLSNavigationMenu.tsx +228 -0
  138. package/src/components/navigation-menu/navigation-menu.ts +2 -2
  139. package/src/components/package-managers/RLSPackageManagers.tsx +204 -0
  140. package/src/components/page/RLSPage.tsx +21 -0
  141. package/src/components/page-aside/RLSPageAside.tsx +21 -0
  142. package/src/components/page-body/RLSPageBody.tsx +21 -0
  143. package/src/components/page-header/RLSPageHeader.tsx +21 -0
  144. package/src/components/page-section/RLSPageSection.tsx +201 -0
  145. package/src/components/pagination/RLSPagination.tsx +114 -0
  146. package/src/components/password/RLSPassword.tsx +27 -0
  147. package/src/components/phone-mockup/RLSPhoneMockup.tsx +27 -0
  148. package/src/components/placeholder/RLSPlaceholder.tsx +47 -0
  149. package/src/components/popover/RLAPopover.astro +2 -2
  150. package/src/components/popover/RLSPopover.tsx +124 -0
  151. package/src/components/post/RLSPost.tsx +134 -0
  152. package/src/components/pricing-plan/RLSPricingPlan.tsx +26 -0
  153. package/src/components/pricing-table/RLSPricingTable.tsx +26 -0
  154. package/src/components/progress/RLSProgress.tsx +53 -0
  155. package/src/components/prose/RLSProse.tsx +26 -0
  156. package/src/components/qr-code/RLSQrCode.tsx +26 -0
  157. package/src/components/quote/RLAQuote.astro +10 -6
  158. package/src/components/quote/RLSQuote.tsx +37 -0
  159. package/src/components/quote/quote.theme.ts +5 -2
  160. package/src/components/radio-group/RLSRadioGroup.tsx +37 -0
  161. package/src/components/rating/RLSRating.tsx +27 -0
  162. package/src/components/scroll-area/RLAScrollArea.astro +1 -1
  163. package/src/components/scroll-area/RLSScrollArea.tsx +210 -0
  164. package/src/components/scroll-to-top/RLAScrollToTop.astro +5 -4
  165. package/src/components/scroll-to-top/RLSScrollToTop.tsx +145 -0
  166. package/src/components/search/RLASearch.astro +6 -6
  167. package/src/components/search/RLSSearch.tsx +237 -0
  168. package/src/components/select/RLASelect.astro +67 -4
  169. package/src/components/select/RLSSelect.tsx +107 -39
  170. package/src/components/select/RLVSelect.vue +50 -1
  171. package/src/components/select/select.theme.ts +30 -10
  172. package/src/components/select/select.ts +20 -1
  173. package/src/components/separator/RLSSeparator.tsx +92 -0
  174. package/src/components/share/RLSShare.tsx +66 -0
  175. package/src/components/shortcuts/RLAShortcuts.astro +2 -2
  176. package/src/components/shortcuts/RLSShortcuts.tsx +393 -0
  177. package/src/components/sidebar/RLASidebar.astro +1 -1
  178. package/src/components/sidebar/RLSSidebar.tsx +271 -0
  179. package/src/components/skeleton/RLSSkeleton.tsx +21 -0
  180. package/src/components/slideover/RLASlideover.astro +1 -1
  181. package/src/components/slideover/RLSSlideover.tsx +159 -0
  182. package/src/components/slider/RLSSlider.tsx +112 -0
  183. package/src/components/speed-dial/RLSSpeedDial.tsx +27 -0
  184. package/src/components/spinner/RLSSpinner.tsx +22 -0
  185. package/src/components/splitter/RLASplitter.astro +1 -1
  186. package/src/components/splitter/RLSSplitter.tsx +178 -0
  187. package/src/components/spoiler/RLSSpoiler.tsx +26 -0
  188. package/src/components/stepper/RLAStepper.astro +9 -9
  189. package/src/components/stepper/RLSStepper.tsx +205 -0
  190. package/src/components/steps/RLSSteps.tsx +108 -0
  191. package/src/components/sticky-surface/RLSStickySurface.tsx +63 -0
  192. package/src/components/surround/RLSSurround.tsx +57 -0
  193. package/src/components/switch/RLSSwitch.tsx +56 -0
  194. package/src/components/table/RLATable.astro +1044 -579
  195. package/src/components/table/RLSTable.tsx +893 -0
  196. package/src/components/table/table.theme.ts +47 -16
  197. package/src/components/table/table.ts +104 -66
  198. package/src/components/table-of-contents/RLSTableOfContents.tsx +196 -0
  199. package/src/components/tabs/RLATabs.astro +8 -8
  200. package/src/components/tabs/RLSTabs.tsx +298 -0
  201. package/src/components/textarea/RLATextarea.astro +1 -0
  202. package/src/components/textarea/RLSTextarea.tsx +3 -1
  203. package/src/components/theme-selector/RLAThemeSelector.astro +85 -56
  204. package/src/components/theme-selector/RLSThemeSelector.tsx +131 -0
  205. package/src/components/theme-selector/theme-selector.theme.ts +5 -7
  206. package/src/components/theme-selector/theme-selector.ts +11 -1
  207. package/src/components/timeline/RLSTimeline.tsx +171 -0
  208. package/src/components/toast/RLAToast.astro +2 -2
  209. package/src/components/toast/RLSToast.tsx +179 -0
  210. package/src/components/toaster/RLSToaster.tsx +82 -0
  211. package/src/components/tooltip/RLSTooltip.tsx +48 -0
  212. package/src/components/tour/RLSTour.tsx +26 -0
  213. package/src/components/tree/RLSTree.tsx +26 -0
  214. package/src/components/user/RLSUser.tsx +26 -0
  215. package/src/components/video/RLAVideo.astro +4 -1
  216. package/src/components/video/RLSVideo.tsx +158 -0
  217. package/src/components/watermark/RLSWatermark.tsx +27 -0
  218. package/src/components/window-mockup/RLSWindowMockup.tsx +27 -0
  219. package/src/preset.ts +73 -1
  220. package/src/resolver.ts +6 -1
  221. package/src/virtual.d.ts +6 -0
  222. package/dist/icons--RzV1RTU.d.mts +0 -72
@@ -0,0 +1,131 @@
1
+ import {
2
+ createMemo,
3
+ createSignal,
4
+ onCleanup,
5
+ onMount,
6
+ splitProps,
7
+ type Component,
8
+ type JSX
9
+ } from "solid-js"
10
+ import type { ThemeSelectorProps } from "./theme-selector"
11
+ import { themeSelectorTheme } from "./theme-selector.theme"
12
+ import RLSSelect from "../select/RLSSelect"
13
+ import RLSIcon from "../icon/RLSIcon"
14
+ import { defineShortcuts } from "../../shortcuts"
15
+
16
+ export interface RLSThemeSelectorProps extends ThemeSelectorProps {
17
+ children?: JSX.Element
18
+ onChange?: (theme: string) => void
19
+ }
20
+
21
+ const themeItems = [
22
+ { label: "System", value: "system", icon: "i-lucide-laptop" },
23
+ { label: "Light", value: "light", icon: "i-rl-sun" },
24
+ { label: "Dark", value: "dark", icon: "i-rl-moon" }
25
+ ]
26
+
27
+ const RLSThemeSelector: Component<RLSThemeSelectorProps> = (allProps) => {
28
+ const [props, rest] = splitProps(allProps, [
29
+ "mode",
30
+ "size",
31
+ "theme",
32
+ "ui",
33
+ "class",
34
+ "children",
35
+ "onChange"
36
+ ])
37
+
38
+ const [currentPreference, setCurrentPreference] = createSignal<string>("system")
39
+
40
+ const getPreference = () => {
41
+ if (typeof localStorage === "undefined") return "system"
42
+ const stored = localStorage.getItem("theme")
43
+ return stored === "system" || stored === "light" || stored === "dark" ? stored : "system"
44
+ }
45
+
46
+ const applyTheme = (next: string) => {
47
+ setCurrentPreference(next)
48
+ if (typeof document !== "undefined") {
49
+ const resolved =
50
+ next === "system"
51
+ ? typeof window !== "undefined" &&
52
+ window.matchMedia("(prefers-color-scheme: dark)").matches
53
+ ? "dark"
54
+ : "light"
55
+ : next
56
+ document.documentElement.setAttribute("data-theme", resolved)
57
+ localStorage.setItem("theme", next)
58
+ }
59
+ props.onChange?.(next)
60
+ }
61
+
62
+ onMount(() => {
63
+ const pref = getPreference()
64
+ applyTheme(pref)
65
+
66
+ const cycle = () => {
67
+ const cur = currentPreference()
68
+ const next = cur === "system" ? "light" : cur === "light" ? "dark" : "system"
69
+ applyTheme(next)
70
+ }
71
+
72
+ const cleanupShortcut = defineShortcuts({
73
+ meta_alt_t: {
74
+ handler: cycle,
75
+ label: "Cycle Theme",
76
+ description: "Cycle between system, light, and dark theme mode",
77
+ category: "system"
78
+ }
79
+ })
80
+
81
+ onCleanup(() => cleanupShortcut())
82
+ })
83
+
84
+ const mode = () => props.mode || "select"
85
+ const size = () => props.size || "md"
86
+
87
+ const resolvedClasses = createMemo(() =>
88
+ themeSelectorTheme({
89
+ ui: props.ui,
90
+ class: props.class
91
+ })
92
+ )
93
+
94
+ const activeIcon = () => {
95
+ const pref = currentPreference()
96
+ if (pref === "light") return "i-rl-sun"
97
+ if (pref === "dark") return "i-rl-moon"
98
+ return "i-lucide-laptop"
99
+ }
100
+
101
+ return (
102
+ <div
103
+ class={resolvedClasses().root}
104
+ data-theme-selector
105
+ data-mode={mode()}
106
+ data-theme={props.theme}
107
+ data-theme-preference={currentPreference()}
108
+ {...rest}
109
+ >
110
+ <div class={resolvedClasses().wrapper}>
111
+ <RLSSelect
112
+ items={themeItems}
113
+ value={currentPreference()}
114
+ onChange={(e) => applyTheme(e.currentTarget.value)}
115
+ size={size() as any}
116
+ variant={mode() === "icon" ? "icon" : "default"}
117
+ aria-label="Toggle theme"
118
+ class={resolvedClasses().select}
119
+ leading={
120
+ <span class="flex items-center">
121
+ <RLSIcon name={activeIcon()} class="size-4" />
122
+ </span>
123
+ }
124
+ />
125
+ </div>
126
+ {props.children}
127
+ </div>
128
+ )
129
+ }
130
+
131
+ export default RLSThemeSelector
@@ -1,12 +1,10 @@
1
1
  import { defineTheme } from "../../resolver"
2
2
 
3
3
  export const themeSelectorTheme = defineTheme("theme-selector", {
4
- slots: ["root", "sun", "moon"],
4
+ slots: ["root", "wrapper", "select"],
5
5
  base: {
6
- root: "group rounded-full hover:bg-neutral-900/50 transition-colors inline-flex items-center justify-center text-neutral-400 hover:text-white cursor-pointer",
7
- sun: "rla-theme-sun w-5 h-5 text-current",
8
- moon: "rla-theme-moon w-5 h-5 text-current"
9
- },
10
- variants: {},
11
- defaultVariants: {}
6
+ root: "inline-flex flex-col gap-1.5",
7
+ wrapper: "relative inline-block",
8
+ select: ""
9
+ }
12
10
  })
@@ -1,8 +1,18 @@
1
1
  export interface ThemeSelectorProps {
2
2
  /**
3
- * The size of the button.
3
+ * The display mode of the theme selector.
4
+ *
5
+ * @default "select"
6
+ */
7
+ mode?: "select" | "icon"
8
+ /**
9
+ * The size of the select/button.
4
10
  */
5
11
  size?: "xs" | "sm" | "md" | "lg" | "xl"
12
+ /**
13
+ * Theme variant/mode.
14
+ */
15
+ theme?: "light" | "dark"
6
16
  /**
7
17
  * Slot-specific CSS class overrides.
8
18
  */
@@ -0,0 +1,171 @@
1
+ import { createMemo, For, splitProps, type Component, type JSX } from "solid-js"
2
+ import { Dynamic } from "solid-js/web"
3
+ import type { TimelineProps, TimelineItem } from "./timeline"
4
+ import { timelineTheme } from "./timeline.theme"
5
+ import RLSAvatar from "../avatar/RLSAvatar"
6
+ import RLSIcon from "../icon/RLSIcon"
7
+
8
+ export interface RLSTimelineProps extends TimelineProps {
9
+ children?: JSX.Element
10
+ indicator?: (ctx: { item: TimelineItem; index: number }) => JSX.Element
11
+ wrapper?: (ctx: { item: TimelineItem; index: number }) => JSX.Element
12
+ }
13
+
14
+ const RLSTimeline: Component<RLSTimelineProps> = (allProps) => {
15
+ const [props, rest] = splitProps(allProps, [
16
+ "as",
17
+ "items",
18
+ "size",
19
+ "color",
20
+ "orientation",
21
+ "valueKey",
22
+ "defaultValue",
23
+ "modelValue",
24
+ "reverse",
25
+ "ui",
26
+ "class",
27
+ "children",
28
+ "indicator",
29
+ "wrapper"
30
+ ])
31
+
32
+ const items = (): TimelineItem[] => props.items ?? []
33
+ const valueKey = (): string => props.valueKey ?? "value"
34
+ const reverse = (): boolean => props.reverse === true
35
+ const orientation = (): string => props.orientation ?? "vertical"
36
+
37
+ const getItemValue = (item: TimelineItem, index: number): string | number =>
38
+ item[valueKey()] !== undefined ? item[valueKey()] : index
39
+
40
+ const getItemState = (_item: TimelineItem, index: number): "active" | "completed" | undefined => {
41
+ const activeVal = props.modelValue !== undefined ? props.modelValue : props.defaultValue
42
+ if (activeVal === undefined) return undefined
43
+
44
+ let currentIndex = -1
45
+ if (items().length > 0) {
46
+ if (typeof activeVal === "string") {
47
+ currentIndex = items().findIndex((i) => getItemValue(i, items().indexOf(i)) === activeVal)
48
+ } else if (typeof activeVal === "number") {
49
+ currentIndex = reverse() ? items().length - 1 - activeVal : activeVal
50
+ }
51
+ }
52
+
53
+ if (currentIndex === -1) return undefined
54
+ if (index === currentIndex) return "active"
55
+ if (reverse()) return index > currentIndex ? "completed" : undefined
56
+ return index < currentIndex ? "completed" : undefined
57
+ }
58
+
59
+ const resolvedClasses = createMemo(() =>
60
+ timelineTheme({
61
+ size: props.size ?? "md",
62
+ color: props.color ?? "primary",
63
+ orientation: props.orientation ?? "vertical",
64
+ reverse: props.reverse ?? false,
65
+ ui: props.ui,
66
+ class: props.class
67
+ })
68
+ )
69
+
70
+ return (
71
+ <Dynamic
72
+ component={props.as || "div"}
73
+ data-slot="root"
74
+ class={resolvedClasses().root}
75
+ data-orientation={orientation()}
76
+ {...rest}
77
+ >
78
+ {items().length > 0 ? (
79
+ <For each={items()}>
80
+ {(item, index) => {
81
+ const state = getItemState(item, index())
82
+ const isLast = index() === items().length - 1
83
+ const avatar =
84
+ typeof item.avatar === "object" && item.avatar !== null ? item.avatar : undefined
85
+
86
+ return (
87
+ <div
88
+ data-slot="item"
89
+ class={`${resolvedClasses().item} ${item.ui?.item || ""} ${item.class || ""}`}
90
+ data-state={state}
91
+ >
92
+ <div
93
+ data-slot="container"
94
+ class={`${resolvedClasses().container} ${item.ui?.container || ""}`}
95
+ >
96
+ <RLSAvatar
97
+ size={props.size ?? "md"}
98
+ src={avatar?.src}
99
+ alt={avatar?.alt}
100
+ {...(avatar ? avatar : {})}
101
+ data-slot="indicator"
102
+ class={`${resolvedClasses().indicator} ${item.ui?.indicator || ""}`}
103
+ ui={{
104
+ icon: "text-highlighted group-data-[state=completed]:text-inverted group-data-[state=active]:text-inverted",
105
+ fallback:
106
+ "text-highlighted group-data-[state=completed]:text-inverted group-data-[state=active]:text-inverted"
107
+ }}
108
+ >
109
+ {props.indicator ? (
110
+ props.indicator({ item, index: index() })
111
+ ) : item.icon ? (
112
+ <RLSIcon name={item.icon} class="text-inherit" />
113
+ ) : null}
114
+ </RLSAvatar>
115
+
116
+ {!isLast ? (
117
+ <div
118
+ data-slot="separator"
119
+ class={`${resolvedClasses().separator} ${item.ui?.separator || ""}`}
120
+ data-orientation={orientation()}
121
+ />
122
+ ) : null}
123
+ </div>
124
+
125
+ <div
126
+ data-slot="wrapper"
127
+ class={`${resolvedClasses().wrapper} ${item.ui?.wrapper || ""}`}
128
+ >
129
+ {props.wrapper ? (
130
+ props.wrapper({ item, index: index() })
131
+ ) : (
132
+ <>
133
+ {item.date ? (
134
+ <div
135
+ data-slot="date"
136
+ class={`${resolvedClasses().date} ${item.ui?.date || ""}`}
137
+ >
138
+ {item.date}
139
+ </div>
140
+ ) : null}
141
+ {item.title ? (
142
+ <div
143
+ data-slot="title"
144
+ class={`${resolvedClasses().title} ${item.ui?.title || ""}`}
145
+ >
146
+ {item.title}
147
+ </div>
148
+ ) : null}
149
+ {item.description ? (
150
+ <div
151
+ data-slot="description"
152
+ class={`${resolvedClasses().description} ${item.ui?.description || ""}`}
153
+ >
154
+ {item.description}
155
+ </div>
156
+ ) : null}
157
+ </>
158
+ )}
159
+ </div>
160
+ </div>
161
+ )
162
+ }}
163
+ </For>
164
+ ) : props.children ? (
165
+ props.children
166
+ ) : null}
167
+ </Dynamic>
168
+ )
169
+ }
170
+
171
+ export default RLSTimeline
@@ -31,7 +31,7 @@ const variantIcons: Record<string, string> = {
31
31
  info: "i-rl-info",
32
32
  }
33
33
 
34
- const icon = variantIcons[variant] ?? variantIcons.default!
34
+ const icon = variantIcons[variant] ?? variantIcons["default"]!
35
35
  const isError = variant === "error"
36
36
  ---
37
37
 
@@ -102,7 +102,7 @@ const isError = variant === "error"
102
102
  if (!dismissable) return;
103
103
 
104
104
  const close = toast.querySelector("[data-toast-close]");
105
- const duration = parseInt(toast.dataset.duration ?? "6000", 10);
105
+ const duration = parseInt(toast.dataset["duration"] ?? "6000", 10);
106
106
  let timerId: ReturnType<typeof setTimeout> | null = null;
107
107
  let startTime = Date.now();
108
108
  let remaining = duration;
@@ -0,0 +1,179 @@
1
+ import {
2
+ createMemo,
3
+ createSignal,
4
+ onMount,
5
+ onCleanup,
6
+ splitProps,
7
+ type Component,
8
+ type JSX
9
+ } from "solid-js"
10
+ import type { ToastProps } from "./toast"
11
+ import { toastTheme } from "./toast.theme"
12
+ import RLSIcon from "../icon/RLSIcon"
13
+
14
+ export interface RLSToastProps extends ToastProps {
15
+ onDismiss?: () => void
16
+ children?: JSX.Element
17
+ titleSlot?: JSX.Element
18
+ descriptionSlot?: JSX.Element
19
+ actionsSlot?: JSX.Element
20
+ }
21
+
22
+ const variantIcons: Record<string, string> = {
23
+ default: "i-rl-bell",
24
+ error: "i-rl-circleCheck",
25
+ success: "i-rl-circleCheck",
26
+ warning: "i-rl-alertTriangle",
27
+ info: "i-rl-info"
28
+ }
29
+
30
+ const RLSToast: Component<RLSToastProps> = (allProps) => {
31
+ const [props, rest] = splitProps(allProps, [
32
+ "title",
33
+ "description",
34
+ "variant",
35
+ "actionLabel",
36
+ "duration",
37
+ "dismissable",
38
+ "onDismiss",
39
+ "ui",
40
+ "class",
41
+ "children",
42
+ "titleSlot",
43
+ "descriptionSlot",
44
+ "actionsSlot"
45
+ ])
46
+
47
+ const [leaving, setLeaving] = createSignal(false)
48
+ let rootRef: HTMLDivElement | undefined
49
+ let timerId: ReturnType<typeof setTimeout> | null = null
50
+ let dismissTimerId: ReturnType<typeof setTimeout> | undefined
51
+ let startTime = 0
52
+ let remaining = props.duration ?? 6000
53
+
54
+ const isError = () => props.variant === "error"
55
+
56
+ const resolvedClasses = createMemo(() =>
57
+ toastTheme({
58
+ variant: ["success", "error", "warning", "info"].includes(props.variant ?? "")
59
+ ? (props.variant as "success" | "error" | "warning" | "info")
60
+ : "default",
61
+ ui: props.ui,
62
+ class: props.class
63
+ })
64
+ )
65
+
66
+ const icon = () => variantIcons[props.variant ?? ""] ?? variantIcons["default"]!
67
+
68
+ const dismiss = () => {
69
+ if (leaving()) return
70
+ setLeaving(true)
71
+ if (props.onDismiss) {
72
+ if (dismissTimerId !== undefined) clearTimeout(dismissTimerId)
73
+ dismissTimerId = setTimeout(props.onDismiss, 300)
74
+ }
75
+ }
76
+
77
+ const startTimer = () => {
78
+ const duration = props.duration ?? 6000
79
+ if (duration > 0 && remaining > 0 && timerId === null) {
80
+ startTime = Date.now()
81
+ timerId = setTimeout(dismiss, remaining)
82
+ }
83
+ }
84
+
85
+ const pauseTimer = () => {
86
+ if (timerId !== null) {
87
+ clearTimeout(timerId)
88
+ timerId = null
89
+ remaining -= Date.now() - startTime
90
+ }
91
+ }
92
+
93
+ onMount(() => {
94
+ const root = rootRef
95
+ if (!root) return
96
+
97
+ const duration = props.duration ?? 6000
98
+ if (duration > 0) {
99
+ startTimer()
100
+ root.addEventListener("mouseenter", pauseTimer)
101
+ root.addEventListener("mouseleave", startTimer)
102
+ root.addEventListener("focusin", pauseTimer)
103
+ root.addEventListener("focusout", (e) => {
104
+ if (!root.contains(e.relatedTarget as Node)) startTimer()
105
+ })
106
+ }
107
+
108
+ onCleanup(() => {
109
+ if (timerId !== null) clearTimeout(timerId)
110
+ if (dismissTimerId !== undefined) clearTimeout(dismissTimerId)
111
+ root.removeEventListener("mouseenter", pauseTimer)
112
+ root.removeEventListener("mouseleave", startTimer)
113
+ root.removeEventListener("focusin", pauseTimer)
114
+ })
115
+ })
116
+
117
+ return (
118
+ <div
119
+ ref={(el) => (rootRef = el)}
120
+ class={`${resolvedClasses().root} ${leaving() ? "opacity-0 translate-y-2 pointer-events-none" : ""}`}
121
+ data-slot="root"
122
+ data-toast
123
+ data-duration={props.duration ?? 6000}
124
+ data-dismissable={(props.dismissable !== false).toString()}
125
+ role={isError() ? "alert" : "status"}
126
+ aria-live={isError() ? "assertive" : "polite"}
127
+ aria-atomic="true"
128
+ tabindex="-1"
129
+ {...rest}
130
+ >
131
+ <RLSIcon name={icon()} class="size-4 shrink-0 mt-0.5" aria-hidden="true" />
132
+
133
+ <div class="flex flex-col gap-0.5 flex-1 min-w-0">
134
+ {props.titleSlot || props.title ? (
135
+ <div class={resolvedClasses().title} data-slot="title">
136
+ {props.titleSlot ? props.titleSlot : props.title}
137
+ </div>
138
+ ) : null}
139
+ {props.descriptionSlot || props.description ? (
140
+ <div class={resolvedClasses().description} data-slot="description">
141
+ {props.descriptionSlot ? props.descriptionSlot : props.description}
142
+ </div>
143
+ ) : null}
144
+ {props.children}
145
+ {props.actionsSlot || props.actionLabel ? (
146
+ <div class="flex items-center justify-end gap-2 mt-3" data-slot="actions">
147
+ {props.actionsSlot ? (
148
+ props.actionsSlot
149
+ ) : (
150
+ <button
151
+ type="button"
152
+ class={resolvedClasses().action}
153
+ data-slot="action"
154
+ data-toast-action
155
+ >
156
+ {props.actionLabel}
157
+ </button>
158
+ )}
159
+ </div>
160
+ ) : null}
161
+ </div>
162
+
163
+ {props.dismissable !== false && (
164
+ <button
165
+ type="button"
166
+ class={resolvedClasses().close}
167
+ data-slot="close"
168
+ data-toast-close
169
+ aria-label="Dismiss notification"
170
+ onClick={dismiss}
171
+ >
172
+ <RLSIcon name="i-rl-close" class="size-3.5" aria-hidden="true" />
173
+ </button>
174
+ )}
175
+ </div>
176
+ )
177
+ }
178
+
179
+ export default RLSToast
@@ -0,0 +1,82 @@
1
+ import { createSignal, For, onMount, onCleanup, splitProps, type Component } from "solid-js"
2
+ import { toasts, removeToast, addToast } from "../toast/store"
3
+ import type { ToastItem } from "../toast/store"
4
+ import RLSToast from "../toast/RLSToast"
5
+
6
+ export interface RLSToasterProps {
7
+ class?: any
8
+ [key: string]: unknown
9
+ }
10
+
11
+ const RLSToaster: Component<RLSToasterProps> = (allProps) => {
12
+ const [props, rest] = splitProps(allProps, ["class"])
13
+ const [list, setList] = createSignal<ToastItem[]>([])
14
+
15
+ onMount(() => {
16
+ const unsubscribe = toasts.subscribe((items) => setList([...items]))
17
+ onCleanup(unsubscribe)
18
+
19
+ const stored = sessionStorage.getItem("pending_toast")
20
+ if (stored) {
21
+ sessionStorage.removeItem("pending_toast")
22
+ try {
23
+ const parsed = JSON.parse(stored)
24
+ if (parsed && parsed.title) {
25
+ addToast(parsed)
26
+ }
27
+ } catch {}
28
+ }
29
+
30
+ const url = new URL(window.location.href)
31
+ let toastTitle = url.searchParams.get("toast_title")
32
+ const toastDesc = url.searchParams.get("toast_desc") ?? undefined
33
+ let toastVariant = url.searchParams.get("toast_variant") || "success"
34
+
35
+ if (!toastTitle) {
36
+ if (url.searchParams.has("signed_in")) {
37
+ toastTitle = "Signed in successfully"
38
+ } else if (url.searchParams.has("new")) {
39
+ toastTitle = "Account created successfully"
40
+ }
41
+ }
42
+
43
+ if (toastTitle) {
44
+ url.searchParams.delete("toast_title")
45
+ url.searchParams.delete("toast_desc")
46
+ url.searchParams.delete("toast_variant")
47
+ url.searchParams.delete("signed_in")
48
+ url.searchParams.delete("new")
49
+ const cleanUrl = url.pathname + (url.search ? url.search : "")
50
+ window.history.replaceState({}, "", cleanUrl)
51
+
52
+ const payload: Record<string, unknown> = { title: toastTitle, variant: toastVariant }
53
+ if (toastDesc) payload["description"] = toastDesc
54
+ addToast(payload as Omit<ToastItem, "id">)
55
+ }
56
+ })
57
+
58
+ return (
59
+ <div
60
+ id="rla-toaster-container"
61
+ class={`fixed bottom-5 right-5 z-[200] flex flex-col gap-2 max-w-sm w-full pointer-events-none ${props.class || ""}`}
62
+ aria-live="polite"
63
+ aria-atomic="false"
64
+ role="status"
65
+ {...rest}
66
+ >
67
+ <For each={list()}>
68
+ {(item) => (
69
+ <RLSToast
70
+ title={item.title}
71
+ {...(item.description ? { description: item.description } : {})}
72
+ {...(item.variant ? { variant: item.variant } : {})}
73
+ {...(item.duration ? { duration: item.duration } : {})}
74
+ onDismiss={() => removeToast(item.id)}
75
+ />
76
+ )}
77
+ </For>
78
+ </div>
79
+ )
80
+ }
81
+
82
+ export default RLSToaster
@@ -0,0 +1,48 @@
1
+ import { createMemo, splitProps, type Component, type JSX } from "solid-js"
2
+ import type { TooltipProps } from "./tooltip"
3
+ import { tooltipTheme } from "./tooltip.theme"
4
+
5
+ export interface RLSTooltipProps extends TooltipProps {
6
+ children?: JSX.Element
7
+ contentSlot?: JSX.Element
8
+ }
9
+
10
+ const RLSTooltip: Component<RLSTooltipProps> = (allProps) => {
11
+ const [props, rest] = splitProps(allProps, [
12
+ "content",
13
+ "placement",
14
+ "ui",
15
+ "class",
16
+ "children",
17
+ "contentSlot"
18
+ ])
19
+
20
+ const placement = () => props.placement ?? "top"
21
+
22
+ const resolvedClasses = createMemo(() =>
23
+ tooltipTheme({
24
+ placement: placement(),
25
+ ui: props.ui,
26
+ class: props.class
27
+ })
28
+ )
29
+
30
+ return (
31
+ <div
32
+ class={resolvedClasses().root}
33
+ data-slot="tooltip-container"
34
+ data-placement={placement()}
35
+ {...rest}
36
+ >
37
+ <div class={resolvedClasses().trigger} data-slot="trigger" tabIndex={0}>
38
+ {props.children}
39
+ </div>
40
+
41
+ <div class={resolvedClasses().content} data-slot="content" role="tooltip">
42
+ {props.contentSlot !== undefined ? props.contentSlot : props.content}
43
+ </div>
44
+ </div>
45
+ )
46
+ }
47
+
48
+ export default RLSTooltip
@@ -0,0 +1,26 @@
1
+ import { createMemo, splitProps, type Component, type JSX } from "solid-js"
2
+ import type { TourProps } from "./tour"
3
+ import { tourTheme } from "./tour.theme"
4
+
5
+ export interface RLSTourProps extends TourProps {
6
+ children?: JSX.Element
7
+ }
8
+
9
+ const RLSTour: Component<RLSTourProps> = (allProps) => {
10
+ const [props, rest] = splitProps(allProps, ["ui", "class", "children"])
11
+
12
+ const resolvedClasses = createMemo(() =>
13
+ tourTheme({
14
+ ui: props.ui,
15
+ class: props.class
16
+ })
17
+ )
18
+
19
+ return (
20
+ <div class={resolvedClasses().root} data-slot="root" {...rest}>
21
+ {props.children}
22
+ </div>
23
+ )
24
+ }
25
+
26
+ export default RLSTour