@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
@@ -1,20 +1,29 @@
1
- import { createMemo, splitProps, For, type Component, type JSX } from "solid-js"
2
- import type { SelectItem } from "./select"
1
+ import { createMemo, createSignal, splitProps, For, type Component, type JSX } from "solid-js"
2
+ import type { SelectItem, SelectProps } from "./select"
3
3
  import { selectTheme } from "./select.theme"
4
+ import RLSButton, { type RLSButtonProps } from "../button/RLSButton"
4
5
  import RLSIcon from "../icon/RLSIcon"
5
6
 
6
- export interface RLSSelectProps {
7
+ export interface RLSSelectProps extends Partial<Omit<SelectProps, "onChange" | "onBlur">> {
7
8
  id?: string
8
9
  name?: string
9
- value?: string | number
10
- defaultValue?: string | number
10
+ value?: string | number | (string | number)[]
11
+ defaultValue?: string | number | (string | number)[]
11
12
  placeholder?: string
12
13
  disabled?: boolean
13
14
  required?: boolean
15
+ multiple?: boolean
14
16
  size?: "xs" | "sm" | "md" | "lg" | "xl"
17
+ variant?: "default" | "icon" | "outline" | "soft" | "subtle" | "ghost" | "none"
18
+ buttonVariant?: RLSButtonProps["variant"]
19
+ buttonColor?: RLSButtonProps["color"]
15
20
  class?: string
16
21
  items?: SelectItem[]
22
+ leadingIcon?: string
23
+ leading?: JSX.Element
17
24
  children?: JSX.Element
25
+ theme?: string
26
+ ui?: any
18
27
  onChange?: (e: Event & { currentTarget: HTMLSelectElement }) => void
19
28
  onBlur?: (e: FocusEvent & { currentTarget: HTMLSelectElement }) => void
20
29
  }
@@ -28,17 +37,33 @@ const RLSSelect: Component<RLSSelectProps> = (allProps) => {
28
37
  "placeholder",
29
38
  "disabled",
30
39
  "required",
40
+ "multiple",
31
41
  "size",
42
+ "variant",
43
+ "buttonVariant",
44
+ "buttonColor",
32
45
  "class",
33
46
  "items",
47
+ "leadingIcon",
48
+ "leading",
34
49
  "children",
50
+ "theme",
51
+ "ui",
35
52
  "onChange",
36
53
  "onBlur"
37
54
  ])
38
55
 
56
+ const resolvedVariant = () =>
57
+ props.variant === "default" || props.variant === "icon" ? props.variant : "default"
58
+
59
+ const buttonVariant = () => props.buttonVariant ?? "ghost"
60
+ const buttonColor = () => props.buttonColor ?? "neutral"
61
+
39
62
  const classes = createMemo(() =>
40
63
  selectTheme({
41
64
  size: props.size,
65
+ variant: resolvedVariant(),
66
+ ui: props.ui,
42
67
  class: props.class
43
68
  })
44
69
  )
