@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.
- package/dist/index.d.mts +4 -5
- package/dist/preset.mjs +73 -1
- package/dist/resolver.d.mts +3 -4
- package/dist/resolver.mjs +2 -4
- package/dist/shortcuts.d.mts +10 -11
- package/dist/stores.d.mts +3 -4
- package/package.json +8 -6
- package/src/components/3d-hover/RLS3dHover.tsx +21 -0
- package/src/components/accordion/RLSAccordion.tsx +112 -0
- package/src/components/app/RLSApp.tsx +21 -0
- package/src/components/aspect-ratio/RLSAspectRatio.tsx +30 -0
- package/src/components/audio/RLSAudio.tsx +27 -0
- package/src/components/avatar/RLSAvatar.tsx +142 -0
- package/src/components/avatar/avatar.ts +22 -21
- package/src/components/avatar-group/RLSAvatarGroup.tsx +163 -0
- package/src/components/badge/RLSBadge.tsx +1 -1
- package/src/components/badge/RLVBadge.vue +5 -3
- package/src/components/banner/RLSBanner.tsx +151 -0
- package/src/components/breadcrumb/RLSBreadcrumb.tsx +194 -0
- package/src/components/browser-mockup/RLSBrowserMockup.tsx +21 -0
- package/src/components/button/RLSButton.tsx +49 -40
- package/src/components/button/RLVButton.vue +44 -32
- package/src/components/calendar/RLSCalendar.tsx +26 -0
- package/src/components/callout/RLSCallout.tsx +151 -0
- package/src/components/card/RLSCard.tsx +4 -0
- package/src/components/card/RLVCard.vue +4 -0
- package/src/components/card/card.ts +10 -0
- package/src/components/carousel/RLACarousel.astro +14 -1
- package/src/components/carousel/RLSCarousel.tsx +260 -0
- package/src/components/chart/RLSChart.tsx +299 -0
- package/src/components/chat/RLSChat.tsx +27 -0
- package/src/components/chat-message/RLSChatMessage.tsx +27 -0
- package/src/components/chat-messages/RLSChatMessages.tsx +27 -0
- package/src/components/chat-palette/RLSChatPalette.tsx +27 -0
- package/src/components/chat-prompt/RLSChatPrompt.tsx +27 -0
- package/src/components/chat-prompt-submit/RLSChatPromptSubmit.tsx +27 -0
- package/src/components/chat-reasoning/RLSChatReasoning.tsx +27 -0
- package/src/components/chat-shimmer/RLSChatShimmer.tsx +27 -0
- package/src/components/chat-tool/RLSChatTool.tsx +27 -0
- package/src/components/checkbox/RLACheckbox.astro +1 -0
- package/src/components/checkbox/RLSCheckbox.tsx +1 -1
- package/src/components/checkbox/checkbox.theme.ts +2 -2
- package/src/components/chip/RLSChip.tsx +65 -0
- package/src/components/collapsible/RLSCollapsible.tsx +89 -0
- package/src/components/color-area/RLSColorArea.tsx +554 -0
- package/src/components/color-field/RLSColorField.tsx +236 -0
- package/src/components/color-picker/RLSColorPicker.tsx +26 -0
- package/src/components/color-slider/RLSColorSlider.tsx +373 -0
- package/src/components/command-palette/RLSCommandPalette.tsx +26 -0
- package/src/components/compare/RLSCompare.tsx +26 -0
- package/src/components/confirm/RLSConfirm.tsx +173 -0
- package/src/components/container/RLSContainer.tsx +24 -0
- package/src/components/context-menu/RLSContextMenu.tsx +26 -0
- package/src/components/copy-markdown/RLSCopyMarkdown.tsx +57 -0
- package/src/components/dashboard-group/RLSDashboardGroup.tsx +29 -0
- package/src/components/dashboard-navbar/RLSDashboardNavbar.tsx +116 -0
- package/src/components/dashboard-panel/RLSDashboardPanel.tsx +84 -0
- package/src/components/dashboard-resize-handle/RLSDashboardResizeHandle.tsx +35 -0
- package/src/components/dashboard-search/RLADashboardSearch.astro +1 -1
- package/src/components/dashboard-search/RLSDashboardSearch.tsx +125 -0
- package/src/components/dashboard-search-button/RLSDashboardSearchButton.tsx +82 -0
- package/src/components/dashboard-sidebar/RLSDashboardSidebar.tsx +184 -0
- package/src/components/dashboard-sidebar-collapse/RLSDashboardSidebarCollapse.tsx +46 -0
- package/src/components/dashboard-sidebar-toggle/RLSDashboardSidebarToggle.tsx +35 -0
- package/src/components/dashboard-toolbar/RLSDashboardToolbar.tsx +49 -0
- package/src/components/date/RLSDate.tsx +34 -0
- package/src/components/dock/RLSDock.tsx +26 -0
- package/src/components/drawer/RLSDrawer.tsx +177 -0
- package/src/components/dropdown-menu/RLADropdownMenu.astro +250 -241
- package/src/components/dropdown-menu/RLSDropdownMenu.tsx +183 -86
- package/src/components/editor/RLSEditor.tsx +26 -0
- package/src/components/empty/RLSEmpty.tsx +132 -0
- package/src/components/error/RLSError.tsx +26 -0
- package/src/components/field-group/RLSFieldGroup.tsx +46 -0
- package/src/components/fieldset/RLSFieldset.tsx +26 -0
- package/src/components/file-upload/RLSFileUpload.tsx +163 -0
- package/src/components/floating-action/RLSFloatingAction.tsx +26 -0
- package/src/components/footer/RLSFooter.tsx +56 -0
- package/src/components/form/RLSForm.tsx +34 -0
- package/src/components/gallery/RLSGallery.tsx +21 -0
- package/src/components/gamepad/RLSGamepad.tsx +269 -0
- package/src/components/grid/RLSGrid.tsx +29 -0
- package/src/components/head/RLAHead.astro +9 -0
- package/src/components/head/RLSHead.tsx +42 -0
- package/src/components/head/UIHead.astro +3 -0
- package/src/components/header/RLSHeader.tsx +87 -0
- package/src/components/hover-card/RLSHoverCard.tsx +72 -0
- package/src/components/icon/RLSIcon.tsx +3 -1
- package/src/components/image/RLAImage.astro +447 -138
- package/src/components/image/RLSImage.tsx +545 -0
- package/src/components/image/image.theme.ts +19 -3
- package/src/components/image/image.ts +31 -1
- package/src/components/input/RLAInput.astro +62 -51
- package/src/components/input/RLSInput.tsx +1 -1
- package/src/components/input-date/RLSInputDate.tsx +92 -0
- package/src/components/input-menu/RLSInputMenu.tsx +199 -0
- package/src/components/input-number/RLSInputNumber.tsx +184 -0
- package/src/components/input-pin/RLSInputPin.tsx +185 -0
- package/src/components/input-rating/RLSInputRating.tsx +198 -0
- package/src/components/input-rating/input-rating.ts +4 -0
- package/src/components/input-tags/RLSInputTags.tsx +94 -0
- package/src/components/input-time/RLSInputTime.tsx +92 -0
- package/src/components/kbd/RLSKbd.tsx +37 -0
- package/src/components/keyboard/RLSKeyboard.tsx +476 -0
- package/src/components/knob/RLSKnob.tsx +27 -0
- package/src/components/label/RLSLabel.tsx +27 -0
- package/src/components/layout-grid/RLSLayoutGrid.tsx +402 -0
- package/src/components/layout-grid/layout-grid.ts +25 -1
- package/src/components/link/RLSLink.tsx +2 -1
- package/src/components/link/link.ts +21 -12
- package/src/components/link-group/RLSLinkGroup.tsx +76 -0
- package/src/components/listbox/RLSListbox.tsx +27 -0
- package/src/components/locale-selector/RLALocaleSelector.astro +2 -1
- package/src/components/locale-selector/RLSLocaleSelector.tsx +178 -0
- package/src/components/logo/RLALogo.astro +69 -4
- package/src/components/logo/RLSLogo.tsx +129 -0
- package/src/components/main/RLSMain.tsx +40 -0
- package/src/components/marquee/RLSMarquee.tsx +80 -0
- package/src/components/meter/RLSMeter.tsx +27 -0
- package/src/components/modal/RLAModal.astro +1 -1
- package/src/components/modal/RLSModal.tsx +109 -72
- package/src/components/navigation-menu/RLSNavigationMenu.tsx +228 -0
- package/src/components/navigation-menu/navigation-menu.ts +2 -2
- package/src/components/package-managers/RLSPackageManagers.tsx +204 -0
- package/src/components/page/RLSPage.tsx +21 -0
- package/src/components/page-aside/RLSPageAside.tsx +21 -0
- package/src/components/page-body/RLSPageBody.tsx +21 -0
- package/src/components/page-header/RLSPageHeader.tsx +21 -0
- package/src/components/page-section/RLSPageSection.tsx +201 -0
- package/src/components/pagination/RLSPagination.tsx +114 -0
- package/src/components/password/RLSPassword.tsx +27 -0
- package/src/components/phone-mockup/RLSPhoneMockup.tsx +27 -0
- package/src/components/placeholder/RLSPlaceholder.tsx +47 -0
- package/src/components/popover/RLSPopover.tsx +124 -0
- package/src/components/post/RLSPost.tsx +134 -0
- package/src/components/pricing-plan/RLSPricingPlan.tsx +26 -0
- package/src/components/pricing-table/RLSPricingTable.tsx +26 -0
- package/src/components/progress/RLSProgress.tsx +53 -0
- package/src/components/prose/RLSProse.tsx +26 -0
- package/src/components/qr-code/RLSQrCode.tsx +26 -0
- package/src/components/quote/RLAQuote.astro +10 -6
- package/src/components/quote/RLSQuote.tsx +37 -0
- package/src/components/quote/quote.theme.ts +5 -2
- package/src/components/radio-group/RLSRadioGroup.tsx +37 -0
- package/src/components/rating/RLSRating.tsx +27 -0
- package/src/components/scroll-area/RLSScrollArea.tsx +210 -0
- package/src/components/scroll-to-top/RLAScrollToTop.astro +1 -0
- package/src/components/scroll-to-top/RLSScrollToTop.tsx +145 -0
- package/src/components/search/RLSSearch.tsx +237 -0
- package/src/components/select/RLASelect.astro +67 -4
- package/src/components/select/RLSSelect.tsx +107 -39
- package/src/components/select/RLVSelect.vue +50 -1
- package/src/components/select/select.theme.ts +30 -10
- package/src/components/select/select.ts +20 -1
- package/src/components/separator/RLSSeparator.tsx +92 -0
- package/src/components/share/RLSShare.tsx +66 -0
- package/src/components/shortcuts/RLSShortcuts.tsx +393 -0
- package/src/components/sidebar/RLSSidebar.tsx +271 -0
- package/src/components/skeleton/RLSSkeleton.tsx +21 -0
- package/src/components/slideover/RLASlideover.astro +1 -1
- package/src/components/slideover/RLSSlideover.tsx +159 -0
- package/src/components/slider/RLSSlider.tsx +112 -0
- package/src/components/speed-dial/RLSSpeedDial.tsx +27 -0
- package/src/components/spinner/RLSSpinner.tsx +22 -0
- package/src/components/splitter/RLSSplitter.tsx +178 -0
- package/src/components/spoiler/RLSSpoiler.tsx +26 -0
- package/src/components/stepper/RLSStepper.tsx +205 -0
- package/src/components/steps/RLSSteps.tsx +108 -0
- package/src/components/sticky-surface/RLSStickySurface.tsx +63 -0
- package/src/components/surround/RLSSurround.tsx +57 -0
- package/src/components/switch/RLSSwitch.tsx +56 -0
- package/src/components/table/RLATable.astro +1044 -579
- package/src/components/table/RLSTable.tsx +893 -0
- package/src/components/table/table.theme.ts +47 -16
- package/src/components/table/table.ts +104 -66
- package/src/components/table-of-contents/RLSTableOfContents.tsx +196 -0
- package/src/components/tabs/RLSTabs.tsx +298 -0
- package/src/components/textarea/RLATextarea.astro +1 -0
- package/src/components/textarea/RLSTextarea.tsx +3 -1
- package/src/components/theme-selector/RLAThemeSelector.astro +85 -56
- package/src/components/theme-selector/RLSThemeSelector.tsx +131 -0
- package/src/components/theme-selector/theme-selector.theme.ts +5 -7
- package/src/components/theme-selector/theme-selector.ts +11 -1
- package/src/components/timeline/RLSTimeline.tsx +171 -0
- package/src/components/toast/RLSToast.tsx +179 -0
- package/src/components/toaster/RLSToaster.tsx +82 -0
- package/src/components/tooltip/RLSTooltip.tsx +48 -0
- package/src/components/tour/RLSTour.tsx +26 -0
- package/src/components/tree/RLSTree.tsx +26 -0
- package/src/components/user/RLSUser.tsx +26 -0
- package/src/components/video/RLAVideo.astro +4 -1
- package/src/components/video/RLSVideo.tsx +158 -0
- package/src/components/watermark/RLSWatermark.tsx +27 -0
- package/src/components/window-mockup/RLSWindowMockup.tsx +27 -0
- package/src/preset.ts +73 -1
- package/src/resolver.ts +6 -1
- 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
|
|
@@ -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
|