@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,554 @@
1
+ import {
2
+ createEffect,
3
+ createMemo,
4
+ createSignal,
5
+ splitProps,
6
+ type Component,
7
+ type JSX
8
+ } from "solid-js"
9
+ import type { ColorAreaProps } from "./color-area"
10
+ import { colorAreaTheme } from "./color-area.theme"
11
+
12
+ export interface RLSColorAreaProps extends ColorAreaProps {
13
+ onChange?: (value: string) => void
14
+ onValueChange?: (value: string) => void
15
+ onChangeEnd?: (value: string) => void
16
+ children?: JSX.Element
17
+ }
18
+
19
+ type Channel =
20
+ | "hue"
21
+ | "saturation"
22
+ | "red"
23
+ | "green"
24
+ | "blue"
25
+ | "alpha"
26
+ | "lightness"
27
+ | "brightness"
28
+
29
+ interface ChannelState {
30
+ hue: number
31
+ sat: number
32
+ light: number
33
+ bright: number
34
+ red: number
35
+ green: number
36
+ blue: number
37
+ }
38
+
39
+ const clamp = (val: number, min: number, max: number) => Math.max(min, Math.min(max, val))
40
+
41
+ const hexToRgb = (hex: string): [number, number, number] => {
42
+ const shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i
43
+ const fullHex = hex.replace(shorthandRegex, (_, r, g, b) => r + r + g + g + b + b)
44
+ const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(fullHex)
45
+ return result
46
+ ? [parseInt(result[1]!, 16), parseInt(result[2]!, 16), parseInt(result[3]!, 16)]
47
+ : [0, 0, 0]
48
+ }
49
+
50
+ const toHex = (c: number): string => {
51
+ const hex = Math.max(0, Math.min(255, c)).toString(16)
52
+ return hex.length === 1 ? "0" + hex : hex
53
+ }
54
+
55
+ const rgbToHex = (r: number, g: number, b: number): string => "#" + toHex(r) + toHex(g) + toHex(b)
56
+
57
+ const rgbToHsl = (r: number, g: number, b: number): [number, number, number] => {
58
+ r /= 255
59
+ g /= 255
60
+ b /= 255
61
+ const max = Math.max(r, g, b)
62
+ const min = Math.min(r, g, b)
63
+ let h = 0
64
+ let s = 0
65
+ const l = (max + min) / 2
66
+ if (max !== min) {
67
+ const d = max - min
68
+ s = l > 0.5 ? d / (2 - max - min) : d / (max + min)
69
+ switch (max) {
70
+ case r:
71
+ h = (g - b) / d + (g < b ? 6 : 0)
72
+ break
73
+ case g:
74
+ h = (b - r) / d + 2
75
+ break
76
+ case b:
77
+ h = (r - g) / d + 4
78
+ break
79
+ }
80
+ h /= 6
81
+ }
82
+ return [Math.round(h * 360), Math.round(s * 100), Math.round(l * 100)]
83
+ }
84
+
85
+ const hue2rgb = (p: number, q: number, t: number): number => {
86
+ if (t < 0) t += 1
87
+ if (t > 1) t -= 1
88
+ if (t < 1 / 6) return p + (q - p) * 6 * t
89
+ if (t < 1 / 2) return q
90
+ if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6
91
+ return p
92
+ }
93
+
94
+ const hslToRgb = (h: number, s: number, l: number): [number, number, number] => {
95
+ h /= 360
96
+ s /= 100
97
+ l /= 100
98
+ let r = l
99
+ let g = l
100
+ let b = l
101
+ if (s !== 0) {
102
+ const q = l < 0.5 ? l * (1 + s) : l + s - l * s
103
+ const p = 2 * l - q
104
+ r = hue2rgb(p, q, h + 1 / 3)
105
+ g = hue2rgb(p, q, h)
106
+ b = hue2rgb(p, q, h - 1 / 3)
107
+ }
108
+ return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)]
109
+ }
110
+
111
+ const rgbToHsb = (r: number, g: number, b: number): [number, number, number] => {
112
+ r /= 255
113
+ g /= 255
114
+ b /= 255
115
+ const max = Math.max(r, g, b)
116
+ const min = Math.min(r, g, b)
117
+ let h = 0
118
+ let s = 0
119
+ const v = max
120
+ const d = max - min
121
+ s = max === 0 ? 0 : d / max
122
+ if (max !== min) {
123
+ switch (max) {
124
+ case r:
125
+ h = (g - b) / d + (g < b ? 6 : 0)
126
+ break
127
+ case g:
128
+ h = (b - r) / d + 2
129
+ break
130
+ case b:
131
+ h = (r - g) / d + 4
132
+ break
133
+ }
134
+ h /= 6
135
+ }
136
+ return [Math.round(h * 360), Math.round(s * 100), Math.round(v * 100)]
137
+ }
138
+
139
+ const hsbToRgb = (h: number, s: number, b: number): [number, number, number] => {
140
+ h /= 360
141
+ s /= 100
142
+ b /= 100
143
+ let r = 0
144
+ let g = 0
145
+ let bl = 0
146
+ const i = Math.floor(h * 6)
147
+ const f = h * 6 - i
148
+ const p = b * (1 - s)
149
+ const q = b * (1 - f * s)
150
+ const t = b * (1 - (1 - f) * s)
151
+ switch (i % 6) {
152
+ case 0:
153
+ r = b
154
+ g = t
155
+ bl = p
156
+ break
157
+ case 1:
158
+ r = q
159
+ g = b
160
+ bl = p
161
+ break
162
+ case 2:
163
+ r = p
164
+ g = b
165
+ bl = t
166
+ break
167
+ case 3:
168
+ r = p
169
+ g = q
170
+ bl = b
171
+ break
172
+ case 4:
173
+ r = t
174
+ g = p
175
+ bl = b
176
+ break
177
+ case 5:
178
+ r = b
179
+ g = p
180
+ bl = q
181
+ break
182
+ }
183
+ return [Math.round(r * 255), Math.round(g * 255), Math.round(bl * 255)]
184
+ }
185
+
186
+ const getChannelRange = (channel: string): { min: number; max: number } => {
187
+ switch (channel) {
188
+ case "hue":
189
+ return { min: 0, max: 360 }
190
+ case "alpha":
191
+ return { min: 0, max: 100 }
192
+ case "red":
193
+ case "green":
194
+ case "blue":
195
+ return { min: 0, max: 255 }
196
+ default:
197
+ return { min: 0, max: 100 }
198
+ }
199
+ }
200
+
201
+ const RLSColorArea: Component<RLSColorAreaProps> = (allProps) => {
202
+ const [props, rest] = splitProps(allProps, [
203
+ "colorSpace",
204
+ "defaultValue",
205
+ "disabled",
206
+ "modelValue",
207
+ "name",
208
+ "required",
209
+ "xChannel",
210
+ "xName",
211
+ "yChannel",
212
+ "yName",
213
+ "color",
214
+ "theme",
215
+ "ui",
216
+ "class",
217
+ "onChange",
218
+ "onValueChange",
219
+ "onChangeEnd",
220
+ "children"
221
+ ])
222
+
223
+ const colorSpace = props.colorSpace ?? "hsl"
224
+ const xChannel: Channel = props.xChannel ?? "saturation"
225
+ const yChannel: Channel = props.yChannel ?? "lightness"
226
+
227
+ const initialValue = props.modelValue || props.defaultValue || "#ff0000"
228
+
229
+ const [value, setValue] = createSignal<string>(initialValue)
230
+ const [isDragging, setIsDragging] = createSignal(false)
231
+ const [state, setState] = createSignal<ChannelState>({
232
+ hue: 0,
233
+ sat: 0,
234
+ light: 50,
235
+ bright: 100,
236
+ red: 255,
237
+ green: 0,
238
+ blue: 0
239
+ })
240
+ let areaRef: HTMLDivElement | undefined
241
+
242
+ const syncChannelsFromValue = (hex: string, current: ChannelState): ChannelState => {
243
+ const rgb = hexToRgb(hex)
244
+ const hsl = rgbToHsl(rgb[0], rgb[1], rgb[2])
245
+ const hsb = rgbToHsb(rgb[0], rgb[1], rgb[2])
246
+ const max = Math.max(rgb[0], rgb[1], rgb[2])
247
+ const min = Math.min(rgb[0], rgb[1], rgb[2])
248
+ return {
249
+ hue: max !== min ? hsl[0] : current.hue,
250
+ sat: hsl[1],
251
+ light: hsl[2],
252
+ bright: hsb[2],
253
+ red: rgb[0],
254
+ green: rgb[1],
255
+ blue: rgb[2]
256
+ }
257
+ }
258
+
259
+ createEffect(() => {
260
+ const hex = value()
261
+ setState((prev) => syncChannelsFromValue(hex, prev))
262
+ })
263
+
264
+ const resolvedClasses = createMemo(() =>
265
+ colorAreaTheme({
266
+ color: props.color ?? "primary",
267
+ theme: props.theme,
268
+ ui: props.ui,
269
+ class: props.class
270
+ })
271
+ )
272
+
273
+ const channelValue = (ch: Channel, s: ChannelState): number => {
274
+ switch (ch) {
275
+ case "hue":
276
+ return s.hue
277
+ case "saturation":
278
+ return s.sat
279
+ case "lightness":
280
+ return s.light
281
+ case "brightness":
282
+ return s.bright
283
+ case "red":
284
+ return s.red
285
+ case "green":
286
+ return s.green
287
+ case "blue":
288
+ return s.blue
289
+ default:
290
+ return 0
291
+ }
292
+ }
293
+
294
+ const pctX = createMemo(() => {
295
+ const range = getChannelRange(xChannel)
296
+ const s = state()
297
+ return ((channelValue(xChannel, s) - range.min) / (range.max - range.min)) * 100
298
+ })
299
+
300
+ const pctY = createMemo(() => {
301
+ const range = getChannelRange(yChannel)
302
+ const s = state()
303
+ return 100 - ((channelValue(yChannel, s) - range.min) / (range.max - range.min)) * 100
304
+ })
305
+
306
+ const xVal = createMemo(() => channelValue(xChannel, state()))
307
+ const yVal = createMemo(() => channelValue(yChannel, state()))
308
+
309
+ const areaStyle = createMemo(() => {
310
+ const hueVal = state().hue
311
+ let background: string
312
+ if (colorSpace === "hsl" && xChannel === "saturation" && yChannel === "lightness") {
313
+ background =
314
+ "linear-gradient(to top, #000 0%, transparent 50%, #fff 100%), linear-gradient(to right, #808080 0%, transparent 100%), hsl(" +
315
+ hueVal +
316
+ ", 100%, 50%)"
317
+ } else if (colorSpace === "hsb" && xChannel === "saturation" && yChannel === "brightness") {
318
+ background =
319
+ "linear-gradient(to top, #000 0%, transparent 100%), linear-gradient(to right, #fff 0%, transparent 100%), hsl(" +
320
+ hueVal +
321
+ ", 100%, 50%)"
322
+ } else {
323
+ background = `hsl(${hueVal}, 100%, 50%)`
324
+ }
325
+ return {
326
+ background,
327
+ backgroundRepeat: "no-repeat",
328
+ backgroundSize: "100% 100%"
329
+ }
330
+ })
331
+
332
+ const applyPointer = (clientX: number, clientY: number) => {
333
+ const area = areaRef
334
+ if (!area) return
335
+ if (props.disabled) return
336
+ const rect = area.getBoundingClientRect()
337
+ const x = clamp((clientX - rect.left) / rect.width, 0, 1)
338
+ const y = 1 - clamp((clientY - rect.top) / rect.height, 0, 1)
339
+
340
+ const xRange = getChannelRange(xChannel)
341
+ const yRange = getChannelRange(yChannel)
342
+ const newX = Math.round(xRange.min + x * (xRange.max - xRange.min))
343
+ const newY = Math.round(yRange.min + y * (yRange.max - yRange.min))
344
+
345
+ const cur = state()
346
+ let hue = cur.hue
347
+ let saturation = cur.sat
348
+ let lightness = cur.light
349
+ let brightness = cur.bright
350
+ let r = cur.red
351
+ let g = cur.green
352
+ let b = cur.blue
353
+
354
+ let newRgb: [number, number, number] = [r, g, b]
355
+
356
+ if (colorSpace === "hsl") {
357
+ if (xChannel === "saturation") saturation = newX
358
+ if (yChannel === "lightness") lightness = newY
359
+ if (xChannel === "lightness") lightness = newX
360
+ if (yChannel === "saturation") saturation = newY
361
+ if (xChannel === "hue") hue = newX
362
+ if (yChannel === "hue") hue = newY
363
+ newRgb = hslToRgb(hue, saturation, lightness)
364
+ } else if (colorSpace === "hsb") {
365
+ if (xChannel === "saturation") saturation = newX
366
+ if (yChannel === "brightness") brightness = newY
367
+ if (xChannel === "brightness") brightness = newX
368
+ if (yChannel === "saturation") saturation = newY
369
+ if (xChannel === "hue") hue = newX
370
+ if (yChannel === "hue") hue = newY
371
+ newRgb = hsbToRgb(hue, saturation, brightness)
372
+ } else if (colorSpace === "rgb") {
373
+ if (xChannel === "red") r = newX
374
+ if (yChannel === "green") g = newY
375
+ if (xChannel === "green") g = newX
376
+ if (yChannel === "red") r = newY
377
+ if (xChannel === "blue") b = newX
378
+ if (yChannel === "blue") b = newY
379
+ newRgb = [r, g, b]
380
+ }
381
+
382
+ const newValue = rgbToHex(newRgb[0], newRgb[1], newRgb[2])
383
+ if (newValue !== value()) {
384
+ setState({
385
+ hue,
386
+ sat: saturation,
387
+ light: lightness,
388
+ bright: brightness,
389
+ red: newRgb[0],
390
+ green: newRgb[1],
391
+ blue: newRgb[2]
392
+ })
393
+ setValue(newValue)
394
+ props.onChange?.(newValue)
395
+ props.onValueChange?.(newValue)
396
+ }
397
+ }
398
+
399
+ const handlePointerDown = (e: PointerEvent) => {
400
+ if (props.disabled) return
401
+ setIsDragging(true)
402
+ try {
403
+ ;(e.currentTarget as HTMLElement).setPointerCapture(e.pointerId)
404
+ } catch {}
405
+ applyPointer(e.clientX, e.clientY)
406
+ }
407
+
408
+ const handlePointerMove = (e: PointerEvent) => {
409
+ if (!isDragging()) return
410
+ applyPointer(e.clientX, e.clientY)
411
+ }
412
+
413
+ const handlePointerUp = (e: PointerEvent) => {
414
+ if (!isDragging()) return
415
+ setIsDragging(false)
416
+ try {
417
+ ;(e.currentTarget as HTMLElement).releasePointerCapture(e.pointerId)
418
+ } catch {}
419
+ props.onChangeEnd?.(value())
420
+ }
421
+
422
+ const handleKeyDown = (e: KeyboardEvent) => {
423
+ if (props.disabled) return
424
+ const isShift = e.shiftKey
425
+ const stepSize = isShift ? 10 : 1
426
+ const xRange = getChannelRange(xChannel)
427
+ const yRange = getChannelRange(yChannel)
428
+ let posX = xVal()
429
+ let posY = yVal()
430
+ let handled = false
431
+
432
+ if (e.key === "ArrowLeft") {
433
+ posX = clamp(posX - stepSize, xRange.min, xRange.max)
434
+ handled = true
435
+ } else if (e.key === "ArrowRight") {
436
+ posX = clamp(posX + stepSize, xRange.min, xRange.max)
437
+ handled = true
438
+ } else if (e.key === "ArrowUp") {
439
+ posY = clamp(posY + stepSize, yRange.min, yRange.max)
440
+ handled = true
441
+ } else if (e.key === "ArrowDown") {
442
+ posY = clamp(posY - stepSize, yRange.min, yRange.max)
443
+ handled = true
444
+ } else if (e.key === "Home") {
445
+ posX = xRange.min
446
+ handled = true
447
+ } else if (e.key === "End") {
448
+ posX = xRange.max
449
+ handled = true
450
+ }
451
+
452
+ if (handled) {
453
+ e.preventDefault()
454
+ const cur = state()
455
+ let hue = cur.hue
456
+ let saturation = cur.sat
457
+ let lightness = cur.light
458
+ let brightness = cur.bright
459
+ let r = cur.red
460
+ let g = cur.green
461
+ let b = cur.blue
462
+
463
+ let newRgb: [number, number, number] = [r, g, b]
464
+
465
+ if (colorSpace === "hsl") {
466
+ if (xChannel === "saturation") saturation = posX
467
+ if (yChannel === "lightness") lightness = posY
468
+ if (xChannel === "lightness") lightness = posX
469
+ if (yChannel === "saturation") saturation = posY
470
+ if (xChannel === "hue") hue = posX
471
+ if (yChannel === "hue") hue = posY
472
+ newRgb = hslToRgb(hue, saturation, lightness)
473
+ } else if (colorSpace === "hsb") {
474
+ if (xChannel === "saturation") saturation = posX
475
+ if (yChannel === "brightness") brightness = posY
476
+ if (xChannel === "brightness") brightness = posX
477
+ if (yChannel === "saturation") saturation = posY
478
+ if (xChannel === "hue") hue = posX
479
+ if (yChannel === "hue") hue = posY
480
+ newRgb = hsbToRgb(hue, saturation, brightness)
481
+ } else if (colorSpace === "rgb") {
482
+ if (xChannel === "red") r = posX
483
+ if (yChannel === "green") g = posY
484
+ if (xChannel === "green") g = posX
485
+ if (yChannel === "red") r = posY
486
+ if (xChannel === "blue") b = posX
487
+ if (yChannel === "blue") b = posY
488
+ newRgb = [r, g, b]
489
+ }
490
+
491
+ const newValue = rgbToHex(newRgb[0], newRgb[1], newRgb[2])
492
+ if (newValue !== value()) {
493
+ setState({
494
+ hue,
495
+ sat: saturation,
496
+ light: lightness,
497
+ bright: brightness,
498
+ red: newRgb[0],
499
+ green: newRgb[1],
500
+ blue: newRgb[2]
501
+ })
502
+ setValue(newValue)
503
+ props.onChange?.(newValue)
504
+ props.onValueChange?.(newValue)
505
+ }
506
+ }
507
+ }
508
+
509
+ return (
510
+ <div
511
+ class={`${resolvedClasses().root} ${props.disabled ? "opacity-50 pointer-events-none" : ""}`}
512
+ data-slot="root"
513
+ data-color-space={colorSpace}
514
+ data-value={value()}
515
+ data-x-channel={xChannel}
516
+ data-y-channel={yChannel}
517
+ data-disabled={props.disabled ? "true" : "false"}
518
+ data-theme={props.theme}
519
+ {...rest}
520
+ >
521
+ <div
522
+ ref={(el) => (areaRef = el)}
523
+ class={resolvedClasses().area}
524
+ data-slot="area"
525
+ style={areaStyle()}
526
+ onPointerDown={handlePointerDown}
527
+ onPointerMove={handlePointerMove}
528
+ onPointerUp={handlePointerUp}
529
+ onPointerCancel={handlePointerUp}
530
+ >
531
+ <div
532
+ class={resolvedClasses().thumb}
533
+ data-slot="thumb"
534
+ role="slider"
535
+ aria-label="Color Area Thumb"
536
+ tabindex={0}
537
+ style={{
538
+ "left": `${pctX()}%`,
539
+ "top": `${pctY()}%`,
540
+ "background-color": value()
541
+ }}
542
+ onKeyDown={handleKeyDown}
543
+ />
544
+ </div>
545
+ {props.name ? (
546
+ <input type="hidden" name={props.name} value={value()} data-main-input />
547
+ ) : null}
548
+ {props.xName ? <input type="hidden" name={props.xName} value={xVal()} data-x-input /> : null}
549
+ {props.yName ? <input type="hidden" name={props.yName} value={yVal()} data-y-input /> : null}
550
+ </div>
551
+ )
552
+ }
553
+
554
+ export default RLSColorArea