@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
@@ -1,51 +1,62 @@
1
- ---
2
- import type { InputProps } from "./input"
3
- import { inputTheme } from "./input.theme"
4
-
5
-
6
-
7
- const {
8
- type = "text",
9
- value = "",
10
- placeholder,
11
- disabled = false,
12
- readonly = false,
13
- name,
14
- required = false,
15
- error = false,
16
- leadingIcon,
17
- trailingIcon,
18
- theme,
19
- ...rest
20
- } = Astro.props as InputProps
21
-
22
-
23
-
24
- const classes = inputTheme({
25
- ...Astro.props,
26
- error: !!error
27
- });
28
- ---
29
- <div class={classes.root} data-slot="root" data-theme={theme}>
30
- {(leadingIcon || Astro.slots.has("leading")) && (
31
- <span class={classes.leading} data-slot="leading">
32
- {leadingIcon ? <span class={leadingIcon} /> : <slot name="leading" />}
33
- </span>
34
- )}
35
- <input
36
- type={type}
37
- class={classes.input}
38
- value={value}
39
- placeholder={placeholder}
40
- disabled={disabled}
41
- readonly={readonly}
42
- name={name}
43
- required={required}
44
- {...rest}
45
- />
46
- {(trailingIcon || Astro.slots.has("trailing")) && (
47
- <span class={classes.trailing} data-slot="trailing">
48
- {trailingIcon ? <span class={trailingIcon} /> : <slot name="trailing" />}
49
- </span>
50
- )}
51
- </div>
1
+ ---
2
+ import type { InputProps } from "./input"
3
+ import { inputTheme } from "./input.theme"
4
+ import RLAIcon from "../icon/RLAIcon.astro"
5
+
6
+ const {
7
+ type = "text",
8
+ value = "",
9
+ placeholder,
10
+ disabled = false,
11
+ readonly = false,
12
+ name,
13
+ required = false,
14
+ error = false,
15
+ leadingIcon,
16
+ trailingIcon,
17
+ size = "md",
18
+ variant = "default",
19
+ theme,
20
+ class: className,
21
+ ui,
22
+ ...rest
23
+ } = Astro.props as InputProps
24
+
25
+ const hasLeading = !!(leadingIcon || Astro.slots.has("leading"))
26
+ const hasTrailing = !!(trailingIcon || Astro.slots.has("trailing"))
27
+
28
+ const classes = inputTheme({
29
+ variant,
30
+ size,
31
+ hasLeading,
32
+ hasTrailing,
33
+ error: !!error,
34
+ theme,
35
+ ui,
36
+ class: className
37
+ })
38
+ ---
39
+ <div class={classes.root} data-slot="root" data-theme={theme}>
40
+ {(leadingIcon || Astro.slots.has("leading")) && (
41
+ <span class={classes.leading} data-slot="leading">
42
+ {leadingIcon ? <RLAIcon name={leadingIcon} size="sm" aria-hidden="true" /> : <slot name="leading" />}
43
+ </span>
44
+ )}
45
+ <input
46
+ type={type}
47
+ class={classes.input}
48
+ data-slot="input"
49
+ value={value}
50
+ placeholder={placeholder}
51
+ disabled={disabled}
52
+ readonly={readonly}
53
+ name={name}
54
+ required={required}
55
+ {...rest}
56
+ />
57
+ {(trailingIcon || Astro.slots.has("trailing")) && (
58
+ <span class={classes.trailing} data-slot="trailing">
59
+ {trailingIcon ? <RLAIcon name={trailingIcon} size="sm" aria-hidden="true" /> : <slot name="trailing" />}
60
+ </span>
61
+ )}
62
+ </div>
@@ -59,7 +59,7 @@ const RLSInput: Component<RLSInputProps> = (allProps) => {
59
59
  )
60
60
 