@@ -68,26 +93,76 @@ const RLSSelect: Component<RLSSelectProps> = (allProps) => {
68
93
 
69
94
  const currentValue = createMemo(() =>
70
95
  props.value !== undefined
71
- ? String(props.value)
96
+ ? props.value
72
97
  : props.defaultValue !== undefined
73
- ? String(props.defaultValue)
98
+ ? props.defaultValue
74
99
  : undefined
75
100
  )
76
101
 
102
+ const labelFrom = (value?: string | number | (string | number)[]) => {
103
+ if (props.placeholder && (value === undefined || value === "")) return props.placeholder
104
+ if (Array.isArray(value)) return props.placeholder ?? ""
105
+ const item = normalizedItems().find((i) => String(i.value) === String(value))
106
+ return item?.label ?? ""
107
+ }
108
+
109
+ const [labelText, setLabelText] = createSignal(labelFrom(currentValue()))
110
+
111
+ const handleChange = (e: Event & { currentTarget: HTMLSelectElement }) => {
112
+ setLabelText(e.currentTarget.options[e.currentTarget.selectedIndex]?.text ?? "")
113
+ props.onChange?.(e)
114
+ }
115
+
116
+ const triggerProps = () => {
117
+ const p: RLSButtonProps = {
118
+ "variant": buttonVariant(),
119
+ "color": buttonColor(),
120
+ "square": true,
121
+ "aria-hidden": "true",
122
+ "tabIndex": -1,
123
+ "data-slot": "trigger",
124
+ "type": "button"
125
+ }
126
+ if (props.size) p.size = props.size
127
+ if (props.disabled !== undefined) p.disabled = props.disabled
128
+ if (props.leadingIcon) p.leadingIcon = props.leadingIcon
129
+ if (props.leading) p.leading = props.leading
130
+ return p
131
+ }
132
+
77
133
  return (
78
- <div class={`${classes().root}`}>
134
+ <div class={classes().root} data-slot="root" data-theme={props.theme}>
135
+ {resolvedVariant() === "icon" ? (
136
+ <RLSButton data-slot="trigger" {...triggerProps()} />
137
+ ) : props.leading ? (
138
+ <span class={classes().leading} data-slot="leading">
139
+ {props.leading}
140
+ </span>
141
+ ) : props.leadingIcon ? (
142
+ <span class={classes().leading} data-slot="leading">
143
+ <RLSIcon name={props.leadingIcon} size="sm" class="size-4" />
144
+ </span>
145
+ ) : null}
146
+
147
+ {resolvedVariant() !== "icon" ? (
148
+ <span class={classes().label} data-slot="label" aria-hidden="true">
149
+ {labelText()}
150
+ </span>
151
+ ) : null}
152
+
79
153
  <select
80
154
  id={props.id}
81
155
  name={props.name}
82
156
  disabled={props.disabled}
83
157
  required={props.required}
84
- onChange={props.onChange}
158
+ multiple={props.multiple}
159
+ onChange={handleChange}
85
160
  onBlur={props.onBlur}
86
161
  class={classes().select}
87
162
  data-slot="select"
88
163
  {...rest}
89
164
  >
90
- {props.placeholder ? (
165
+ {props.placeholder && !props.multiple ? (
91
166
  <option value="" disabled selected={!currentValue()}>
92
167
  {props.placeholder}
93
168
  </option>
@@ -97,40 +172,33 @@ const RLSSelect: Component<RLSSelectProps> = (allProps) => {
97
172
  props.children
98
173
  ) : (
99
174
  <For each={normalizedItems()}>
100
- {(item) => (
101
- <option
102
- value={item.value}
103
- disabled={item.disabled}
104
- selected={currentValue() !== undefined ? currentValue() === item.value : undefined}
105
- >
106
- {item.icon ? <RLSIcon name={item.icon} class="rl-select-item-icon" /> : null}
107
- {item.avatar ? (
108
- <img src={item.avatar.src} alt={item.avatar.alt} class="rl-select-item-icon" />
109
- ) : null}
110
- {item.label}
111
- </option>
112
- )}
175
+ {(item) => {
176
+ const val = currentValue()
177
+ const isSelected = Array.isArray(val)
178
+ ? val.map(String).includes(String(item.value))
179
+ : val !== undefined
180
+ ? String(val) === String(item.value)
181
+ : undefined
182
+ return (
183
+ <option value={item.value} disabled={item.disabled} selected={isSelected}>
184
+ {item.icon ? <RLSIcon name={item.icon} class="rl-select-item-icon" /> : null}
185
+ {item.avatar ? (
186
+ <img src={item.avatar.src} alt={item.avatar.alt} class="rl-select-item-icon" />
187
+ ) : null}
188
+ {item.label}
189
+ </option>
190
+ )
191
+ }}
113
192
  </For>
114
193
  )}
115
194
  </select>
116
195
 
117
196
  {/* Custom Chevron arrow */}
118
- <span class={classes().icon} data-slot="icon">
119
- <svg
120
- xmlns="http://www.w3.org/2000/svg"
121
- width="14"
122
- height="14"
123
- viewBox="0 0 24 24"
124
- fill="none"
125
- stroke="currentColor"
126
- stroke-width="2"
127
- stroke-linecap="round"
128
- stroke-linejoin="round"
129
- aria-hidden="true"
130
- >
131
- <path d="M6 9l6 6 6-6" />
132
- </svg>
133
- </span>
197
+ {resolvedVariant() !== "icon" ? (
198
+ <span class={classes().icon} data-slot="icon">
199
+ <RLSIcon name="chevronDown" size="sm" class="size-4" aria-hidden="true" />
200
+ </span>
201
+ ) : null}
134
202
 
135
203
  <style>{`
136
204
  select.rl-select,
@@ -2,6 +2,7 @@
2
2
  import { computed, useAttrs } from "vue"
3
3
  import type { SelectProps } from "./select"
4
4
  import { selectTheme } from "./select.theme"
5
+ import RLVButton from "../button/RLVButton.vue"
5
6
  import RLVIcon from "../icon/RLVIcon.vue"
6
7
 
7
8
  defineOptions({ name: "RLVSelect" })
@@ -12,13 +13,21 @@ const modelValue = defineModel<string | number | undefined>()
12
13
 
13
14
  const props = withDefaults(defineProps<SelectProps>(), {
14
15
  size: "md",
16
+ variant: "default",
17
+ buttonVariant: "ghost",
18
+ buttonColor: "neutral",
15
19
  color: "neutral",
16
20
  disabled: false
17
21
  })
18
22
 
23
+ const resolvedVariant = computed(() =>
24
+ props.variant === "default" || props.variant === "icon" ? props.variant : "default"
25
+ )
26
+
19
27
  const resolvedClasses = computed(() =>
20
28
  selectTheme({
21
29
  size: props.size,
30
+ variant: resolvedVariant.value,
22
31
  color: props.color,
23
32
  disabled: props.disabled,
24
33
  class: props.class
@@ -34,10 +43,50 @@ const normalizedItems = computed(() => {
34
43
  return item
35
44
  })
36
45
  })
46
+
47
+ const displayLabel = computed(() => {
48
+ const value = modelValue.value
49
+ if (props.placeholder && (value === undefined || value === "")) return props.placeholder
50
+ const item = normalizedItems.value.find((i) => String(i.value) === String(value))
51
+ return item?.label ?? ""
52
+ })
37
53
  </script>
38
54
 
39
55
  <template>
40
56
  <div :class="resolvedClasses.root" data-slot="root">
57
+ <RLVButton
58
+ v-if="resolvedVariant === 'icon'"
59
+ :variant="buttonVariant"
60
+ :color="buttonColor"
61
+ :size="size"
62
+ square
63
+ :disabled="disabled"
64
+ :leading-icon="leadingIcon"
65
+ aria-hidden="true"
66
+ tabindex="-1"
67
+ type="button"
68
+ data-slot="trigger"
69
+ >
70
+ <template #leading>
71
+ <slot name="leading" />
72
+ </template>
73
+ </RLVButton>
74
+ <div
75
+ v-else-if="$slots.leading || leadingIcon"
76
+ :class="resolvedClasses.leading"
77
+ data-slot="leading"
78
+ >
79
+ <RLVIcon v-if="leadingIcon" :name="leadingIcon" class="size-4" />
80
+ <slot v-else name="leading" />
81
+ </div>
82
+ <span
83
+ v-if="resolvedVariant !== 'icon'"
84
+ :class="resolvedClasses.label"
85
+ data-slot="label"
86
+ aria-hidden="true"
87
+ >
88
+ {{ displayLabel }}
89
+ </span>
41
90
  <select
42
91
  v-bind="attrs"
43
92
  v-model="modelValue"
@@ -65,7 +114,7 @@ const normalizedItems = computed(() => {
65
114
  {{ item.label }}
66
115
  </option>
67
116
  </select>
68
- <span :class="resolvedClasses.icon" data-slot="icon">
117
+ <span v-if="resolvedVariant !== 'icon'" :class="resolvedClasses.icon" data-slot="icon">
69
118
  <RLVIcon name="i-lucide-chevron-down" class="size-4" />
70
119
  </span>
71
120
  </div>
@@ -1,23 +1,43 @@
1
1
  import { defineTheme } from "../../resolver"
2
2
 
3
3
  export const selectTheme = defineTheme("select", {
4
- slots: ["root", "select", "icon"],
4
+ slots: ["root", "select", "icon", "leading", "label"],
5
5
  base: {
6
- root: "relative inline-flex items-center w-full",
7
- select:
8
- "rl-select w-full cursor-pointer rounded-md border border-default bg-default text-highlighted shadow-sm outline-none transition-colors focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-50",
9
- icon: "pointer-events-none absolute right-2 flex items-center text-muted"
6
+ root: "relative inline-flex items-center gap-2",
7
+ select: "rl-select appearance-none absolute inset-0 h-full w-full opacity-0 cursor-pointer",
8
+ label: "text-sm font-medium",
9
+ icon: "pointer-events-none absolute inset-y-0 right-2.5 flex items-center text-current",
10
+ leading: "flex items-center text-current shrink-0 pointer-events-none self-center"
10
11
  },
11
12
  variants: {
13
+ variant: {
14
+ default: {
15
+ root: "w-full rounded-md border border-default bg-default shadow-sm text-highlighted hover:bg-accented/50 transition-colors cursor-pointer"
16
+ },
17
+ icon: {
18
+ root: "rounded-lg focus-within:ring-2 focus-within:ring-ring",
19
+ label: "hidden",
20
+ icon: "hidden",
21
+ leading: "hidden"
22
+ }
23
+ },
12
24
  size: {
13
- xs: { select: "py-0.5 pl-2 pr-6 text-xs" },
14
- sm: { select: "py-1 pl-2.5 pr-7 text-xs" },
15
- md: { select: "py-1.5 pl-3 pr-8 text-sm" },
16
- lg: { select: "py-2 pl-3.5 pr-9 text-base" },
17
- xl: { select: "py-2.5 pl-4 pr-10 text-base" }
25
+ xs: { root: "text-xs", label: "text-xs pr-5" },
26
+ sm: { root: "text-xs", label: "text-xs pr-6" },
27
+ md: { root: "text-sm", label: "text-sm pr-7" },
28
+ lg: { root: "text-base", label: "text-base pr-8" },
29
+ xl: { root: "text-base", label: "text-base pr-9" }
18
30
  }
19
31
  },
32
+ compoundVariants: [
33
+ { variant: "default", size: "xs", class: { root: "px-2 py-0.5" } },
34
+ { variant: "default", size: "sm", class: { root: "px-2.5 py-1" } },
35
+ { variant: "default", size: "md", class: { root: "px-3 py-1.5" } },
36
+ { variant: "default", size: "lg", class: { root: "px-3.5 py-2" } },
37
+ { variant: "default", size: "xl", class: { root: "px-4 py-2.5" } }
38
+ ],
20
39
  defaultVariants: {
40
+ variant: "default",
21
41
  size: "md"
22
42
  }
23
43
  })
@@ -48,7 +48,26 @@ export interface SelectProps {
48
48
  | "warning"
49
49
  | "error"
50
50
  | "neutral"
51
- variant?: "outline" | "soft" | "subtle" | "ghost" | "none"
51
+ /**
52
+ * The visual variant of the select.
53
+ *
54
+ * `icon` renders the trigger as an icon-only `RLButton` that opens the option picker.
55
+ *
56
+ * @default "default"
57
+ */
58
+ variant?: "default" | "icon" | "outline" | "soft" | "subtle" | "ghost" | "none"
59
+ /**
60
+ * The `RLButton` variant used when `variant="icon"`.
61
+ *
62
+ * @default "ghost"
63
+ */
64
+ buttonVariant?: "solid" | "outline" | "soft" | "subtle" | "ghost" | "link"
65
+ /**
66
+ * The `RLButton` color used when `variant="icon"`.
67
+ *
68
+ * @default "neutral"
69
+ */
70
+ buttonColor?: ThemeColor
52
71
  theme?: "light" | "dark"
53
72
  size?: "xs" | "sm" | "md" | "lg" | "xl"
54
73
  highlight?: boolean
@@ -0,0 +1,92 @@
1
+ import { createMemo, splitProps, type Component, type JSX } from "solid-js"
2
+ import type { SeparatorProps } from "./separator"
3
+ import { separatorTheme } from "./separator.theme"
4
+ import RLSAvatar from "../avatar/RLSAvatar"
5
+
6
+ export interface RLSSeparatorProps extends SeparatorProps {
7
+ children?: JSX.Element
8
+ avatarSlot?: JSX.Element
9
+ iconSlot?: JSX.Element
10
+ label?: any
11
+ icon?: string
12
+ avatar?: string | Record<string, any>
13
+ }
14
+
15
+ const RLSSeparator: Component<RLSSeparatorProps> = (allProps) => {
16
+ const [props, rest] = splitProps(allProps, [
17
+ "color",
18
+ "size",
19
+ "type",
20
+ "position",
21
+ "orientation",
22
+ "decorative",
23
+ "label",
24
+ "icon",
25
+ "avatar",
26
+ "ui",
27
+ "class",
28
+ "children",
29
+ "avatarSlot",
30
+ "iconSlot"
31
+ ])
32
+
33
+ const classes = createMemo(() =>
34
+ separatorTheme({
35
+ color: props.color ?? "neutral",
36
+ size: props.size ?? "xs",
37
+ type: props.type ?? "solid",
38
+ position: props.position,
39
+ orientation: props.orientation ?? "horizontal",
40
+ ui: props.ui,
41
+ class: props.class
42
+ })
43
+ )
44
+
45
+ const decorative = props.decorative ?? true
46
+
47
+ return (
48
+ <div
49
+ class={classes()["root"]}
50
+ data-slot="root"
51
+ role={decorative ? "none" : "separator"}
52
+ aria-orientation={decorative ? undefined : props.orientation}
53
+ {...rest}
54
+ >
55
+ <div class={classes()["border"]} />
56
+
57
+ {(props.label || props.icon || props.avatar || props.children !== undefined) && (
58
+ <>
59
+ <div class={classes()["container"]} data-slot="container">
60
+ {props.avatarSlot !== undefined ? (
61
+ props.avatarSlot
62
+ ) : props.avatar ? (
63
+ <RLSAvatar
64
+ {...(typeof props.avatar === "string" ? { src: props.avatar } : props.avatar)}
65
+ size={classes()["avatarSize"] as any}
66
+ class={classes()["avatar"]}
67
+ data-slot="avatar"
68
+ />
69
+ ) : null}
70
+
71
+ {props.iconSlot !== undefined ? (
72
+ props.iconSlot
73
+ ) : props.icon ? (
74
+ <span class={classes()["icon"]} data-slot="icon">
75
+ <span class={props.icon} aria-hidden="true" />
76
+ </span>
77
+ ) : null}
78
+
79
+ <span class={classes()["label"]} data-slot="label">
80
+ {props.label}
81
+ {props.children}
82
+ </span>
83
+ </div>
84
+
85
+ <div class={classes()["border"]} />
86
+ </>
87
+ )}
88
+ </div>
89
+ )
90
+ }
91
+
92
+ export default RLSSeparator
@@ -0,0 +1,66 @@
1
+ import { createSignal, onCleanup, splitProps, type Component } from "solid-js"
2
+ import type { ButtonProps } from "../button/button"
3
+ import RLSButton from "../button/RLSButton"
4
+
5
+ export interface RLSShareProps extends Omit<
6
+ ButtonProps,
7
+ | "href"
8
+ | "label"
9
+ | "leadingIcon"
10
+ | "trailingIcon"
11
+ | "loading"
12
+ | "loadingAuto"
13
+ | "square"
14
+ | "active"
15
+ | "activeColor"
16
+ | "activeVariant"
17
+ > {}
18
+
19
+ const RLSShare: Component<RLSShareProps> = (allProps) => {
20
+ const [props, rest] = splitProps(allProps, ["class", "ui"])
21
+ const [copied, setCopied] = createSignal(false)
22
+ let timeoutId: ReturnType<typeof setTimeout> | undefined
23
+
24
+ onCleanup(() => {
25
+ if (timeoutId !== undefined) clearTimeout(timeoutId)
26
+ })
27
+
28
+ const handleShare = async () => {
29
+ if (typeof navigator.share === "function") {
30
+ try {
31
+ await navigator.share({ title: document.title, url: window.location.href })
32
+ } catch (err) {
33
+ const error = err as { name?: string }
34
+ if (error.name !== "AbortError") {
35
+ console.error("Share failed:", err)
36
+ }
37
+ }
38
+ return
39
+ }
40
+ try {
41
+ await navigator.clipboard.writeText(window.location.href)
42
+ setCopied(true)
43
+ if (timeoutId !== undefined) clearTimeout(timeoutId)
44
+ timeoutId = setTimeout(() => setCopied(false), 2000)
45
+ } catch (err) {
46
+ console.error("Failed to copy link:", err)
47
+ }
48
+ }
49
+
50
+ return (
51
+ <RLSButton
52
+ id="rl-share"
53
+ class={props.class}
54
+ color="neutral"
55
+ variant="outline"
56
+ size="sm"
57
+ leadingIcon="share"
58
+ label={copied() ? "Link Copied!" : "Share"}
59
+ ui={props.ui}
60
+ onClick={handleShare}
61
+ {...rest}
62
+ />
63
+ )
64
+ }
65
+
66
+ export default RLSShare