@rimelight/ui 0.0.34 → 0.0.36

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 (185) hide show
  1. package/README.md +1 -0
  2. package/package.json +19 -24
  3. package/src/components/astro/RLAAccordion.astro +94 -18
  4. package/src/components/astro/RLAAvatar.astro +135 -68
  5. package/src/components/astro/RLABadge.astro +4 -2
  6. package/src/components/astro/RLABanner.astro +138 -23
  7. package/src/components/astro/RLABreadcrumb.astro +13 -0
  8. package/src/components/astro/RLAButton.astro +8 -4
  9. package/src/components/astro/RLACallout.astro +112 -0
  10. package/src/components/astro/RLACard.astro +6 -5
  11. package/src/components/astro/RLACarousel.astro +104 -75
  12. package/src/components/astro/RLAChart.astro +4 -1
  13. package/src/components/astro/RLAChip.astro +11 -5
  14. package/src/components/astro/RLACollapsible.astro +4 -1
  15. package/src/components/astro/RLAColorArea.astro +432 -0
  16. package/src/components/astro/RLAColorField.astro +300 -0
  17. package/src/components/astro/RLAColorSlider.astro +413 -0
  18. package/src/components/astro/RLAConfirm.astro +13 -11
  19. package/src/components/astro/RLACopyMarkdown.astro +78 -0
  20. package/src/components/astro/RLADate.astro +30 -0
  21. package/src/components/astro/RLADrawer.astro +50 -3
  22. package/src/components/astro/RLADropdownMenu.astro +78 -51
  23. package/src/components/astro/RLAFieldGroup.astro +4 -1
  24. package/src/components/astro/RLAFileUpload.astro +114 -100
  25. package/src/components/astro/RLAFooter.astro +2 -1
  26. package/src/components/astro/RLAFormField.astro +10 -6
  27. package/src/components/astro/RLAGrid.astro +31 -39
  28. package/src/components/astro/RLAHead.astro +139 -39
  29. package/src/components/astro/RLAHeader.astro +2 -1
  30. package/src/components/astro/RLAImage.astro +274 -251
  31. package/src/components/astro/RLAInput.astro +14 -9
  32. package/src/components/astro/RLAInputMenu.astro +119 -83
  33. package/src/components/astro/RLAKbd.astro +5 -5
  34. package/src/components/astro/RLALayoutGrid.astro +395 -0
  35. package/src/components/astro/RLALink.astro +23 -1
  36. package/src/components/astro/RLALinkGroup.astro +99 -99
  37. package/src/components/astro/RLALocaleSelector.astro +34 -41
  38. package/src/components/astro/RLALogo.astro +117 -90
  39. package/src/components/astro/RLAModal.astro +48 -18
  40. package/src/components/astro/RLANavigationMenu.astro +381 -326
  41. package/src/components/astro/{RLADocsPackageManagers.astro → RLAPackageManagers.astro} +81 -87
  42. package/src/components/astro/RLAPageSection.astro +4 -2
  43. package/src/components/astro/RLAPopover.astro +4 -3
  44. package/src/components/astro/RLAPost.astro +11 -2
  45. package/src/components/astro/RLAScrollArea.astro +4 -1
  46. package/src/components/astro/RLAScrollToTop.astro +200 -172
  47. package/src/components/astro/RLASearch.astro +282 -0
  48. package/src/components/astro/RLASelect.astro +78 -55
  49. package/src/components/astro/RLASeparator.astro +11 -6
  50. package/src/components/astro/RLAShare.astro +60 -0
  51. package/src/components/astro/RLAShortcuts.astro +429 -0
  52. package/src/components/astro/RLASidebar.astro +158 -212
  53. package/src/components/astro/RLASlideover.astro +47 -17
  54. package/src/components/astro/RLASplitter.astro +194 -141
  55. package/src/components/astro/RLASteps.astro +118 -71
  56. package/src/components/astro/RLASurround.astro +39 -0
  57. package/src/components/astro/RLATable.astro +4 -1
  58. package/src/components/astro/RLATableOfContents.astro +109 -23
  59. package/src/components/astro/RLATabs.astro +147 -133
  60. package/src/components/astro/RLATextarea.astro +4 -1
  61. package/src/components/astro/RLAThemeSelector.astro +105 -76
  62. package/src/components/astro/RLAToast.astro +35 -21
  63. package/src/components/vue/RLVBanner.vue +230 -0
  64. package/src/components/vue/RLVButton.vue +3 -2
  65. package/src/components/vue/RLVCheckbox.vue +4 -2
  66. package/src/components/vue/RLVFooter.vue +3 -2
  67. package/src/components/vue/RLVHeader.vue +3 -2
  68. package/src/components/vue/RLVIcon.vue +4 -2
  69. package/src/components/vue/RLVInput.vue +5 -4
  70. package/src/components/vue/RLVLogo.vue +25 -3
  71. package/src/components/vue/RLVPlaceholder.vue +3 -2
  72. package/src/components/vue/RLVPost.vue +8 -2
  73. package/src/components/vue/RLVProgress.vue +60 -0
  74. package/src/components/vue/RLVScrollToTop.vue +65 -52
  75. package/src/components/vue/RLVSection.vue +14 -13
  76. package/src/components/vue/RLVToast.vue +17 -4
  77. package/src/composables/index.ts +1 -0
  78. package/src/composables/useHeaderStore.ts +1 -0
  79. package/src/composables/useShortcuts.ts +11 -0
  80. package/src/config/security.ts +43 -36
  81. package/src/config/site.config.ts +1 -0
  82. package/src/docs/components/ApiChangelog.astro +147 -0
  83. package/src/{plugins/starlightDocsApi → docs}/components/ApiEmits.astro +4 -4
  84. package/src/{plugins/starlightDocsApi → docs}/components/ApiProps.astro +4 -4
  85. package/src/{plugins/starlightDocsApi → docs}/components/ApiSlots.astro +4 -4
  86. package/src/docs/components/ApiTheme.astro +100 -0
  87. package/src/docs/extractAll.ts +94 -0
  88. package/src/docs/extractors/extractAstro.ts +69 -0
  89. package/src/docs/extractors/extractTheme.ts +56 -0
  90. package/src/{plugins/starlightDocsApi/extract-vue.ts → docs/extractors/extractVue.ts} +164 -15
  91. package/src/{plugins/starlightDocsApi → docs}/utils.ts +1 -2
  92. package/src/env.d.ts +0 -12
  93. package/src/integrations/ui.ts +35 -19
  94. package/src/middleware/security.ts +75 -19
  95. package/src/presets/index.ts +118 -293
  96. package/src/styles/index.css +0 -2
  97. package/src/themes/accordion.theme.ts +29 -3
  98. package/src/themes/aspect-ratio.theme.ts +1 -1
  99. package/src/themes/avatar-group.theme.ts +1 -1
  100. package/src/themes/avatar.theme.ts +2 -2
  101. package/src/themes/badge.theme.ts +2 -3
  102. package/src/themes/banner.theme.ts +40 -4
  103. package/src/themes/breadcrumb.theme.ts +1 -1
  104. package/src/themes/button.theme.ts +21 -22
  105. package/src/themes/{alert.theme.ts → callout.theme.ts} +12 -39
  106. package/src/themes/card.theme.ts +17 -9
  107. package/src/themes/carousel.theme.ts +1 -1
  108. package/src/themes/checkbox.theme.ts +1 -2
  109. package/src/themes/chip.theme.ts +2 -3
  110. package/src/themes/color-area.theme.ts +33 -0
  111. package/src/themes/color-field.theme.ts +32 -0
  112. package/src/themes/color-slider.theme.ts +34 -0
  113. package/src/themes/confirm.theme.ts +1 -1
  114. package/src/themes/container.theme.ts +1 -1
  115. package/src/themes/drawer.theme.ts +1 -1
  116. package/src/themes/footer.theme.ts +2 -2
  117. package/src/themes/grid.theme.ts +38 -0
  118. package/src/themes/header.theme.ts +4 -3
  119. package/src/themes/hover-card.theme.ts +1 -1
  120. package/src/themes/image.theme.ts +11 -1
  121. package/src/themes/input.theme.ts +7 -1
  122. package/src/themes/kbd.theme.ts +2 -3
  123. package/src/themes/label.theme.ts +1 -1
  124. package/src/themes/layout-grid.theme.ts +16 -0
  125. package/src/themes/link-group.theme.ts +0 -4
  126. package/src/themes/marquee.theme.ts +1 -1
  127. package/src/themes/modal.theme.ts +1 -1
  128. package/src/themes/navigation-menu.theme.ts +2 -2
  129. package/src/themes/page-section.theme.ts +4 -2
  130. package/src/themes/pagination.theme.ts +1 -1
  131. package/src/themes/pin-input.theme.ts +1 -1
  132. package/src/themes/popover.theme.ts +1 -1
  133. package/src/themes/post.theme.ts +23 -3
  134. package/src/themes/progress.theme.ts +1 -2
  135. package/src/themes/scroll-to-top.theme.ts +2 -3
  136. package/src/themes/search.theme.ts +64 -0
  137. package/src/themes/separator.theme.ts +1 -1
  138. package/src/themes/slideover.theme.ts +1 -1
  139. package/src/themes/slider.theme.ts +1 -2
  140. package/src/themes/spinner.theme.ts +1 -2
  141. package/src/themes/{megamenu.theme.ts → steps.theme.ts} +3 -3
  142. package/src/themes/sticky-surface.theme.ts +1 -1
  143. package/src/themes/switch.theme.ts +1 -2
  144. package/src/themes/table-of-contents.theme.ts +21 -2
  145. package/src/themes/timeline.theme.ts +7 -2
  146. package/src/themes/toast.theme.ts +1 -1
  147. package/src/types/components/accordion.ts +35 -2
  148. package/src/types/components/avatar.ts +16 -0
  149. package/src/types/components/banner.ts +42 -0
  150. package/src/types/components/button.ts +3 -4
  151. package/src/types/components/{alert.ts → callout.ts} +6 -6
  152. package/src/types/components/color-area.ts +19 -0
  153. package/src/types/components/color-field.ts +21 -0
  154. package/src/types/components/color-slider.ts +20 -0
  155. package/src/types/components/grid.ts +23 -0
  156. package/src/types/components/input.ts +4 -0
  157. package/src/types/components/layout-grid.ts +145 -0
  158. package/src/types/components/link-group.ts +4 -2
  159. package/src/types/components/link.ts +15 -0
  160. package/src/types/components/logo.ts +3 -3
  161. package/src/types/components/post.ts +12 -0
  162. package/src/types/components/search.ts +29 -0
  163. package/src/types/components/sidebar.ts +2 -6
  164. package/src/types/components/{megamenu.ts → steps.ts} +7 -1
  165. package/src/types/components/table-of-contents.ts +22 -0
  166. package/src/types/components/toast.ts +4 -0
  167. package/src/types/docs.ts +40 -0
  168. package/src/types/index.ts +151 -1
  169. package/src/types/theme.ts +6 -6
  170. package/src/utils/color.ts +165 -0
  171. package/src/utils/docs.ts +260 -110
  172. package/src/utils/headerStack.ts +24 -4
  173. package/src/utils/index.ts +2 -0
  174. package/src/utils/shortcuts.ts +322 -0
  175. package/src/components/TableOfContents.astro +0 -107
  176. package/src/components/astro/RLAAlert.astro +0 -93
  177. package/src/components/astro/RLAChangelog.astro +0 -23
  178. package/src/components/astro/RLAMegamenu.astro +0 -23
  179. package/src/plugins/index.ts +0 -2
  180. package/src/plugins/starlightDocsApi/components/ApiTheme.astro +0 -27
  181. package/src/plugins/starlightDocsApi/index.ts +0 -272
  182. package/src/styles/prism.css +0 -42
  183. package/src/themes/changelog.theme.ts +0 -13
  184. package/src/types/components/index.ts +0 -134
  185. /package/src/{plugins/starlightDocsApi → docs}/types.ts +0 -0