61
61
  return (
62
- <div class={resolvedClasses().root} data-slot="root">
62
+ <div class={resolvedClasses().root} data-slot="root" data-theme={props.theme}>
63
63
  {props.leading ? (
64
64
  props.leading
65
65
  ) : props.leadingIcon ? (
@@ -0,0 +1,92 @@
1
+ import { createMemo, splitProps, type Component, type JSX } from "solid-js"
2
+ import type { InputDateProps } from "./input-date"
3
+ import { inputDateTheme } from "./input-date.theme"
4
+ import { inputTheme } from "../input/input.theme"
5
+
6
+ export interface RLSInputDateProps extends InputDateProps {
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 RLSInputDate: Component<RLSInputDateProps> = (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
+ inputDateTheme({
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="date"
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 RLSInputDate
@@ -100,7 +100,7 @@ const initialLabel = selectedItem ? selectedItem.label : ""
100
100
  const onSearchInput = (e: Event) => {
101
101
  const q = (e.target as HTMLInputElement).value.toLowerCase();
102
102
  items.forEach(item => {
103
- const label = (item as HTMLElement).dataset.label?.toLowerCase() || "";
103
+ const label = (item as HTMLElement).dataset["label"]?.toLowerCase() || "";
104
104
  if (label.includes(q)) {
105
105
  (item as HTMLElement).classList.remove("hidden");
106
106
  } else {
@@ -114,8 +114,8 @@ const initialLabel = selectedItem ? selectedItem.label : ""
114
114
  items.forEach(item => {
115
115
  const onItemClick = (e: MouseEvent) => {
116
116
  e.stopPropagation();
117
- const val = (item as HTMLElement).dataset.value || "";
118
- const label = (item as HTMLElement).dataset.label || "";
117
+ const val = (item as HTMLElement).dataset["value"] || "";
118
+ const label = (item as HTMLElement).dataset["label"] || "";
119
119
 
120
120
  if (hiddenInput) hiddenInput.value = val;
121
121
  if (valueSpan) valueSpan.textContent = label;
@@ -0,0 +1,199 @@
1
+ import {
2
+ createMemo,
3
+ createSignal,
4
+ splitProps,
5
+ For,
6
+ Show,
7
+ onMount,
8
+ onCleanup,
9
+ createEffect,
10
+ type Component
11
+ } from "solid-js"
12
+ import type { InputMenuProps } from "./input-menu"
13
+ import { inputMenuTheme } from "./input-menu.theme"
14
+ import RLSIcon from "../icon/RLSIcon"
15
+
16
+ export interface RLSInputMenuProps extends InputMenuProps {
17
+ defaultValue?: string
18
+ onValueChange?: (value: string) => void
19
+ }
20
+
21
+ type InputMenuItem = { label: string; value: string; [key: string]: any }
22
+
23
+ const RLSInputMenu: Component<RLSInputMenuProps> = (allProps) => {
24
+ const [props, rest] = splitProps(allProps, [
25
+ "items",
26
+ "value",
27
+ "defaultValue",
28
+ "placeholder",
29
+ "disabled",
30
+ "name",
31
+ "label",
32
+ "size",
33
+ "color",
34
+ "ui",
35
+ "class",
36
+ "onValueChange"
37
+ ])
38
+
39
+ const resolvedClasses = createMemo(() =>
40
+ inputMenuTheme({
41
+ size: props.size ?? "md",
42
+ color: props.color,
43
+ ui: props.ui,
44
+ class: props.class
45
+ })
46
+ )
47
+
48
+ const normalizedItems = createMemo<InputMenuItem[]>(() =>
49
+ (props.items ?? []).map((item) =>
50
+ typeof item === "string" ? { label: item, value: item } : item
51
+ )
52
+ )
53
+
54
+ const [selectedValue, setSelectedValue] = createSignal<string>(
55
+ props.value !== undefined
56
+ ? String(props.value)
57
+ : props.defaultValue !== undefined
58
+ ? String(props.defaultValue)
59
+ : ""
60
+ )
61
+ const currentValue = () => (props.value !== undefined ? String(props.value) : selectedValue())
62
+
63
+ const selectedItem = createMemo(() =>
64
+ normalizedItems().find((item) => String(item.value) === String(currentValue()))
65
+ )
66
+
67
+ const visibleLabel = createMemo(() => {
68
+ if (props.placeholder && (currentValue() === "" || currentValue() === "undefined")) {
69
+ return props.placeholder
70
+ }
71
+ return selectedItem()?.label ?? props.placeholder ?? "Select item..."
72
+ })
73
+
74
+ const [open, setOpen] = createSignal(false)
75
+ const [query, setQuery] = createSignal("")
76
+
77
+ let searchRef: HTMLInputElement | undefined
78
+ let hiddenRef: HTMLInputElement | undefined
79
+
80
+ const filteredItems = createMemo(() => {
81
+ const q = query().toLowerCase().trim()
82
+ if (!q) return normalizedItems()
83
+ return normalizedItems().filter((item) => item.label.toLowerCase().includes(q))
84
+ })
85
+
86
+ const selectItem = (value: string, _label: string) => {
87
+ if (props.value === undefined) setSelectedValue(value)
88
+ if (hiddenRef) hiddenRef.value = value
89
+ props.onValueChange?.(value)
90
+ setQuery("")
91
+ setOpen(false)
92
+ }
93
+
94
+ const handleTriggerClick = (e: MouseEvent) => {
95
+ e.stopPropagation()
96
+ if (props.disabled) return
97
+ setOpen(!open())
98
+ }
99
+
100
+ const handleItemClick = (e: MouseEvent, item: InputMenuItem) => {
101
+ e.stopPropagation()
102
+ selectItem(item.value, item.label)
103
+ }
104
+
105
+ createEffect(() => {
106
+ if (open()) searchRef?.focus()
107
+ })
108
+
109
+ onMount(() => {
110
+ const handleDocumentClick = () => {
111
+ setOpen(false)
112
+ }
113
+ document.addEventListener("click", handleDocumentClick)
114
+ onCleanup(() => document.removeEventListener("click", handleDocumentClick))
115
+ })
116
+
117
+ return (
118
+ <div
119
+ class={resolvedClasses().root}
120
+ data-slot="root"
121
+ data-disabled={props.disabled ? "" : undefined}
122
+ {...rest}
123
+ >
124
+ {props.label ? (
125
+ <label class={resolvedClasses().label} data-slot="label">
126
+ {props.label}
127
+ </label>
128
+ ) : null}
129
+
130
+ <div class="relative w-full" data-inputMenu-wrapper>
131
+ <button
132
+ type="button"
133
+ class={resolvedClasses().trigger}
134
+ data-slot="trigger"
135
+ disabled={props.disabled}
136
+ data-inputMenu-trigger
137
+ onClick={handleTriggerClick}
138
+ >
139
+ <span data-inputMenu-value>{visibleLabel()}</span>
140
+ <RLSIcon name="i-rl-chevronsUpDown" class="opacity-50" aria-hidden="true" />
141
+ </button>
142
+
143
+ <Show when={open()}>
144
+ <div
145
+ class={`${resolvedClasses().content} absolute z-50`}
146
+ data-inputMenu-dropdown
147
+ data-slot="content"
148
+ >
149
+ <input
150
+ type="text"
151
+ class={resolvedClasses().input}
152
+ placeholder="Search..."
153
+ data-inputMenu-search
154
+ ref={(el) => (searchRef = el)}
155
+ onInput={(e) => setQuery(e.currentTarget.value)}
156
+ />
157
+ <div class="py-1" data-inputMenu-items>
158
+ <For each={filteredItems()}>
159
+ {(item) => (
160
+ <div
161
+ class={resolvedClasses().item}
162
+ data-slot="item"
163
+ data-value={item.value}
164
+ data-label={item.label}
165
+ data-inputMenu-item
166
+ data-state={
167
+ String(item.value) === String(currentValue()) ? "selected" : undefined
168
+ }
169
+ onClick={(e) => handleItemClick(e, item)}
170
+ >
171
+ <span class={resolvedClasses().itemText}>{item.label}</span>
172
+ <RLSIcon
173
+ name="i-rl-check"
174
+ class={`${resolvedClasses().itemIcon} ${
175
+ String(item.value) === String(currentValue()) ? "" : "hidden"
176
+ }`}
177
+ data-check-icon
178
+ aria-hidden="true"
179
+ />
180
+ </div>
181
+ )}
182
+ </For>
183
+ </div>
184
+ </div>
185
+ </Show>
186
+ </div>
187
+
188
+ <input
189
+ type="hidden"
190
+ name={props.name}
191
+ value={currentValue()}
192
+ data-inputMenu-hidden-input
193
+ ref={(el) => (hiddenRef = el)}
194
+ />
195
+ </div>
196
+ )
197
+ }
198
+
199
+ export default RLSInputMenu
@@ -0,0 +1,184 @@
1
+ import { createMemo, createSignal, splitProps, type Component, type JSX } from "solid-js"
2
+ import type { InputNumberProps } from "./input-number"
3
+ import { inputNumberTheme } from "./input-number.theme"
4
+ import { inputTheme } from "../input/input.theme"
5
+ import RLSIcon from "../icon/RLSIcon"
6
+
7
+ export interface RLSInputNumberProps extends InputNumberProps {
8
+ children?: JSX.Element
9
+ value?: number
10
+ defaultValue?: number
11
+ min?: number
12
+ max?: number
13
+ step?: number
14
+ name?: string
15
+ placeholder?: string
16
+ disabled?: boolean
17
+ readonly?: boolean
18
+ required?: boolean
19
+ size?: "sm" | "md" | "lg"
20
+ onInput?: (e: InputEvent & { currentTarget: HTMLInputElement }) => void
21
+ onChange?: (e: Event & { currentTarget: HTMLInputElement }) => void
22
+ onBlur?: (e: FocusEvent & { currentTarget: HTMLInputElement }) => void
23
+ onFocus?: (e: FocusEvent & { currentTarget: HTMLInputElement }) => void
24
+ onKeyDown?: (e: KeyboardEvent & { currentTarget: HTMLInputElement }) => void
25
+ onValueChange?: (value: number) => void
26
+ }
27
+
28
+ const RLSInputNumber: Component<RLSInputNumberProps> = (allProps) => {
29
+ const [props, rest] = splitProps(allProps, [
30
+ "children",
31
+ "value",
32
+ "defaultValue",
33
+ "min",
34
+ "max",
35
+ "step",
36
+ "name",
37
+ "placeholder",
38
+ "disabled",
39
+ "readonly",
40
+ "required",
41
+ "size",
42
+ "ui",
43
+ "class",
44
+ "onInput",
45
+ "onChange",
46
+ "onBlur",
47
+ "onFocus",
48
+ "onKeyDown",
49
+ "onValueChange"
50
+ ])
51
+
52
+ const resolvedClasses = createMemo(() =>
53
+ inputNumberTheme({
54
+ ui: props.ui,
55
+ class: props.class
56
+ })
57
+ )
58
+
59
+ const inputClasses = createMemo(() =>
60
+ inputTheme({
61
+ variant: "default",
62
+ size: props.size ?? "md",
63
+ error: false,
64
+ ui: props.ui
65
+ })
66
+ )
67
+
68
+ const clamp = (value: number) =>
69
+ Math.min(
70
+ props.max ?? Number.POSITIVE_INFINITY,
71
+ Math.max(props.min ?? Number.NEGATIVE_INFINITY, value)
72
+ )
73
+
74
+ const [internalValue, setInternalValue] = createSignal<number | undefined>(props.defaultValue)
75
+ const boundValue = () => (props.value !== undefined ? props.value : internalValue())
76
+
77
+ let inputRef: HTMLInputElement | undefined
78
+
79
+ const updateValue = (next: number) => {
80
+ const clamped = clamp(next)
81
+ if (props.value === undefined) setInternalValue(clamped)
82
+ props.onValueChange?.(clamped)
83
+ }
84
+
85
+ const stepBy = (dir: 1 | -1) => {
86
+ if (props.disabled || props.readonly) return
87
+ const raw = inputRef ? Number(inputRef.value) : Number(boundValue())
88
+ const base = Number.isNaN(raw) ? Number(boundValue() || 0) : raw
89
+ updateValue((Number.isNaN(base) ? 0 : base) + dir * (props.step ?? 1))
90
+ if (inputRef)
91
+ inputRef.value = String(clamp((Number.isNaN(base) ? 0 : base) + dir * (props.step ?? 1)))
92
+ }
93
+
94
+ const changeEvent = (el: HTMLInputElement): Event & { currentTarget: HTMLInputElement } => {
95
+ const ev = new Event("change", { bubbles: true })
96
+ Object.defineProperty(ev, "currentTarget", { value: el })
97
+ return ev as Event & { currentTarget: HTMLInputElement }
98
+ }
99
+
100
+ const commit = () => {
101
+ const el = inputRef
102
+ if (!el) return
103
+ const raw = Number(el.value)
104
+ if (el.value !== "" && !Number.isNaN(raw)) {
105
+ const clamped = clamp(raw)
106
+ if (props.value === undefined) setInternalValue(clamped)
107
+ if (clamped !== raw) el.value = String(clamped)
108
+ props.onValueChange?.(clamped)
109
+ }
110
+ props.onChange?.(changeEvent(el))
111
+ }
112
+
113
+ const handleWheel = (e: WheelEvent) => {
114
+ if (props.disabled || props.readonly) return
115
+ e.preventDefault()
116
+ stepBy(e.deltaY < 0 ? 1 : -1)
117
+ }
118
+
119
+ const handleKeyDown = (e: KeyboardEvent & { currentTarget: HTMLInputElement }) => {
120
+ props.onKeyDown?.(e)
121
+ if (e.key === "ArrowUp" || e.key === "ArrowDown") {
122
+ e.preventDefault()
123
+ stepBy(e.key === "ArrowUp" ? 1 : -1)
124
+ } else if (e.key === "Enter") {
125
+ e.preventDefault()
126
+ commit()
127
+ }
128
+ }
129
+
130
+ return (
131
+ <div class={resolvedClasses().root} data-slot="root" {...rest}>
132
+ <div class={`relative w-full ${inputClasses().root}`}>
133
+ <input
134
+ ref={(el) => (inputRef = el)}
135
+ type="number"
136
+ name={props.name}
137
+ value={props.value !== undefined ? props.value : ""}
138
+ placeholder={props.placeholder}
139
+ min={props.min}
140
+ max={props.max}
141
+ step={props.step}
142
+ disabled={props.disabled}
143
+ readonly={props.readonly}
144
+ required={props.required}
145
+ class={`${inputClasses().input} pr-11 [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none`}
146
+ data-slot="input"
147
+ onInput={props.onInput}
148
+ onChange={props.onChange}
149
+ onBlur={commit}
150
+ onFocus={props.onFocus}
151
+ onKeyDown={handleKeyDown}
152
+ onWheel={handleWheel}
153
+ />
154
+ <div class="absolute right-1 top-1/2 flex -translate-y-1/2 flex-col">
155
+ <button
156
+ type="button"
157
+ tabIndex={-1}
158
+ aria-label="Increment"
159
+ class="flex size-6 items-center justify-center rounded-sm text-muted hover:bg-muted/60 hover:text-highlighted disabled:cursor-not-allowed disabled:opacity-50"
160
+ data-slot="increment"
161
+ disabled={props.disabled || props.readonly}
162
+ onClick={() => stepBy(1)}
163
+ >
164
+ <RLSIcon name="arrowUp" size="xs" aria-hidden="true" />
165
+ </button>
166
+ <button
167
+ type="button"
168
+ tabIndex={-1}
169
+ aria-label="Decrement"
170
+ class="flex size-6 items-center justify-center rounded-sm text-muted hover:bg-muted/60 hover:text-highlighted disabled:cursor-not-allowed disabled:opacity-50"
171
+ data-slot="decrement"
172
+ disabled={props.disabled || props.readonly}
173
+ onClick={() => stepBy(-1)}
174
+ >
175
+ <RLSIcon name="arrowDown" size="xs" aria-hidden="true" />
176
+ </button>
177
+ </div>
178
+ </div>
179
+ {props.children}
180
+ </div>
181
+ )
182
+ }
183
+
184
+ export default RLSInputNumber