✨(frontend) add Switch Field component with custom layout handling
Introduce new Field variant using Switch input with different props structure from other input components. Displays description after switch component rather than mixed with label due to layout requirements, preventing reuse of standard label and description composition patterns.
This commit is contained in:
committed by
aleb_the_flash
parent
34fde10854
commit
740355d494
@@ -20,6 +20,7 @@ import { Checkbox } from './Checkbox'
|
||||
import { Select } from './Select'
|
||||
import { Text } from './Text'
|
||||
import { Div } from './Div'
|
||||
import { Switch, type SwitchProps } from './Switch'
|
||||
import { css } from '@/styled-system/css'
|
||||
|
||||
const FieldWrapper = styled('div', {
|
||||
@@ -67,6 +68,7 @@ type PartialSelectProps<T extends object> = Omit<
|
||||
SelectProps<T>,
|
||||
OmittedRACProps
|
||||
>
|
||||
type PartialSwitchProps = Omit<SwitchProps, OmittedRACProps>
|
||||
type FieldProps<T extends object> = (
|
||||
| ({
|
||||
type: 'text'
|
||||
@@ -101,6 +103,11 @@ type FieldProps<T extends object> = (
|
||||
validate?: (value: T) => ReactNode | ReactNode[] | true | null | undefined
|
||||
} & Items<string> &
|
||||
PartialSelectProps<T>)
|
||||
| ({
|
||||
type: 'switch'
|
||||
items?: never
|
||||
validate?: never
|
||||
} & PartialSwitchProps)
|
||||
) & {
|
||||
label: string
|
||||
description?: string
|
||||
@@ -250,6 +257,34 @@ export const Field = <T extends object>({
|
||||
</FieldWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
if (type === 'switch') {
|
||||
return (
|
||||
<FieldWrapper {...props.wrapperProps}>
|
||||
<div
|
||||
className={css({
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
})}
|
||||
>
|
||||
{label}
|
||||
<Switch aria-label={label} {...(props as PartialSwitchProps)} />
|
||||
</div>
|
||||
{description && (
|
||||
<Text
|
||||
variant="note"
|
||||
wrap={'pretty'}
|
||||
className={css({
|
||||
textStyle: 'sm',
|
||||
marginBottom: '0.5rem',
|
||||
})}
|
||||
>
|
||||
{description}
|
||||
</Text>
|
||||
)}
|
||||
</FieldWrapper>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const FieldItem = ({
|
||||
|
||||
@@ -4,7 +4,6 @@ import {
|
||||
} from 'react-aria-components'
|
||||
import { styled } from '@/styled-system/jsx'
|
||||
import { StyledVariantProps } from '@/styled-system/types'
|
||||
import { ReactNode } from 'react'
|
||||
|
||||
export const StyledSwitch = styled(RACSwitch, {
|
||||
base: {
|
||||
@@ -100,21 +99,25 @@ export const StyledSwitch = styled(RACSwitch, {
|
||||
})
|
||||
|
||||
export type SwitchProps = StyledVariantProps<typeof StyledSwitch> &
|
||||
RACSwitchProps & { children: ReactNode }
|
||||
RACSwitchProps
|
||||
|
||||
/**
|
||||
* Styled RAC Switch.
|
||||
*/
|
||||
export const Switch = ({ children, ...props }: SwitchProps) => (
|
||||
<StyledSwitch {...props}>
|
||||
<div className="indicator">
|
||||
<span className="checkmark" aria-hidden="true">
|
||||
✓
|
||||
</span>
|
||||
<span className="cross" aria-hidden="true">
|
||||
✕
|
||||
</span>
|
||||
</div>
|
||||
{children}
|
||||
{(renderProps) => (
|
||||
<>
|
||||
<div className="indicator">
|
||||
<span className="checkmark" aria-hidden="true">
|
||||
✓
|
||||
</span>
|
||||
<span className="cross" aria-hidden="true">
|
||||
✕
|
||||
</span>
|
||||
</div>
|
||||
{typeof children === 'function' ? children(renderProps) : children}
|
||||
</>
|
||||
)}
|
||||
</StyledSwitch>
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user