Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 14 additions & 36 deletions src/components/RLButton/RLButton.tsx
Original file line number Diff line number Diff line change
@@ -1,31 +1,9 @@
import { forwardRef } from 'react'
import SlButton from '@shoelace-style/shoelace/dist/react/button/index.js'
import type SlButtonElement from '@shoelace-style/shoelace/dist/components/button/button.js'
import type { RLButtonProps } from './types'

declare global {
namespace JSX {
interface IntrinsicElements {
'sl-button': React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement> & {
variant?: string
size?: string
caret?: boolean
disabled?: boolean
loading?: boolean
outline?: boolean
pill?: boolean
circle?: boolean
type?: string
name?: string
value?: string
href?: string
target?: string
form?: string
class?: string
}
}
}
}

export const RLButton = forwardRef<HTMLElement, RLButtonProps>(
export const RLButton = forwardRef<SlButtonElement, RLButtonProps>(
(
{
variant = 'default',
Expand All @@ -51,29 +29,29 @@ export const RLButton = forwardRef<HTMLElement, RLButtonProps>(
ref
) => {
return (
<sl-button
<SlButton
ref={ref}
class={className}
className={className}
variant={variant}
size={size}
caret={caret || undefined}
disabled={disabled || undefined}
loading={loading || undefined}
outline={outline || undefined}
pill={pill || undefined}
circle={circle || undefined}
caret={caret}
disabled={disabled}
loading={loading}
outline={outline}
pill={pill}
circle={circle}
type={type}
name={name || undefined}
name={name}
value={value}
href={href || undefined}
href={href}
target={target}
form={form}
onClick={onClick}
>
{prefix && <span slot="prefix">{prefix}</span>}
{children}
{suffix && <span slot="suffix">{suffix}</span>}
</sl-button>
</SlButton>
)
}
)
Expand Down
96 changes: 41 additions & 55 deletions src/components/RLCheckbox/RLCheckbox.tsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,10 @@
import { forwardRef, useImperativeHandle, useCallback, useEffect } from 'react'
import { forwardRef, useImperativeHandle, useCallback, useEffect, useRef } from 'react'
import SlCheckbox from '@shoelace-style/shoelace/dist/react/checkbox/index.js'
import type SlCheckboxElement from '@shoelace-style/shoelace/dist/components/checkbox/checkbox.js'
import type { RLCheckboxProps, RLCheckboxRef } from './types'
import type { SlInputEvent } from '../utils/types'
import { ErrorMessage } from '../utils/ErrorMessage'
import { useValidation } from '../../hooks/useValidation'

declare global {
namespace JSX {
interface IntrinsicElements {
'sl-checkbox': React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement> & {
name?: string
value?: boolean
size?: string
disabled?: boolean
checked?: boolean
indeterminate?: boolean
defaultChecked?: boolean
form?: string
required?: boolean
class?: string
onSlInput?: (event: Event) => void
onSlChange?: (event: Event) => void
onSlBlur?: (event: Event) => void
onSlFocus?: (event: Event) => void
onSlInvalid?: (event: Event) => void
}
}
}
}

export const RLCheckbox = forwardRef<RLCheckboxRef, RLCheckboxProps>(
(
{
Expand All @@ -52,6 +29,13 @@ export const RLCheckbox = forwardRef<RLCheckboxRef, RLCheckboxProps>(
ref
) => {
const { errorMessage, isValid, validate } = useValidation({ rules, externalError: error })
const checkboxRef = useRef<SlCheckboxElement>(null)

useEffect(() => {
if (checkboxRef.current && checked !== undefined && checkboxRef.current.checked !== checked) {
checkboxRef.current.checked = checked
}
}, [checked])

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

const handleInput = useCallback(
(event: Event) => {
const evt = event as unknown as SlInputEvent
const target = evt.target as HTMLInputElement & { checked: boolean }
onChange?.(target?.checked ?? false)
onInput?.(evt)
const handleChange = useCallback(
(event: CustomEvent) => {
const target = event.target as SlCheckboxElement
const newChecked = target?.checked ?? false
validate(newChecked)
onChange?.(newChecked)
onSlChange?.(event)
},
[onChange, onInput]
[onChange, onSlChange, validate]
)

const handleChange = useCallback(
(event: Event) => {
onSlChange?.(event as unknown as Parameters<NonNullable<typeof onSlChange>>[0])
const handleInput = useCallback(
(event: CustomEvent) => {
onInput?.(event)
},
[onSlChange]
[onInput]
)

const handleBlur = useCallback(
(event: Event) => {
onBlur?.(event as unknown as Parameters<NonNullable<typeof onBlur>>[0])
(event: CustomEvent) => {
onBlur?.(event)
},
[onBlur]
)

const handleFocus = useCallback(
(event: Event) => {
onFocus?.(event as unknown as Parameters<NonNullable<typeof onFocus>>[0])
(event: CustomEvent) => {
onFocus?.(event)
},
[onFocus]
)

const handleInvalid = useCallback(
(event: Event) => {
onInvalid?.(event as unknown as Parameters<NonNullable<typeof onInvalid>>[0])
(event: CustomEvent) => {
onInvalid?.(event)
},
[onInvalid]
)

const combinedClassName = `flex items-center ${errorMessage ? 'error' : ''}`

return (
<div className="relative">
<sl-checkbox
class={`flex items-center ${errorMessage ? 'error' : ''}`}
value={checked}
name={name || undefined}
<SlCheckbox
ref={checkboxRef}
className={combinedClassName}
name={name}
size={size}
disabled={disabled || undefined}
checked={checked || undefined}
indeterminate={indeterminate || undefined}
defaultChecked={defaultChecked || undefined}
form={form || undefined}
required={required || undefined}
onSlInput={handleInput}
disabled={disabled}
defaultChecked={checked ?? defaultChecked}
indeterminate={indeterminate}
form={form}
required={required}
onSlChange={handleChange}
onSlInput={handleInput}
onSlBlur={handleBlur}
onSlFocus={handleFocus}
onSlInvalid={handleInvalid}
Expand All @@ -126,7 +112,7 @@ export const RLCheckbox = forwardRef<RLCheckboxRef, RLCheckboxProps>(
{label}
</span>
)}
</sl-checkbox>
</SlCheckbox>
{errorMessage && <ErrorMessage>{errorMessage}</ErrorMessage>}
</div>
)
Expand Down
61 changes: 21 additions & 40 deletions src/components/RLColorPicker/RLColorPicker.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,11 @@
import { forwardRef, useCallback, useRef, useEffect } from 'react'
import SlDropdown from '@shoelace-style/shoelace/dist/react/dropdown/index.js'
import SlColorPicker from '@shoelace-style/shoelace/dist/react/color-picker/index.js'
import SlButton from '@shoelace-style/shoelace/dist/react/button/index.js'
import type SlColorPickerElement from '@shoelace-style/shoelace/dist/components/color-picker/color-picker.js'
import type { RLColorPickerProps } from './types'

declare global {
namespace JSX {
interface IntrinsicElements {
'sl-dropdown': React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement> & {
hoist?: boolean
open?: boolean
}
'sl-color-picker': React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement> & {
hoist?: boolean
inline?: boolean
noFormatToggle?: boolean
opacity?: boolean
value?: string
name?: string
defaultValue?: string
required?: boolean
disabled?: boolean
}
}
}
}

export const RLColorPicker = forwardRef<HTMLElement, RLColorPickerProps>(
export const RLColorPicker = forwardRef<SlColorPickerElement, RLColorPickerProps>(
(
{
value = '#000000',
Expand All @@ -39,7 +21,6 @@ export const RLColorPicker = forwardRef<HTMLElement, RLColorPickerProps>(
ref
) => {
const colorPreviewRef = useRef<HTMLDivElement>(null)
const slColorPickerRef = useRef<HTMLElement>(null)

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

const handleChange = useCallback(
(event: Event) => {
const target = event.target as HTMLInputElement
(event: CustomEvent) => {
const target = event.target as SlColorPickerElement
onChange?.(target?.value ?? '')
},
[onChange]
)

const handleShow = useCallback((event: Event) => {
const handleShow = useCallback((event: CustomEvent) => {
event.stopPropagation()
}, [])

const handleHide = useCallback((event: Event) => {
const handleHide = useCallback((event: CustomEvent) => {
event.stopPropagation()
}, [])

return (
<sl-dropdown ref={ref} hoist onsl-show={handleShow} onsl-hide={handleHide}>
<SlDropdown hoist onSlShow={handleShow} onSlHide={handleHide}>
<div className={className} slot="trigger">
<div className="w-full">{label}</div>
<sl-button class="w-full" caret disabled={disabled || undefined}>
<SlButton className="w-full" caret disabled={disabled}>
<div className="flex items-center gap-4">
{value && <div ref={colorPreviewRef} className="w-6 h-6 rounded-full" />}
{value}
</div>
</sl-button>
</SlButton>
</div>
<sl-color-picker
ref={slColorPickerRef}
<SlColorPicker
ref={ref}
hoist
inline
noFormatToggle
opacity={opacity || undefined}
opacity={opacity}
value={value}
name={name || undefined}
defaultValue={defaultValue || undefined}
required={required || undefined}
disabled={disabled || undefined}
onsl-change={handleChange}
name={name}
defaultValue={defaultValue}
required={required}
disabled={disabled}
onSlChange={handleChange}
/>
</sl-dropdown>
</SlDropdown>
)
}
)
Expand Down
Loading