Skip to content

Commit b8cc16b

Browse files
committed
Migrate RLButton, RLCheckbox, RLColorPicker and RLExpansionCard to Shoelace React component
1 parent 889ee37 commit b8cc16b

5 files changed

Lines changed: 128 additions & 162 deletions

File tree

src/components/RLButton/RLButton.tsx

Lines changed: 14 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,9 @@
11
import { forwardRef } from 'react'
2+
import SlButton from '@shoelace-style/shoelace/dist/react/button/index.js'
3+
import type SlButtonElement from '@shoelace-style/shoelace/dist/components/button/button.js'
24
import type { RLButtonProps } from './types'
35

4-
declare global {
5-
namespace JSX {
6-
interface IntrinsicElements {
7-
'sl-button': React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement> & {
8-
variant?: string
9-
size?: string
10-
caret?: boolean
11-
disabled?: boolean
12-
loading?: boolean
13-
outline?: boolean
14-
pill?: boolean
15-
circle?: boolean
16-
type?: string
17-
name?: string
18-
value?: string
19-
href?: string
20-
target?: string
21-
form?: string
22-
class?: string
23-
}
24-
}
25-
}
26-
}
27-
28-
export const RLButton = forwardRef<HTMLElement, RLButtonProps>(
6+
export const RLButton = forwardRef<SlButtonElement, RLButtonProps>(
297
(
308
{
319
variant = 'default',
@@ -51,29 +29,29 @@ export const RLButton = forwardRef<HTMLElement, RLButtonProps>(
5129
ref
5230
) => {
5331
return (
54-
<sl-button
32+
<SlButton
5533
ref={ref}
56-
class={className}
34+
className={className}
5735
variant={variant}
5836
size={size}
59-
caret={caret || undefined}
60-
disabled={disabled || undefined}
61-
loading={loading || undefined}
62-
outline={outline || undefined}
63-
pill={pill || undefined}
64-
circle={circle || undefined}
37+
caret={caret}
38+
disabled={disabled}
39+
loading={loading}
40+
outline={outline}
41+
pill={pill}
42+
circle={circle}
6543
type={type}
66-
name={name || undefined}
44+
name={name}
6745
value={value}
68-
href={href || undefined}
46+
href={href}
6947
target={target}
7048
form={form}
7149
onClick={onClick}
7250
>
7351
{prefix && <span slot="prefix">{prefix}</span>}
7452
{children}
7553
{suffix && <span slot="suffix">{suffix}</span>}
76-
</sl-button>
54+
</SlButton>
7755
)
7856
}
7957
)

src/components/RLCheckbox/RLCheckbox.tsx

Lines changed: 41 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,10 @@
1-
import { forwardRef, useImperativeHandle, useCallback, useEffect } from 'react'
1+
import { forwardRef, useImperativeHandle, useCallback, useEffect, useRef } from 'react'
2+
import SlCheckbox from '@shoelace-style/shoelace/dist/react/checkbox/index.js'
3+
import type SlCheckboxElement from '@shoelace-style/shoelace/dist/components/checkbox/checkbox.js'
24
import type { RLCheckboxProps, RLCheckboxRef } from './types'
3-
import type { SlInputEvent } from '../utils/types'
45
import { ErrorMessage } from '../utils/ErrorMessage'
56
import { useValidation } from '../../hooks/useValidation'
67

7-
declare global {
8-
namespace JSX {
9-
interface IntrinsicElements {
10-
'sl-checkbox': React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement> & {
11-
name?: string
12-
value?: boolean
13-
size?: string
14-
disabled?: boolean
15-
checked?: boolean
16-
indeterminate?: boolean
17-
defaultChecked?: boolean
18-
form?: string
19-
required?: boolean
20-
class?: string
21-
onSlInput?: (event: Event) => void
22-
onSlChange?: (event: Event) => void
23-
onSlBlur?: (event: Event) => void
24-
onSlFocus?: (event: Event) => void
25-
onSlInvalid?: (event: Event) => void
26-
}
27-
}
28-
}
29-
}
30-
318
export const RLCheckbox = forwardRef<RLCheckboxRef, RLCheckboxProps>(
329
(
3310
{
@@ -52,6 +29,13 @@ export const RLCheckbox = forwardRef<RLCheckboxRef, RLCheckboxProps>(
5229
ref
5330
) => {
5431
const { errorMessage, isValid, validate } = useValidation({ rules, externalError: error })
32+
const checkboxRef = useRef<SlCheckboxElement>(null)
33+
34+
useEffect(() => {
35+
if (checkboxRef.current && checked !== undefined && checkboxRef.current.checked !== checked) {
36+
checkboxRef.current.checked = checked
37+
}
38+
}, [checked])
5539

5640
useEffect(() => {
5741
if (checked !== undefined) {
@@ -64,59 +48,61 @@ export const RLCheckbox = forwardRef<RLCheckboxRef, RLCheckboxProps>(
6448
validate: () => validate(checked)
6549
}))
6650

67-
const handleInput = useCallback(
68-
(event: Event) => {
69-
const evt = event as unknown as SlInputEvent
70-
const target = evt.target as HTMLInputElement & { checked: boolean }
71-
onChange?.(target?.checked ?? false)
72-
onInput?.(evt)
51+
const handleChange = useCallback(
52+
(event: CustomEvent) => {
53+
const target = event.target as SlCheckboxElement
54+
const newChecked = target?.checked ?? false
55+
validate(newChecked)
56+
onChange?.(newChecked)
57+
onSlChange?.(event)
7358
},
74-
[onChange, onInput]
59+
[onChange, onSlChange, validate]
7560
)
7661

77-
const handleChange = useCallback(
78-
(event: Event) => {
79-
onSlChange?.(event as unknown as Parameters<NonNullable<typeof onSlChange>>[0])
62+
const handleInput = useCallback(
63+
(event: CustomEvent) => {
64+
onInput?.(event)
8065
},
81-
[onSlChange]
66+
[onInput]
8267
)
8368

8469
const handleBlur = useCallback(
85-
(event: Event) => {
86-
onBlur?.(event as unknown as Parameters<NonNullable<typeof onBlur>>[0])
70+
(event: CustomEvent) => {
71+
onBlur?.(event)
8772
},
8873
[onBlur]
8974
)
9075

9176
const handleFocus = useCallback(
92-
(event: Event) => {
93-
onFocus?.(event as unknown as Parameters<NonNullable<typeof onFocus>>[0])
77+
(event: CustomEvent) => {
78+
onFocus?.(event)
9479
},
9580
[onFocus]
9681
)
9782

9883
const handleInvalid = useCallback(
99-
(event: Event) => {
100-
onInvalid?.(event as unknown as Parameters<NonNullable<typeof onInvalid>>[0])
84+
(event: CustomEvent) => {
85+
onInvalid?.(event)
10186
},
10287
[onInvalid]
10388
)
10489

90+
const combinedClassName = `flex items-center ${errorMessage ? 'error' : ''}`
91+
10592
return (
10693
<div className="relative">
107-
<sl-checkbox
108-
class={`flex items-center ${errorMessage ? 'error' : ''}`}
109-
value={checked}
110-
name={name || undefined}
94+
<SlCheckbox
95+
ref={checkboxRef}
96+
className={combinedClassName}
97+
name={name}
11198
size={size}
112-
disabled={disabled || undefined}
113-
checked={checked || undefined}
114-
indeterminate={indeterminate || undefined}
115-
defaultChecked={defaultChecked || undefined}
116-
form={form || undefined}
117-
required={required || undefined}
118-
onSlInput={handleInput}
99+
disabled={disabled}
100+
defaultChecked={checked ?? defaultChecked}
101+
indeterminate={indeterminate}
102+
form={form}
103+
required={required}
119104
onSlChange={handleChange}
105+
onSlInput={handleInput}
120106
onSlBlur={handleBlur}
121107
onSlFocus={handleFocus}
122108
onSlInvalid={handleInvalid}
@@ -126,7 +112,7 @@ export const RLCheckbox = forwardRef<RLCheckboxRef, RLCheckboxProps>(
126112
{label}
127113
</span>
128114
)}
129-
</sl-checkbox>
115+
</SlCheckbox>
130116
{errorMessage && <ErrorMessage>{errorMessage}</ErrorMessage>}
131117
</div>
132118
)

src/components/RLColorPicker/RLColorPicker.tsx

Lines changed: 21 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,11 @@
11
import { forwardRef, useCallback, useRef, useEffect } from 'react'
2+
import SlDropdown from '@shoelace-style/shoelace/dist/react/dropdown/index.js'
3+
import SlColorPicker from '@shoelace-style/shoelace/dist/react/color-picker/index.js'
4+
import SlButton from '@shoelace-style/shoelace/dist/react/button/index.js'
5+
import type SlColorPickerElement from '@shoelace-style/shoelace/dist/components/color-picker/color-picker.js'
26
import type { RLColorPickerProps } from './types'
37

4-
declare global {
5-
namespace JSX {
6-
interface IntrinsicElements {
7-
'sl-dropdown': React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement> & {
8-
hoist?: boolean
9-
open?: boolean
10-
}
11-
'sl-color-picker': React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement> & {
12-
hoist?: boolean
13-
inline?: boolean
14-
noFormatToggle?: boolean
15-
opacity?: boolean
16-
value?: string
17-
name?: string
18-
defaultValue?: string
19-
required?: boolean
20-
disabled?: boolean
21-
}
22-
}
23-
}
24-
}
25-
26-
export const RLColorPicker = forwardRef<HTMLElement, RLColorPickerProps>(
8+
export const RLColorPicker = forwardRef<SlColorPickerElement, RLColorPickerProps>(
279
(
2810
{
2911
value = '#000000',
@@ -39,7 +21,6 @@ export const RLColorPicker = forwardRef<HTMLElement, RLColorPickerProps>(
3921
ref
4022
) => {
4123
const colorPreviewRef = useRef<HTMLDivElement>(null)
42-
const slColorPickerRef = useRef<HTMLElement>(null)
4324

4425
useEffect(() => {
4526
if (colorPreviewRef.current && value) {
@@ -48,46 +29,46 @@ export const RLColorPicker = forwardRef<HTMLElement, RLColorPickerProps>(
4829
}, [value])
4930

5031
const handleChange = useCallback(
51-
(event: Event) => {
52-
const target = event.target as HTMLInputElement
32+
(event: CustomEvent) => {
33+
const target = event.target as SlColorPickerElement
5334
onChange?.(target?.value ?? '')
5435
},
5536
[onChange]
5637
)
5738

58-
const handleShow = useCallback((event: Event) => {
39+
const handleShow = useCallback((event: CustomEvent) => {
5940
event.stopPropagation()
6041
}, [])
6142

62-
const handleHide = useCallback((event: Event) => {
43+
const handleHide = useCallback((event: CustomEvent) => {
6344
event.stopPropagation()
6445
}, [])
6546

6647
return (
67-
<sl-dropdown ref={ref} hoist onsl-show={handleShow} onsl-hide={handleHide}>
48+
<SlDropdown hoist onSlShow={handleShow} onSlHide={handleHide}>
6849
<div className={className} slot="trigger">
6950
<div className="w-full">{label}</div>
70-
<sl-button class="w-full" caret disabled={disabled || undefined}>
51+
<SlButton className="w-full" caret disabled={disabled}>
7152
<div className="flex items-center gap-4">
7253
{value && <div ref={colorPreviewRef} className="w-6 h-6 rounded-full" />}
7354
{value}
7455
</div>
75-
</sl-button>
56+
</SlButton>
7657
</div>
77-
<sl-color-picker
78-
ref={slColorPickerRef}
58+
<SlColorPicker
59+
ref={ref}
7960
hoist
8061
inline
8162
noFormatToggle
82-
opacity={opacity || undefined}
63+
opacity={opacity}
8364
value={value}
84-
name={name || undefined}
85-
defaultValue={defaultValue || undefined}
86-
required={required || undefined}
87-
disabled={disabled || undefined}
88-
onsl-change={handleChange}
65+
name={name}
66+
defaultValue={defaultValue}
67+
required={required}
68+
disabled={disabled}
69+
onSlChange={handleChange}
8970
/>
90-
</sl-dropdown>
71+
</SlDropdown>
9172
)
9273
}
9374
)

0 commit comments

Comments
 (0)