@@ -0,0 +1,432 @@
1
+ ---
2
+ import { scv } from "css-variants"
3
+ import { useUi, resolveClasses } from "../../utils"
4
+ import colorAreaThemeDefault, { createColorAreaTheme } from "../../themes/color-area.theme"
5
+ import { getUIConfig } from "virtual:rimelight-ui"
6
+
7
+ const uiConfig = getUIConfig()
8
+ const colorAreaTheme = uiConfig.colors ? createColorAreaTheme(uiConfig.colors) : colorAreaThemeDefault
9
+ const colorArea = scv(colorAreaTheme)
10
+
11
+ export interface Props {
12
+ colorSpace?: "hsl" | "rgb" | "hsb"
13
+ defaultValue?: string
14
+ disabled?: boolean
15
+ modelValue?: string
16
+ name?: string
17
+ required?: boolean
18
+ xChannel?: "hue" | "saturation" | "red" | "green" | "blue" | "alpha" | "lightness" | "brightness"
19
+ xName?: string
20
+ yChannel?: "hue" | "saturation" | "red" | "green" | "blue" | "alpha" | "lightness" | "brightness"
21
+ yName?: string
22
+ color?: any
23
+ theme?: any
24
+ ui?: any
25
+ class?: string
26
+ }
27
+
28
+ const {
29
+ colorSpace = "hsl",
30
+ defaultValue = "#ff0000",
31
+ disabled = false,
32
+ modelValue,
33
+ name,
34
+ required,
35
+ xChannel = "saturation",
36
+ xName,
37
+ yChannel = "lightness",
38
+ yName,
39
+ color = "primary",
40
+ theme,
41
+ ui: uiProp,
42
+ class: className,
43
+ ...rest
44
+ } = Astro.props as Props
45
+
46
+ const classes = resolveClasses(colorArea, {
47
+ color,
48
+ theme
49
+ }, useUi("colorArea", uiProp), className)
50
+
51
+ const initialValue = modelValue || defaultValue
52
+ ---
53
+ <rla-color-area
54
+ data-color-space={colorSpace}
55
+ data-value={initialValue}
56
+ data-x-channel={xChannel}
57
+ data-y-channel={yChannel}
58
+ data-disabled={disabled ? "true" : "false"}
59
+ {...rest}
60
+ >
61
+ <div class={classes.root} data-slot="root">
62
+ <div class={classes.area} data-slot="area">
63
+ <div class={classes.thumb} data-slot="thumb" role="slider" aria-label="Color Area Thumb"></div>
64
+ </div>
65
+ {name && <input type="hidden" name={name} value={initialValue} data-main-input />}
66
+ {xName && <input type="hidden" name={xName} data-x-input />}
67
+ {yName && <input type="hidden" name={yName} data-y-input />}
68
+ </div>
69
+ </rla-color-area>
70
+
71
+ <script>
72
+ import {
73
+ hexToRgb,
74
+ rgbToHex,
75
+ rgbToHsl,
76
+ hslToRgb,
77
+ rgbToHsb,
78
+ hsbToRgb,
79
+ getChannelRange,
80
+ clamp
81
+ } from "../../utils/color"
82
+
83
+ if (typeof HTMLElement !== 'undefined') {
84
+ class RLAColorArea extends HTMLElement {
85
+ private cleanup: (() => void) | null = null
86
+ private colorSpace: string = "hsl"
87
+ private xChannel: string = "saturation"
88
+ private yChannel: string = "lightness"
89
+ private value: string = "#ff0000"
90
+
91
+ // Internal channel state to prevent hue loss when dragging to grayscale regions (black/white/gray)
92
+ private hue: number = 0
93
+ private saturation: number = 100
94
+ private lightness: number = 50
95
+ private brightness: number = 100
96
+ private red: number = 255
97
+ private green: number = 0
98
+ private blue: number = 0
99
+
100
+ connectedCallback() {
101
+ this.style.display = 'contents'
102
+ this.colorSpace = this.getAttribute("data-color-space") || "hsl"
103
+ this.xChannel = this.getAttribute("data-x-channel") || "saturation"
104
+ this.yChannel = this.getAttribute("data-y-channel") || "lightness"
105
+ this.value = this.getAttribute("data-value") || "#ff0000"
106
+
107
+ const root = this.querySelector('[data-slot="root"]') as HTMLElement
108
+ const area = this.querySelector('[data-slot="area"]') as HTMLElement
109
+ const thumb = this.querySelector('[data-slot="thumb"]') as HTMLElement
110
+
111
+ if (!area || !thumb) return
112
+
113
+ const updateChannelsFromValue = (hex: string) => {
114
+ const rgb = hexToRgb(hex)
115
+ const hsl = rgbToHsl(rgb[0], rgb[1], rgb[2])
116
+ const hsb = rgbToHsb(rgb[0], rgb[1], rgb[2])
117
+
118
+ const max = Math.max(rgb[0], rgb[1], rgb[2])
119
+ const min = Math.min(rgb[0], rgb[1], rgb[2])
120
+ if (max !== min) {
121
+ this.hue = hsl[0]
122
+ }
123
+ this.saturation = hsl[1]
124
+ this.lightness = hsl[2]
125
+ this.brightness = hsb[2]
126
+ this.red = rgb[0]
127
+ this.green = rgb[1]
128
+ this.blue = rgb[2]
129
+ }
130
+
131
+ updateChannelsFromValue(this.value)
132
+
133
+ const updateUI = () => {
134
+ const disabled = this.getAttribute("data-disabled") === "true"
135
+ if (disabled) {
136
+ root.classList.add("opacity-50", "pointer-events-none")
137
+ } else {
138
+ root.classList.remove("opacity-50", "pointer-events-none")
139
+ }
140
+
141
+ const hue = this.hue
142
+
143
+ // Gradient backgrounds
144
+ if (this.colorSpace === "hsl" && this.xChannel === "saturation" && this.yChannel === "lightness") {
145
+ area.style.background = `
146
+ linear-gradient(to top, #000 0%, transparent 50%, #fff 100%),
147
+ linear-gradient(to right, #808080 0%, transparent 100%),
148
+ hsl(${hue}, 100%, 50%)
149
+ `
150
+ } else if (this.colorSpace === "hsb" && this.xChannel === "saturation" && this.yChannel === "brightness") {
151
+ area.style.background = `
152
+ linear-gradient(to top, #000 0%, transparent 100%),
153
+ linear-gradient(to right, #fff 0%, transparent 100%),
154
+ hsl(${hue}, 100%, 50%)
155
+ `
156
+ } else {
157
+ area.style.background = `hsl(${hue}, 100%, 50%)`
158
+ }
159
+ area.style.backgroundRepeat = "no-repeat"
160
+ area.style.backgroundSize = "100% 100%"
161
+
162
+ // Set thumb background color
163
+ thumb.style.backgroundColor = this.value
164
+
165
+ // Calculate Thumb Position
166
+ const xRange = getChannelRange(this.xChannel)
167
+ const yRange = getChannelRange(this.yChannel)
168
+
169
+ let xVal = 0
170
+ let yVal = 0
171
+
172
+ if (this.colorSpace === "hsl") {
173
+ const indexX = ["hue", "saturation", "lightness"].indexOf(this.xChannel)
174
+ const indexY = ["hue", "saturation", "lightness"].indexOf(this.yChannel)
175
+ const hsl = [this.hue, this.saturation, this.lightness]
176
+ xVal = indexX !== -1 ? hsl[indexX]! : 0
177
+ yVal = indexY !== -1 ? hsl[indexY]! : 0
178
+ } else if (this.colorSpace === "hsb") {
179
+ const indexX = ["hue", "saturation", "brightness"].indexOf(this.xChannel)
180
+ const indexY = ["hue", "saturation", "brightness"].indexOf(this.yChannel)
181
+ const hsb = [this.hue, this.saturation, this.brightness]
182
+ xVal = indexX !== -1 ? hsb[indexX]! : 0
183
+ yVal = indexY !== -1 ? hsb[indexY]! : 0
184
+ } else if (this.colorSpace === "rgb") {
185
+ const indexX = ["red", "green", "blue"].indexOf(this.xChannel)
186
+ const indexY = ["red", "green", "blue"].indexOf(this.yChannel)
187
+ const rgb = [this.red, this.green, this.blue]
188
+ xVal = indexX !== -1 ? rgb[indexX]! : 0
189
+ yVal = indexY !== -1 ? rgb[indexY]! : 0
190
+ }
191
+
192
+ const pctX = ((xVal - xRange.min) / (xRange.max - xRange.min)) * 100
193
+ const pctY = 100 - (((yVal - yRange.min) / (yRange.max - yRange.min)) * 100)
194
+
195
+ thumb.style.left = `${pctX}%`
196
+ thumb.style.top = `${pctY}%`
197
+
198
+ // Update inputs
199
+ const mainInput = this.querySelector("[data-main-input]") as HTMLInputElement
200
+ if (mainInput) mainInput.value = this.value
201
+
202
+ const xInput = this.querySelector("[data-x-input]") as HTMLInputElement
203
+ if (xInput) xInput.value = xVal.toString()
204
+
205
+ const yInput = this.querySelector("[data-y-input]") as HTMLInputElement
206
+ if (yInput) yInput.value = yVal.toString()
207
+ }
208
+
209
+ updateUI()
210
+
211
+ const observer = new MutationObserver((mutations) => {
212
+ mutations.forEach((mutation) => {
213
+ if (mutation.type === "attributes") {
214
+ if (mutation.attributeName === "data-value") {
215
+ const newVal = this.getAttribute("data-value") || "#ff0000"
216
+ if (newVal !== this.value) {
217
+ this.value = newVal
218
+ updateChannelsFromValue(this.value)
219
+ updateUI()
220
+ }
221
+ }
222
+ if (mutation.attributeName === "data-disabled") {
223
+ updateUI()
224
+ }
225
+ }
226
+ })
227
+ })
228
+ observer.observe(this, { attributes: true })
229
+
230
+ let isDragging = false
231
+
232
+ const handlePointer = (e: PointerEvent) => {
233
+ if (this.getAttribute("data-disabled") === "true") return
234
+ const rect = area.getBoundingClientRect()
235
+ const x = clamp((e.clientX - rect.left) / rect.width, 0, 1)
236
+ const y = 1 - clamp((e.clientY - rect.top) / rect.height, 0, 1)
237
+
238
+ const xRange = getChannelRange(this.xChannel)
239
+ const yRange = getChannelRange(this.yChannel)
240
+
241
+ const newX = Math.round(xRange.min + x * (xRange.max - xRange.min))
242
+ const newY = Math.round(yRange.min + y * (yRange.max - yRange.min))
243
+
244
+ let newRgb: [number, number, number] = [this.red, this.green, this.blue]
245
+
246
+ if (this.colorSpace === "hsl") {
247
+ if (this.xChannel === "saturation") this.saturation = newX
248
+ if (this.yChannel === "lightness") this.lightness = newY
249
+ if (this.xChannel === "lightness") this.lightness = newX
250
+ if (this.yChannel === "saturation") this.saturation = newY
251
+ if (this.xChannel === "hue") this.hue = newX
252
+ if (this.yChannel === "hue") this.hue = newY
253
+ newRgb = hslToRgb(this.hue, this.saturation, this.lightness)
254
+ } else if (this.colorSpace === "hsb") {
255
+ if (this.xChannel === "saturation") this.saturation = newX
256
+ if (this.yChannel === "brightness") this.brightness = newY
257
+ if (this.xChannel === "brightness") this.brightness = newX
258
+ if (this.yChannel === "saturation") this.saturation = newY
259
+ if (this.xChannel === "hue") this.hue = newX
260
+ if (this.yChannel === "hue") this.hue = newY
261
+ newRgb = hsbToRgb(this.hue, this.saturation, this.brightness)
262
+ } else if (this.colorSpace === "rgb") {
263
+ if (this.xChannel === "red") this.red = newX
264
+ if (this.yChannel === "green") this.green = newY
265
+ if (this.xChannel === "green") this.green = newX
266
+ if (this.yChannel === "red") this.red = newY
267
+ if (this.xChannel === "blue") this.blue = newX
268
+ if (this.yChannel === "blue") this.blue = newY
269
+ newRgb = [this.red, this.green, this.blue]
270
+ }
271
+
272
+ const newValue = rgbToHex(newRgb[0], newRgb[1], newRgb[2])
273
+ const valueChanged = newValue !== this.value
274
+ if (valueChanged) {
275
+ this.value = newValue
276
+ this.setAttribute("data-value", newValue)
277
+ }
278
+
279
+ updateUI()
280
+
281
+ if (valueChanged) {
282
+ this.dispatchEvent(new CustomEvent("change", { detail: newValue }))
283
+ this.dispatchEvent(new CustomEvent("update:modelValue", { detail: newValue }))
284
+
285
+ const rootId = this.getAttribute("id")
286
+ if (rootId) {
287
+ document.querySelectorAll(`[data-color-link="${rootId}"]`).forEach((el) => {
288
+ el.setAttribute("data-value", newValue)
289
+ })
290
+ }
291
+ }
292
+ }
293
+
294
+ const onPointerDown = (e: PointerEvent) => {
295
+ isDragging = true
296
+ area.setPointerCapture(e.pointerId)
297
+ handlePointer(e)
298
+ }
299
+
300
+ const onPointerMove = (e: PointerEvent) => {
301
+ if (!isDragging) return
302
+ handlePointer(e)
303
+ }
304
+
305
+ const onPointerUp = (e: PointerEvent) => {
306
+ if (!isDragging) return
307
+ isDragging = false
308
+ area.releasePointerCapture(e.pointerId)
309
+ this.dispatchEvent(new CustomEvent("changeEnd", { detail: this.value }))
310
+ }
311
+
312
+ area.addEventListener("pointerdown", onPointerDown)
313
+ area.addEventListener("pointermove", onPointerMove)
314
+ area.addEventListener("pointerup", onPointerUp)
315
+
316
+ const onKeyDown = (e: KeyboardEvent) => {
317
+ if (this.getAttribute("data-disabled") === "true") return
318
+ const isShift = e.shiftKey
319
+ const stepSize = isShift ? 10 : 1
320
+
321
+ const xRange = getChannelRange(this.xChannel)
322
+ const yRange = getChannelRange(this.yChannel)
323
+
324
+ let xVal = 0
325
+ let yVal = 0
326
+
327
+ if (this.colorSpace === "hsl") {
328
+ const indexX = ["hue", "saturation", "lightness"].indexOf(this.xChannel)
329
+ const indexY = ["hue", "saturation", "lightness"].indexOf(this.yChannel)
330
+ const hsl = [this.hue, this.saturation, this.lightness]
331
+ xVal = indexX !== -1 ? hsl[indexX]! : 0
332
+ yVal = indexY !== -1 ? hsl[indexY]! : 0
333
+ } else if (this.colorSpace === "hsb") {
334
+ const indexX = ["hue", "saturation", "brightness"].indexOf(this.xChannel)
335
+ const indexY = ["hue", "saturation", "brightness"].indexOf(this.yChannel)
336
+ const hsb = [this.hue, this.saturation, this.brightness]
337
+ xVal = indexX !== -1 ? hsb[indexX]! : 0
338
+ yVal = indexY !== -1 ? hsb[indexY]! : 0
339
+ } else if (this.colorSpace === "rgb") {
340
+ const indexX = ["red", "green", "blue"].indexOf(this.xChannel)
341
+ const indexY = ["red", "green", "blue"].indexOf(this.yChannel)
342
+ const rgb = [this.red, this.green, this.blue]
343
+ xVal = indexX !== -1 ? rgb[indexX]! : 0
344
+ yVal = indexY !== -1 ? rgb[indexY]! : 0
345
+ }
346
+
347
+ let handled = false
348
+ if (e.key === "ArrowLeft") {
349
+ xVal = clamp(xVal - stepSize, xRange.min, xRange.max)
350
+ handled = true
351
+ } else if (e.key === "ArrowRight") {
352
+ xVal = clamp(xVal + stepSize, xRange.min, xRange.max)
353
+ handled = true
354
+ } else if (e.key === "ArrowUp") {
355
+ yVal = clamp(yVal + stepSize, yRange.min, yRange.max)
356
+ handled = true
357
+ } else if (e.key === "ArrowDown") {
358
+ yVal = clamp(yVal - stepSize, yRange.min, yRange.max)
359
+ handled = true
360
+ } else if (e.key === "Home") {
361
+ xVal = xRange.min
362
+ handled = true
363
+ } else if (e.key === "End") {
364
+ xVal = xRange.max
365
+ handled = true
366
+ }
367
+
368
+ if (handled) {
369
+ e.preventDefault()
370
+ let newRgb: [number, number, number] = [this.red, this.green, this.blue]
371
+
372
+ if (this.colorSpace === "hsl") {
373
+ if (this.xChannel === "saturation") this.saturation = xVal
374
+ if (this.yChannel === "lightness") this.lightness = yVal
375
+ if (this.xChannel === "lightness") this.lightness = xVal
376
+ if (this.yChannel === "saturation") this.saturation = yVal
377
+ if (this.xChannel === "hue") this.hue = xVal
378
+ if (this.yChannel === "hue") this.hue = yVal
379
+ newRgb = hslToRgb(this.hue, this.saturation, this.lightness)
380
+ } else if (this.colorSpace === "hsb") {
381
+ if (this.xChannel === "saturation") this.saturation = xVal
382
+ if (this.yChannel === "brightness") this.brightness = yVal
383
+ if (this.xChannel === "brightness") this.brightness = xVal
384
+ if (this.yChannel === "saturation") this.saturation = yVal
385
+ if (this.xChannel === "hue") this.hue = xVal
386
+ if (this.yChannel === "hue") this.hue = yVal
387
+ newRgb = hsbToRgb(this.hue, this.saturation, this.brightness)
388
+ } else if (this.colorSpace === "rgb") {
389
+ if (this.xChannel === "red") this.red = xVal
390
+ if (this.yChannel === "green") this.green = yVal
391
+ if (this.xChannel === "green") this.green = xVal
392
+ if (this.yChannel === "red") this.red = yVal
393
+ if (this.xChannel === "blue") this.blue = xVal
394
+ if (this.yChannel === "blue") this.blue = yVal
395
+ newRgb = [this.red, this.green, this.blue]
396
+ }
397
+
398
+ const newValue = rgbToHex(newRgb[0], newRgb[1], newRgb[2])
399
+ if (newValue !== this.value) {
400
+ this.value = newValue
401
+ this.setAttribute("data-value", newValue)
402
+ updateUI()
403
+ this.dispatchEvent(new CustomEvent("change", { detail: newValue }))
404
+ }
405
+ }
406
+ }
407
+
408
+ thumb.setAttribute("tabindex", "0")
409
+ thumb.addEventListener("keydown", onKeyDown)
410
+
411
+ this.cleanup = () => {
412
+ area.removeEventListener("pointerdown", onPointerDown)
413
+ area.removeEventListener("pointermove", onPointerMove)
414
+ area.removeEventListener("pointerup", onPointerUp)
415
+ thumb.removeEventListener("keydown", onKeyDown)
416
+ observer.disconnect()
417
+ }
418
+ }
419
+
420
+ disconnectedCallback() {
421
+ if (this.cleanup) {
422
+ this.cleanup()
423
+ this.cleanup = null
424
+ }
425
+ }
426
+ }
427
+
428
+ if (!customElements.get("rla-color-area")) {
429
+ customElements.define("rla-color-area", RLAColorArea)
430
+ }
431
+ }
432
+ </script>