@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,185 @@
1
+ import { createMemo, createSignal, splitProps, For, type Component, type JSX } from "solid-js"
2
+ import type { InputPinProps } from "./input-pin"
3
+ import { inputPinTheme } from "./input-pin.theme"
4
+ import { inputTheme } from "../input/input.theme"
5
+
6
+ export interface RLSInputPinProps extends InputPinProps {
7
+ children?: JSX.Element
8
+ length?: number
9
+ value?: string
10
+ defaultValue?: string
11
+ name?: string
12
+ disabled?: boolean
13
+ required?: boolean
14
+ type?: "text" | "numeric" | "alphanumeric"
15
+ size?: "sm" | "md" | "lg"
16
+ onInput?: (e: InputEvent & { currentTarget: HTMLInputElement }) => void
17
+ onChange?: (e: Event & { currentTarget: HTMLInputElement }) => void
18
+ onKeyDown?: (e: KeyboardEvent & { currentTarget: HTMLInputElement }) => void
19
+ onComplete?: (value: string) => void
20
+ }
21
+
22
+ const RLSInputPin: Component<RLSInputPinProps> = (allProps) => {
23
+ const [props, rest] = splitProps(allProps, [
24
+ "children",
25
+ "length",
26
+ "value",
27
+ "defaultValue",
28
+ "name",
29
+ "disabled",
30
+ "required",
31
+ "type",
32
+ "size",
33
+ "ui",
34
+ "class",
35
+ "onInput",
36
+ "onChange",
37
+ "onKeyDown",
38
+ "onComplete"
39
+ ])
40
+
41
+ const resolvedClasses = createMemo(() =>
42
+ inputPinTheme({
43
+ ui: props.ui,
44
+ class: props.class
45
+ })
46
+ )
47
+
48
+ const cellsClasses = createMemo(() =>
49
+ inputTheme({
50
+ variant: "default",
51
+ size: props.size ?? "md",
52
+ error: false,
53
+ ui: props.ui
54
+ })
55
+ )
56
+
57
+ const length = () => props.length ?? 4
58
+ const pinType = () => props.type ?? "numeric"
59
+
60
+ const initial = (props.value ?? props.defaultValue ?? "").split("")
61
+ const cells = createMemo(() => Array.from({ length: length() }))
62
+
63
+ const [current, setCurrent] = createSignal<string>(props.value ?? props.defaultValue ?? "")
64
+
65
+ let pinRefs: Array<HTMLInputElement | undefined> = []
66
+
67
+ const setCellRef = (el: HTMLInputElement | undefined, index: number) => {
68
+ pinRefs[index] = el
69
+ }
70
+
71
+ const focusCell = (index: number) => {
72
+ const el = pinRefs[index]
73
+ if (el) {
74
+ el.focus()
75
+ el.select()
76
+ }
77
+ }
78
+
79
+ const handleInput = (e: InputEvent & { currentTarget: HTMLInputElement }, index: number) => {
80
+ const input = e.currentTarget
81
+ let digit = input.value
82
+ if (pinType() === "numeric") {
83
+ digit = digit.replace(/[^0-9]/g, "")
84
+ } else if (pinType() === "alphanumeric") {
85
+ digit = digit.replace(/[^0-9a-zA-Z]/g, "")
86
+ } else {
87
+ digit = digit.replace(/[^0-9]/g, "")
88
+ }
89
+ digit = digit.slice(-1)
90
+ input.value = digit
91
+ const next = current().slice(0, index) + digit + current().slice(index + 1)
92
+ setCurrent(next)
93
+ props.onInput?.(e)
94
+ props.onChange?.(e)
95
+ if (digit) {
96
+ if (index < length() - 1) {
97
+ focusCell(index + 1)
98
+ } else if (next.length === length()) {
99
+ props.onComplete?.(next)
100
+ }
101
+ }
102
+ }
103
+
104
+ const handleKeyDown = (e: KeyboardEvent & { currentTarget: HTMLInputElement }, index: number) => {
105
+ props.onKeyDown?.(e)
106
+ const input = e.currentTarget
107
+ if (e.key === "Backspace" && input.value === "") {
108
+ e.preventDefault()
109
+ if (index > 0) focusCell(index - 1)
110
+ } else if (e.key === "ArrowLeft") {
111
+ e.preventDefault()
112
+ if (index > 0) focusCell(index - 1)
113
+ } else if (e.key === "ArrowRight") {
114
+ e.preventDefault()
115
+ if (index < length() - 1) focusCell(index + 1)
116
+ }
117
+ }
118
+
119
+ const handlePaste = (e: ClipboardEvent, index: number) => {
120
+ const pasted = (e.clipboardData?.getData("text") ?? "")
121
+ .replace(pinType() === "numeric" ? /[^0-9]/g : /[^0-9a-zA-Z]/g, "")
122
+ .slice(0, length())
123
+ if (!pasted) return
124
+ e.preventDefault()
125
+ const next = current().split("")
126
+ for (let i = 0; i < pasted.length; i++) {
127
+ const char = pasted[i]
128
+ if (char !== undefined && index + i < length()) next[index + i] = char
129
+ }
130
+ const joined = next.join("")
131
+ setCurrent(joined)
132
+ const endIndex = Math.min(index + pasted.length, length() - 1)
133
+ const endEl = pinRefs[endIndex]
134
+ if (endEl) {
135
+ endEl.value = joined[endIndex] ?? ""
136
+ endEl.focus()
137
+ }
138
+ if (joined.length === length()) props.onComplete?.(joined)
139
+ }
140
+
141
+ return (
142
+ <div class={resolvedClasses().root} data-slot="root" {...rest}>
143
+ <div
144
+ role="group"
145
+ aria-label="One-time code"
146
+ class="flex items-center gap-2"
147
+ data-slot="group"
148
+ >
149
+ <For each={cells()}>
150
+ {(_, index) => (
151
+ <div
152
+ class={`${cellsClasses().root} w-12 h-12 flex items-center justify-center rounded-md`}
153
+ data-slot="cell"
154
+ >
155
+ <input
156
+ ref={(el) => setCellRef(el, index())}
157
+ type="text"
158
+ name={props.name ? `${props.name}-${index()}` : undefined}
159
+ inputMode={pinType() === "numeric" ? "numeric" : "text"}
160
+ autocomplete="one-time-code"
161
+ maxLength={1}
162
+ value={initial[index()] ?? ""}
163
+ disabled={props.disabled}
164
+ required={props.required}
165
+ aria-label={`Digit ${index() + 1}`}
166
+ class={`${cellsClasses().input} w-full text-center`}
167
+ data-slot="input"
168
+ onInput={(e) =>
169
+ handleInput(e as InputEvent & { currentTarget: HTMLInputElement }, index())
170
+ }
171
+ onKeyDown={(e) =>
172
+ handleKeyDown(e as KeyboardEvent & { currentTarget: HTMLInputElement }, index())
173
+ }
174
+ onPaste={(e) => handlePaste(e, index())}
175
+ />
176
+ </div>
177
+ )}
178
+ </For>
179
+ </div>
180
+ {props.children}
181
+ </div>
182
+ )
183
+ }
184
+
185
+ export default RLSInputPin
@@ -0,0 +1,198 @@
1
+ import { createMemo, createSignal, splitProps, For, type Component } from "solid-js"
2
+ import type { InputRatingProps } from "./input-rating"
3
+ import { inputRatingTheme } from "./input-rating.theme"
4
+ import RLSIcon from "../icon/RLSIcon"
5
+
6
+ export interface RLSInputRatingProps extends InputRatingProps {
7
+ onValueChange?: (value: number) => void
8
+ }
9
+
10
+ const RLSInputRating: Component<RLSInputRatingProps> = (allProps) => {
11
+ const [props, rest] = splitProps(allProps, [
12
+ "id",
13
+ "readonly",
14
+ "icon",
15
+ "emptyIcon",
16
+ "color",
17
+ "size",
18
+ "orientation",
19
+ "step",
20
+ "disabled",
21
+ "required",
22
+ "name",
23
+ "modelValue",
24
+ "defaultValue",
25
+ "value",
26
+ "length",
27
+ "clearable",
28
+ "hoverable",
29
+ "ui",
30
+ "class",
31
+ "onValueChange"
32
+ ])
33
+
34
+ const resolvedClasses = createMemo(() =>
35
+ inputRatingTheme({
36
+ color: props.color ?? "primary",
37
+ size: props.size ?? "md",
38
+ orientation: props.orientation ?? "horizontal",
39
+ readonly: !!props.readonly,
40
+ disabled: !!props.disabled,
41
+ ui: props.ui,
42
+ class: props.class
43
+ })
44
+ )
45
+
46
+ const step = () => props.step ?? 1
47
+ const length = () => props.length ?? 5
48
+ const itemSize = () => {
49
+ const map: Record<string, string> = {
50
+ xs: "0.75rem",
51
+ sm: "1rem",
52
+ md: "1.25rem",
53
+ lg: "1.5rem",
54
+ xl: "1.75rem"
55
+ }
56
+ return map[props.size ?? "md"] ?? "1.25rem"
57
+ }
58
+
59
+ const [internalValue, setInternalValue] = createSignal<number>(
60
+ props.value !== undefined
61
+ ? props.value
62
+ : props.modelValue !== undefined
63
+ ? props.modelValue
64
+ : (props.defaultValue ?? 0)
65
+ )
66
+ const value = () =>
67
+ props.value !== undefined
68
+ ? props.value
69
+ : props.modelValue !== undefined
70
+ ? props.modelValue
71
+ : internalValue()
72
+
73
+ const [hoverValue, setHoverValue] = createSignal<number | null>(null)
74
+ const display = (): number => (hoverValue() !== null ? hoverValue()! : value())
75
+
76
+ const items = createMemo(() => Array.from({ length: length() }, (_, idx) => idx + 1))
77
+
78
+ const getWidthForVal = (val: number, itemIndex: number) => {
79
+ if (val >= itemIndex) return "100%"
80
+ if (val <= itemIndex - 1) return "0%"
81
+ return `${(val - (itemIndex - 1)) * 100}%`
82
+ }
83
+
84
+ const getValueFromEvent = (e: MouseEvent, el: HTMLElement, index: number) => {
85
+ const rect = el.getBoundingClientRect()
86
+ const x = (e.clientX - rect.left) / rect.width
87
+ const steppedX = Math.ceil(x / step()) * step()
88
+ return Math.min(Math.max(index - 1 + steppedX, 0), length())
89
+ }
90
+
91
+ const handleMouseMove = (e: MouseEvent, el: HTMLElement, index: number) => {
92
+ if (props.disabled || props.readonly) return
93
+ if (props.hoverable) setHoverValue(getValueFromEvent(e, el, index))
94
+ }
95
+
96
+ const handleMouseLeave = () => {
97
+ setHoverValue(null)
98
+ }
99
+
100
+ const handleClick = (e: MouseEvent, el: HTMLElement, index: number) => {
101
+ if (props.disabled || props.readonly) return
102
+ const val = getValueFromEvent(e, el, index)
103
+ let finalVal = val
104
+ if (props.clearable && value() === val) finalVal = 0
105
+ if (props.value === undefined && props.modelValue === undefined) setInternalValue(finalVal)
106
+ props.onValueChange?.(finalVal)
107
+ }
108
+
109
+ const handleKeyDown = (e: KeyboardEvent) => {
110
+ if (props.disabled || props.readonly) return
111
+ let newVal = value()
112
+ if (e.key === "ArrowRight" || e.key === "ArrowUp") {
113
+ newVal = Math.min(value() + step(), length())
114
+ } else if (e.key === "ArrowLeft" || e.key === "ArrowDown") {
115
+ newVal = Math.max(value() - step(), 0)
116
+ } else if (e.key === "Home") {
117
+ newVal = 0
118
+ } else if (e.key === "End") {
119
+ newVal = length()
120
+ } else {
121
+ return
122
+ }
123
+ e.preventDefault()
124
+ if (props.value === undefined && props.modelValue === undefined) setInternalValue(newVal)
125
+ props.onValueChange?.(newVal)
126
+ }
127
+
128
+ return (
129
+ <div
130
+ class={resolvedClasses().root}
131
+ data-slot="root"
132
+ data-step={step()}
133
+ data-length={length()}
134
+ data-clearable={props.clearable ? "true" : "false"}
135
+ data-hoverable={props.hoverable ? "true" : "false"}
136
+ data-disabled={props.disabled ? "true" : "false"}
137
+ data-readonly={props.readonly ? "true" : "false"}
138
+ id={props.id}
139
+ role="slider"
140
+ aria-valuenow={value()}
141
+ aria-valuemin={0}
142
+ aria-valuemax={length()}
143
+ aria-readonly={props.readonly ? "true" : "false"}
144
+ aria-disabled={props.disabled ? "true" : "false"}
145
+ tabIndex={props.disabled || props.readonly ? undefined : 0}
146
+ onKeyDown={handleKeyDown}
147
+ {...rest}
148
+ >
149
+ <input
150
+ type="hidden"
151
+ name={props.name}
152
+ value={value()}
153
+ required={props.required}
154
+ disabled={props.disabled || props.readonly}
155
+ class="rating-hidden-input"
156
+ />
157
+
158
+ <For each={items()}>
159
+ {(i) => (
160
+ <div
161
+ class={`input-rating-item ${resolvedClasses().item}`}
162
+ data-slot="item"
163
+ data-index={i}
164
+ style={{ "--item-size": itemSize(), "width": itemSize(), "height": itemSize() }}
165
+ onMouseMove={(e) => handleMouseMove(e, e.currentTarget, i)}
166
+ onMouseLeave={handleMouseLeave}
167
+ onClick={(e) => handleClick(e, e.currentTarget, i)}
168
+ >
169
+ <div class={resolvedClasses().emptyIcon} data-slot="emptyIcon">
170
+ <RLSIcon
171
+ name={props.emptyIcon || props.icon || "star"}
172
+ size={props.size ?? "md"}
173
+ class={resolvedClasses().icon}
174
+ aria-hidden="true"
175
+ />
176
+ </div>
177
+
178
+ <div
179
+ class={`rating-item-indicator ${resolvedClasses().indicator}`}
180
+ data-slot="indicator"
181
+ data-state={display() >= i - 0.99 ? "active" : "inactive"}
182
+ style={{ width: getWidthForVal(display(), i) }}
183
+ >
184
+ <RLSIcon
185
+ name={props.icon || "star"}
186
+ size={props.size ?? "md"}
187
+ class={resolvedClasses().icon}
188
+ aria-hidden="true"
189
+ />
190
+ </div>
191
+ </div>
192
+ )}
193
+ </For>
194
+ </div>
195
+ )
196
+ }
197
+
198
+ export default RLSInputRating
@@ -71,6 +71,10 @@ export interface InputRatingProps {
71
71
  * The name of the field, submitted with form data.
72
72
  */
73
73
  name?: string
74
+ /**
75
+ * The controlled rating value.
76
+ */
77
+ value?: number
74
78
  /**
75
79
  * The controlled rating value. Can be bound with v-model.
76
80
  */
@@ -0,0 +1,94 @@
1
+ import { createMemo, createSignal, For, Show, splitProps, type Component, type JSX } from "solid-js"
2
+ import type { InputTagsProps, TagItem } from "./input-tags"
3
+ import { inputTagsTheme } from "./input-tags.theme"
4
+
5
+ export interface RLSInputTagsProps extends InputTagsProps {
6
+ children?: JSX.Element
7
+ onAddTag?: (tag: string) => void
8
+ onRemoveTag?: (tag: TagItem) => void
9
+ }
10
+
11
+ const RLSInputTags: Component<RLSInputTagsProps> = (allProps) => {
12
+ const [props, rest] = splitProps(allProps, [
13
+ "items",
14
+ "displayLimit",
15
+ "estimatedTagWidth",
16
+ "showInput",
17
+ "name",
18
+ "placeholder",
19
+ "ui",
20
+ "class",
21
+ "children",
22
+ "onAddTag",
23
+ "onRemoveTag"
24
+ ])
25
+
26
+ const [inputValue, setInputValue] = createSignal("")
27
+ const limit = () => props.displayLimit ?? 4
28
+
29
+ const normalizedItems = createMemo<TagItem[]>(() =>
30
+ (props.items ?? []).map((item) =>
31
+ typeof item === "string" ? { label: item, value: item } : item
32
+ )
33
+ )
34
+
35
+ const renderedItems = () => normalizedItems().slice(0, limit())
36
+ const overflowCount = () => Math.max(0, normalizedItems().length - limit())
37
+
38
+ const handleKeyDown: JSX.EventHandler<HTMLInputElement, KeyboardEvent> = (e) => {
39
+ if (e.key === "Enter") {
40
+ e.preventDefault()
41
+ const val = inputValue().trim()
42
+ if (val) {
43
+ props.onAddTag?.(val)
44
+ setInputValue("")
45
+ }
46
+ }
47
+ }
48
+
49
+ const resolvedClasses = createMemo(() =>
50
+ inputTagsTheme({
51
+ ui: props.ui,
52
+ class: props.class
53
+ })
54
+ )
55
+
56
+ return (
57
+ <div class={resolvedClasses().root} data-slot="root" {...rest}>
58
+ <Show when={normalizedItems().length > 0} fallback={props.children}>
59
+ <For each={renderedItems()}>
60
+ {(item) => (
61
+ <span class={resolvedClasses().tag} data-slot="tag">
62
+ <span class={resolvedClasses().tagLabel}>{item.label}</span>
63
+ <Show when={props.name}>
64
+ <input type="hidden" name={props.name} value={item.value ?? item.label} />
65
+ </Show>
66
+ </span>
67
+ )}
68
+ </For>
69
+
70
+ <Show when={overflowCount() > 0}>
71
+ <span class={resolvedClasses().more} data-slot="more" aria-hidden="true">
72
+ +{overflowCount()} more
73
+ </span>
74
+ </Show>
75
+ </Show>
76
+
77
+ <Show when={props.showInput}>
78
+ <input
79
+ type="text"
80
+ name={props.name ? `${props.name}__input` : undefined}
81
+ placeholder={props.placeholder || "Add tag…"}
82
+ value={inputValue()}
83
+ onInput={(e) => setInputValue(e.currentTarget.value)}
84
+ onKeyDown={handleKeyDown}
85
+ class={resolvedClasses().input}
86
+ data-slot="input"
87
+ autocomplete="off"
88
+ />
89
+ </Show>
90
+ </div>
91
+ )
92
+ }
93
+
94
+ export default RLSInputTags
@@ -0,0 +1,92 @@
1
+ import { createMemo, splitProps, type Component, type JSX } from "solid-js"
2
+ import type { InputTimeProps } from "./input-time"
3
+ import { inputTimeTheme } from "./input-time.theme"
4
+ import { inputTheme } from "../input/input.theme"
5
+
6
+ export interface RLSInputTimeProps extends InputTimeProps {
7
+ children?: JSX.Element
8
+ value?: string
9
+ defaultValue?: string
10
+ name?: string
11
+ placeholder?: string
12
+ disabled?: boolean
13
+ readonly?: boolean
14
+ required?: boolean
15
+ min?: string
16
+ max?: string
17
+ step?: number
18
+ size?: "sm" | "md" | "lg"
19
+ onInput?: (e: InputEvent & { currentTarget: HTMLInputElement }) => void
20
+ onChange?: (e: Event & { currentTarget: HTMLInputElement }) => void
21
+ onBlur?: (e: FocusEvent & { currentTarget: HTMLInputElement }) => void
22
+ onFocus?: (e: FocusEvent & { currentTarget: HTMLInputElement }) => void
23
+ onKeyDown?: (e: KeyboardEvent & { currentTarget: HTMLInputElement }) => void
24
+ }
25
+
26
+ const RLSInputTime: Component<RLSInputTimeProps> = (allProps) => {
27
+ const [props, rest] = splitProps(allProps, [
28
+ "children",
29
+ "value",
30
+ "defaultValue",
31
+ "name",
32
+ "placeholder",
33
+ "disabled",
34
+ "readonly",
35
+ "required",
36
+ "min",
37
+ "max",
38
+ "step",
39
+ "size",
40
+ "ui",
41
+ "class",
42
+ "onInput",
43
+ "onChange",
44
+ "onBlur",
45
+ "onFocus",
46
+ "onKeyDown"
47
+ ])
48
+
49
+ const resolvedClasses = createMemo(() =>
50
+ inputTimeTheme({
51
+ ui: props.ui,
52
+ class: props.class
53
+ })
54
+ )
55
+
56
+ const inputClasses = createMemo(() =>
57
+ inputTheme({
58
+ variant: "default",
59
+ size: props.size ?? "md",
60
+ error: false,
61
+ ui: props.ui
62
+ })
63
+ )
64
+
65
+ return (
66
+ <div class={`${resolvedClasses().root} ${inputClasses().root}`} data-slot="root">
67
+ <input
68
+ type="time"
69
+ name={props.name}
70
+ value={props.value !== undefined ? props.value : (props.defaultValue ?? "")}
71
+ placeholder={props.placeholder}
72
+ disabled={props.disabled}
73
+ readonly={props.readonly}
74
+ required={props.required}
75
+ min={props.min}
76
+ max={props.max}
77
+ step={props.step}
78
+ class={inputClasses().input}
79
+ data-slot="input"
80
+ onInput={props.onInput}
81
+ onChange={props.onChange}
82
+ onBlur={props.onBlur}
83
+ onFocus={props.onFocus}
84
+ onKeyDown={props.onKeyDown}
85
+ {...rest}
86
+ />
87
+ {props.children}
88
+ </div>
89
+ )
90
+ }
91
+
92
+ export default RLSInputTime
@@ -0,0 +1,37 @@
1
+ import { createMemo, splitProps, type Component, type JSX } from "solid-js"
2
+ import type { KbdProps } from "./kbd"
3
+ import { kbdTheme } from "./kbd.theme"
4
+
5
+ export interface RLSKbdProps extends KbdProps {
6
+ children?: JSX.Element
7
+ }
8
+
9
+ const RLSKbd: Component<RLSKbdProps> = (allProps) => {
10
+ const [props, rest] = splitProps(allProps, [
11
+ "color",
12
+ "variant",
13
+ "size",
14
+ "theme",
15
+ "ui",
16
+ "class",
17
+ "children"
18
+ ])
19
+
20
+ const classes = createMemo(() =>
21
+ kbdTheme({
22
+ color: props.color ?? "neutral",
23
+ variant: props.variant ?? "outline",
24
+ size: props.size ?? "md",
25
+ ui: props.ui,
26
+ class: props.class
27
+ })
28
+ )
29
+
30
+ return (
31
+ <kbd class={classes()["root"]} data-slot="root" data-theme={props.theme} {...rest}>
32
+ {props.children}
33
+ </kbd>
34
+ )
35
+ }
36
+
37
+ export default RLSKbd