You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
220 lines
6.5 KiB
220 lines
6.5 KiB
'use client';
|
|
import React from 'react';
|
|
import { createRadio } from '@gluestack-ui/radio';
|
|
import { Pressable, View, Platform, Text } from 'react-native';
|
|
import { tva } from '@gluestack-ui/nativewind-utils/tva';
|
|
import {
|
|
withStyleContext,
|
|
useStyleContext,
|
|
} from '@gluestack-ui/nativewind-utils/withStyleContext';
|
|
import { cssInterop } from 'nativewind';
|
|
import type { VariantProps } from '@gluestack-ui/nativewind-utils';
|
|
import { PrimitiveIcon, UIIcon } from '@gluestack-ui/icon';
|
|
|
|
const SCOPE = 'Radio';
|
|
|
|
const UIRadio = createRadio({
|
|
Root: (Platform.OS === 'web'
|
|
? withStyleContext(View, SCOPE)
|
|
: withStyleContext(Pressable, SCOPE)) as ReturnType<
|
|
typeof withStyleContext<typeof Pressable>
|
|
>,
|
|
Group: View,
|
|
Icon: UIIcon,
|
|
Indicator: View,
|
|
Label: Text,
|
|
});
|
|
|
|
cssInterop(PrimitiveIcon, {
|
|
className: {
|
|
target: 'style',
|
|
nativeStyleToProp: {
|
|
height: true,
|
|
width: true,
|
|
fill: true,
|
|
color: 'classNameColor',
|
|
stroke: true,
|
|
},
|
|
},
|
|
});
|
|
|
|
const radioStyle = tva({
|
|
base: 'group/radio flex-row justify-start items-center web:cursor-pointer data-[disabled=true]:web:cursor-not-allowed',
|
|
variants: {
|
|
size: {
|
|
sm: 'gap-1.5',
|
|
md: 'gap-2',
|
|
lg: 'gap-2',
|
|
},
|
|
},
|
|
});
|
|
|
|
const radioGroupStyle = tva({
|
|
base: 'gap-2',
|
|
});
|
|
|
|
const radioIconStyle = tva({
|
|
base: 'rounded-full justify-center items-center text-primary-800 fill-primary-800',
|
|
|
|
parentVariants: {
|
|
size: {
|
|
sm: 'h-[9px] w-[9px]',
|
|
md: 'h-3 w-3',
|
|
lg: 'h-4 w-4',
|
|
},
|
|
},
|
|
});
|
|
|
|
const radioIndicatorStyle = tva({
|
|
base: 'justify-center items-center bg-transparent border-outline-400 border-2 rounded-full data-[focus-visible=true]:web:outline-2 data-[focus-visible=true]:web:outline-primary-700 data-[focus-visible=true]:web:outline data-[checked=true]:border-primary-600 data-[checked=true]:bg-transparent data-[hover=true]:border-outline-500 data-[hover=true]:bg-transparent data-[hover=true]:data-[checked=true]:bg-transparent data-[hover=true]:data-[checked=true]:border-primary-700 data-[hover=true]:data-[invalid=true]:border-error-700 data-[hover=true]:data-[disabled=true]:opacity-40 data-[hover=true]:data-[disabled=true]:border-outline-400 data-[hover=true]:data-[disabled=true]:data-[invalid=true]:border-error-400 data-[active=true]:bg-transparent data-[active=true]:border-primary-800 data-[invalid=true]:border-error-700 data-[disabled=true]:opacity-40 data-[disabled=true]:data-[checked=true]:border-outline-400 data-[disabled=true]:data-[checked=true]:bg-transparent data-[disabled=true]:data-[invalid=true]:border-error-400',
|
|
parentVariants: {
|
|
size: {
|
|
sm: 'h-4 w-4',
|
|
md: 'h-5 w-5',
|
|
lg: 'h-6 w-6',
|
|
},
|
|
},
|
|
});
|
|
|
|
const radioLabelStyle = tva({
|
|
base: 'text-typography-600 data-[checked=true]:text-typography-900 data-[hover=true]:text-typography-900 data-[hover=true]:data-[disabled=true]:text-typography-600 data-[hover=true]:data-[disabled=true]:data-[checked=true]:text-typography-900 data-[active=true]:text-typography-900 data-[active=true]:data-[checked=true]:text-typography-900 data-[disabled=true]:opacity-40 web:select-none',
|
|
parentVariants: {
|
|
size: {
|
|
'2xs': 'text-2xs',
|
|
'xs': 'text-xs',
|
|
'sm': 'text-sm',
|
|
'md': 'text-base',
|
|
'lg': 'text-lg',
|
|
'xl': 'text-xl',
|
|
'2xl': 'text-2xl',
|
|
'3xl': 'text-3xl',
|
|
'4xl': 'text-4xl',
|
|
'5xl': 'text-5xl',
|
|
'6xl': 'text-6xl',
|
|
},
|
|
},
|
|
});
|
|
|
|
type IRadioProps = Omit<React.ComponentProps<typeof UIRadio>, 'context'> &
|
|
VariantProps<typeof radioStyle>;
|
|
const Radio = React.forwardRef<React.ComponentRef<typeof UIRadio>, IRadioProps>(
|
|
function Radio({ className, size = 'md', ...props }, ref) {
|
|
return (
|
|
<UIRadio
|
|
className={radioStyle({ class: className, size })}
|
|
{...props}
|
|
ref={ref}
|
|
context={{ size }}
|
|
/>
|
|
);
|
|
}
|
|
);
|
|
|
|
type IRadioGroupProps = React.ComponentProps<typeof UIRadio.Group> &
|
|
VariantProps<typeof radioGroupStyle>;
|
|
const RadioGroup = React.forwardRef<
|
|
React.ComponentRef<typeof UIRadio.Group>,
|
|
IRadioGroupProps
|
|
>(function RadioGroup({ className, ...props }, ref) {
|
|
return (
|
|
<UIRadio.Group
|
|
className={radioGroupStyle({ class: className })}
|
|
{...props}
|
|
ref={ref}
|
|
/>
|
|
);
|
|
});
|
|
|
|
type IRadioIndicatorProps = React.ComponentProps<typeof UIRadio.Indicator> &
|
|
VariantProps<typeof radioIndicatorStyle>;
|
|
const RadioIndicator = React.forwardRef<
|
|
React.ComponentRef<typeof UIRadio.Indicator>,
|
|
IRadioIndicatorProps
|
|
>(function RadioIndicator({ className, ...props }, ref) {
|
|
const { size } = useStyleContext(SCOPE);
|
|
return (
|
|
<UIRadio.Indicator
|
|
className={radioIndicatorStyle({
|
|
parentVariants: { size },
|
|
class: className,
|
|
})}
|
|
ref={ref}
|
|
{...props}
|
|
/>
|
|
);
|
|
});
|
|
|
|
type IRadioLabelProps = React.ComponentProps<typeof UIRadio.Label> &
|
|
VariantProps<typeof radioIndicatorStyle>;
|
|
const RadioLabel = React.forwardRef<
|
|
React.ComponentRef<typeof UIRadio.Label>,
|
|
IRadioLabelProps
|
|
>(function RadioLabel({ className, ...props }, ref) {
|
|
const { size } = useStyleContext(SCOPE);
|
|
return (
|
|
<UIRadio.Label
|
|
className={radioLabelStyle({
|
|
parentVariants: { size },
|
|
class: className,
|
|
})}
|
|
ref={ref}
|
|
{...props}
|
|
/>
|
|
);
|
|
});
|
|
|
|
type IRadioIconProps = React.ComponentProps<typeof UIRadio.Icon> &
|
|
VariantProps<typeof radioIconStyle> & {
|
|
height?: number;
|
|
width?: number;
|
|
};
|
|
const RadioIcon = React.forwardRef<
|
|
React.ComponentRef<typeof UIRadio.Icon>,
|
|
IRadioIconProps
|
|
>(function RadioIcon({ className, size, ...props }, ref) {
|
|
const { size: parentSize } = useStyleContext(SCOPE);
|
|
|
|
if (typeof size === 'number') {
|
|
return (
|
|
<UIRadio.Icon
|
|
ref={ref}
|
|
{...props}
|
|
className={radioIconStyle({ class: className })}
|
|
size={size}
|
|
/>
|
|
);
|
|
} else if (
|
|
(props.height !== undefined || props.width !== undefined) &&
|
|
size === undefined
|
|
) {
|
|
return (
|
|
<UIRadio.Icon
|
|
ref={ref}
|
|
{...props}
|
|
className={radioIconStyle({ class: className })}
|
|
/>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<UIRadio.Icon
|
|
{...props}
|
|
className={radioIconStyle({
|
|
parentVariants: {
|
|
size: parentSize,
|
|
},
|
|
size,
|
|
class: className,
|
|
})}
|
|
ref={ref}
|
|
/>
|
|
);
|
|
});
|
|
|
|
Radio.displayName = 'Radio';
|
|
RadioGroup.displayName = 'RadioGroup';
|
|
RadioIndicator.displayName = 'RadioIndicator';
|
|
RadioLabel.displayName = 'RadioLabel';
|
|
RadioIcon.displayName = 'RadioIcon';
|
|
|
|
export { Radio, RadioGroup, RadioIndicator, RadioLabel, RadioIcon };
|