@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,236 @@
1
+ import {
2
+ createEffect,
3
+ createMemo,
4
+ createSignal,
5
+ Show,
6
+ splitProps,
7
+ type Component,
8
+ type JSX
9
+ } from "solid-js"
10
+ import type { ColorFieldProps } from "./color-field"
11
+ import { colorFieldTheme } from "./color-field.theme"
12
+ import {
13
+ clamp,
14
+ getChannelRange,
15
+ hexToRgb,
16
+ hslToRgb,
17
+ hsbToRgb,
18
+ rgbToHex,
19
+ rgbToHsb,
20
+ rgbToHsl
21
+ } from "../color-picker/color"
22
+
23
+ export interface RLSColorFieldProps extends ColorFieldProps {
24
+ "children"?: JSX.Element
25
+ "value"?: string
26
+ "onChange"?: (val: string) => void
27
+ "onUpdate:modelValue"?: (val: string) => void
28
+ }
29
+
30
+ const RLSColorField: Component<RLSColorFieldProps> = (allProps) => {
31
+ const [props, rest] = splitProps(allProps, [
32
+ "channel",
33
+ "colorSpace",
34
+ "defaultValue",
35
+ "disabled",
36
+ "disableWheelChange",
37
+ "locale",
38
+ "modelValue",
39
+ "value",
40
+ "name",
41
+ "placeholder",
42
+ "readonly",
43
+ "required",
44
+ "step",
45
+ "color",
46
+ "theme",
47
+ "ui",
48
+ "class",
49
+ "children",
50
+ "onChange",
51
+ "onUpdate:modelValue"
52
+ ])
53
+
54
+ const colorSpace = () => props.colorSpace ?? "hsl"
55
+ const stepValue = () => props.step ?? 1
56
+ const initialHex = () => props.modelValue ?? props.value ?? props.defaultValue ?? "#000000"
57
+
58
+ const [currentHex, setCurrentHex] = createSignal(initialHex())
59
+
60
+ createEffect(() => {
61
+ const controlled = props.modelValue ?? props.value
62
+ if (controlled !== undefined) {
63
+ setCurrentHex(controlled)
64
+ }
65
+ })
66
+
67
+ const getDisplayValue = () => {
68
+ const hex = currentHex()
69
+ if (!props.channel) return hex
70
+
71
+ const rgb = hexToRgb(hex)
72
+ if (colorSpace() === "hsl") {
73
+ const hsl = rgbToHsl(rgb[0], rgb[1], rgb[2])
74
+ const index = ["hue", "saturation", "lightness"].indexOf(props.channel)
75
+ return index !== -1 ? String(hsl[index]!) : "0"
76
+ } else if (colorSpace() === "hsb") {
77
+ const hsb = rgbToHsb(rgb[0], rgb[1], rgb[2])
78
+ const index = ["hue", "saturation", "brightness"].indexOf(props.channel)
79
+ return index !== -1 ? String(hsb[index]!) : "0"
80
+ } else if (colorSpace() === "rgb") {
81
+ const index = ["red", "green", "blue"].indexOf(props.channel)
82
+ return index !== -1 ? String(rgb[index]!) : "0"
83
+ }
84
+ return "0"
85
+ }
86
+
87
+ const [displayValue, setDisplayValue] = createSignal(getDisplayValue())
88
+
89
+ createEffect(() => {
90
+ currentHex()
91
+ setDisplayValue(getDisplayValue())
92
+ })
93
+
94
+ const updateColor = (newHex: string) => {
95
+ if (props.modelValue === undefined && props.value === undefined) {
96
+ setCurrentHex(newHex)
97
+ }
98
+ props.onChange?.(newHex)
99
+ props["onUpdate:modelValue"]?.(newHex)
100
+ }
101
+
102
+ const updateFromChannelValue = (val: number) => {
103
+ if (!props.channel) return
104
+ const range = getChannelRange(props.channel)
105
+ const clampedVal = clamp(val, range.min, range.max)
106
+
107
+ const rgb = hexToRgb(currentHex())
108
+ const hsl = rgbToHsl(rgb[0], rgb[1], rgb[2])
109
+ const hsb = rgbToHsb(rgb[0], rgb[1], rgb[2])
110
+ let newRgb = [...rgb] as [number, number, number]
111
+
112
+ if (colorSpace() === "hsl") {
113
+ const index = ["hue", "saturation", "lightness"].indexOf(props.channel)
114
+ if (index !== -1) hsl[index] = clampedVal
115
+ newRgb = hslToRgb(hsl[0], hsl[1], hsl[2])
116
+ } else if (colorSpace() === "hsb") {
117
+ const index = ["hue", "saturation", "brightness"].indexOf(props.channel)
118
+ if (index !== -1) hsb[index] = clampedVal
119
+ newRgb = hsbToRgb(hsb[0], hsb[1], hsb[2])
120
+ } else if (colorSpace() === "rgb") {
121
+ const index = ["red", "green", "blue"].indexOf(props.channel)
122
+ if (index !== -1) newRgb[index] = clampedVal
123
+ }
124
+
125
+ const newHex = rgbToHex(newRgb[0], newRgb[1], newRgb[2])
126
+ updateColor(newHex)
127
+ }
128
+
129
+ const handleInputChange: JSX.EventHandler<HTMLInputElement, InputEvent> = (e) => {
130
+ if (props.disabled || props.readonly) return
131
+ const raw = e.currentTarget.value.trim()
132
+ setDisplayValue(raw)
133
+
134
+ if (!props.channel) {
135
+ if (/^#[0-9A-F]{6}$/i.test(raw)) {
136
+ updateColor(raw)
137
+ }
138
+ } else {
139
+ const num = parseFloat(raw)
140
+ if (!isNaN(num)) {
141
+ updateFromChannelValue(num)
142
+ }
143
+ }
144
+ }
145
+
146
+ const handleKeyDown: JSX.EventHandler<HTMLInputElement, KeyboardEvent> = (e) => {
147
+ if (props.disabled || props.readonly) return
148
+ const stepSize = (e.shiftKey ? 10 : 1) * stepValue()
149
+
150
+ if (props.channel) {
151
+ const currentVal = parseFloat(displayValue()) || 0
152
+ let handled = false
153
+ let newVal = currentVal
154
+
155
+ if (e.key === "ArrowUp") {
156
+ newVal = currentVal + stepSize
157
+ handled = true
158
+ } else if (e.key === "ArrowDown") {
159
+ newVal = currentVal - stepSize
160
+ handled = true
161
+ } else if (e.key === "PageUp") {
162
+ newVal = currentVal + stepSize * 10
163
+ handled = true
164
+ } else if (e.key === "PageDown") {
165
+ newVal = currentVal - stepSize * 10
166
+ handled = true
167
+ } else if (e.key === "Home") {
168
+ newVal = getChannelRange(props.channel).min
169
+ handled = true
170
+ } else if (e.key === "End") {
171
+ newVal = getChannelRange(props.channel).max
172
+ handled = true
173
+ }
174
+
175
+ if (handled) {
176
+ e.preventDefault()
177
+ updateFromChannelValue(newVal)
178
+ }
179
+ }
180
+ }
181
+
182
+ const handleWheel: JSX.EventHandler<HTMLInputElement, WheelEvent> = (e) => {
183
+ if (props.disableWheelChange || props.disabled || props.readonly || !props.channel) return
184
+ e.preventDefault()
185
+ const direction = e.deltaY < 0 ? 1 : -1
186
+ const stepSize = stepValue() * direction
187
+ const currentVal = parseFloat(displayValue()) || 0
188
+ updateFromChannelValue(currentVal + stepSize)
189
+ }
190
+
191
+ const resolvedClasses = createMemo(() =>
192
+ colorFieldTheme({
193
+ color: props.color,
194
+ ui: props.ui,
195
+ class: props.class
196
+ })
197
+ )
198
+
199
+ return (
200
+ <div
201
+ class={resolvedClasses().root}
202
+ data-slot="root"
203
+ data-theme={props.theme}
204
+ data-channel={props.channel}
205
+ data-color-space={colorSpace()}
206
+ data-value={currentHex()}
207
+ data-disabled={props.disabled ? "true" : "false"}
208
+ data-readonly={props.readonly ? "true" : "false"}
209
+ {...rest}
210
+ >
211
+ <div
212
+ class="w-5 h-5 rounded border border-default mr-2 shrink-0 shadow-sm"
213
+ data-slot="swatch"
214
+ style={{ "background-color": currentHex() }}
215
+ />
216
+ <input
217
+ type="text"
218
+ class={resolvedClasses().input}
219
+ placeholder={props.placeholder}
220
+ required={props.required}
221
+ disabled={props.disabled}
222
+ readOnly={props.readonly}
223
+ value={displayValue()}
224
+ onInput={handleInputChange}
225
+ onKeyDown={handleKeyDown}
226
+ onWheel={handleWheel}
227
+ data-slot="input"
228
+ />
229
+ <Show when={props.name}>
230
+ <input type="hidden" name={props.name} value={currentHex()} data-main-input />
231
+ </Show>
232
+ </div>
233
+ )
234
+ }
235
+
236
+ export default RLSColorField
@@ -0,0 +1,26 @@
1
+ import { createMemo, splitProps, type Component, type JSX } from "solid-js"
2
+ import type { ColorPickerProps } from "./color-picker"
3
+ import { colorPickerTheme } from "./color-picker.theme"
4
+
5
+ export interface RLSColorPickerProps extends ColorPickerProps {
6
+ children?: JSX.Element
7
+ }
8
+
9
+ const RLSColorPicker: Component<RLSColorPickerProps> = (allProps) => {
10
+ const [props, rest] = splitProps(allProps, ["ui", "class", "children"])
11
+
12
+ const resolvedClasses = createMemo(() =>
13
+ colorPickerTheme({
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 RLSColorPicker
@@ -0,0 +1,373 @@
1
+ import {
2
+ createEffect,
3
+ createMemo,
4
+ createSignal,
5
+ Show,
6
+ splitProps,
7
+ type Component,
8
+ type JSX
9
+ } from "solid-js"
10
+ import type { ColorSliderProps } from "./color-slider"
11
+ import { colorSliderTheme } from "./color-slider.theme"
12
+ import {
13
+ clamp,
14
+ getChannelRange,
15
+ hexToRgb,
16
+ hslToRgb,
17
+ hsbToRgb,
18
+ rgbToHex,
19
+ rgbToHsb,
20
+ rgbToHsl
21
+ } from "../color-picker/color"
22
+
23
+ export interface RLSColorSliderProps extends ColorSliderProps {
24
+ "children"?: JSX.Element
25
+ "value"?: string
26
+ "onChange"?: (val: string) => void
27
+ "onChangeEnd"?: (val: string) => void
28
+ "onUpdate:modelValue"?: (val: string) => void
29
+ }
30
+
31
+ const RLSColorSlider: Component<RLSColorSliderProps> = (allProps) => {
32
+ const [props, rest] = splitProps(allProps, [
33
+ "channel",
34
+ "colorSpace",
35
+ "defaultValue",
36
+ "dir",
37
+ "disabled",
38
+ "inverted",
39
+ "modelValue",
40
+ "value",
41
+ "name",
42
+ "orientation",
43
+ "required",
44
+ "step",
45
+ "color",
46
+ "theme",
47
+ "ui",
48
+ "class",
49
+ "children",
50
+ "onChange",
51
+ "onChangeEnd",
52
+ "onUpdate:modelValue"
53
+ ])
54
+
55
+ const channel = () => props.channel || "hue"
56
+ const colorSpace = () => props.colorSpace ?? "hsl"
57
+ const orientation = () => props.orientation ?? "horizontal"
58
+ const stepValue = () => props.step ?? 1
59
+ const initialHex = () => props.modelValue ?? props.value ?? props.defaultValue ?? "#000000"
60
+
61
+ const [currentHex, setCurrentHex] = createSignal(initialHex())
62
+
63
+ createEffect(() => {
64
+ const controlled = props.modelValue ?? props.value
65
+ if (controlled !== undefined) {
66
+ setCurrentHex(controlled)
67
+ }
68
+ })
69
+
70
+ const updateColor = (newHex: string, isFinal = false) => {
71
+ if (props.modelValue === undefined && props.value === undefined) {
72
+ setCurrentHex(newHex)
73
+ }
74
+ props.onChange?.(newHex)
75
+ props["onUpdate:modelValue"]?.(newHex)
76
+ if (isFinal) {
77
+ props.onChangeEnd?.(newHex)
78
+ }
79
+ }
80
+
81
+ let trackRef: HTMLDivElement | null = null
82
+
83
+ const channelValue = () => {
84
+ const hex = currentHex()
85
+ const rgb = hexToRgb(hex)
86
+ const ch = channel()
87
+ const cs = colorSpace()
88
+
89
+ if (cs === "hsl") {
90
+ const hsl = rgbToHsl(rgb[0], rgb[1], rgb[2])
91
+ const index = ["hue", "saturation", "lightness"].indexOf(ch)
92
+ return index !== -1 ? hsl[index]! : 0
93
+ } else if (cs === "hsb") {
94
+ const hsb = rgbToHsb(rgb[0], rgb[1], rgb[2])
95
+ const index = ["hue", "saturation", "brightness"].indexOf(ch)
96
+ return index !== -1 ? hsb[index]! : 0
97
+ } else if (cs === "rgb") {
98
+ const index = ["red", "green", "blue"].indexOf(ch)
99
+ return index !== -1 ? rgb[index]! : 0
100
+ }
101
+ return 0
102
+ }
103
+
104
+ const thumbPercent = createMemo(() => {
105
+ const range = getChannelRange(channel())
106
+ let pct = ((channelValue() - range.min) / (range.max - range.min)) * 100
107
+ if (props.inverted) {
108
+ pct = 100 - pct
109
+ }
110
+ return clamp(pct, 0, 100)
111
+ })
112
+
113
+ const trackGradient = createMemo(() => {
114
+ const isHoriz = orientation() === "horizontal"
115
+ const dir = isHoriz ? "to right" : "to top"
116
+ const ch = channel()
117
+ const cs = colorSpace()
118
+
119
+ if (ch === "hue") {
120
+ return `linear-gradient(${dir}, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%)`
121
+ }
122
+
123
+ const rgb = hexToRgb(currentHex())
124
+ const hsl = rgbToHsl(rgb[0], rgb[1], rgb[2])
125
+ const hsb = rgbToHsb(rgb[0], rgb[1], rgb[2])
126
+ const range = getChannelRange(ch)
127
+
128
+ let startHex = "#000000"
129
+ let endHex = "#ffffff"
130
+
131
+ if (cs === "hsl") {
132
+ const index = ["hue", "saturation", "lightness"].indexOf(ch)
133
+ if (index !== -1) {
134
+ const startHsl = [...hsl] as [number, number, number]
135
+ const endHsl = [...hsl] as [number, number, number]
136
+ startHsl[index] = range.min
137
+ endHsl[index] = range.max
138
+ const startRgb = hslToRgb(startHsl[0], startHsl[1], startHsl[2])
139
+ const endRgb = hslToRgb(endHsl[0], endHsl[1], endHsl[2])
140
+ startHex = rgbToHex(startRgb[0], startRgb[1], startRgb[2])
141
+ endHex = rgbToHex(endRgb[0], endRgb[1], endRgb[2])
142
+ }
143
+ } else if (cs === "hsb") {
144
+ const index = ["hue", "saturation", "brightness"].indexOf(ch)
145
+ if (index !== -1) {
146
+ const startHsb = [...hsb] as [number, number, number]
147
+ const endHsb = [...hsb] as [number, number, number]
148
+ startHsb[index] = range.min
149
+ endHsb[index] = range.max
150
+ const startRgb = hsbToRgb(startHsb[0], startHsb[1], startHsb[2])
151
+ const endRgb = hsbToRgb(endHsb[0], endHsb[1], endHsb[2])
152
+ startHex = rgbToHex(startRgb[0], startRgb[1], startRgb[2])
153
+ endHex = rgbToHex(endRgb[0], endRgb[1], endRgb[2])
154
+ }
155
+ } else if (cs === "rgb") {
156
+ const index = ["red", "green", "blue"].indexOf(ch)
157
+ if (index !== -1) {
158
+ const startRgb = [...rgb] as [number, number, number]
159
+ const endRgb = [...rgb] as [number, number, number]
160
+ startRgb[index] = range.min
161
+ endRgb[index] = range.max
162
+ startHex = rgbToHex(startRgb[0], startRgb[1], startRgb[2])
163
+ endHex = rgbToHex(endRgb[0], endRgb[1], endRgb[2])
164
+ }
165
+ }
166
+
167
+ return `linear-gradient(${dir}, ${startHex}, ${endHex})`
168
+ })
169
+
170
+ const updateFromPointer = (clientX: number, clientY: number, isFinal = false) => {
171
+ const track = trackRef
172
+ if (!track || props.disabled) return
173
+ const rect = track.getBoundingClientRect()
174
+ let pct = 0
175
+
176
+ if (orientation() === "horizontal") {
177
+ pct = clamp((clientX - rect.left) / rect.width, 0, 1)
178
+ } else {
179
+ pct = 1 - clamp((clientY - rect.top) / rect.height, 0, 1)
180
+ }
181
+
182
+ if (props.inverted) {
183
+ pct = 1 - pct
184
+ }
185
+
186
+ const range = getChannelRange(channel())
187
+ const step = stepValue()
188
+ let targetVal = range.min + pct * (range.max - range.min)
189
+ targetVal = Math.round(targetVal / step) * step
190
+ targetVal = clamp(targetVal, range.min, range.max)
191
+
192
+ const rgb = hexToRgb(currentHex())
193
+ const hsl = rgbToHsl(rgb[0], rgb[1], rgb[2])
194
+ const hsb = rgbToHsb(rgb[0], rgb[1], rgb[2])
195
+ let newRgb = [...rgb] as [number, number, number]
196
+ const ch = channel()
197
+ const cs = colorSpace()
198
+
199
+ if (cs === "hsl") {
200
+ const index = ["hue", "saturation", "lightness"].indexOf(ch)
201
+ if (index !== -1) hsl[index] = targetVal
202
+ newRgb = hslToRgb(hsl[0], hsl[1], hsl[2])
203
+ } else if (cs === "hsb") {
204
+ const index = ["hue", "saturation", "brightness"].indexOf(ch)
205
+ if (index !== -1) hsb[index] = targetVal
206
+ newRgb = hsbToRgb(hsb[0], hsb[1], hsb[2])
207
+ } else if (cs === "rgb") {
208
+ const index = ["red", "green", "blue"].indexOf(ch)
209
+ if (index !== -1) newRgb[index] = targetVal
210
+ }
211
+
212
+ const newHex = rgbToHex(newRgb[0], newRgb[1], newRgb[2])
213
+ updateColor(newHex, isFinal)
214
+ }
215
+
216
+ let isDragging = false
217
+
218
+ const handlePointerDown = (e: PointerEvent) => {
219
+ if (props.disabled) return
220
+ isDragging = true
221
+ ;(e.currentTarget as HTMLElement).setPointerCapture(e.pointerId)
222
+ updateFromPointer(e.clientX, e.clientY)
223
+ }
224
+
225
+ const handlePointerMove = (e: PointerEvent) => {
226
+ if (!isDragging || props.disabled) return
227
+ updateFromPointer(e.clientX, e.clientY)
228
+ }
229
+
230
+ const handlePointerUp = (e: PointerEvent) => {
231
+ if (!isDragging) return
232
+ isDragging = false
233
+ try {
234
+ ;(e.currentTarget as HTMLElement).releasePointerCapture(e.pointerId)
235
+ } catch {
236
+ // ignore
237
+ }
238
+ updateFromPointer(e.clientX, e.clientY, true)
239
+ }
240
+
241
+ const handleKeyDown = (e: KeyboardEvent) => {
242
+ if (props.disabled) return
243
+ const stepMultiplier = e.shiftKey ? 10 : 1
244
+ const stepSize = stepValue() * stepMultiplier
245
+ const range = getChannelRange(channel())
246
+ const currentVal = channelValue()
247
+
248
+ let handled = false
249
+ let newVal = currentVal
250
+
251
+ if (orientation() === "horizontal") {
252
+ if (e.key === "ArrowLeft") {
253
+ newVal = currentVal - stepSize
254
+ handled = true
255
+ } else if (e.key === "ArrowRight") {
256
+ newVal = currentVal + stepSize
257
+ handled = true
258
+ }
259
+ } else {
260
+ if (e.key === "ArrowDown") {
261
+ newVal = currentVal - stepSize
262
+ handled = true
263
+ } else if (e.key === "ArrowUp") {
264
+ newVal = currentVal + stepSize
265
+ handled = true
266
+ }
267
+ }
268
+
269
+ if (e.key === "Home") {
270
+ newVal = range.min
271
+ handled = true
272
+ } else if (e.key === "End") {
273
+ newVal = range.max
274
+ handled = true
275
+ } else if (e.key === "PageUp") {
276
+ newVal = currentVal + stepSize * 10
277
+ handled = true
278
+ } else if (e.key === "PageDown") {
279
+ newVal = currentVal - stepSize * 10
280
+ handled = true
281
+ }
282
+
283
+ if (handled) {
284
+ e.preventDefault()
285
+ newVal = clamp(newVal, range.min, range.max)
286
+
287
+ const rgb = hexToRgb(currentHex())
288
+ const hsl = rgbToHsl(rgb[0], rgb[1], rgb[2])
289
+ const hsb = rgbToHsb(rgb[0], rgb[1], rgb[2])
290
+ let newRgb = [...rgb] as [number, number, number]
291
+ const ch = channel()
292
+ const cs = colorSpace()
293
+
294
+ if (cs === "hsl") {
295
+ const index = ["hue", "saturation", "lightness"].indexOf(ch)
296
+ if (index !== -1) hsl[index] = newVal
297
+ newRgb = hslToRgb(hsl[0], hsl[1], hsl[2])
298
+ } else if (cs === "hsb") {
299
+ const index = ["hue", "saturation", "brightness"].indexOf(ch)
300
+ if (index !== -1) hsb[index] = newVal
301
+ newRgb = hsbToRgb(hsb[0], hsb[1], hsb[2])
302
+ } else if (cs === "rgb") {
303
+ const index = ["red", "green", "blue"].indexOf(ch)
304
+ if (index !== -1) newRgb[index] = newVal
305
+ }
306
+
307
+ const newHex = rgbToHex(newRgb[0], newRgb[1], newRgb[2])
308
+ updateColor(newHex, true)
309
+ }
310
+ }
311
+
312
+ const resolvedClasses = createMemo(() =>
313
+ colorSliderTheme({
314
+ color: props.color,
315
+ ui: props.ui,
316
+ class: props.class
317
+ })
318
+ )
319
+
320
+ return (
321
+ <div
322
+ class={`${resolvedClasses().root} ${props.disabled ? "opacity-50 pointer-events-none" : ""}`}
323
+ data-slot="root"
324
+ data-theme={props.theme}
325
+ data-orientation={orientation()}
326
+ data-channel={channel()}
327
+ data-color-space={colorSpace()}
328
+ data-value={currentHex()}
329
+ data-disabled={props.disabled ? "true" : "false"}
330
+ data-inverted={props.inverted ? "true" : "false"}
331
+ {...rest}
332
+ >
333
+ <div
334
+ ref={(el) => (trackRef = el)}
335
+ class={resolvedClasses().track}
336
+ data-slot="track"
337
+ style={{ background: trackGradient() }}
338
+ onPointerDown={handlePointerDown}
339
+ onPointerMove={handlePointerMove}
340
+ onPointerUp={handlePointerUp}
341
+ >
342
+ <div
343
+ class={resolvedClasses().thumb}
344
+ data-slot="thumb"
345
+ role="slider"
346
+ aria-label="Color Slider Thumb"
347
+ tabIndex={props.disabled ? -1 : 0}
348
+ onKeyDown={handleKeyDown}
349
+ style={
350
+ orientation() === "horizontal"
351
+ ? {
352
+ "left": `${thumbPercent()}%`,
353
+ "top": "50%",
354
+ "transform": "translate(-50%, -50%)",
355
+ "background-color": currentHex()
356
+ }
357
+ : {
358
+ "left": "50%",
359
+ "top": `${100 - thumbPercent()}%`,
360
+ "transform": "translate(-50%, -50%)",
361
+ "background-color": currentHex()
362
+ }
363
+ }
364
+ />
365
+ </div>
366
+ <Show when={props.name}>
367
+ <input type="hidden" name={props.name} value={currentHex()} data-main-input />
368
+ </Show>
369
+ </div>
370
+ )
371
+ }
372
+
373
+ export default RLSColorSlider
@@ -0,0 +1,26 @@
1
+ import { createMemo, splitProps, type Component, type JSX } from "solid-js"
2
+ import type { CommandPaletteProps } from "./command-palette"
3
+ import { commandPaletteTheme } from "./command-palette.theme"
4
+
5
+ export interface RLSCommandPaletteProps extends CommandPaletteProps {
6
+ children?: JSX.Element
7
+ }
8
+
9
+ const RLSCommandPalette: Component<RLSCommandPaletteProps> = (allProps) => {
10
+ const [props, rest] = splitProps(allProps, ["ui", "class", "children"])
11
+
12
+ const resolvedClasses = createMemo(() =>
13
+ commandPaletteTheme({
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 RLSCommandPalette
@@ -0,0 +1,26 @@
1
+ import { createMemo, splitProps, type Component, type JSX } from "solid-js"
2
+ import type { CompareProps } from "./compare"
3
+ import { compareTheme } from "./compare.theme"
4
+
5
+ export interface RLSCompareProps extends CompareProps {
6
+ children?: JSX.Element
7
+ }
8
+
9
+ const RLSCompare: Component<RLSCompareProps> = (allProps) => {
10
+ const [props, rest] = splitProps(allProps, ["ui", "class", "children"])
11
+
12
+ const classes = createMemo(() =>
13
+ compareTheme({
14
+ ui: props.ui,
15
+ class: props.class
16
+ })
17
+ )
18
+
19
+ return (
20
+ <div class={classes()["root"]} data-slot="root" {...rest}>
21
+ {props.children}
22
+ </div>
23
+ )
24
+ }
25
+
26
+ export default RLSCompare