@rimelight/ui 0.0.47 → 0.0.49

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 (197) hide show
  1. package/dist/index.d.mts +4 -5
  2. package/dist/preset.mjs +73 -1
  3. package/dist/resolver.d.mts +3 -4
  4. package/dist/resolver.mjs +2 -4
  5. package/dist/shortcuts.d.mts +10 -11
  6. package/dist/stores.d.mts +3 -4
  7. package/package.json +8 -6
  8. package/src/components/3d-hover/RLS3dHover.tsx +21 -0
  9. package/src/components/accordion/RLSAccordion.tsx +112 -0
  10. package/src/components/app/RLSApp.tsx +21 -0
  11. package/src/components/aspect-ratio/RLSAspectRatio.tsx +30 -0
  12. package/src/components/audio/RLSAudio.tsx +27 -0
  13. package/src/components/avatar/RLSAvatar.tsx +142 -0
  14. package/src/components/avatar/avatar.ts +22 -21
  15. package/src/components/avatar-group/RLSAvatarGroup.tsx +163 -0
  16. package/src/components/badge/RLSBadge.tsx +1 -1
  17. package/src/components/badge/RLVBadge.vue +5 -3
  18. package/src/components/banner/RLSBanner.tsx +151 -0
  19. package/src/components/breadcrumb/RLSBreadcrumb.tsx +194 -0
  20. package/src/components/browser-mockup/RLSBrowserMockup.tsx +21 -0
  21. package/src/components/button/RLSButton.tsx +49 -40
  22. package/src/components/button/RLVButton.vue +44 -32
  23. package/src/components/calendar/RLSCalendar.tsx +26 -0
  24. package/src/components/callout/RLSCallout.tsx +151 -0
  25. package/src/components/card/RLSCard.tsx +4 -0
  26. package/src/components/card/RLVCard.vue +4 -0
  27. package/src/components/card/card.ts +10 -0
  28. package/src/components/carousel/RLACarousel.astro +14 -1
  29. package/src/components/carousel/RLSCarousel.tsx +260 -0
  30. package/src/components/chart/RLSChart.tsx +299 -0
  31. package/src/components/chat/RLSChat.tsx +27 -0
  32. package/src/components/chat-message/RLSChatMessage.tsx +27 -0
  33. package/src/components/chat-messages/RLSChatMessages.tsx +27 -0
  34. package/src/components/chat-palette/RLSChatPalette.tsx +27 -0
  35. package/src/components/chat-prompt/RLSChatPrompt.tsx +27 -0
  36. package/src/components/chat-prompt-submit/RLSChatPromptSubmit.tsx +27 -0
  37. package/src/components/chat-reasoning/RLSChatReasoning.tsx +27 -0
  38. package/src/components/chat-shimmer/RLSChatShimmer.tsx +27 -0
  39. package/src/components/chat-tool/RLSChatTool.tsx +27 -0
  40. package/src/components/checkbox/RLACheckbox.astro +1 -0
  41. package/src/components/checkbox/RLSCheckbox.tsx +1 -1
  42. package/src/components/checkbox/checkbox.theme.ts +2 -2
  43. package/src/components/chip/RLSChip.tsx +65 -0
  44. package/src/components/collapsible/RLSCollapsible.tsx +89 -0
  45. package/src/components/color-area/RLSColorArea.tsx +554 -0
  46. package/src/components/color-field/RLSColorField.tsx +236 -0
  47. package/src/components/color-picker/RLSColorPicker.tsx +26 -0
  48. package/src/components/color-slider/RLSColorSlider.tsx +373 -0
  49. package/src/components/command-palette/RLSCommandPalette.tsx +26 -0
  50. package/src/components/compare/RLSCompare.tsx +26 -0
  51. package/src/components/confirm/RLSConfirm.tsx +173 -0
  52. package/src/components/container/RLSContainer.tsx +24 -0
  53. package/src/components/context-menu/RLSContextMenu.tsx +26 -0
  54. package/src/components/copy-markdown/RLSCopyMarkdown.tsx +57 -0
  55. package/src/components/dashboard-group/RLSDashboardGroup.tsx +29 -0
  56. package/src/components/dashboard-navbar/RLSDashboardNavbar.tsx +116 -0
  57. package/src/components/dashboard-panel/RLSDashboardPanel.tsx +84 -0
  58. package/src/components/dashboard-resize-handle/RLSDashboardResizeHandle.tsx +35 -0
  59. package/src/components/dashboard-search/RLADashboardSearch.astro +1 -1
  60. package/src/components/dashboard-search/RLSDashboardSearch.tsx +125 -0
  61. package/src/components/dashboard-search-button/RLSDashboardSearchButton.tsx +82 -0
  62. package/src/components/dashboard-sidebar/RLSDashboardSidebar.tsx +184 -0
  63. package/src/components/dashboard-sidebar-collapse/RLSDashboardSidebarCollapse.tsx +46 -0
  64. package/src/components/dashboard-sidebar-toggle/RLSDashboardSidebarToggle.tsx +35 -0
  65. package/src/components/dashboard-toolbar/RLSDashboardToolbar.tsx +49 -0
  66. package/src/components/date/RLSDate.tsx +34 -0
  67. package/src/components/dock/RLSDock.tsx +26 -0
  68. package/src/components/drawer/RLSDrawer.tsx +177 -0
  69. package/src/components/dropdown-menu/RLADropdownMenu.astro +250 -241
  70. package/src/components/dropdown-menu/RLSDropdownMenu.tsx +183 -86
  71. package/src/components/editor/RLSEditor.tsx +26 -0
  72. package/src/components/empty/RLSEmpty.tsx +132 -0
  73. package/src/components/error/RLSError.tsx +26 -0
  74. package/src/components/field-group/RLSFieldGroup.tsx +46 -0
  75. package/src/components/fieldset/RLSFieldset.tsx +26 -0
  76. package/src/components/file-upload/RLSFileUpload.tsx +163 -0
  77. package/src/components/floating-action/RLSFloatingAction.tsx +26 -0
  78. package/src/components/footer/RLSFooter.tsx +56 -0
  79. package/src/components/form/RLSForm.tsx +34 -0
  80. package/src/components/gallery/RLSGallery.tsx +21 -0
  81. package/src/components/gamepad/RLSGamepad.tsx +269 -0
  82. package/src/components/grid/RLSGrid.tsx +29 -0
  83. package/src/components/head/RLAHead.astro +9 -0
  84. package/src/components/head/RLSHead.tsx +42 -0
  85. package/src/components/head/UIHead.astro +3 -0
  86. package/src/components/header/RLSHeader.tsx +87 -0
  87. package/src/components/hover-card/RLSHoverCard.tsx +72 -0
  88. package/src/components/icon/RLSIcon.tsx +3 -1
  89. package/src/components/image/RLAImage.astro +447 -138
  90. package/src/components/image/RLSImage.tsx +545 -0
  91. package/src/components/image/image.theme.ts +19 -3
  92. package/src/components/image/image.ts +31 -1
  93. package/src/components/input/RLAInput.astro +62 -51
  94. package/src/components/input/RLSInput.tsx +1 -1
  95. package/src/components/input-date/RLSInputDate.tsx +92 -0
  96. package/src/components/input-menu/RLSInputMenu.tsx +199 -0
  97. package/src/components/input-number/RLSInputNumber.tsx +184 -0
  98. package/src/components/input-pin/RLSInputPin.tsx +185 -0
  99. package/src/components/input-rating/RLSInputRating.tsx +198 -0
  100. package/src/components/input-rating/input-rating.ts +4 -0
  101. package/src/components/input-tags/RLSInputTags.tsx +94 -0
  102. package/src/components/input-time/RLSInputTime.tsx +92 -0
  103. package/src/components/kbd/RLSKbd.tsx +37 -0
  104. package/src/components/keyboard/RLSKeyboard.tsx +476 -0
  105. package/src/components/knob/RLSKnob.tsx +27 -0
  106. package/src/components/label/RLSLabel.tsx +27 -0
  107. package/src/components/layout-grid/RLSLayoutGrid.tsx +402 -0
  108. package/src/components/layout-grid/layout-grid.ts +25 -1
  109. package/src/components/link/RLSLink.tsx +2 -1
  110. package/src/components/link/link.ts +21 -12
  111. package/src/components/link-group/RLSLinkGroup.tsx +76 -0
  112. package/src/components/listbox/RLSListbox.tsx +27 -0
  113. package/src/components/locale-selector/RLALocaleSelector.astro +2 -1
  114. package/src/components/locale-selector/RLSLocaleSelector.tsx +178 -0
  115. package/src/components/logo/RLALogo.astro +69 -4
  116. package/src/components/logo/RLSLogo.tsx +129 -0
  117. package/src/components/main/RLSMain.tsx +40 -0
  118. package/src/components/marquee/RLSMarquee.tsx +80 -0
  119. package/src/components/meter/RLSMeter.tsx +27 -0
  120. package/src/components/modal/RLAModal.astro +1 -1
  121. package/src/components/modal/RLSModal.tsx +109 -72
  122. package/src/components/navigation-menu/RLSNavigationMenu.tsx +228 -0
  123. package/src/components/navigation-menu/navigation-menu.ts +2 -2
  124. package/src/components/package-managers/RLSPackageManagers.tsx +204 -0
  125. package/src/components/page/RLSPage.tsx +21 -0
  126. package/src/components/page-aside/RLSPageAside.tsx +21 -0
  127. package/src/components/page-body/RLSPageBody.tsx +21 -0
  128. package/src/components/page-header/RLSPageHeader.tsx +21 -0
  129. package/src/components/page-section/RLSPageSection.tsx +201 -0
  130. package/src/components/pagination/RLSPagination.tsx +114 -0
  131. package/src/components/password/RLSPassword.tsx +27 -0
  132. package/src/components/phone-mockup/RLSPhoneMockup.tsx +27 -0
  133. package/src/components/placeholder/RLSPlaceholder.tsx +47 -0
  134. package/src/components/popover/RLSPopover.tsx +124 -0
  135. package/src/components/post/RLSPost.tsx +134 -0
  136. package/src/components/pricing-plan/RLSPricingPlan.tsx +26 -0
  137. package/src/components/pricing-table/RLSPricingTable.tsx +26 -0
  138. package/src/components/progress/RLSProgress.tsx +53 -0
  139. package/src/components/prose/RLSProse.tsx +26 -0
  140. package/src/components/qr-code/RLSQrCode.tsx +26 -0
  141. package/src/components/quote/RLAQuote.astro +10 -6
  142. package/src/components/quote/RLSQuote.tsx +37 -0
  143. package/src/components/quote/quote.theme.ts +5 -2
  144. package/src/components/radio-group/RLSRadioGroup.tsx +37 -0
  145. package/src/components/rating/RLSRating.tsx +27 -0
  146. package/src/components/scroll-area/RLSScrollArea.tsx +210 -0
  147. package/src/components/scroll-to-top/RLAScrollToTop.astro +1 -0
  148. package/src/components/scroll-to-top/RLSScrollToTop.tsx +145 -0
  149. package/src/components/search/RLSSearch.tsx +237 -0
  150. package/src/components/select/RLASelect.astro +67 -4
  151. package/src/components/select/RLSSelect.tsx +107 -39
  152. package/src/components/select/RLVSelect.vue +50 -1
  153. package/src/components/select/select.theme.ts +30 -10
  154. package/src/components/select/select.ts +20 -1
  155. package/src/components/separator/RLSSeparator.tsx +92 -0
  156. package/src/components/share/RLSShare.tsx +66 -0
  157. package/src/components/shortcuts/RLSShortcuts.tsx +393 -0
  158. package/src/components/sidebar/RLSSidebar.tsx +271 -0
  159. package/src/components/skeleton/RLSSkeleton.tsx +21 -0
  160. package/src/components/slideover/RLASlideover.astro +1 -1
  161. package/src/components/slideover/RLSSlideover.tsx +159 -0
  162. package/src/components/slider/RLSSlider.tsx +112 -0
  163. package/src/components/speed-dial/RLSSpeedDial.tsx +27 -0
  164. package/src/components/spinner/RLSSpinner.tsx +22 -0
  165. package/src/components/splitter/RLSSplitter.tsx +178 -0
  166. package/src/components/spoiler/RLSSpoiler.tsx +26 -0
  167. package/src/components/stepper/RLSStepper.tsx +205 -0
  168. package/src/components/steps/RLSSteps.tsx +108 -0
  169. package/src/components/sticky-surface/RLSStickySurface.tsx +63 -0
  170. package/src/components/surround/RLSSurround.tsx +57 -0
  171. package/src/components/switch/RLSSwitch.tsx +56 -0
  172. package/src/components/table/RLATable.astro +1044 -579
  173. package/src/components/table/RLSTable.tsx +893 -0
  174. package/src/components/table/table.theme.ts +47 -16
  175. package/src/components/table/table.ts +104 -66
  176. package/src/components/table-of-contents/RLSTableOfContents.tsx +196 -0
  177. package/src/components/tabs/RLSTabs.tsx +298 -0
  178. package/src/components/textarea/RLATextarea.astro +1 -0
  179. package/src/components/textarea/RLSTextarea.tsx +3 -1
  180. package/src/components/theme-selector/RLAThemeSelector.astro +85 -56
  181. package/src/components/theme-selector/RLSThemeSelector.tsx +131 -0
  182. package/src/components/theme-selector/theme-selector.theme.ts +5 -7
  183. package/src/components/theme-selector/theme-selector.ts +11 -1
  184. package/src/components/timeline/RLSTimeline.tsx +171 -0
  185. package/src/components/toast/RLSToast.tsx +179 -0
  186. package/src/components/toaster/RLSToaster.tsx +82 -0
  187. package/src/components/tooltip/RLSTooltip.tsx +48 -0
  188. package/src/components/tour/RLSTour.tsx +26 -0
  189. package/src/components/tree/RLSTree.tsx +26 -0
  190. package/src/components/user/RLSUser.tsx +26 -0
  191. package/src/components/video/RLAVideo.astro +4 -1
  192. package/src/components/video/RLSVideo.tsx +158 -0
  193. package/src/components/watermark/RLSWatermark.tsx +27 -0
  194. package/src/components/window-mockup/RLSWindowMockup.tsx +27 -0
  195. package/src/preset.ts +73 -1
  196. package/src/resolver.ts +6 -1
  197. package/src/virtual.d.ts +6 -0
@@ -0,0 +1,402 @@
1
+ import {
2
+ createMemo,
3
+ createSignal,
4
+ createEffect,
5
+ splitProps,
6
+ Show,
7
+ onMount,
8
+ onCleanup,
9
+ type Component
10
+ } from "solid-js"
11
+ import { Dynamic } from "solid-js/web"
12
+ import type { LayoutGridProps } from "./layout-grid"
13
+ import { layoutGridTheme } from "./layout-grid.theme"
14
+ import { defineShortcuts } from "../../shortcuts"
15
+
16
+ const isDev = (import.meta as ImportMeta & { env?: { DEV?: boolean } }).env?.DEV === true
17
+
18
+ const normalizeArray = (val: number | number[] | undefined, defaultValue: number): number[] => {
19
+ if (val === undefined)
20
+ return [defaultValue, defaultValue, defaultValue, defaultValue, defaultValue]
21
+ if (!Array.isArray(val)) return [val, val, val, val, val]
22
+ const arr = [...val]
23
+ while (arr.length < 5) {
24
+ const lastVal = arr[arr.length - 1]
25
+ arr.push(lastVal !== undefined ? lastVal : defaultValue)
26
+ }
27
+ return arr
28
+ }
29
+
30
+ const hexToRgba = (hex: string, alpha: number): string => {
31
+ const cleanHex = hex.replace("#", "")
32
+ const num = parseInt(cleanHex, 16)
33
+ const r = (num >> 16) & 255
34
+ const g = (num >> 8) & 255
35
+ const b = num & 255
36
+ return `rgba(${r}, ${g}, ${b}, ${alpha})`
37
+ }
38
+
39
+ export interface RLSLayoutGridProps extends LayoutGridProps {}
40
+
41
+ const RLSLayoutGrid: Component<RLSLayoutGridProps> = (allProps) => {
42
+ const [props, rest] = splitProps(allProps, [
43
+ "cols",
44
+ "smCols",
45
+ "mdCols",
46
+ "lgCols",
47
+ "xlCols",
48
+ "smBreakpoint",
49
+ "mdBreakpoint",
50
+ "lgBreakpoint",
51
+ "xlBreakpoint",
52
+ "gutter",
53
+ "margin",
54
+ "gridColor",
55
+ "gridOpacity",
56
+ "maxWidth",
57
+ "innerMaxWidth",
58
+ "innerGridColor",
59
+ "innerGridOpacity",
60
+ "showInnerBackground",
61
+ "showBackground",
62
+ "showFullWidth",
63
+ "fullWidthGridColor",
64
+ "fullWidthGridOpacity",
65
+ "showFullWidthBackground",
66
+ "zIndex",
67
+ "shortcut",
68
+ "devOnly",
69
+ "ui",
70
+ "class"
71
+ ])
72
+
73
+ const resolvedClasses = createMemo(() => layoutGridTheme({ ui: props.ui, class: props.class }))
74
+
75
+ const gutterArray = createMemo(() => normalizeArray(props.gutter ?? [0.75, 1, 1.5, 2, 2], 1))
76
+ const marginArray = createMemo(() => normalizeArray(props.margin ?? [0.75, 1, 1.5, 2, 2], 1))
77
+
78
+ const shouldRender = () => !(props.devOnly ?? true) || isDev
79
+
80
+ let hostRef: HTMLElement | undefined
81
+ let overlayRef: HTMLElement | undefined
82
+ let columnsRef: HTMLElement | undefined
83
+ let indicatorRef: HTMLElement | undefined
84
+
85
+ const [visible, setVisible] = createSignal(false)
86
+ const [currentBreakpoint, setCurrentBreakpoint] = createSignal<
87
+ "base" | "sm" | "md" | "lg" | "xl"
88
+ >("base")
89
+
90
+ const toggleGrid = () => {
91
+ setVisible((wasVisible) => {
92
+ const next = !wasVisible
93
+ if (typeof localStorage !== "undefined") {
94
+ localStorage.setItem("rla-grid-visible", next ? "true" : "false")
95
+ }
96
+ if (overlayRef) overlayRef.style.display = next ? "block" : "none"
97
+ return next
98
+ })
99
+ }
100
+
101
+ onMount(() => {
102
+ if (typeof localStorage !== "undefined") {
103
+ setVisible(localStorage.getItem("rla-grid-visible") === "true")
104
+ }
105
+
106
+ const updateBreakpoint = () => {
107
+ const width = document.documentElement.clientWidth
108
+ const sm = props.smBreakpoint ?? 640
109
+ const md = props.mdBreakpoint ?? 768
110
+ const lg = props.lgBreakpoint ?? 1024
111
+ const xl = props.xlBreakpoint ?? 1280
112
+ let next: "base" | "sm" | "md" | "lg" | "xl" = "base"
113
+ if (width >= xl) next = "xl"
114
+ else if (width >= lg) next = "lg"
115
+ else if (width >= md) next = "md"
116
+ else if (width >= sm) next = "sm"
117
+ setCurrentBreakpoint(next)
118
+ }
119
+ updateBreakpoint()
120
+
121
+ const resizeObserver = new ResizeObserver(updateBreakpoint)
122
+ resizeObserver.observe(document.documentElement)
123
+
124
+ const cleanupShortcuts = defineShortcuts({
125
+ [props.shortcut ?? "meta_shift_g"]: {
126
+ handler: (e) => {
127
+ e.preventDefault()
128
+ toggleGrid()
129
+ },
130
+ label: "Toggle Layout Grid",
131
+ description: "Show or hide the development layout grid guide overlay",
132
+ category: "development"
133
+ }
134
+ })
135
+
136
+ onCleanup(() => {
137
+ resizeObserver.disconnect()
138
+ cleanupShortcuts()
139
+ })
140
+ })
141
+
142
+ const updateGrid = () => {
143
+ const columnsContainer = columnsRef
144
+ const indicatorElement = indicatorRef
145
+ if (!columnsContainer || !visible()) return
146
+
147
+ const width = document.documentElement.clientWidth
148
+ const smBreakpoint = props.smBreakpoint ?? 640
149
+ const mdBreakpoint = props.mdBreakpoint ?? 768
150
+ const lgBreakpoint = props.lgBreakpoint ?? 1024
151
+ const xlBreakpoint = props.xlBreakpoint ?? 1280
152
+
153
+ let breakpointIndex = 0
154
+ let colCount = props.cols ?? 4
155
+ let breakpointThreshold = 0
156
+
157
+ switch (currentBreakpoint()) {
158
+ case "xl":
159
+ breakpointIndex = 4
160
+ colCount = props.xlCols ?? 12
161
+ breakpointThreshold = xlBreakpoint
162
+ break
163
+ case "lg":
164
+ breakpointIndex = 3
165
+ colCount = props.lgCols ?? 12
166
+ breakpointThreshold = lgBreakpoint
167
+ break
168
+ case "md":
169
+ breakpointIndex = 2
170
+ colCount = props.mdCols ?? 8
171
+ breakpointThreshold = mdBreakpoint
172
+ break
173
+ case "sm":
174
+ breakpointIndex = 1
175
+ colCount = props.smCols ?? 4
176
+ breakpointThreshold = smBreakpoint
177
+ break
178
+ default:
179
+ breakpointIndex = 0
180
+ colCount = props.cols ?? 4
181
+ breakpointThreshold = 0
182
+ break
183
+ }
184
+
185
+ const gutters = gutterArray()
186
+ const margins = marginArray()
187
+ const gutterValue = gutters[breakpointIndex] ?? gutters[gutters.length - 1] ?? 1
188
+ const marginValue = margins[breakpointIndex] ?? margins[margins.length - 1] ?? 1
189
+
190
+ const gridColor = props.gridColor ?? "#ff0000"
191
+ const gridOpacity = props.gridOpacity ?? 0.1
192
+ const showBackground = props.showBackground ?? true
193
+ const showFullWidth = props.showFullWidth ?? true
194
+ const fullWidthColor = props.fullWidthGridColor ?? "#3b82f6"
195
+ const fullWidthOpacity = props.fullWidthGridOpacity ?? 0.05
196
+ const showFullWidthBackground = props.showFullWidthBackground ?? true
197
+
198
+ const rootFontSize = parseFloat(getComputedStyle(document.documentElement).fontSize) || 16
199
+ const marginPx = marginValue * rootFontSize
200
+ const gutterPx = gutterValue * rootFontSize
201
+
202
+ const maxWidthVal = props.maxWidth ?? "1440px"
203
+ let maxWidthPx = width
204
+ if (!maxWidthVal.includes("vw")) {
205
+ maxWidthPx = parseInt(maxWidthVal)
206
+ }
207
+
208
+ const innerMaxWidthVal = props.innerMaxWidth ?? "768px"
209
+ let innerMaxWidthPx = width
210
+ if (!innerMaxWidthVal.includes("vw")) {
211
+ innerMaxWidthPx = parseInt(innerMaxWidthVal)
212
+ }
213
+
214
+ const innerGridColor = props.innerGridColor ?? "#10b981"
215
+ const innerGridOpacity = props.innerGridOpacity ?? 0.1
216
+ const showInnerBackground = props.showInnerBackground ?? true
217
+
218
+ const activeWidth = width > maxWidthPx ? maxWidthPx : width
219
+ const innerWidth = activeWidth - 2 * marginPx
220
+ const colWidth = (innerWidth - (colCount - 1) * gutterPx) / colCount
221
+
222
+ const containerLeft = (width - maxWidthPx) / 2
223
+ const containerRight = (width + maxWidthPx) / 2
224
+
225
+ columnsContainer.innerHTML = ""
226
+
227
+ hostRef?.style.setProperty("--rla-grid-cols", colCount.toString())
228
+ hostRef?.style.setProperty("--rla-grid-gap", `${gutterPx}px`)
229
+ hostRef?.style.setProperty("--rla-grid-margin", `${marginPx}px`)
230
+ hostRef?.style.setProperty("--rla-grid-max-width", maxWidthVal)
231
+
232
+ const rootStyle = document.documentElement.style
233
+ rootStyle.setProperty("--rla-grid-cols", colCount.toString())
234
+ rootStyle.setProperty("--rla-grid-gap", `${gutterPx}px`)
235
+ rootStyle.setProperty("--rla-grid-gutter", `${gutterPx}px`)
236
+ rootStyle.setProperty("--rla-grid-col-width", `${colWidth}px`)
237
+ rootStyle.setProperty("--rla-grid-margin", `${marginPx}px`)
238
+ rootStyle.setProperty("--rla-grid-max-width", maxWidthVal)
239
+
240
+ const containerStartX = width > maxWidthPx ? containerLeft + marginPx : marginPx
241
+ const step = colWidth + gutterPx
242
+
243
+ let totalCols = colCount
244
+ if (width > maxWidthPx && showFullWidth) {
245
+ let leftX = marginPx
246
+ while (leftX + colWidth < containerLeft) {
247
+ totalCols++
248
+ leftX += step
249
+ }
250
+ let rightX = width - marginPx - colWidth
251
+ while (rightX > containerRight) {
252
+ totalCols++
253
+ rightX -= step
254
+ }
255
+ }
256
+
257
+ if (indicatorElement) {
258
+ indicatorElement.innerHTML = `<span style="color: #3b82f6;">${currentBreakpoint().toUpperCase()} (${breakpointThreshold}px)</span> <span style="opacity: 0.35;">|</span> <span>${width}px</span> <span style="opacity: 0.35;">|</span> <span style="color: #ef4444;">${totalCols} Cols</span>`
259
+ }
260
+
261
+ const gridWrapper = document.createElement("div")
262
+ gridWrapper.className =
263
+ "mx-auto w-full max-w-[1440px] px-xs sm:px-md md:px-xl lg:px-xl gap-xs sm:gap-md md:gap-xl lg:gap-xl h-full box-border grid"
264
+ gridWrapper.style.gridTemplateColumns = "repeat(var(--rla-grid-cols), 1fr)"
265
+
266
+ const innerLeft = (width - innerMaxWidthPx) / 2
267
+ const innerRight = (width + innerMaxWidthPx) / 2
268
+
269
+ for (let i = 0; i < colCount; i++) {
270
+ const colX = containerStartX + i * step
271
+ const colRight = colX + colWidth
272
+ const isInner = colX >= innerLeft - 1 && colRight <= innerRight + 1
273
+
274
+ const col = document.createElement("div")
275
+ col.className = "grid-column"
276
+ const color = isInner ? innerGridColor : gridColor
277
+ const opacity = isInner ? innerGridOpacity : gridOpacity
278
+ const bg = isInner ? showInnerBackground : showBackground
279
+ Object.assign(col.style, {
280
+ height: "100%",
281
+ borderInline: `1px solid ${color}`,
282
+ boxSizing: "border-box",
283
+ backgroundColor: bg ? hexToRgba(color, opacity) : "transparent"
284
+ })
285
+ gridWrapper.appendChild(col)
286
+ }
287
+
288
+ columnsContainer.appendChild(gridWrapper)
289
+
290
+ if (width > maxWidthPx && showFullWidth) {
291
+ const drawOuterColumn = (x: number) => {
292
+ const col = document.createElement("div")
293
+ col.className = "rla-outer-column"
294
+ Object.assign(col.style, {
295
+ position: "absolute",
296
+ top: "0",
297
+ left: `${x}px`,
298
+ width: `${colWidth}px`,
299
+ height: "100%",
300
+ borderInline: `1px solid ${fullWidthColor}`,
301
+ boxSizing: "border-box",
302
+ backgroundColor: showFullWidthBackground
303
+ ? hexToRgba(fullWidthColor, fullWidthOpacity)
304
+ : "transparent"
305
+ })
306
+ columnsContainer.appendChild(col)
307
+ }
308
+
309
+ let leftX = marginPx
310
+ while (leftX + colWidth < containerLeft) {
311
+ drawOuterColumn(leftX)
312
+ leftX += step
313
+ }
314
+
315
+ let rightX = width - marginPx - colWidth
316
+ while (rightX > containerRight) {
317
+ drawOuterColumn(rightX)
318
+ rightX -= step
319
+ }
320
+ }
321
+ }
322
+
323
+ createEffect(() => {
324
+ if (overlayRef) overlayRef.style.display = visible() ? "block" : "none"
325
+ updateGrid()
326
+ })
327
+
328
+ return (
329
+ <Show when={shouldRender()}>
330
+ <Dynamic
331
+ component={"rla-layout-grid"}
332
+ ref={(el: Element) => (hostRef = el as HTMLElement | undefined)}
333
+ class={resolvedClasses().root}
334
+ data-cols={props.cols ?? 4}
335
+ data-sm-cols={props.smCols ?? 4}
336
+ data-md-cols={props.mdCols ?? 8}
337
+ data-lg-cols={props.lgCols ?? 12}
338
+ data-xl-cols={props.xlCols ?? 12}
339
+ data-sm-breakpoint={props.smBreakpoint ?? 640}
340
+ data-md-breakpoint={props.mdBreakpoint ?? 768}
341
+ data-lg-breakpoint={props.lgBreakpoint ?? 1024}
342
+ data-xl-breakpoint={props.xlBreakpoint ?? 1280}
343
+ data-gutter={JSON.stringify(gutterArray())}
344
+ data-margin={JSON.stringify(marginArray())}
345
+ data-grid-color={props.gridColor ?? "#ff0000"}
346
+ data-grid-opacity={props.gridOpacity ?? 0.1}
347
+ data-show-background={(props.showBackground ?? true) ? "true" : "false"}
348
+ data-max-width={props.maxWidth ?? "1440px"}
349
+ data-inner-max-width={props.innerMaxWidth ?? "768px"}
350
+ data-inner-color={props.innerGridColor ?? "#10b981"}
351
+ data-inner-opacity={props.innerGridOpacity ?? 0.1}
352
+ data-show-inner-background={(props.showInnerBackground ?? true) ? "true" : "false"}
353
+ data-show-full-width={(props.showFullWidth ?? true) ? "true" : "false"}
354
+ data-full-width-color={props.fullWidthGridColor ?? "#3b82f6"}
355
+ data-full-width-opacity={props.fullWidthGridOpacity ?? 0.05}
356
+ data-show-full-width-background={(props.showFullWidthBackground ?? true) ? "true" : "false"}
357
+ data-shortcut={props.shortcut ?? "meta_shift_g"}
358
+ style={{ display: "contents" }}
359
+ {...rest}
360
+ >
361
+ <aside
362
+ ref={(el) => (overlayRef = el as HTMLElement | undefined)}
363
+ class={resolvedClasses().overlay}
364
+ data-slot="overlay"
365
+ style={{ "z-index": `${props.zIndex ?? 1000}`, "display": "none" }}
366
+ id="rla-layout-grid-overlay"
367
+ >
368
+ <div
369
+ ref={(el) => (columnsRef = el as HTMLElement | undefined)}
370
+ style={{ position: "relative", width: "100%", height: "100%" }}
371
+ data-slot="columns-container"
372
+ />
373
+ <div
374
+ ref={(el) => (indicatorRef = el as HTMLElement | undefined)}
375
+ data-slot="indicator"
376
+ style={{
377
+ "position": "fixed",
378
+ "bottom": "20px",
379
+ "right": "20px",
380
+ "background": "rgba(0,0,0,0.85)",
381
+ "color": "#fff",
382
+ "padding": "6px 12px",
383
+ "border-radius": "6px",
384
+ "font-family": "var(--font-mono, monospace)",
385
+ "font-size": "11px",
386
+ "font-weight": "bold",
387
+ "pointer-events": "none",
388
+ "border": "1px solid rgba(255,255,255,0.15)",
389
+ "box-shadow": "0 4px 12px rgba(0,0,0,0.5)",
390
+ "letter-spacing": "0.05em",
391
+ "display": "flex",
392
+ "align-items": "center",
393
+ "gap": "8px"
394
+ }}
395
+ />
396
+ </aside>
397
+ </Dynamic>
398
+ </Show>
399
+ )
400
+ }
401
+
402
+ export default RLSLayoutGrid
@@ -133,6 +133,30 @@ export interface LayoutGridProps {
133
133
  * @default true
134
134
  */
135
135
  devOnly?: boolean
136
+ /**
137
+ * Maximum width of the inner content container (CSS max-width string).
138
+ *
139
+ * @default "768px"
140
+ */
141
+ innerMaxWidth?: string
142
+ /**
143
+ * Color value for inner grid.
144
+ *
145
+ * @default "#10b981"
146
+ */
147
+ innerGridColor?: string
148
+ /**
149
+ * Opacity for inner grid background.
150
+ *
151
+ * @default 0.1
152
+ */
153
+ innerGridOpacity?: number
154
+ /**
155
+ * Whether to display background for inner grid.
156
+ *
157
+ * @default true
158
+ */
159
+ showInnerBackground?: boolean
136
160
  /**
137
161
  * UI class overrides for components elements slots.
138
162
  */
@@ -141,5 +165,5 @@ export interface LayoutGridProps {
141
165
  * CSS class to apply to the root wrapper.
142
166
  */
143
167
  class?: any
144
- [key: string]: unknown
168
+ [key: string]: any
145
169
  }
@@ -4,7 +4,7 @@ import { linkTheme } from "./link.theme"
4
4
  import RLSIcon from "../icon/RLSIcon"
5
5
  import { resolveLinkAttrs } from "./helpers"
6
6
 
7
- type RLSLinkProps = LinkProps & {
7
+ export interface RLSLinkProps extends LinkProps {
8
8
  children?: JSX.Element
9
9
  leading?: JSX.Element
10
10
  trailing?: JSX.Element
@@ -55,6 +55,7 @@ const RLSLink: Component<RLSLinkProps> = (allProps) => {
55
55
  <a
56
56
  class={classes()["root"]}
57
57
  data-slot="root"
58
+ data-theme={props.theme}
58
59
  href={attrs().href}
59
60
  target={attrs().target}
60
61
  rel={attrs().rel}
@@ -22,71 +22,80 @@ export interface LinkProps {
22
22
  *
23
23
  * @default false
24
24
  */
25
- external?: boolean
25
+ external?: boolean | undefined
26
26
  /**
27
27
  * Custom external link icon name.
28
28
  *
29
29
  * @default "externalLink"
30
30
  */
31
- externalIcon?: string
31
+ externalIcon?: string | undefined
32
32
  /**
33
33
  * Suppress the automatic external link icon.
34
34
  *
35
35
  * @default false
36
36
  */
37
- noExternalIcon?: boolean
37
+ noExternalIcon?: boolean | undefined
38
38
  /**
39
39
  * Where to open the linked URL. External links default to `"_blank"`.
40
40
  *
41
41
  * @default undefined
42
42
  */
43
- target?: string
43
+ target?: string | undefined
44
44
  /**
45
45
  * Relationship of the linked URL. External links default to `"noopener noreferrer"`. Set to empty
46
46
  * string to suppress the attribute entirely.
47
47
  *
48
48
  * @default undefined
49
49
  */
50
- rel?: string | null
50
+ rel?: string | null | undefined
51
51
  /**
52
52
  * Enables Astro's built-in prefetch strategy.
53
53
  *
54
54
  * @default undefined;
55
55
  */
56
- prefetch?: boolean | "hover" | "tap" | "load" | "viewport"
56
+ prefetch?: boolean | "hover" | "tap" | "load" | "viewport" | undefined
57
57
  /**
58
58
  * Applies active styling to the link.
59
59
  *
60
60
  * @default undefined
61
61
  */
62
- active?: boolean
62
+ active?: boolean | undefined
63
63
  /**
64
64
  * Disables the link, preventing navigation and applying disabled styling.
65
65
  *
66
66
  * @default false
67
67
  */
68
- disabled?: boolean
68
+ disabled?: boolean | undefined
69
69
  /**
70
70
  * When true, only `class` is applied — all default theme styles are skipped.
71
71
  *
72
72
  * @default false
73
73
  */
74
- raw?: boolean
74
+ raw?: boolean | undefined
75
75
  /**
76
76
  * Screen reader accessibility label. When omitted on external links, "(opens in a new tab)" is
77
77
  * appended automatically.
78
78
  */
79
- ariaLabel?: string
79
+ ariaLabel?: string | undefined
80
80
  /**
81
81
  * The value of `aria-current` when the link is the active/current page.
82
82
  *
83
83
  * @default "page"
84
84
  */
85
- ariaCurrentValue?: "page" | "step" | "location" | "date" | "time" | "true" | "false" | boolean
85
+ ariaCurrentValue?:
86
+ | "page"
87
+ | "step"
88
+ | "location"
89
+ | "date"
90
+ | "time"
91
+ | "true"
92
+ | "false"
93
+ | boolean
94
+ | undefined
86
95
  /**
87
96
  * Force a color-scheme context on the component.
88
97
  */
89
- theme?: Theme
98
+ theme?: Theme | undefined
90
99
  /**
91
100
  * Slot-specific CSS class overrides.
92
101
  */
@@ -0,0 +1,76 @@
1
+ import { createMemo, splitProps, For, Show, type Component, type JSX } from "solid-js"
2
+ import type { LinkGroupProps } from "./link-group"
3
+ import { linkGroupTheme } from "./link-group.theme"
4
+ import RLSLink from "../link/RLSLink"
5
+ import RLSIcon from "../icon/RLSIcon"
6
+
7
+ export interface RLSLinkGroupProps extends LinkGroupProps {
8
+ children?: JSX.Element
9
+ }
10
+
11
+ const RLSLinkGroup: Component<RLSLinkGroupProps> = (allProps) => {
12
+ const [props, rest] = splitProps(allProps, [
13
+ "label",
14
+ "leadingIcon",
15
+ "trailingIcon",
16
+ "href",
17
+ "links",
18
+ "theme",
19
+ "ui",
20
+ "class",
21
+ "children"
22
+ ])
23
+
24
+ const resolvedClasses = createMemo(() =>
25
+ linkGroupTheme({
26
+ ui: props.ui,
27
+ class: props.class
28
+ })
29
+ )
30
+
31
+ const normalizedLinks = createMemo(() => {
32
+ if (!props.links) return []
33
+ return Array.isArray(props.links) ? props.links : [props.links]
34
+ })
35
+
36
+ return (
37
+ <div class={resolvedClasses().root} data-slot="root" data-theme={props.theme} {...rest}>
38
+ {props.label ? (
39
+ <h4 class={resolvedClasses().title} data-slot="title">
40
+ {props.href ? (
41
+ <a href={props.href} class="hover:underline flex items-center gap-1.5">
42
+ {props.leadingIcon && <RLSIcon name={props.leadingIcon} size="sm" />}
43
+ <span>{props.label}</span>
44
+ {props.trailingIcon && <RLSIcon name={props.trailingIcon} size="sm" />}
45
+ </a>
46
+ ) : (
47
+ <span class="flex items-center gap-1.5">
48
+ {props.leadingIcon && <RLSIcon name={props.leadingIcon} size="sm" />}
49
+ <span>{props.label}</span>
50
+ {props.trailingIcon && <RLSIcon name={props.trailingIcon} size="sm" />}
51
+ </span>
52
+ )}
53
+ </h4>
54
+ ) : null}
55
+
56
+ <ul class={resolvedClasses().list} data-slot="list">
57
+ <Show when={!props.children} fallback={props.children}>
58
+ <For each={normalizedLinks()}>
59
+ {(link) => (
60
+ <li class={resolvedClasses().item} data-slot="item">
61
+ <RLSLink
62
+ theme={link.theme ?? props.theme}
63
+ class={`${resolvedClasses().link} w-full !justify-start`}
64
+ data-slot="link"
65
+ {...link}
66
+ />
67
+ </li>
68
+ )}
69
+ </For>
70
+ </Show>
71
+ </ul>
72
+ </div>
73
+ )
74
+ }
75
+
76
+ export default RLSLinkGroup
@@ -0,0 +1,27 @@
1
+ import { createMemo, splitProps, type Component, type JSX } from "solid-js"
2
+ import type { ListboxProps } from "./listbox"
3
+ import { listboxTheme } from "./listbox.theme"
4
+
5
+ export interface RLSListboxProps extends ListboxProps {
6
+ children?: JSX.Element
7
+ }
8
+
9
+ const RLSListbox: Component<RLSListboxProps> = (allProps) => {
10
+ const [props, rest] = splitProps(allProps, ["ui", "class", "children"])
11
+
12
+ const resolvedClasses = createMemo(() =>
13
+ listboxTheme({
14
+ ui: props.ui,
15
+ class: props.class,
16
+ ...allProps
17
+ })
18
+ )
19
+
20
+ return (
21
+ <div class={resolvedClasses().root} data-slot="root" {...rest}>
22
+ {props.children}
23
+ </div>
24
+ )
25
+ }
26
+
27
+ export default RLSListbox
@@ -8,6 +8,7 @@ const {
8
8
  currentLocale = "en",
9
9
  size = "md",
10
10
  theme,
11
+ class: classAttr,
11
12
  ...rest
12
13
  } = Astro.props as LocaleSelectorProps;
13
14
 
@@ -69,7 +70,7 @@ const currentLocaleUrl = items.find(item => item.code === currentLocale)?.value
69
70
  ---
70
71
 
71
72
  <rla-locale-selector data-theme={theme} {...rest}>
72
- <div class:list={[classes.root]} data-locale-selector>
73
+ <div class:list={[classes.root, classAttr]} data-locale-selector>
73
74
  {Astro.slots.has("label") && (
74
75
  <label class:list={[classes.label]}>
75
76
  <slot name="label" />